Skip to content

Commit 7b1e45d

Browse files
committed
Expand OpenVPN data key usage
1 parent 07de450 commit 7b1e45d

File tree

1 file changed

+97
-36
lines changed

1 file changed

+97
-36
lines changed

openvpn-wire-protocol.xml

Lines changed: 97 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,15 +1187,23 @@ available) to drop revoked keys.)</li>
11871187
renegotiation can start using the CONTROL_V1 OPCODE.
11881188
</t>
11891189
<t>
1190-
When the ACK_V1 packet is being sent, the key_id field
1191-
MUST be incremented to ensure the connection can still
1192-
use the old keys for a shorter time until the transition
1193-
has completed. Any following packets need to use the new
1194-
key-id until the old key has been removed and the new
1195-
key-id replaces it completely. [FIXME/schwabe:THIS IS WRONG)
1190+
This session will be negotiated the same as the inital
1191+
session up to the point that the control channel is
1192+
establish. At this point the control channel of the new
1193+
session will replace the control channel of the old channel.
11961194
</t>
11971195
<t>
1198-
[FIXME: Elaborate more on how re-keying happens]
1196+
Unlike in the initial TLS session wih the key-id 0, the client
1197+
will not send PUSH_REQUEST messages to request server to query
1198+
its configuration but continue to use the configuration
1199+
negotiated in the initial TLS session.
1200+
</t>
1201+
<t>
1202+
Whenever a new TLS session is renegotiated the key-id is increased
1203+
by one. However, only succesful renegotiation will increase the
1204+
key-id. If a renegotiation fails and is reattempted, the key-id
1205+
will not be increased. Only the intial TLS session will use the key-id
1206+
0. If the key-id reaches 7, the following key-id is 1.
11991207
</t>
12001208
</section>
12011209

@@ -1533,15 +1541,95 @@ struct datakeys {
15331541
key_c2s and auth_c2s are used to encrypt/authenticate data from client to server
15341542
and key_s2c and auth_s2c are used to encrypt/authenticate from server to client.
15351543
</t>
1544+
<section title="Data channel key generation">
1545+
<t>
1546+
Every time a OpenVPN control channel session is succesfully established, a data channel key in the above format is
1547+
generated and assigned to the key-id of the control channel.
1548+
</t>
15361549
<t>
15371550
This key structure is normally generated by using <xref target="RFC5705">RFC 5705 key material exporter</xref>
15381551
from the Control Channel session with the label <tt>EXPORTER-OpenVPN-datakeys</tt>
15391552
and using the 256 bytes length of the structure.
1553+
</t>
1554+
<t>
1555+
When a client or server lack the support for generating data channel keys using TLS Key material
1556+
export and do not annoounce the support in IV_CIPHER, the server may reject a client. At the same
1557+
time a client that does not get signalled by the server by `key-derivation tls-ekm` or
1558+
`protocol-flags tls-ekm` to use TLS Key material can abort the connection.
1559+
</t>
1560+
<t>
1561+
If support for older server or clients is desired that do not support TLS EKM, client and
1562+
server can fall back to the old mechanism of using the
1563+
<xref target="openvpnprf"> OpenVPN data channel PRF</xref>.
1564+
</t>
1565+
</section>
1566+
<section anchor="openvpnprf" title="OpenVPN data channel PRF">
1567+
<t>
1568+
This is a deprecated way of deriving the data channel keys. It should be only implemented if
1569+
compatibility with older OpenVPN versions is required that do not support key derivation via
1570+
the RFC5705 key material exporter. It also requires the MD5 algorithm which often
1571+
modern crypto libraries do not readily support anymore.</t>
1572+
1573+
<t>This uses the <tt>key_random</tt>, <tt>random1</tt>, and <tt>random2</tt> from the key
1574+
exchange messages. These will be prefixed with client and server here to indicate from which
1575+
packet these field are coming. Also the session id of the control channel will be used here</t>
1576+
1577+
<t>
1578+
Here TLS_PRF(seed, secret) is the TLS PRF function according to RFC 2246 with
1579+
MD5 and SHA1 as used in TLS 1.0/1.1.
1580+
1581+
<figure>
1582+
<sourcecode>
1583+
seed = "OpenVPN master secret" | client.random1 | server.random1
1584+
secret = client.key_random
1585+
master_secret - TLS_PRF(seed, secret)
15401586

1541-
Older clients use the mechanism described in the section OpenVPN data channel
1542-
PRF.
1587+
key_seed = "OpenVPN key expansion " | client.random2 | server.random2
1588+
datakeys = TLS_PRF(key_seed, key_seed)
1589+
</sourcecode>
1590+
</figure>
15431591
</t>
1592+
</section>
15441593
</section>
1594+
<section title="Data channel key rotation">
1595+
<t>
1596+
Whenever a reneogiation of a key has finshed, a new data channel key is generated.
1597+
This new key will consider the pending key. A pending key is considered valid for
1598+
decryption of packets with that key-id but will not be used for encryption yet.
1599+
</t>
1600+
<t>
1601+
After a set time period the pending key is promoted to being the active key and
1602+
the active key is set to be the retired key (sometimes also referred to as lame
1603+
duck key). The retired key will be used only for decryption but no longer for
1604+
encryption.
1605+
</t>
1606+
<t>
1607+
In the default configuration of OpenVPN, the time period of promoting a key from
1608+
pending to active is calucated as
1609+
<artwork>
1610+
min(handshake_window, renegotiation_time/2)
1611+
</artwork>
1612+
set by the --hand-window and --renog-sec options, which default to 60 and 3600
1613+
respectively. So the default time to promote a key from pending to active is 60s.
1614+
</t>
1615+
<t>
1616+
This approach to defer using the key with a timeout is done to avoid key
1617+
desynchronisation. It allows installing the new keys with enough lead time
1618+
that at the point that any side switches from pending to active key, the
1619+
other side will have the key already installed as pending key and is able
1620+
to decrypt the packets. Likewise, keeping the old key as retired key for
1621+
some time after the pending key is switched to active ensures that the
1622+
if the peer takes longer to switch the pending key to active key, the
1623+
receiver will still be able to decrypt the packets using the retiring key.
1624+
</t>
1625+
<t>
1626+
Should a renegotiation complete before a pending key is promoted to an active
1627+
key, the pending key will replace the active key and the new pending key will
1628+
be the pending key. Note that that implementations are allowed to
1629+
limit themselves just two key slots with either active/pending or active/retired
1630+
and in this scenario will drop active key without moving it to retired state first.
1631+
</t>
1632+
</section>
15451633
<section title="Peer-ID">
15461634
<t>
15471635
The purpose of this feature is to allow a client to float between various client
@@ -1755,33 +1843,6 @@ struct data_packet_xfb {
17551843
<t>For unencrypted data packets the same format as CBC without IV is used.</t>
17561844
</t>
17571845
</section>
1758-
<section title="OpenVPN data channel PRF">
1759-
<t>
1760-
This is a deprecated way of deriving the data channel keys. It should be only implemented if
1761-
compatibility with older OpenVPN versions is required that do not support key derivation via
1762-
the RFC5705 key material exporter. It also requires the MD5 algorithm which often
1763-
modern crypto libraries do not readily support anymore.</t>
1764-
1765-
<t>This uses the <tt>key_random</tt>, <tt>random1</tt>, and <tt>random2</tt> from the key
1766-
exchange messages. These will be prefixed with client and server here to indicate from which
1767-
packet these field are coming. Also the session id of the control channel will be used here</t>
1768-
1769-
<t>
1770-
Here TLS_PRF(seed, secret) is the TLS PRF function according to RFC 2246 with
1771-
MD5 and SHA1 as used in TLS 1.0/1.1.
1772-
1773-
<figure>
1774-
<sourcecode>
1775-
seed = "OpenVPN master secret" | client.random1 | server.random1
1776-
secret = client.key_random
1777-
master_secret - TLS_PRF(seed, secret)
1778-
1779-
key_seed = "OpenVPN key expansion " | client.random2 | server.random2
1780-
datakeys = TLS_PRF(key_seed, key_seed)
1781-
</sourcecode>
1782-
</figure>
1783-
</t>
1784-
</section>
17851846
</section>
17861847
<section title="Control channel messages">
17871848
<section title="Message format">

0 commit comments

Comments
 (0)