From 81e5443b3fda500aad7440e9a228ec57963b4aca Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Mon, 30 Sep 2024 12:30:47 +0200 Subject: [PATCH] Expand OpenVPN data key usage Signed-off-by: Arne Schwabe --- openvpn-wire-protocol.xml | 137 ++++++++++++++++++++++++++++---------- 1 file changed, 101 insertions(+), 36 deletions(-) diff --git a/openvpn-wire-protocol.xml b/openvpn-wire-protocol.xml index 0a821d0..22a3366 100644 --- a/openvpn-wire-protocol.xml +++ b/openvpn-wire-protocol.xml @@ -1187,15 +1187,27 @@ available) to drop revoked keys.) renegotiation can start using the CONTROL_V1 OPCODE. - When the ACK_V1 packet is being sent, the key_id field - MUST be incremented to ensure the connection can still - use the old keys for a shorter time until the transition - has completed. Any following packets need to use the new - key-id until the old key has been removed and the new - key-id replaces it completely. [FIXME/schwabe:THIS IS WRONG) + This session will be negotiated the same as the inital + session up to the point that the control channel is + establish. At this point the control channel of the new + session will replace the control channel of the old channel. - [FIXME: Elaborate more on how re-keying happens] + Unlike in the initial TLS session wih the key-id 0, the client + will not send PUSH_REQUEST messages to request server to query + its configuration but continue to use the configuration + negotiated in the initial TLS session. + + + Whenever a renegotiation happens, the new TLS session will use + the current key-id increased by one. When the renegotiation + succeeds, the key-id of the renegotion will also be used for all + data channel packets and further control channel packet that + belong/derive from this TLS session. If a renegotiation fails + and is reattempted, the key-id from the failed attempt will be + reused for a new renegotiation attempt. + Only the intial TLS session will use the key-id 0. If the key-id + reaches 7, the following key-id is 1 when increasing the key-id. @@ -1533,15 +1545,95 @@ struct datakeys { 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. +
+ + Every time a OpenVPN control channel session is succesfully established, a data channel key in the above format is + generated and assigned to the key-id of the control channel. + This key structure is normally generated by using RFC 5705 key material exporter from the Control Channel session with the label EXPORTER-OpenVPN-datakeys and using the 256 bytes length of the structure. + + + When a client or server lack the support for generating data channel keys using TLS Key material + export and do not annoounce the support in IV_CIPHER, the server may reject a client. At the same + time a client that does not get signalled by the server by `key-derivation tls-ekm` or + `protocol-flags tls-ekm` to use TLS Key material can abort the connection. + + + If support for older server or clients is desired that do not support TLS EKM, client and + server can fall back to the old mechanism of using the + OpenVPN data channel PRF. + +
+
+ + This is a deprecated way of deriving the data channel keys. It should be only implemented if + compatibility with older OpenVPN versions is required that do not support key derivation via + the RFC5705 key material exporter. It also requires the MD5 algorithm which often + modern crypto libraries do not readily support anymore. + + This uses the key_random, random1, and random2 from the key + exchange messages. These will be prefixed with client and server here to indicate from which + packet these field are coming. Also the session id of the control channel will be used here + + + Here TLS_PRF(seed, secret) is the TLS PRF function according to RFC 2246 with + MD5 and SHA1 as used in TLS 1.0/1.1. + +
+ +seed = "OpenVPN master secret" | client.random1 | server.random1 +secret = client.key_random +master_secret - TLS_PRF(seed, secret) - Older clients use the mechanism described in the section OpenVPN data channel - PRF. +key_seed = "OpenVPN key expansion " | client.random2 | server.random2 +datakeys = TLS_PRF(key_seed, key_seed) + +
+
+
+ + Whenever a reneogiation of a key has finshed, a new data channel key is generated. + This new key will consider the pending key. A pending key is considered valid for + decryption of packets with that key-id but will not be used for encryption yet. + + + After a set time period the pending key is promoted to being the active key and + the active key is set to be the retired key (sometimes also referred to as lame + duck key). The retired key will be used only for decryption but no longer for + encryption. + + + In the default configuration of OpenVPN, the time period of promoting a key from + pending to active is calucated as + + min(handshake_window, renegotiation_time/2) + + set by the --hand-window and --reneg-sec options, which default to 60 and 3600 + respectively. So the default time to promote a key from pending to active is 60s. + + + This approach to defer using the key with a timeout is done to avoid key + desynchronisation. It allows installing the new keys with enough lead time + that at the point that any side switches from pending to active key, the + other side will have the key already installed as pending key and is able + to decrypt the packets. Likewise, keeping the old key as retired key for + some time after the pending key is switched to active ensures that the + if the peer takes longer to switch the pending key to active key, the + receiver will still be able to decrypt the packets using the retiring key. + + + Should a renegotiation complete before a pending key is promoted to an active + key, the pending key will replace the active key and the new pending key will + be the pending key. Note that that implementations are allowed to + 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 purpose of this feature is to allow a client to float between various client @@ -1755,33 +1847,6 @@ struct data_packet_xfb { For unencrypted data packets the same format as CBC without IV is used.
-
- - This is a deprecated way of deriving the data channel keys. It should be only implemented if - compatibility with older OpenVPN versions is required that do not support key derivation via - the RFC5705 key material exporter. It also requires the MD5 algorithm which often - modern crypto libraries do not readily support anymore. - - This uses the key_random, random1, and random2 from the key - exchange messages. These will be prefixed with client and server here to indicate from which - packet these field are coming. Also the session id of the control channel will be used here - - - Here TLS_PRF(seed, secret) is the TLS PRF function according to RFC 2246 with - MD5 and SHA1 as used in TLS 1.0/1.1. - -
- -seed = "OpenVPN master secret" | client.random1 | server.random1 -secret = client.key_random -master_secret - TLS_PRF(seed, secret) - -key_seed = "OpenVPN key expansion " | client.random2 | server.random2 -datakeys = TLS_PRF(key_seed, key_seed) - -
-
-