diff --git a/openvpn-wire-protocol.xml b/openvpn-wire-protocol.xml index 21de264..6cf3bc1 100644 --- a/openvpn-wire-protocol.xml +++ b/openvpn-wire-protocol.xml @@ -980,13 +980,32 @@ available) to drop revoked keys.) Control CONTROL_HARD_RESET_CLIENT_V3 X - Current + 11 Control CONTROL_WKC_V1 X Current + + 12 + Control + CONTROL_OOB_V1 + X + Current + + 13 + Control + CONTROL_OOB_WKC_V1 + X + Current + + 14 + Control + CONTROL_DATA_V1 + X + Current + @@ -1331,6 +1350,55 @@ available) to drop revoked keys.) message. See TLS crypt v2 for details. +
+ + The CONTROL_OOB_V1 message carries messages that do not belong to an established control. + Instead this message carries a message like a server ping. Since these message are out-of-band + they are inherently considered unreliable. There is no protocol level provision to retry + messages. + + + These share the same control channel protection and wrapping as regular control channel message. + When tls-crypt is not used, the messages are unencrypted and without tls-auth even unauthenticated. + That means that when designing messages, this should be kept in mind. + +
+ +
+ + Identical to the CONTROL_OOB_V1 message but with a wrapped client key appended to the message + similar to the CONTROL_HARD_RESET_CLIENT_V3/CONTROL_WKC_V1 message. + + Since the messages do not belong to an already established session, the client + needs to append the WKc to allow the server to process the message if tls-crypt-v2 is used. + See TLS crypt v2 for details. + +
+ +
+ + The CONTROL_DATA_V1 uses an identical framing, replay protection and packet format + to the DATA_V2 message. Its purpose is to send unreliable data to a peer without the + need to use the data channel. This can be used for things like MTU discovery or other + unreliable messages that need to be exchanged between the control plane instances. + + + These packets will use the same cipher as negotiated for the data channel. In contrast to + the data channel that support multiple different data for different generations of + OpenVPN peers, this message only supports epoch + data channel format. + + If the peer does not support TLS EKM and data epoch, the feature of CONTROL_DATA_V1 + is not available. If the negotiated data channel cipher is not an AEAD cipher, the + feature is not available either. + + + Earlier OpenVPN version had a similar protocol called OCC (option consistency check) + that relied on a special prefix for data message to implement MTU discovery. With + the strict separation of control channel and data channel (e.g. via DCO), this + approach is no longer a viable option. + +
@@ -1512,6 +1580,7 @@ struct key_exchange { has a 48 bit packet counters together with a 16 bit key-id that form a 64-bit packet id.
  • bit 11: The client is capable of parsing and receiving the dns messages pushed option.
  • bit 12: The client is capable of receiving PUSH_UPDATE message.
  • +
  • bit 13: The client is capable of receiving and replying to the ECHO_REQ CONTROL_DATA_V1 message
  • @@ -1554,7 +1623,7 @@ struct key_exchange {
    - Negotiation is the process in which two peers agree on the optional features and other negotiable paramters. Some + Negotiation is the process in which two peers agree on the optional features and other negotiable parameters. Some asepects of the protocol cannot be negotiated like tls-crypt or tls-auth as these need to be identical to establish a connection. @@ -1902,7 +1971,6 @@ struct { previous epoch keys if they don't want to make this trade-off.
    -
    Whenever a reneogiation of a key has finshed, a new data channel key is generated. @@ -1941,6 +2009,28 @@ struct { limit themselves just two key slots with either active/pending or active/retired and in this scenario will drop active key without moving it to retired state first. +
    +
    + + The encryption and replay protection of the CONTROL_DATA_V1 packets is + identical to the DATA_V2 packets using epoch data keys. However, the amount + of data packets on this channel is expected to be quite low, so the key rotation + is not necessary. Instead of providing a window of epoch keys that can + decrypt the messages, only epoch key 1 will be used. + + + Since we want distinct keys from the data channel to avoid key reuse, the + control data keys will be generated using: + + K_i = OVPN-Expand-Label(E_i, "control_data_key", "", key_size) + implicit_iv = OVPN-Expand-Label(E_i, "control_data_iv", "", implicit_iv_len) + + + + While this key generation allows generation for other epochs than epoch 1, an + implementation is only required to generate and accept packets encrypted with + epoch 1. +
    @@ -2481,8 +2571,373 @@ INFO,EXTRA
    +
    + + This section details the format of the payload used by the CONTROL_DATA_V1, CONTROL_OOB_V1 and CONTROL_OOB_WKC_V1. + Anything that uses OOB messages might be unencrypted and unauthenticated. Unless specified otherwise, all integers + are using network byte order (big endian). + + + Note that even though OOB and CONTROL_DATA are distinct we define the op codes to be from the same numerical space to avoid + confusion. We also start the type at 0x100 to avoid confusion with the op codes of the OpenVPN packet opcodes and start TLV + types at 0x200. + +
    + + The embedding follows the same format as normal P_CONTROL_V1 packets but without the fields required for reliability layer. I.e. a normal + packet without tls-auth or tls-crypt will still have the Session ID but not have the message packet id or acked message ids: + +struct oob_control_v1_no_auth { + uint opcode:5; + uint key_id:3; + uint64 own_session_id; + uint8 oob_payload[]; +} + + + + And for tls-auth and tls-crypt this includes the required replay packet id and other attributes that these wrapping schemes require. Example for tls-auth: + +struct oob_control_v1_tls_auth { + int opcode:5; + int keyid:3; + uint64_t own_session_id; + uint8[16-64] hmac; + uint64_t replay_packet_id; + uint8_t oob_payload[]; +} + + Example for tls-crypt: + +struct oob_control_tlscrypt { + int opcode:5; + int keyid:3; + uint64_t own_session_id; + uint64_t replay_packet_id; + uint8 auth_tag[32]; + uint8[] enc_oob_payload; +} + + The CONTROL_OOB_WKC_V1 variant will have the wrapped client key after the enc_oob_payload. The enc_oob_payload is the same as + the oob_payload in the previous two example, just with the required tls-crypt based encryption. + + + The own_session_id is same ID that the client would use to establish a connection with this server but is not required to + use the same. Since neither tls-auth nor tls-crypt-the replay_packet_id are strictly tied to a connection but rather use + a global state the client should use the same rules. This includes avoiding to reuse replay_packet_id ids and + have ids going backwards. + +
    +
    + + The packet structure is quite simple. The structure starts with a type and then has a number of TLV entries: + + +struct { + uint16 type; + tlv_entry entries[]; +} + + + + The individual TLV entries have the following structure + +struct tlv_entry { + int optional:1; + int type:15; + uint16 length; + uint8 data[]; +} + + + The boolean bit optional, which can also been seen as the highest bit of the type field, indicates if a client can ignore an unknown TLV entry. + + If this bit is set to 1 an implementation that does not understand a specific TLV entry type SHOULD + ignore this TLV entry and treat the message as if this TLV was not present. + + + + The length field does not include the header of the TLV and defines the length of the data of the TLV. For example, a TLV + with a length field of 7 will be 11 bytes long (4 byte header + 7 byte data). + +
    +
    + + Type + Name + OOB + CONTROL + + 0x100 + SERVER_PROBE + x + + + 0x101 + PROBE_REPLY + x + + + + 0x102 + ECHO_REQ + + x + + 0x103 + ECHO_REPLY + + x + + 0x104 + ACC + + x + + +
    +
    + + This details the currently defined TLV entries. + + + Overview of all defined TLV entries. + + + Type + Name + OOB + CONTROL + + 0x200 + probe parameter + x + + + 0x201 + probe reply + x + + + 0x202 + echo request parameter + + x + + 0x203 + echo reply + + x + + + 0x204 + ACC message + + x + + + +
    + + The probe parameter TLV contains a simple timestamp to indicate the current time of the client and indicates client capabilities. + +struct probe_parameter { + int optional:1 = 0; + int type:15 = 0x200; + uint16 length = 12; + uint64 timestamp; + uint32 flags; +} + + + + The timestamp value should be set to the current time as UNIX timestamp as returned by + functions like the gettimeofday function. + + + Any OOB SERVER_PROBE MUST include this TLV. The timestamp allows a server to silently + drop any request that is not in an acceptable window of time to reduce the attack + surface for replay attacks. + + + The flags field indicates client capabilities that need to be known early in the handshake. Must be 0. + + + This TLV is considered to be extendable in the future. A server encountering a longer length than they + expect, should ignore the excess bytes. The minimum length of this struct is 12 bytes. Smaller sizes are + considered invalid. + +
    +
    + + The probe reply TLV is intended to be present in a PROBE_REPLY from a server. It gives the client + feedback about the viability of the server beyond the round-trip of the probe request and its reply. + + +struct probe_reply { + int optional:1 = 0; + int type:15 = 0x201; + uint16 length = 18; + uint64 peer_session_id; + uint16 priority; + uint16 weight; + uint16 max_latency_diff; + uint16 connect_lifetime; + uint32 flags; +} + + + + The priority and weight attributes are designed to have the same semantics as the DNS SRV entries. + Select the server with the lowest numerical priority and if multiple server have the same priority, + select the server according to their weight value. Since we want to include the RTT in the decision + the max_latency_diff allows to control when a server is considered to be a candidate. + + + Each client implementation is free to implement their own algorithm to sort the server using round-trip + time (RTT), priority, max_latency_diff and weight, especially if a client present a UI for a user to pick + a server. + + + The reference implementation first sorts server by priority. Lowest number to highest. + + + Within each priority determine the lowest RTT of all remotes in this priority. + The group of candidates remotes then includes all remotes have a RTT that is no more their max_latency_diff + larger than the lowest RTT. + + + This group of candidate remotes is then sorted randomly taking the weight into account. A simple algorithm for this + is to give each remote a random value between 0 and weight and then sort them descending by that value + + + The connect_lifetime value indicates how long (in seconds) the server considers the ping + request/response to be valid as part of a three-way handshake instead of + CONTROL_HARD_RESET_CLIENT_V3/CONTROL_HARD_RESET_CLIENT_V2 and CONTROL_HARD_RESET_SERVER_V2. If set to 0 + or more than connect_lifetime seconds have passed the client must initiate a regular three-way handshake. + If the client can send from the same source IP and port and use the same client and server session ID, the + client MAY skip the handshake and start with third packet of the three-way handshake instead. + + + This is useful for server that either save the client requests for a small amount of time to allow + quicker connects after a client finds the best server or for server that use an HMAC based mechanism + similar to SYN cookies for the initial three-way handshake like the OpenVPN 2.x implementation. + + + This TLV is considered to be extendable in the future. A client encountering a longer length than they + expect, should ignore the excess bytes. The minimum size of this struct is 18 bytes. Smaller sizes are + considered invalid. + + + The peer_session_id field repeats the session id of the request. While without tls-auth or tls-crypt, + the response can be easily forged, the authentication of tls-auth and tls-crypt and randomness of the + client session id prevents replays of the response. + + + The flags field indicates the capabilities or behaviour that the server wants the client to use. +
      +
    • bit 0: Use CONTROL_WKC_V1 when completing the three way handshake.
    • +
    +
    +
    +
    + + The echo request TLV contains a payload to create a certain sized packet and also allows + to control the size of the reply. + +struct echo_request { + int optional:1 = 0; + int type:15 = 0x202; + uint16 length; + uint16 sequence_number; + uint16 total_reply_len; + uint8 payload[]; +} + + + + The field total_reply_len is the total length the payload of reply should have. This includes the header + of the message and all other TLV. This can be used to trigger a response of a certain size to see if certain + sized packets are able to traverse the network in the opposite direction. If the field total_reply_len is zero + the reply should just copy the payload of the request to the reply. + + + The sequence number will be echoed back in the echo reply + +
    +
    + + The echo reply TLV contains the response to an echo request. + +struct echo_reply { + int optional:1 = 0; + int type:15 = 0x203; + uint16 length; + uint16 sequence_number; + uint8 payload[]; +} + + The payload should be filled with either random data or with the payload of the echo_request to ensure that + the reply has the total_reply_len of the echo_request. Any other TLVs present in the reply should be accounted + for and the length adjusted accordingly. + + + The sequence_number field MUST match the sequence number of the request. + +
    + +
    + + +struct acc_message { + int optional:1 = 0; + int type:15 = 0x204; + uint16 length; + uint8 proto_len; + uint8 proto[]; + uint8 payload[]; +} + + The acc message struct has the same function as the regular ACC control message. + But there is no splitting of the message and also no reliability. The first proto_len bytes of the payload of + the struct are considered to be the proto name and the remainder the payload. The payload is considered to be not + encoded. + + +
    +
    +
    + + The primary idea is to ping all available remotes to get a quick response to + select the best server. For this the client will send a SERVER_PROBE message with the probe_parameter + TLV to the server. The server can then reply with a PROBE_REPLY with the probe_reply TLV. + + + These messages can also replace the typical three handshake messages. In that case the client and server + need to continue to session as if the CONTROL_HARD_RESET_CLIENT_V3/CONTROL_HARD_RESET_CLIENT_V2 and + CONTROL_HARD_RESET_SERVER_V2 had been exchanged. Especially they need to assume that the message-id + 0 of the peer has been received and acknowledged. + +
    +
    + + The messages that are with the CONTROL_DATA packet allow to send/receive packets of controlled + size to diagnose problems with certain sized packets on the connection. They can also be used + to have a simple check if the peer is still alive. + + + However, since the data layer might be in a different process, these packets might not count + towards the normal keepalive. + +
    +
    + + The ACC message carries a single ACC message TLV and semantics are explained in the TLV description. + +
    +
    TBD