OpenVPN Wire Protocol (work in progress)
OpenVPN is an open source SSL/TLS based VPN solution which had its first release in May 2001. This document describes the wire protocol OpenVPN makes use of for establishing end-to-end-connections. Even though OpenVPN bases its communication on SSL/TLS, it is not a traditional SSL/TLS protocol which utilizes only TCP. OpenVPN supports some enhanced security features as well as providing SSL/TLS connections both over TCP as well as UDP.
This document focuses on the modern/current variant of the OpenVPN protocol. Some of the features used in older variants of the protocol are not documented.
WORK IN PROGRESS
Please not that this document is work in progress and should not considered a complete or correct documentation of the OpenVPN protocol yet. Please check the current implementations.
Introduction
OpenVPN is an open source SSL/TLS based VPN solution which was first released in 2001. The communication between OpenVPN instances are based on SSL/TLS but it has added several additional features on top of the standard SSL/TLS protocol. The wire protocol this document describes will go into the depths of how OpenVPN processes communicates with each other.
The wire protocol is dynamic, which means it will be slightly different depending on which features the OpenVPN processes have been configured to use. New implementations SHOULD implement all features.
The OpenVPN Wire Protocol
Since OpenVPN can work both in a traditional server-client setupas well as a peer-to-peer setup, this document tries to avoid the concept of server and clients. It will refer to these as either the local or remote sites. In a peer-to-peer setup only a single tunnel can be established, while in a server-client setup several clients can connect to a single server at the same time.
If the terms server and client are used these are almost always synonymous with the peer’s role as either TLS server or TLS client.
TCP and UDP transport modes
OpenVPN is capable of using both UDP and TCP for transporting SSL/TLS traffic. The SSL/TLS protocol is strictly written for TCP but OpenVPN makes that possible through encapsulating the SSL/TLS packets and adding a reliability layer to avoid issues when packets get resent.
Basic OpenVPN packet format
The wire packet identical for both UDP and TCP transport modes with one exception. For UDP packets the size of a payload packet is derived from UDP packet length. Since TCP present a stream of bytes to the application, TCP payloads carry a 16 bits packet length indicator of the size of the payload. Splitting too large payload and combining multiple payload into packets is done by the TCP/IP stack of the operating system.
The basic OpenVPN packet format that is common to both control and data channel is that the first byte (after the length in TCP mode) in a packet consists of an opcode (highest 5 bits) that determines the packet type and a key id (low 3 bit).
Static-key mode and TLS operational modes
Static-key mode
The OpenVPN protocol has a mode where it does not use dynamic key derivation but instead uses static keys. The mode does not make use of any TLS features, so it is called static key mode. In this mode there is no control channel and all the data on the wire is plain encrypted packets transported over a standard UDP or TCP connection.
Peer-to-peer mode also depends on a shared secret key between both ends of the VPN tunnel. Again, as there are no SSL/TLShandshakes between either side, this method does not have any possibilities to enable Perfect Forward Secrecy (PFS). The data channel is encrypted solely by the shared static secret. This mode does not negotiate any ephemeral session keys for the tunneled data.
Using pre-shared secrets also significantly weakens the guarantees for no IV reuse, so modern ciphers like AES in GCM mode are not available in this mode.
This mode is deprecated and this document does not provide documentation for it.
TLS mode
With TLS mode the control channel gets activated and this requires both sides to make use of private keys and X.509 Certificates. These requirements are due to this operational mode utilizing the TLS/SSL protocol. This mode is also the only operational mode which uses the client-server terminology in OpenVPN.
The use of X.509 certificates on the client side is OPTIONAL and is REQUIRED on the server side. It is highly RECOMMENDED to always enable user/password authentication when X.509 client certificates are not used.
It is highly RECOMMENDED to enforce certificate authentication against a locally controlled Certificate Authority (CA) certificate. The use of public Certification Authorities will reduce the security of the tunnel dramatically, as it can easily enable man-in-the-middle attacks where the client cannot verify the true identity of a server, or a server cannot verify the true identity of a client.
The TLS mode will use the same communication channel for both TLS handshakes and the tunnel data. The TLS handshakesare referred to as the control channel and tunnel data is referred to as the data channel. Each packet in TLS mode contains an OPCODE which defines if the following payload is a control channel or data channel packet.
HMAC authentication of control channel packets
HMAC authentication enables an additional authentication on the packet level. HMAC authentication is only possible with TLS mode and will only impact the control channel. The data channel is already protected by HMAC authentication embedded in the SSL/TLS payload.
This authentication can strengthen the overall security on both client and server side as OpenVPN will validate the HMAC signature before it is sent to the SSL/TLS layer for decryption. This can protect server and client from SSL/TLS protocol issues from all users not having access to a valid HMAC key.
The keys used for HMAC signatures are static and shared between server and all clients. The default hashing algorithm is HMAC-SHA1 but any hashing algorithms supported by the SSL/TLS protocol can be used as long as the clients and server use the same algorithm. The choice of hashing algorithms defines the length of the HMAC field in the control packet. HMAC-SHA1 uses 20 bytes, HMAC-SHA512 uses 64 bytes.
HMAC authentication subkeys
HMAC packet authentication uses two independent pre-shared static keys for the authentication. One key is used for signing packets and the other key is used to verify signatures from the remote side. The OpenVPN terminology for this is key-direction. The key-direction defines which set of keys is used for signing and for verification. All clients MUST use the same key-direction while the server MUST use the opposite key-direction.
Encrypting control channel packets
With OpenVPN v2.4 and later, the client and server MAY use TLS control channel encryption instead of HMAC authentication. This operational mode will encrypt the control packet channel payload with a static key. The static keying material is the same which HMAC authentication uses, but the key-direction is fixed according to the local process' role (server or client).
This feature is called tls-crypt, which uses a pre-shared static key (like the tls-auth method) to encrypt control channel packets.
Encrypting control channel packets has three main advantages:
It provides more privacy by hiding the certificate used for the TLS connection. It is harder to identify OpenVPN traffic as such. It provides “poor-man’s” post-quantum security, against attackers who will never know the pre-shared key (i.e. no forward secrecy).
Control channel packet encryption
The following encryption method is used, based on the SIV construction , to achieve nonce misuse-resistant authenticated encryption:
msg = control channel plaintext
header = opcode (1 byte) || session_id (8 bytes) || packet_id (8 bytes)
Ka = authentication key (256 bits)
Ke = encryption key (256 bits)
(Ka and Ke are pre-shared keys, like with --tls-auth)
auth_tag = HMAC-SHA256(Ka, header || msg)
IV = 128 most-significant bits of auth_tag
ciph = AES256-CTR(Ke, IV, msg)
output = Header || Tag || Ciph
This boils down to the following on-the-wire packet format:
-opcode- || -session_id- || -packet_id- || auth_tag || * payload *
Where
<tt>-XXX-</tt> means authenticated, and
<tt>* XXX *</tt> means authenticated and encrypted.
Which is very similar to the current tls-auth packet format, and has the same overhead as “–tls-auth” with “–auth SHA256”.
The use of a nonce misuse-resistant authenticated encryption scheme allows us to worry less about the risks of nonce collisions. This is important, because in contrast with the data channel in TLS mode, we will not be able to rotate tls-crypt keys often or fully guarantee nonce uniqueness. For non misuse-resistant modes such as GCM , the data channel in TLS mode only has to ensure that the packet counter never rolls over, while tls-crypt would have to provide nonce uniqueness over all control channel packets sent by all clients, for the lifetime of the tls-crypt key.
Unlike with tls-auth, no –key-direction has to be specified for tls-crypt. TLS servers always use key direction 1, and TLS clients always use key direction 2, which means that client->server traffic and server->client traffic always use different keys, without requiring configuration.
Using fixed, secure, encryption and authentication algorithms makes both implementation and configuration easier. If we ever want to, we can extend this to support other crypto primitives. Since tls-crypt should provide privacy as well as DoS protection, these should not be made negotiable.
tls-crypt Security considerations
tls-crypt is a best-effort mechanism that aims to provide as much privacy and security as possible, while staying as simple as possible. The following are some security considerations for this scheme.
The same tls-crypt key is potentially shared by a lot of peers, so it is quite likely to get compromised. Once an attacker acquires the tls-crypt key, this mechanism no longer provides any security against the attacker.
Since many peers potentially use the tls-crypt key for a long time, a lot of data might be encrypted under the tls-crypt key. This leads to two potential problems:
The opcode || session id || packet id combination might collide. This might happen in larger setups, because the session id contains just 64 bits of random. Using the uniqueness requirement from the GCM spec (a collision probability of less than 2^(-32)), uniqueness is achieved when using the tls-crypt key for at most 2^16 (65536) connections per process start. (The packet id includes the daemon start time in the packet ID, which should be different after stopping and restarting OpenVPN.)
And if a collision happens, an attacker can only learn whether colliding packets contain the same plaintext. Attackers will not be able to learn anything else about the plaintext (unless the attacker knows the plaintext of one of these packets, of course). Since the impact is limited, we consider this an acceptable remaining risk.
The IVs used in encryption might collide. When two IVs collide, an attacker can learn the xor of the two plaintexts by xor-ing the ciphertexts. This is a serious loss of confidentiality. The IVs are 128-bit, so when HMAC-SHA256 is a secure PRF (an assumption that must also hold for TLS), and we use the same uniqueness requirement from , this limits the total amount of control channel messages for all peers in the setup to 2^48. Assuming a large setup of 2^16 (65536) clients, and a (conservative) number of 2^16 control channel packets per connection on average, this means that clients may set up 2^16 connections on average. We think these numbers are reasonable.
Client-specific tls-crypt keys (tls-crypt-v2)
This section describes configuring OpenVPN to use client-specific tls-crypt keys.
Rationale
--tls-auth
and tls-crypt
use a pre-shared group key, which is shared among all clients and servers in an OpenVPN deployment. If any client or server is compromised, the attacker will have access to this shared key, and it will no longer provide any security. To reduce the risk of losing pre-shared keys, tls-crypt-v2
adds the ability to supply each client with a unique tls-crypt key. This allows large organizations and VPN providers to profit from the same DoS and TLS stack protection that small deployments can already achieve using tls-auth
or tls-crypt
.
Also, for tls-crypt
, even if all these peers succeed in keeping the key secret, the key lifetime is limited to roughly 8000 years, divided by the number of clients (see the --tls-crypt
section of the man page). [FIXME/flichtenheld: either include or remove reference] Using client-specific keys, we lift this lifetime requirement to roughly 8000 years for each client key (which “Should Be Enough For Everybody (tm)").
Introduction
tls-crypt-v2
uses an encrypted cookie mechanism to introduce client-specific tls-crypt keys without introducing a lot of server-side state. The client-specific key is encrypted using a server key. The server key is the same for all servers in a group. When a client connects, it first sends the encrypted key to the server, such that the server can decrypt the key and all messages can thereafter be encrypted using the client-specific key.
A wrapped (encrypted and authenticated) client-specific key can also contain metadata. The metadata is wrapped together with the key, and can be used to allow servers to identify clients and/or key validity. This allows the server to abort the connection immediately after receiving the first packet, rather than performing an entire TLS handshake. Aborting the connection this early greatly improves the DoS resilience and reduces attack surface against malicious clients that have the tls-crypt
or tls-auth
key. This is particularly relevant for large deployments (think lost key or disgruntled employee) and VPN providers (clients are not trusted).
To allow for a smooth transition, tls-crypt-v2
is designed such that a server can enable both tls-crypt-v2
and either tls-crypt
or tls-auth
. This is achieved by introducing a CONTROL_HARD_RESET_CLIENT_V3 opcode, that indicates that the client wants to use tls-crypt-v2
for the current connection.
Implementation
When setting up a tls-crypt-v2 group (similar to generating a tls-crypt or tls-auth key previously):
Generate a tls-crypt-v2 server key using OpenVPN’s --genkey tls-crypt-v2-server
. This key contains 2 512-bit keys, of which we use:
the first 256 bits of key 1 as AES-256-CTR encryption key Ke
the first 256 bits of key 2 as HMAC-SHA-256 authentication key Ka
This format is similar to the format for regular tls-crypt
/tls-auth
and data channel keys, which allows us to reuse code.
Add the tls-crypt-v2 server key to all server configs (tls-crypt-v2 /path/to/server.key
)
When provisioning a client, create a client-specific tls-crypt key:
Generate 2048 bits client-specific key Kc
using OpenVPN’s --genkey tls-crypt-v2-client
Optionally generate metadata.
The first byte of the metadata determines the type. The initial implementation supports the following types:
0x00 (USER): User-defined free-form data. 0x01 (TIMESTAMP): 64-bit network order unix timestamp of key generation.
The timestamp can be used to reject too-old tls-crypt-v2 client keys.
User metadata could for example contain the users certificate serial, such that the incoming connection can be verified against a CRL.
If no metadata is supplied during key generation, OpenVPN defaults to the TIMESTAMP metadata type.
Create a wrapped client key WKc
, using the same nonce-misuse-resistant SIV construction we use for tls-crypt:
len = len(WKc) (16 bit, network byte order)
T = HMAC-SHA256(Ka, len || Kc || metadata)
IV = 128 most significant bits of T
WKc = T || AES-256-CTR(Ke, IV, Kc || metadata) || len
Note that the length of WKc
can be computed before composing WKc
, because the length of each component is known (and AES-256-CTR does not add any padding).
Create a tls-crypt-v2 client key: PEM-encode Kc || WKc
and store in a file, using the header —–BEGIN OpenVPN tls-crypt-v2 client key—– and the footer —–END OpenVPN tls-crypt-v2 client key—–. (The PEM format is simple, and following PEM allows us to use the crypto library functions for en/decoding.)
Add the tls-crypt-v2 client key to the client config (tls-crypt-v2 /path/to/client-specific.key
)
When setting up the OpenVPN connection:
The client reads the tls-crypt-v2 key from its config, and:
loads Kc
as its tls-crypt key,
stores WKc
in memory for sending to the server.
To start the connection, the client creates a P_CONTROL_HARD_RESET_CLIENT_V3 message, wraps it with tls-crypt using Kc
as the key, and appends WKc
. (WKc
must not be encrypted, to prevent a chicken-and-egg problem.)
The server receives the P_CONTROL_HARD_RESET_CLIENT_V3 message, and
reads the WKc length field from the end of the message, and extracts WKc from the message unwraps WKc
uses unwrapped Kc
to verify the remaining P_CONTROL_HARD_RESET_CLIENT_V3 message’s (encryption and) authentication.
The message is dropped and no error response is sent when any of these steps fails (DoS protection).
Server optionally checks metadata using a –tls-crypt-v2-verify script
This allows early abort of connection, before we expose any of the notoriously dangerous TLS, X.509 and ASN.1 parsers and thereby reduces the attack surface of the server.
The metadata is checked after the OpenVPN three-way handshake has completed, to prevent DoS attacks. (That is, once the client has proved to the server that it possesses Kc, by authenticating a packet that contains the session ID picked by the server.)
A server should not send back any error messages if metadata verification fails, to reduce attack surface and maximize DoS resilience.
Client and server use Kc
for (un)wrapping any following control channel messages. Setting up connection with cookie support
To avoid exhaustion attack and keeping state for connections that fail to complete the three way handshake, the OpenVPN server will use its own session id as challenge that the client must repeat in the third packet of the handshake. This introduces a problem. If the server does not keep the wrapped client key from the initial packet, the server cannot decode the third packet. Therefore, tls-crypt-v2 allows resending the wrapped key in the third packet of the handshake with the P_CONTROL_WKC_V1 message. The modified handshake is as follows (the rest of the handshake is unmodified):
The client creates the P_CONTROL_HARD_RESET_CLIENT_V3 message as before but to indicate that it supports resending the wrapped key by setting the packet id of the replay id to 0x0f000000 where the first byte indicates the early negotiation support and the next byte the flags. All tls-crypt-v2 implementations that support early negotiation, MUST also support resending the wrapped key. The flags byte is therefore empty.
The server responds with a P_CONTROL_HARD_RESET_V2 message. Instead of having an empty payload like normally, the payload consists of TLV (type (uint16), length (uint16), value) packets. TLV was chosen to allow extensibility in the future. Currently only the following TLV is defined:
flags - type 0x01, length 2.
Bit 1 indicates that the client needs to resend the WKC in the third packet.
Instead of normal P_ACK_V1 or P_CONTROL_V1 packet, the client will send a P_CONTROL_WKC_V1 packet. The P_CONTROL_WKC_V1 is identical to a normal P_CONTROL_V1 packet but with the WKc appended.
Normally the first message of the client is either P_ACK_V1, directly followed by a P_CONTROL_V1 message that contains the TLS Client Hello or just a P_CONTROL_V1 message. Instead of a P_ACK_V1 message the client should send a P_CONTROL_WKC_V1 message with an empty payload. This message must also include an ACK for the P_CONTROL_HARD_RESET_V2 message.
When directly sending the TLS Client Hello message in the P_CONTROL_WKC_V1 message, the client must ensure that the resulting P_CONTROL_WKC_V1 message with the appended WKc does not extend the control message length.
Considerations
To allow for a smooth transition, the server implementation allows tls-crypt
or tls-auth
to be used simultaneously with tls-crypt-v2
. This specification does not allow simultaneously using tls-crypt-v2
and connections without any control channel wrapping, because that would break DoS resilience.
WKc includes a length field, so we leave the option for future extension of the P_CONTROL_HEAD_RESET_CLIENT_V3 message open. (E.g. add payload to the reset to indicate low-level protocol features.)
tls-crypt-v2
uses fixed crypto algorithms, because:
The crypto is used before we can do any negotiation, so the algorithms have to be predefined.
The crypto primitives are chosen conservatively, making problems with these primitives unlikely.
Making anything configurable adds complexity, both in implementation and usage. We should not add any more complexity than is absolutely necessary.
Potential tls-crypt-v2
risks:
Slightly more work on first connection (WKc
unwrap + hard reset unwrap) than with tls-crypt
(hard reset unwrap) or tls-auth
(hard reset auth).
Flexible metadata allow mistakes (So we should make it easy to do it right. Provide tooling to create client keys based on cert serial + CA fingerprint, provide script that uses CRL (if available) to drop revoked keys.)
Pushing configuration options and OCC
TBD
Control channel
OpenVPN communicates over two channels which are multiplexed over the same connection; control channel and data channel. The control channel is used for passing configuration and environment data between each side of the tunnel, including encryption session keys. The data channel carries the encrypted tunnel data. The OPCODE determines which channel the packet belongs to.
Overview of OPCODEs
Each packet MUST contain an OPCODE. This is located within the first byte in each UDP packet and the third byte in TCP packets. The high 5 bits contains the OPCODE and the lower 3 bits defines a key-id. The OPCODE defines the contents of the following payload.
OPCODE CHANNAL SHORT NAME PAYLOAD STATUS
1 Control CONTROL_HARD_RESET_CLIENT_V1 Obsolete
2 Control CONTROL_HARD_RESET_SERVER_V1 Obsolete
3 Control CONTROL_SOFT_RESET_V1 - Obsolete
4 Control CONTROL_V1 X Current
5 Control ACK_V1 X Current
6 Data DATA_V1 X Current
7 Control CONTROL_HARD_RESET_CLIENT_V2 - Current
8 Control CONTROL_HARD_RESET_SERVER_V2 - Current
9 Data DATA_V2 X Current
10 Control CONTROL_HARD_RESET_CLIENT_V3 X Current
11 Control CONTROL_WKC_V1 X Current
The Control Channel
The control channel is used to pass configuration and environment information in addition to handle the SSL/TLS handshake process between the server and client.
Control channel wire packet structure
The following table lists all fields found in control channel packets. The fields arrive in the order they are listed in the table.
The TLS auth column indicates fields used when additional HMAC authentication data is added to the control channel packets.
Field name Length (bits) TLS auth Comment
pkt_len 16 Packet length (TCP only)
OPCODE 5
key_id 3 X
own session_id 64 X
HMAC 128-512 X Algorithm defines length
replay_packet_id 64 X ID used for replay protection.
acked_pktid_len 8 X
acked_pktid_list 32 * n X List length defined by acked_pktid_len.
peer session id 64 X Session ID of the remote peer. Present if acked_pktid_len >= 1
packet_id 32 X ID of the control channel packet. ACK packets lack a packet_id
payload (var) X Can be empty
Field: pkt_len
This field is only present when TCP is used as the transport protocol. This value should be the number of bytes being transported in this packet, excluding the pkt_len field.
Field: OPCODE
The OPCODE field is described in detail in the
Field: key_id
This is used to indicate which keys to use when processing the payload. This has a range from 0 to 7. All new sessions starts with key_id 0. After a key renegotiation the key_id will increase by one. After key_id 7, the key_id wraps to 1.
OpenVPN uses 256 byte of key material for encryption/decryption of the data channel. The format of this key material is the following:
struct datakeys { uint8_t key_c2s[64]; uint8_t auth_c2s[64]; uint8_t key_s2c[64]; uint8_t auth_s2c[64]; }
All these keys provide more than enough material to provide encryption keys for all encryption and authentication algorithms. E.g. when 128 bit are required for an encryption cipher, only the first 16 bytes are used.
key_c2s and auth_c2s are used to encrypt/authenticate data from client to server and key_s2c and auth_s2c are used to encrypt/authenticate from server to client.
This key structure is normally generated by using
Older clients use the mechanism described in the section OpenVPN data channel PRF.
Peer-ID
The purpose of this feature is to allow a client to float between various client IP addresses and UDP ports. When a client floats it means that the established encryption and session keys will be reused when the client’s source IP address or source port changes. Reasons for such changes can be NAT firewalls interrupting longer lasting established connections, mobile devices moving from WLAN to a mobile data carrier (such as GPRS, 3G, LTE, etc) and similar scenarios.
Requirements
Each client implementing Peer-ID support MUST indicate its support with the IV_PROTO=2
Clients MUST accept the peer-id option being passed to it via a PUSH_REPLY message and MUST use this value as the Peer-ID in all DATA_V2 packets. Clients MUST provide a valid Peer-ID in all DATA_V2 packets, but it can be the ID used to indicate Peer-ID being disabled.
Server implementations MUST support the IV_PROTO=2 and the DATA_V2 packet format and MUST evaluate the response from the client before assigning and push ing a peer-id option to the client. The server SHOULD use the DATA_V2 packet formats when communicating with the clients.
The client is not expected to parse the Peer-ID in DATA_V2 packets. The server should send the same Peer-ID provided in packets from the server to client.
The Peer-ID is included protected in the HMAC signature/AEAD tag of DATA_V2 packets.
Allowing floating clients
The server MUST ensure the packet integrity is intact, through checking HMAC or GCM authentication tags, replay protection, etc
of the DATA_V2 packet.
In addition the server MUST ensure the float does not clobber a pre-existing client, such as a client floating to a source IP address used by a different client unless it can be verified that the pre-existing client is a previous instance of the floating client.
Replay protection
The replay protection in OpenVPN uses a fairly standard approach with a sliding window with a number of packets n and a timeout t
If a packet arrives that has a higher sequence number than the highest packet sequence seen so far, it is accepted
If a packet arrives out of order, it will only be accepted if the difference between its sequence number and the highest sequence number received so far is less than n.
If a packet arrives out of order, it will only be accepted if it arrives no later than t seconds after any packet containing a higher sequence number.
A packet will be rejected if it is a replay
This means that a client needs to keep track of the highest received sequence number and the n sequence ids lower than the highest received sequence number.
Old OpenVPN peers before 2.4 will enforce a strict packet ordering when using TCP that does not allow reordering.
AEAD encrypted data channel packet
struct aead_packet {
int opcode:5;
int key_id:3;
int peer_id:24;
uint32_t packet_id;
uint8_t[16] authentication_tag;
uint8_t* encrypted_payload;
}
The packet_id together with the implicit IV forms the IV for decryption. The packet_id is also used for the replay protection.
IV = packet_id | implicit_iv;
The implicit part of IV is filled by first bytes of the auth_c2s/auth_s2c of the data channel key. For the current implemented AEAD ciphers Chacha20-Poly1305 and AES-GCM the IV length is 96 bits, 32 bits are from packet_id and the remaining 64 bits (the implicit IV part) are taken from the data channel key.
For DATA_V2 packets the authenticated data includes opcode, key_id and peer_id. For DATA_V1 packets the authenticated data starts on the first byte of packet_id, not including opcode and key_id.
authenticated_data_v1 = packet_id | payload authenticated_data_v2 = opcode| key_id | peer_id | packet_id | payload
The tag size is always 128 bit (16 bytes). (Same size as in TLS)
CBC/OFB/CTR encrypted packet
struct data_packet_cbc {
int opcode:5;
int key_id:3;
int peer_id:24;
uint8_t[HMAC_LEN] hmac;
uint8_t[IV_LEN] iv;
uint32_t encrypted_packet_id;
uint8_t* encrypted_payload
}
struct data_packet_xfb {
int opcode:5;
int key_id:3;
int peer_id:24;
uint8_t[HMAC_LEN] hmac;
uint8_t[IV_LEN] iv;
uint8_t* encrypted_payload
}
HMAC_LEN depends on the length of the HMAC being used, e.g. 20 bytes for SHA1, 32 for SHA256. If no authentication is used (DEPRECATED) then the length of the field is 0.
The HMAC is computed over the complete remainder of the packet. opcode, key_id, and peer_id are NOT included in the HMAC calculation. If HMAC verification fails decryption of the packet MUST NOT be attempted. OpenVPN implements the encrypt-then-MAC approach.
IV_LEN depends on the IV of used cipher. For AES in CBC, CFB and OFB this is 128 bits (IV_LEN=8), for Blowfish in CBC mode (DEPRECATED) 64 bits (IV_LEN=4). For generating the IV use best practices. OpenVPN generates the CBC IV as random bytes with an PRNG. For OFB and CFB the IV has the following format:
IV = 64 bit packet ID | IV_remainder
The IV_remainder SHOULD be random bytes. OpenVPN 2.x uses all zeros instead.
The packet ID in CBC mode is encrypted and included before the payload. In contrast to that, the packet ID in OFB and CFB mode are the first 64 bit of the IV.
For unencrypted data packets the same format as CBC without IV is used.
Control channel messages
Message format
After the control channel has been established the format switch from the binary format of the key exchange message to a text based format. The message are sent in plain text. The current implementation does not allow a message to span more than one TLS record.
PUSH_REQUEST
Format: PUSH_REQUEST
This message is sent from the client to the server and instructs the server that the client is ready to receive a PUSH_REPLY message. The message is periodically repeated until the PUSH_REPLY is received for compatibility with old OpenVPN servers and to act as a keepalive.
PUSH_REPLY
Format: PUSH_REPLY [comma separated options]
This message is sent from the server to the client and has dynamic configuration for the client. See the section “dynamic configuration option” for a detailed description of the options. [FIXME/flichtenheld: proper reference]
If the client has set the IV_PROTO_REQUEST_PUSH bit in the IV_PROTO peerinfo client variable the server MAY send a PUSH_REPLY without waiting for the PUSH_REQUEST from the client.
AUTH_PENDING
Format: AUTH_PENDING
or
AUTH_PENDING,flags
This message is sent from the server to the client to indicate that a multi factor authentication is in use and the authentication is not completed. The authentication can continue inband or out-of-band.
flags is a comma separate key-value list. Currently timeout time is defined and defines the maximum time the server expects the client to stay in the pending auth state.
The client indicates if the extended format with flags is supported by setting the IV_PROTO_AUTH_PENDING_KW bit in the IV_PROTO peerinfo client variable. All new clients MUST support the extended format.
RESTART and HALT
Format:
RESTART[,message]
HALT[,message]
and
RESTART,[[flags]]message
These message are sent from the server to the client and the client to terminate a session. With HALT the client is expected to also not try to try reconnect. With RESTART the client is expected to reconnect. flags is a list of characters that must follow directly after the comma and is enclosed in [ and ]. The client SHOULD purge username and password before reconnecting if flags contains P and reconnect to the next server unless N is in flags in which case it should reconnect to the same server. E.g. when the client receives a RESTART[PN] message it should reconnect to same server with the same username and password.
The optional message indicates a message that can relayed to the user.
AUTH_FAILED
Format:
AUTH_FAILED[,message]
AUTH_FAILED,SESSION:message
AUTH_FAILED,TEMP[keywords]:message AUTH_FAILED,TEMP:message
This message indicates to a client that an authentication attempt was unsuccessful. This message is mostly send in response to a PULL_REQUEST or when a client attempts to renegotiates a TLS session.
The optional message can be relayed to the user. If the message starts with SESSION, this indicates that current credentials are longer valid. This is mostly used to indicate that the temporary session credentials that were pushed with “auth-token” and “auth-token-user” should be purged and the client should reconnect in the same way as a new connection.
The AUTH_FAILED,TEMP message indicates that the authentication temporarily failed and should the client continue to retry to connect. The server can optionally give a user readable message and hint the client a behavior how to proceed. The keywords of AUTH_FAILED,TEMP are comma separated keys/values. Currently defined are:
backoff s - instructs the client to wait at least s seconds before the next connection attempt. If the client has already a higher delay before reconnecting, the delay should NOT be shortened. advance addr - Instructs the client to reconnect to the (IP) address of the current server. advance remote - Instructs the client to skip the remaining IP addresses of the current server and instead connect to the next server specified in the configuration file advance no - Instructs the client to retry connecting to the same server again.
For example a server that might send AUTH_FAILED,TEMP[backoff 42,advance no]: No free IP addresses to indicate that the VPN connection can currently not succeed and instructs the client to retry in 42 seconds again.
The client will announce the capability of understanding AUTH_FAILED,TEMP message by setting the IV_PROTO_AUTH_FAILED_TEMP bit in the IV_PROTO
CR_RESPONSE
Format: CR_RESPONSE,base64reply
This message indicates a reply to prior challenge/response request. The response is specific to the challenge response and is encoded with base64.
INFO_PRE and INFO
Format:
INFO_PRE,EXTRA
INFO,EXTRA
This message is used to send pending auth parameters. See the section on pending auth for more details on the format of the EXTRA parameter. [FIXME/flichtenheld: proper reference]
Cipher negotiation
TBD
TLS mode and PKI
TBD
User authentication
User/password authentication
TBD
Challenge-Response authentication
TBD