-
Notifications
You must be signed in to change notification settings - Fork 3
/
openvpn-wire-protocol.xml
2105 lines (1911 loc) · 90.6 KB
/
openvpn-wire-protocol.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="US-ASCII"?>
<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [
<!-- One method to get references from the online citation libraries.
There has to be one entity for each item to be referenced.
An alternate method (rfc include) is described in the references. -->
<!ENTITY RFC2104 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.2104.xml">
<!ENTITY RFC2119 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.2119.xml">
<!ENTITY RFC3552 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.3552.xml">
<!ENTITY RFC5226 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.5226.xml">
<!ENTITY RFC5246 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.5246.xml">
<!ENTITY RFC5280 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.5280.xml">
<!ENTITY RFC5705 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.5705.xml">
<!ENTITY RFC8452 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.8452.xml">
]>
<!-- give errors regarding ID-nits and DTD validation -->
<?rfc strict="yes" ?>
<!-- control the table of contents (ToC) -->
<?rfc toc="yes"?>
<!-- the number of levels of subsections in ToC. default: 3 -->
<?rfc tocdepth="2"?>
<!-- control references -->
<!-- use symbolic references tags, i.e, [RFC2119] instead of [1] -->
<?rfc symrefs="yes"?>
<!-- sort the reference entries alphabetically -->
<?rfc sortrefs="yes" ?>
<!-- control vertical white space
(using these PIs as follows is recommended by the RFC Editor) -->
<?rfc compact="yes" ?>
<!-- keep one blank line between list items -->
<?rfc subcompact="no" ?>
<!-- end of list of popular I-D processing instructions -->
<rfc category="info" docName="draft-openvpntech-openvpn-wire-protocol-01" ipr="trust200902">
<!-- category values: std, bcp, info, exp, and historic
ipr values: trust200902, noModificationTrust200902, noDerivativesTrust200902,
or pre5378Trust200902
you can add the attributes updates="NNNN" and obsoletes="NNNN"
they will automatically be output with "(if approved)" -->
<front>
<title abbrev="OpenVPN Wire Protocol">OpenVPN Wire Protocol (work in progress)</title>
<author fullname="Arne Schwabe" initials="A.S." surname="Schwabe">
<organization>OpenVPN, Inc</organization>
<address>
<email>[email protected]</email>
</address>
</author>
<author fullname="David Sommerseth" initials="D.S." surname="Sommerseth">
<organization>OpenVPN, Inc</organization>
<address>
<email>[email protected]</email>
</address>
</author>
<author fullname="Steffan Karger" initials="S.K." surname="Karger">
<organization>Fox-IT</organization>
<address>
<email>[email protected]</email>
</address>
</author>
<date year="2038" day="19" month="Jan"/> <!-- Can add day="XX" month="YYY" later on -->
<keyword>OpenVPN</keyword>
<keyword>protocol</keyword>
<keyword>VPN</keyword>
<abstract>
<t>
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.
</t>
</abstract>
</front>
<middle>
<section title="WORK IN PROGRESS">
<t>
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.
</t>
</section>
<section title="Introduction">
<t>
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.
</t>
<t>
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.
</t>
<section title="Requirements Language">
<t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in <xref target="RFC2119">RFC 2119</xref>.</t>
</section>
</section>
<section title="The OpenVPN Wire Protocol">
<t>
Since OpenVPN can work both in a traditional server-client setup
as 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.
</t>
<section title="TCP and UDP transport modes">
<t>
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.
</t>
</section>
<section title="Static-key mode and TLS operational modes">
<section title="Static-key mode">
<t>
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.
</t>
<t>
Peer-to-peer mode also depends on a shared secret key between
both ends of the VPN tunnel. Again, as there are no SSL/TLS
handshakes 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.
</t>
</section>
<section title="TLS mode">
<t>
With TLS mode the control channel gets activated and this
requires both sides to make use of private keys and
<xref target="RFC5280">X.509</xref> Certificates. These requirements are due to this
operational mode utilizing the <xref target="RFC5246">TLS/SSL</xref> protocol.
This mode is also the only operational mode which uses the
client-server terminology in OpenVPN.
</t>
<t>
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.
</t>
<t>
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.
</t>
<t>
[FIXME/syzzer: explain more what happens on the wire during the
SSL/TLS handshake and certificate authentication]
</t>
<t>
The TLS mode will use the same communication channel for
both TLS handshakes and the tunnel data. The TLS handshakes
are 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.
</t>
</section>
</section>
</section>
<section title="OpenVPN wire packet format">
<t>
OpenVPN uses a single UDP or TCP connection between two
peers. Over this connection all packets for the VPN
connection are multiplexed. In UDP one packet is is the same
as one UDP payload. When TCP is used, each packet with started
by a 16 bit length indicator in network byte order, followed
by the packet.
</t>
<t>
Each packet starts with an opcode that determines the packet
type. OpenVPN packets fall can be differentiated into two
types of packets: control channel packets and data channel
apckets. They share the same header but serve different
purposes. The data channel packets transport the VPN
payload, typically IP packets. The control channel packets
are used to setup and control the VPN connection.
</t>
<t>
The key_id specifies a key generation that allow to
multiplex different key generations.
</t>
<t>
<figure>
<sourcecode>
struct tcp_packet {
uint16 len;
int opcode:5;
int keyid:3;
uint8 data[];
}
struct udp_packet {
int opcode:5;
int keyid:3;
uint8 data[];
}
</sourcecode>
</figure>
</t>
<t>
The following sections will often only show the UDP format for brievity. The
TCP format can be infered by prepending the 16 bit length field.
</t>
<t>
The <xref target="datachannel">data channel section</xref>
and <xref target="controlchannel">control channel</xref>
sections describe the formats of the packets in details.
</t>
</section>
<section title="General Control channel format">
<t>
There are three different variants of the control channel format. The
format depends on the variant of control channel authentication and
encryption.
</t>
<section title="Unauthenticated control channel packets">
<t>
<figure>
<sourcecode>
struct control_packet {
int opcode:5;
int keyid:3;
uint64_t own_session_id;
uint8_t acked_pktid_len;
uint8_t[n*8] acked_pktid_list; [only if acked_id_len > 0]
uint64_t peer_session_id; [only if acked_id_len > 0]
uint32_t packet_id;
uint8_t control_channel_payload[];
}
</sourcecode>
</figure>
The basic form of control channe ldoes not involve any additional authentication or
encryption of control channel packets.
</t>
<t>
The <tt>own_session_id</tt> is an opaque id that identifies the session id
from the perspective of the peer. The peer MUST NOT make any assumption about the
format of this id. It is RECOMMEND to use 64 bit of randomness.
</t>
</section>
<section title="OpenVPN mixed timestamp/packet counter format" anchor="longpkt">
<t>
The <tt>replay_packet_id</tt> 64 bit counter that is used by both tls-crypt and tls-auth has internally
the following format
<figure>
<sourcecode>
struct replay_packet_id_packet {
uint32_t packet_id;
uint32_t timestamp;
}
</sourcecode>
</figure>
This format is a legacy from old static key mode from OpenVPN to avoid IV reuse and provide a stable packet counter.
While OpenVPN largely abondoned this format and static key format, this packet counter format still survived in the
replay protection for tls-auth and tls-crypt protocol. Unfortunately, in this format the format the order of the fields
does not represent their significance and when interpreting this as a 64bit counter, the timestamp value represents the
more significant bytes. To turn this structure into a 64bit counter, the timestamp represent the upper 32 bit while the
packet_id represents the lower 32 bits.
(timestamp << 32) | packet_id
</t>
</section>
<section title="HMAC authentication of control channel packets" anchor="tlsauth">
<t>
<figure>
<sourcecode>
struct tlsauth_control {
int opcode:5;
int keyid:3;
uint64_t own session_id;
uint8[8-32] hmac;
uint64_t replay_packet_id;
uint8_t acked_pktid_len;
uint8_t[n*8] acked_pktid_list; [only if acked_id_len > 0]
uint64_t peer_session_id; [only if acked_id_len > 0]
uint32_t packet_id;
uint8_t payload[];
}
</sourcecode>
</figure>
</t>
<t>
In this mode, which is also called tls-auth in existing implementations,
control channel packets are authenticated by the
use of an <xref target="RFC2104">HMAC</xref> signature using a pre-shared key.
</t>
<t>
This authentication can strengthen the overall security on
both client and server side as OpenVPN will validate the HMAC
signature before any other processing on the packet is done.
This can protect server and client from triggering problems in
other parts of implementation such as TLS protocol implementations.
</t>
<t>
The keys used for the HMAC signatures are static and pre-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 are configured to use the
same algorithm. The choice of hashing algorithms defines the length
of the HMAC field in the control packet. HMAC-SHA1 uses 160 bits (20 bytes),
HMAC-SHA512 uses 512 bits (64 bytes).
</t>
<t>
The key used for the HMAC signatures has the same length as the
HAMC signature. A different key is used for each direction
between two peers. The keys can be identical but it is recomended
that they are different.
The appendix <xref target="ovpnkeyfile">OpenVPN static key format</xref>
will provide the file format that is used in existing implementations
to provide these keys.
</t>
<t>
The HMAC is calculated over the foloowing pseudo packet, which moves the
replay_packet_id to the beginning and drops the hmac field.
</t>
<figure>
<sourcecode>
struct tlsauth_control {
uint64_t replay_packet_id;
int opcode:5;
int keyid:3;
uint64_t own session_id;
uint8_t acked_pktid_len;
uint8_t[n*8] acked_pktid_list; [only if acked_id_len > 0]
uint64_t peer_session_id; [only if acked_id_len > 0]
uint32_t packet_id;
uint8_t payload[];
}
</sourcecode>
</figure>
<t>
When sending or resending a packet, an implementation must increase the replay_packet_id
counter, calculate the HMAC and send the packet with the HMAC.
</t>
<t>
On recieving, the receiver MUST check if the replay_packet_id is not an already received
replay_packet_id or is lower by 32 or more than the highest replay_packet_id in an
authenticated packet from a peer and otherwise discard it. The value 32 MAY be
configurable. If the packet passes this test, the HMAC of the packet using the
outlined procedure MUST be calculated and verfied. If the HMAC does not match,
the implementation MUST discard the packet.
</t>
</section>
<section title="Encrypting control channel packets (tls-crypt)" anchor="tlscrypt">
<t>
When using this format of control packets, OpenVPN peers will encrypt the control
packet channel payload using pre-shared static keys. The encryption scheme uses
a pair of encryption key <tt>Ke</tt> (256 bite) and HMAC authentication key <tt>Ka</tt>
(256 bits) per direction, four private keys or 1024 bits in total.
In existing impelmentation this feature is usually referred to as "tls-crypt".
</t>
<t>
Encrypting control channel packets has three main advantages:
<ul>
<li> It provides more privacy by hiding the certificate used
for the TLS connection. </li>
<li> It is harder to identify OpenVPN traffic as such. </li>
<li> It provides "poor-man's" post-quantum security, against
attackers who will never know the pre-shared key
(i.e. no forward secrecy provided by the pre-shared private key). </li>
</ul>
</t>
<section title="Control channel packet encryption">
<t>
The encryption method is based on the SIV construction
<xref target="rogaway2006provable" format="default" sectionFormat="of" derivedContent="rogaway2006provable"/>,
to achieve nonce misuse-resistant authenticated encryption.
Note that this is is using AES256-CTR and HMAC-SHA256 and is not the
<xref target="RFC8452">RFC8452 AES-GCM-SIV</xref>.
</t>
<t>
TODO: Check if our scheme is one that is described in RFC 5297
</t>
<t>
The use of a nonce misuse-resistant authenticated encryption scheme
allows minimising the risks of nonce collisions. This is
important, because in contrast to other encryption as TLS, it is impractical
to rotate the pre-shared keys often or fully guarantee nonce
uniqueness. For non misuse-resistant modes such as GCM
(<xref target="ferguson2005authentication" format="default" sectionFormat="of" derivedContent="ferguson2005authentication"/>,
<xref target="joux2006authentication" format="default" sectionFormat="of" derivedContent="joux2006authentication"/>),
the TLS (or OpenVPN's own data channel) only has to ensure that the packet counter
never rolls over, while the encryption of control packages would have to
provide nonce uniqueness over all control channel packets sent by all clients,
for the lifetime of the pre-shared key.
</t>
<t>
This control channel packet format uses fixed encryption and authentication
algorithms. This encryption intention is to primarely provide privacy as well
as DoS protection, these MUST not be made negotiable.
</t>
<t>
The format of a tls-crypt control packet looks are the following:
<figure>
<artwork>
struct tlscrypt_control {
int opcode:5;
int keyid:3;
uint64_t own session_id;
uint64_t replay_packet_id;
uint8 auth_tag[32];
uint8[] enc_control_payload;
}
</artwork>
</figure>
</t>
<t>
The encrypted payload enc_control_payload consits of encrypting
the following structure:
<figure>
<artwork>
struct clear_control_payload {
uint8_t acked_pktid_len;
uint8_t[n*8] acked_pktid_list; [only if acked_id_len > 0]
uint64_t peer_session_id; [only if acked_id_len > 0]
uint32_t packet_id;
uint8_t control_channel_payload[];
}
</artwork>
</figure>
</t>
<t>
The auth tag is generated by generating a HMAC-SHA256 with the pre-shared HMAC key over the
the cleartext of the tls_auth_control structure and the clear_control_payload struct,
omitting the auth_tagfand enc_control_payload fields:
</t>
<t>
<tt>auth_tag = HMAC-SHA256(Ka, opcode || keyid || own_session_id || replay_packet_id || clear_control_payload)</tt>
</t>
<t> Using the auth_tag, we create the IV from it.
</t>
<t>
<tt>IV = 128 most-significant bits of auth_tag</tt>
</t>
<t>
And finally the <tt>enc_control_payload</tt> is encrypted using AES-CTR with <tt>Ke</tt>
as key and the constructed IV:
</t>
<t>
<tt>enc_control_payload = AES256-CTR(Ke, IV, clear_control_payload)</tt>
</t>
</section>
<section title="Security considerations">
<t>
This encryption scheme is a best-effort mechanism aiming to provide as much
privacy and security as possible, while staying as simple as possible.
The following are some security considerations for this scheme.
</t>
<t>
The same set of pre-shared 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.
</t>
<t>
Since many peers potentially use the same set of keys for a long time, a
lot of data might be encrypted under the encryption keys. This leads
to two potential problems:
<ul>
<li>
<t>
The <tt>opcode || session id || packet id</tt> combination might collide.
This might happen in larger setups, because the session id contains
just 64 bits of randomess. Using the uniqueness requirement from the
GCM spec <xref target="nistgcm" format="default" sectionFormat="of"
derivedContent="nistgcm"/>
(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 (re)starting OpenVPN.)
</t>
<t>
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, this is considered an acceptable
remaining risk.
</t>
</li>
<li>
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 <xref target="nistgcm" format="default"
sectionFormat="of" derivedContent="nistgcm"/>,
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.
</li>
</ul>
</t>
<t>
Typical OpenVPN implementations will use the same key format as for the authentication
of control channel to distribute the pre-shared keys. See Appendix
<xref target="ovpnkeyfile">OpenVPN static key format</xref>
for a description of the format.
</t>
</section>
<section anchor="tlscryptv2" title="Client-specific encryption keys">
<t>
This section describes configuring OpenVPN to use client-specific tls-crypt keys. This feature is
referred to as tls-crypt-v2 in existing implementations.
</t>
<section title="Rationale">
<t>
``--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``.
</t>
<t>
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)").
</t>
</section>
<section title="Introduction">
<t>
The per client encryption key schema 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.
</t>
<t>
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).
</t>
<t>
To allow for a smooth transition, this feature is designed such that a
server can enable both the per client encryption 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.
</t>
</section>
<section title="Implementation">
<t>
This implementation here assumes that all server share the same pre-shared key. Since the
server implementation is transparent to the client, another schema can be potentially used.
</t>
<t>
<ol>
<li>
The server key cosists of 2 512-bit keys, of which we use:
<ul>
<li> the first 256 bits of key 1 as AES-256-CTR encryption key ``Ke``</li>
<li> the first 256 bits of key 2 as HMAC-SHA-256 authentication key ``Ka`` </li>
</ul>
</li>
<li>
This server key is shared by all OpenVPN servers that clients should be considere as equivalent. For different
servers, different sets of keys SHOULD be supported.
</li>
</ol>
</t>
<t>
The client key consists of two parts. The client-specific key ``Kc`` and a wrapped key ``WKc`` that is opaque to the
client.
</t>
<t>
The 2048 bits client-specific key ``Kc`` is identical to the key for the control channel encryption.
</t>
<t>
The wrapped key has the foloowing components:
<ol>
<li>The 2048 bits client-specific key ``Kc`` is identical to the key for the control channel encryption. </li>
<li>
<t> Optional Metadata
The first byte of the metadata determines the type. The initial
implementation supports the following types:
<ul>
<li> 0x00 (USER): User-defined free-form data. </li>
<li> 0x01 (TIMESTAMP): 64-bit network order unix timestamp of key generation. </li>
</ul>
</t>
<t>
The timestamp can be used to reject too-old tls-crypt-v2 client keys.
</t>
<t>
User metadata could for example contain the users certificate serial, such
that the incoming connection can be verified against a CRL.
</t>
<t>
If no metadata is supplied during key generation, an implementation SHOULD default to the
TIMESTAMP metadata type.
</t>
</li>
<li> Create a wrapped client key ``WKc``, using the same nonce-misuse-resistant
SIV construction we use for tls-crypt:
<figure>
<sourcecode>
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
</sourcecode>
</figure>
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).
</li>
<li> Create a tls-crypt-v2 client key: PEM-encode ``Kc || WKc`` and store in a
file, using the header <tt>-----BEGIN OpenVPN tls-crypt-v2 client key-----</tt>
and the footer <tt>-----END OpenVPN tls-crypt-v2 client key-----</tt>. (The PEM
format is simple, and following PEM allows us to use the crypto library functions
for en/decoding.)
</li>
<li> Add the tls-crypt-v2 client key to the client config
(``tls-crypt-v2 /path/to/client-specific.key``)</li>
</ol>
</t>
<t>
When setting up the OpenVPN connection:
<ol>
<li> The client reads the tls-crypt-v2 key from its config, and:
<ol>
<li> loads ``Kc`` as its tls-crypt key, </li>
<li> stores ``WKc`` in memory for sending to the server. </li>
</ol>
</li>
<li> 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.)</li>
<li> The server receives the P_CONTROL_HARD_RESET_CLIENT_V3 message, and
<ol>
<li> reads the WKc length field from the end of the message, and extracts WKc
from the message </li>
<li> unwraps ``WKc`` </li>
<li> uses unwrapped ``Kc`` to verify the remaining
P_CONTROL_HARD_RESET_CLIENT_V3 message's (encryption and) authentication. </li>
</ol>
The message is dropped and no error response is sent when any of these steps fails (DoS protection).
</li>
<li> 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.
</li>
<li> Client and server use ``Kc`` for (un)wrapping any following control channel
messages.</li>
</ol>
</t>
<t>
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):
<ol>
<li> 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.
</li>
<li>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.
</li>
<li>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.
</li>
</ol>
</t>
</section>
<section title="Considerations">
<t>
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.
</t>
<t>
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.)
</t>
<t>
``tls-crypt-v2`` uses fixed crypto algorithms, because:
<ul>
<li>The crypto is used before we can do any negotiation, so the algorithms have
to be predefined.</li>
<li>The crypto primitives are chosen conservatively, making problems with these
primitives unlikely.</li>
<li>Making anything configurable adds complexity, both in implementation and
usage. We should not add any more complexity than is absolutely necessary.</li>
</ul>
</t>
<t>
Potential ``tls-crypt-v2`` risks:
<ul>
<li>Slightly more work on first connection (``WKc`` unwrap + hard reset unwrap)
than with ``tls-crypt`` (hard reset unwrap) or ``tls-auth`` (hard reset auth).</li>
<li>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.)</li>
</ul>
</t>
</section>
</section>
</section>
</section>
<section anchor="controlchannel" title="Control channel">
<t>
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.
</t>
<section title="Overview of OPCODEs">
<t>
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. The op codes
DATA_V1 and DATA_V2 are NOT control channel op coes and will NOT be discussed
in this chapter. They are included for completeness.
</t>
<texttable>
<ttcol>OPCODE</ttcol>
<ttcol>Channel</ttcol>
<ttcol>Short name</ttcol>
<ttcol>Payload</ttcol>
<ttcol>Status</ttcol>
<c>1</c>
<c>Control</c>
<c>CONTROL_HARD_RESET_CLIENT_V1</c>
<c/>
<c>Obsolete</c>
<c>2</c>
<c>Control</c>
<c>CONTROL_HARD_RESET_SERVER_V1</c>
<c/>
<c>Obsolete</c>
<c>3</c>
<c>Control</c>
<c>CONTROL_SOFT_RESET_V1</c>
<c>-</c>
<c>Obsolete</c>
<c>4</c>
<c>Control</c>
<c>CONTROL_V1</c>
<c>X</c>
<c>Current</c>
<c>5</c>
<c>Control</c>
<c>ACK_V1</c>
<c>X</c>
<c>Current</c>
<c>6</c>
<c>Data</c>
<c>DATA_V1</c>
<c>X</c>
<c>Current</c>
<c>7</c>
<c>Control</c>
<c>CONTROL_HARD_RESET_CLIENT_V2</c>
<c>-</c>
<c>Current</c>
<c>8</c>
<c>Control</c>
<c>CONTROL_HARD_RESET_SERVER_V2</c>
<c>-</c> <!-- FIXME: VERIFY -->
<c>Current</c>
<c>9</c>
<c>Data</c>
<c>DATA_V2</c>
<c>X</c>
<c>Current</c>
<c>10</c>
<c>Control</c>
<c>CONTROL_HARD_RESET_CLIENT_V3</c>
<c>X</c>
<c>Current</c>
<c>11</c>
<c>Control</c>
<c>CONTROL_WKC_V1</c>
<c>X</c>
<c>Current</c>
</texttable>
</section>
<section title="The Control Channel">
<t>
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.
</t>
<section title="Control channel wire packet structure">
<t>
The following table lists all fields found in control channel
packets. The fields arrive in the order they are listed in the
table.
</t>
<t>
The TLS auth column indicates fields used when additional
HMAC authentication data is added to the control channel packets.
</t>
<texttable>
<ttcol>Field name</ttcol>
<ttcol align="right">Length (bits)</ttcol>
<ttcol align="center">TLS auth</ttcol>
<ttcol>Comment</ttcol>
<c>pkt_len</c>
<c>16</c>
<c></c>
<c>Packet length (TCP only)</c>
<c>OPCODE</c>
<c>5</c>
<c></c>
<c></c>
<c>key_id</c>
<c>3</c>
<c>X</c>
<c></c>
<c>own session_id</c>
<c>64</c>