Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  md-d2d-rendezvous.proto   Sprache: unbekannt

 
Spracherkennung für: .proto vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// ## Connection Rendezvous Protocol
//
// Some mechanisms may request a 1:1 connection between two devices in order to
// transmit data as direct as possible. Establishing such a connection should
// always require user interaction.
//
// The protocol runs an authentication **handshake** on multiple paths
// simultaneously and applies a heuristic to determine the best available path.
// One of the devices is eligible to **nominate** a path after which arbitrary
// encrypted payloads may be exchanged.
//
// ### Terminology
//
// - `RID`: Rendezvous Initiator Device
// - `RRD`: Rendezvous Responder Device
// - `AK`: Authentication Key
// - `ETK`: Ephemeral Transport Key
// - `STK`: Shared Transport Key
// - `PID`: Path ID
// - `RPH`: Rendevous Path Hash
// - `RIDAK`: RID's Authentication Key
// - `RRDAK`: RRD's Authentication Key
// - `RIDTK`: RID's Transport Key
// - `RRDTK`: RRD's Transport Key
// - `RIDSN`: RID's Sequence Number
// - `RRDSN`: RRD's Sequence Number
//
// ### General Information
//
// **Sequence number:** The sequence number starts with `1` and is counted
// separately for each direction (i.e. there is one sequence number counter for
// the client and one for the server). We will use `RIDSN+` and `RRDSN+` in this
// document to denote that the counter should be increased **after** the value
// has been inserted (i.e. semantically equivalent to `x++` in many languages).
//
// **Framing:** An `extra.transport.frame` is being used to frame all
// transmitted data even if the transport supports datagrams. This intentionally
// allows to fragment a frame across multiple datagrams (e.g. useful for limited
// APIs that cannot deliver data in a streamed fashion).
//
// ### Key Derivation
//
//     RIDAK = BLAKE2b(key=AK.secret, salt='rida', personal='3ma-rendezvous')
//     RRDAK = BLAKE2b(key=AK.secret, salt='rrda', personal='3ma-rendezvous')
//
//     STK = BLAKE2b(
//       key=
//           AK.secret
//        || X25519HSalsa20(<local.ETK>.secret, <remote.ETK>.public)
//       salt='st',
//       personal='3ma-rendezvous'
//     )
//
//     RIDTK = BLAKE2b(key=STK.secret, salt='ridt', personal='3ma-rendezvous')
//     RRDTK = BLAKE2b(key=STK.secret, salt='rrdt', personal='3ma-rendezvous')
//
// ### Encryption Schemes
//
// RID's encryption scheme is defined in the following way:
//
//     ChaCha20-Poly1305(
//       key=<RID*K.secret>,
//       nonce=u32-le(PID) || u32-le(RIDSN+) || <4 zero bytes>,
//     )
//
// RRD's encryption scheme is defined in the following way:
//
//     ChaCha20-Poly1305(
//       key=<RRD*K.secret>,
//       nonce=u32-le(PID) || u32-le(RRDSN+) || <4 zero bytes>,
//     )
//
// ### Rendezvous Path Hash Derivation
//
// A Rendezvous Path Hash (RPH) can be used to ensure that both parties are
// connected to each other and not to some other party who was able to intercept
// AK:
//
//     RPH = BLAKE2b(
//       out-length=32,
//       salt='ph',
//       personal='3ma-rendezvous',
//       input=STK.secret,
//     )
//
// ### Path Matrix
//
//     | Name              | Multiple Paths |
//     |-------------------|----------------|
//     | Direct TCP Server | Yes            |
//     | Relayed WebSocket | No             |
//
// ### Protocol Flow
//
// Connection paths are formed by transmitting a `rendezvous.RendezvousInit`
// from RID to RRD as defined in the description of that message.
//
// The connections are then simultaneously established in the background and
// each path must go through the handshake flow with its authentication
// challenges. While doing so, the peers measure the RTT between challenge and
// response in order to determine a good path candidate for nomination.
//
// One of the peers, defined by the upper-layer protocol, nominates one of the
// established paths. Once nominated, both peers close all other paths (WS:
// `1000`).
//
// Once a path has been nominated, that path will be handed to the upper-layer
// protocol for arbitrary data transmission. That data must be protected by
// continuing the respective encryption scheme of the associated role.
//
// ### Handshake Flow
//
// RRD and RID authenticate one another by the following flow:
//
//     RRD ---- Handshake.RrdToRid.Hello ---> RID
//     RRD <- Handshake.RidToRrd.AuthHello -- RID
//     RRD ---- Handshake.RrdToRid.Auth ----> RID
//
// Before the path can be used by the upper-layer protocol, the chosen path must
// be `Nominate`d by either side. The upper-layer protocol must define which
// side may `Nominate`.
//
//     R*D ------- Handshake.Nominate ------> R*D
//
// ### Path Nomination
//
// The following algorithm should be used to determine which path is to be
// nominated. The upper-layer protocol must clearly define whether RRD or RID
// does nomination.
//
// 1. Let `established` be the list of established connection paths.
// 2. Asynchronously, with each connection becoming established, update
//    `established` with the RTT that was measured during the handshake.
// 3. Wait for the first connection path to become established.
// 4. After a brief timeout (or on a specific user interaction), nominate the
//    connection path in the following way, highest priority first:
//    1. Path with the lowest RTT on a mutually unmetered, fast network
//    2. Path with the lowest RTT on a mutually unmetered, slow network
//    3. Path with the lowest RTT on any other network
//
// Note: It is recommended to warn the user if a metered connection path has
// been nominated in case large amounts of data are to be transmitted.
//
// ### WebSocket Close Codes
//
// When WebSocket is used as rendezvous transport, the following close codes
// should be used:
//
// - Normal (`1000`): The rendezvous connection was not nominated or the
//   upper-layer protocol exited successfully.
// - Rendezvous Protocol Error (`4000`): The rendezvous protocol was violated.
//   Possible examples: Invalid WebSocket path, session full. Error details may
//   be included in the WebSocket close _reason_.
// - Init Timeout (`4003`): The other device did not connect in time.
// - Other Device Disconnected (`4004`): The other device disconnected without a
//   reflectable close code.
// - Upper-Layer Protocol Error (`4100`): The rendezvous connection was
//   nominated but an upper-layer protocol error occurred.
//
// The device should log all other close codes but treat them as a _Rendezvous
// Protocol Error_ (`4000`).
//
// Close codes in the `41xx` range as well as `1000` are reflected by the
// rendezvous server to the other device.
//
// ### Security
//
// To prevent phishing attacks, the CORS `Access-Control-Allow-Origin` of any
// WebSocket rendezvous relay server should be set to the bare minimum required
// by the use case.
//
// ### Threat Model
//
// The security of the protocol relies on the security of the secure channel
// where the `RendezvousInit` is being exchanged.
//
// Arbitrary WebSocket URLs and arbitrary IPv4/IPv6 addresses can be provided by
// RID where RRD would connect to. It is therefore required that RRD can trust
// RID to not be malicious.
//
// AK must be exchanged over a sufficiently secure channel. Concretely, AK must
// be sufficiently protected to at least resist a brute-force attack for the
// time between AK being exchanged and the handshake being fulfilled.
//
// A PID must be unique and not be re-used for a specific AK.

syntax = "proto3";

package rendezvous;

option java_package = "ch.threema.protobuf.d2d.rendezvous";

// Contains the data necessary to initialise a 1:1 connection between two
// devices.
//
// When creating this message, run the following sub-steps simultaneously and
// wait for them to finish:
//
// 1. If the device is able to create a TCP server socket:
//    1. Bind to _any_ IP address with a random port number. Silently ignore
//       failures.
//    2. If successful, let `addresses` be the list of available IP addresses on
//       network interfaces the server has been bound to.
//    3. Drop any loopback and duplicate IP addresses from `addresses`.
//    4. Drop link-local IPv6 addresses associated to interfaces that only
//       provide link-local IPv6 addresses.
//    5. Sort `addresses` in the following way, highest priority first:
//         1. IP addresses on unmetered, fast networks
//         2. IP addresses on unmetered, slow networks
//         3. IP addresses on metered, fast networks
//         4. Any other addresses
//    6. Complete the subroutine and provide `addresses` and other necessary
//       data in the `direct_tcp_server` field.
// 2. Connect to a WebSocket relay server:
//    1. Generate a random 32 byte hex-encoded rendezvous path.
//    2. Connect to the WebSocket relay server URL as provided by the context
//       with the generated hex-encoded rendezvous path.
//    3. Once connected, complete the subroutine and provide the necessary data
//       in the `relayed_web_socket` field.
//
// When receiving this message:
//
// 1. If `version` is unsupported, abort these steps.
// 2. If any `path_id` is not unique, abort these steps.
// 3. If the device is able to create a TCP client connection:
//    1. Let `addresses` be the IP addresses of `direct_tcp_server`.
//    2. Filter `addresses` by discarding IPs with unsupported families (e.g. if
//       the device has no IPv6 address, drop any IPv6 addresses).
//    3. For each IP address in `addresses`:
//       1. Connect to the given IP address in the background.
//       2. Wait 100ms.
// 4. Connect to the provided relayed WebSocket server in the background.
// 5. On each successful direct or relayed connection made in the background,
//    forward an event to the upper-layer protocol in order for it to select one
//    of the paths for nomination.
message RendezvousInit {
  enum Version {
    // Initial version.
    V1_0 = 0;
  }
  Version version = 1;

  // 32 byte ephemeral secret Authentication Key (AK).
  bytes ak = 2;

  // Network cost of an interface
  enum NetworkCost {
    // It is unknown whether the interface is metered or unmetered
    UNKNOWN = 0;
    // The interface is unmetered
    UNMETERED = 1;
    // The interface is metered
    METERED = 2;
  }

  // Relayed WebSocket path
  message RelayedWebSocket {
    // Unique Path ID (PID) of the path
    uint32 path_id = 1;

    // Network cost
    NetworkCost network_cost = 2;

    // Full URL to the WebSocket server with a random 32 byte hex-encoded
    // rendezvous path. Must begin with `wss://`.
    string url = 3;
  }
  RelayedWebSocket relayed_web_socket = 3;

  // Direct path to a TCP server created by the initiator
  message DirectTcpServer {
    // Random 16 bit port. Values greater than 65535 are invalid.
    uint32 port = 1;

    // List of associated IP addresses. Each IP address creates its own path.
    repeated IpAddress ip_addresses = 2;

    // An IP address
    message IpAddress {
      // Unique Path ID (PID) of the path
      uint32 path_id = 1;

      // Network cost
      NetworkCost network_cost = 2;

      // IPv4 or IPv6 address
      string ip = 3;
    }
  }
  DirectTcpServer direct_tcp_server = 4;
}

// Messages required for the initial lock-step handshake between RRD and RID.
message Handshake {
  // Handshake messages from RRD to RID.
  message RrdToRid {
    // Initial message from RRD containing its authentication challenge,
    // encrypted by RRD's encryption scheme with RRDAK.
    message Hello {
      // 16 byte random authentication challenge for RID.
      bytes challenge = 1;

      // 32 byte ephemeral public key (`ETK.public`).
      bytes etk = 2;
    }

    // Final message from RRD responding to RID's authentication challenge,
    // encrypted by RRD's encryption scheme with RRDAK.
    //
    // When receiving this message:
    //
    // 1. If the challenge `response` from RRD does not match the challenge sent
    //    by RID, close the connection with a protocol error (WS: `4000`) and
    //    abort these steps.
    message Auth {
      // 16 byte repeated authentication challenge from RRD.
      bytes response = 1;
    }
  }

  // Handshake messages from RID to RRD.
  message RidToRrd {
    // Initial message from RID responding to RRD's authentication challenge and
    // containing RID's authentication challenge, encrypted by RID's encryption
    // scheme with RIDAK.
    //
    // When receiving this message:
    //
    // 1. If the challenge `response` from RID does not match the challenge sent
    //    by RRD, close the connection with a protocol error (WS: `4000`) and
    //    abort these steps.
    message AuthHello {
      // 16 byte repeated authentication challenge from RRD.
      bytes response = 1;

      // 16 byte random authentication challenge for RRD.
      bytes challenge = 2;

      // 32 byte ephemeral public key (`ETK.public`).
      bytes etk = 3;
    }
  }
}

// Nominates the path. The upper-layer protocol defines whether RID or RRD may
// nominate and is encrypted by the respective encryption scheme with RIDTK or
// RRDTK.
//
// When receiving this message:
//
// 1. If the sender was not eligible to `Nominate`, close the connection with a
//    protocol error (WS: `4000`) and abort these steps.
// 2. Close all other pending or established connection paths (WS: `1000`).¹
//
// ¹: Closing other paths is only triggered by the receiver as it may otherwise
//    lead to a race between nomination and close detection.
message Nominate {}

[Dauer der Verarbeitung: 0.15 Sekunden, vorverarbeitet 2026-04-27]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge