{"id":3699,"date":"2012-12-04T20:47:20","date_gmt":"2012-12-04T12:47:20","guid":{"rendered":"https:\/\/www.icocean.com\/wp\/?p=3699"},"modified":"2012-12-04T22:06:37","modified_gmt":"2012-12-04T14:06:37","slug":"open","status":"publish","type":"post","link":"https:\/\/www.icocean.com\/blog\/?p=3699","title":{"rendered":"OpenVPN Security Overview"},"content":{"rendered":"<p><strong>OpenVPN cryptographic layer<\/strong><br \/>\nThis is a technical overview of OpenVPN&#8217;s cryptographic layer, and assumes a prior understanding of modern cryptographic concepts. For additional discussion on OpenVPN security, see this FAQ item.<br \/>\nOpenVPN has two authentication modes:<\/p>\n<li><strong>Static Key<\/strong> &#8212; Use a pre-shared static key<\/li>\n<li><strong>TLS<\/strong> &#8212; Use SSL\/TLS + certificates for authentication and key exchange<\/li>\n<p>In static key mode, a pre-shared key is generated and shared between both OpenVPN peers before the tunnel is started.<br \/>\n<!--more--><br \/>\nThis static key contains 4 independent keys: HMAC send, HMAC receive, encrypt, and decrypt. By default in static key mode, both hosts will use the same HMAC key and the same encrypt\/decrypt key. However, using the direction parameter to <strong>&#8211;secret<\/strong>, it is possible to use all 4 keys independently.<\/p>\n<p>In SSL\/TLS mode, an SSL session is established with bidirectional authentication (i.e. each side of the connection must present its own certificate). If the SSL\/TLS authentication succeeds, encryption\/decryption and HMAC key source material is then randomly generated by OpenSSL&#8217;s RAND_bytes function and exchanged over the SSL\/TLS connection. Both sides of the connection contribute random source material. This mode never uses any key bidirectionally, so each peer has a distinct send HMAC, receive HMAC, packet encrypt, and packet decrypt key. If <strong>&#8211;key-method 2<\/strong> is used, the actual keys are generated from the random source material using the TLS PRF function. If <strong>&#8211;key-method 1<\/strong> is used, the keys are generated directly from the OpenSSL RAND_bytes function. <strong>&#8211;key-method 2<\/strong> was introduced with OpenVPN 1.5.0 and will be made the default in OpenVPN 2.0.<\/p>\n<p>During SSL\/TLS rekeying, there is a transition-window parameter that permits overlap between old and new key usage, so there is no time pressure or latency bottleneck during SSL\/TLS renegotiations.<\/p>\n<p>Because SSL\/TLS is designed to operate over a reliable transport, OpenVPN provides a reliable transport layer on top of UDP (see diagram below).<\/p>\n<p>Once each peer has its set of keys, the tunnel forwarding operation commences.<br \/>\nThe encrypted packet is formatted as follows:<\/p>\n<li>HMAC(explicit IV, encrypted envelope)<\/li>\n<li>Explicit IV<\/li>\n<li>Encrypted Envelope<\/li>\n<p>The plaintext of the encrypted envelope is formatted as follows:<\/p>\n<li>64 bit sequence number<\/li>\n<li>payload data, i.e. IP packet or Ethernet frame<\/li>\n<p>The HMAC and explicit IV are outside of the encrypted envelope.<\/p>\n<p>The per-packet IV is randomized using a nonce-based PRNG that is initially seeded from the OpenSSL RAND_bytes function.<\/p>\n<p>HMAC, encryption, and decryption functions are provided by the OpenSSL EVP interface and allows the user to select an arbitrary cipher, key size, and message digest for HMAC. BlowFish is the default cipher and SHA1 is the default message digest. The OpenSSL EVP interface handles padding to an even multiple of block size using PKCS#5 padding. CBC-mode cipher usage is encouraged but not required.<\/p>\n<p>One notable security improvement that OpenVPN provides over vanilla TLS is that it gives the user the opportunity to use a pre-shared passphrase (or static key) in conjunction with the &#8211;tls-auth directive to generate an HMAC key to authenticate the packets that are themselves part of the TLS handshake sequence. This protects against buffer overflows in the OpenSSL TLS implementation, because an attacker cannot even initiate a TLS handshake without being able to generate packets with the currect HMAC signature.<\/p>\n<p>OpenVPN multiplexes the SSL\/TLS session used for authentication and key exchange with the actual encrypted tunnel data stream. OpenVPN provides the SSL\/TLS connection with a reliable transport layer (as it is designed to operate over). The actual IP packets, after being encrypted and signed with an HMAC, are tunnelled over UDP without any reliability layer. So if <strong>&#8211;proto udp<\/strong> is used, no IP packets are tunneled over a reliable transport, eliminating the problem of reliability-layer collisions &#8212; Of course, if you are tunneling a TCP session over OpenVPN running in UDP mode, the TCP protocol itself will provide the reliability layer.<br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.icocean.com\/blog\/wp-content\/uploads\/2012\/12\/OpenVPN-TCP-session-over-UDP.png\" alt=\"\" title=\"OpenVPN TCP session over UDP\" width=\"459\" height=\"155\" class=\"alignnone size-full wp-image-3710\" srcset=\"https:\/\/www.icocean.com\/blog\/wp-content\/uploads\/2012\/12\/OpenVPN-TCP-session-over-UDP.png 459w, https:\/\/www.icocean.com\/blog\/wp-content\/uploads\/2012\/12\/OpenVPN-TCP-session-over-UDP-300x101.png 300w\" sizes=\"auto, (max-width: 459px) 100vw, 459px\" \/><\/p>\n<p>This model has the benefit that SSL\/TLS sees a reliable transport layer while the IP packet forwarder sees an unreliable transport layer &#8212; exactly what both components want to see. The reliability and authentication layers are completely independent of one another, i.e. the sequence number is embedded inside the HMAC-signed envelope and is not used for authentication purposes.<br \/>\n<!--nextpage--><br \/>\n<strong>OpenVPN Protocol<\/strong><br \/>\n\/*<br \/>\n* OpenVPN Protocol, taken from ssl.h in OpenVPN source code.<br \/>\n*<br \/>\n* TCP\/UDP Packet:\u00a0 This represents the top-level encapsulation.<br \/>\n*<br \/>\n* TCP\/UDP packet format:<br \/>\n*<br \/>\n*\u00a0\u00a0 Packet length (16 bits, unsigned) &#8212; TCP only, always sent as<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 plaintext.\u00a0 Since TCP is a stream protocol, the packet<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 length words define the packetization of the stream.<br \/>\n*<br \/>\n*\u00a0\u00a0 Packet opcode\/key_id (8 bits) &#8212; TLS only, not used in<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 pre-shared secret mode.<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 packet message type, a P_* constant (high 5 bits)<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 key_id (low 3 bits, see key_id in struct tls_session<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 below for comment).\u00a0 The key_id refers to an<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 already negotiated TLS session.\u00a0 OpenVPN seamlessly<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 renegotiates the TLS session by using a new key_id<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 for the new session.\u00a0 Overlap (controlled by<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 user definable parameters) between old and new TLS<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 sessions is allowed, providing a seamless transition<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 during tunnel operation.<br \/>\n*<br \/>\n*\u00a0\u00a0 Payload (n bytes), which may be a P_CONTROL, P_ACK, or P_DATA<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 message.<br \/>\n*<br \/>\n* Message types:<br \/>\n*<br \/>\n*\u00a0 P_CONTROL_HARD_RESET_CLIENT_V1 &#8212; Key method 1, initial key from<br \/>\n*\u00a0\u00a0\u00a0 client, forget previous state.<br \/>\n*<br \/>\n*\u00a0 P_CONTROL_HARD_RESET_SERVER_V1 &#8212; Key method 2, initial key<br \/>\n*\u00a0\u00a0\u00a0 from server, forget previous state.<br \/>\n*<br \/>\n*\u00a0 P_CONTROL_SOFT_RESET_V1 &#8212; New key, with a graceful transition<br \/>\n*\u00a0\u00a0\u00a0 from old to new key in the sense that a transition window<br \/>\n*\u00a0\u00a0\u00a0 exists where both the old or new key_id can be used.\u00a0 OpenVPN<br \/>\n*\u00a0\u00a0\u00a0 uses two different forms of key_id.\u00a0 The first form is 64 bits<br \/>\n*\u00a0\u00a0\u00a0 and is used for all P_CONTROL messages.\u00a0 P_DATA messages on the<br \/>\n*\u00a0\u00a0\u00a0 other hand use a shortened key_id of 3 bits for efficiency<br \/>\n*\u00a0\u00a0\u00a0 reasons since the vast majority of OpenVPN packets in an<br \/>\n*\u00a0\u00a0\u00a0 active tunnel will be P_DATA messages.\u00a0 The 64 bit form<br \/>\n*\u00a0\u00a0\u00a0 is referred to as a session_id, while the 3 bit form is<br \/>\n*\u00a0\u00a0\u00a0 referred to as a key_id.<br \/>\n*<br \/>\n*\u00a0 P_CONTROL_V1 &#8212; Control channel packet (usually TLS ciphertext).<br \/>\n*<br \/>\n*\u00a0 P_ACK_V1 &#8212; Acknowledgement for P_CONTROL packets received.<br \/>\n*<br \/>\n*\u00a0 P_DATA_V1 &#8212; Data channel packet containing actual tunnel data<br \/>\n*\u00a0\u00a0\u00a0 ciphertext.<br \/>\n*<br \/>\n*\u00a0 P_CONTROL_HARD_RESET_CLIENT_V2 &#8212; Key method 2, initial key from<br \/>\n*\u00a0\u00a0 client, forget previous state.<br \/>\n*<br \/>\n*\u00a0 P_CONTROL_HARD_RESET_SERVER_V2 &#8212; Key method 2, initial key from<br \/>\n*\u00a0\u00a0 server, forget previous state.<br \/>\n*<br \/>\n* P_CONTROL* and P_ACK Payload:\u00a0 The P_CONTROL message type<br \/>\n* indicates a TLS ciphertext packet which has been encapsulated<br \/>\n* inside of a reliability layer.\u00a0 The reliability layer is<br \/>\n* implemented as a straightforward ACK and retransmit model.<br \/>\n*<br \/>\n* P_CONTROL message format:<br \/>\n*<br \/>\n*\u00a0\u00a0 local session_id (random 64 bit value to identify TLS session).<br \/>\n*\u00a0\u00a0 HMAC signature of entire encapsulation header for integrity<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 check if &#8211;tls-auth is specified (usually 16 or 20 bytes).<br \/>\n*\u00a0\u00a0 packet-id for replay protection (4 or 8 bytes, includes<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 sequence number and optional time_t timestamp).<br \/>\n*\u00a0\u00a0 P_ACK packet_id array length (1 byte).<br \/>\n*\u00a0\u00a0 P_ACK packet-id array (if length > 0).<br \/>\n*\u00a0\u00a0 P_ACK remote session_id (if length > 0).<br \/>\n*\u00a0\u00a0 message packet-id (4 bytes).<br \/>\n*\u00a0\u00a0 TLS payload ciphertext (n bytes) (only for P_CONTROL).<br \/>\n*<br \/>\n* Once the TLS session has been initialized and authenticated,<br \/>\n* the TLS channel is used to exchange random key material for<br \/>\n* bidirectional cipher and HMAC keys which will be<br \/>\n* used to secure actual tunnel packets.\u00a0 OpenVPN currently<br \/>\n* implements two key methods.\u00a0 Key method 1 directly<br \/>\n* derives keys using random bits obtained from the RAND_bytes<br \/>\n* OpenSSL function.\u00a0 Key method 2 mixes random key material<br \/>\n* from both sides of the connection using the TLS PRF mixing<br \/>\n* function.\u00a0 Key method 2 is the preferred method and is the default<br \/>\n* for OpenVPN 2.0.<br \/>\n*<br \/>\n* TLS plaintext content:<br \/>\n*<br \/>\n* TLS plaintext packet (if key_method == 1):<br \/>\n*<br \/>\n*\u00a0\u00a0 Cipher key length in bytes (1 byte).<br \/>\n*\u00a0\u00a0 Cipher key (n bytes).<br \/>\n*\u00a0\u00a0 HMAC key length in bytes (1 byte).<br \/>\n*\u00a0\u00a0 HMAC key (n bytes).<br \/>\n*\u00a0\u00a0 Options string (n bytes, null terminated, client\/server options<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string should match).<br \/>\n*<br \/>\n* TLS plaintext packet (if key_method == 2):<br \/>\n*<br \/>\n*\u00a0\u00a0 Literal 0 (4 bytes).<br \/>\n*\u00a0\u00a0 key_method type (1 byte).<br \/>\n*\u00a0\u00a0 key_source structure (pre_master only defined for client -><br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 server).<br \/>\n*\u00a0\u00a0 options_string_length, including null (2 bytes).<br \/>\n*\u00a0\u00a0 Options string (n bytes, null terminated, client\/server options<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string must match).<br \/>\n*\u00a0\u00a0 [The username\/password data below is optional, record can end<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 at this point.]<br \/>\n*\u00a0\u00a0 username_string_length, including null (2 bytes).<br \/>\n*\u00a0\u00a0 Username string (n bytes, null terminated).<br \/>\n*\u00a0\u00a0 password_string_length, including null (2 bytes).<br \/>\n*\u00a0\u00a0 Password string (n bytes, null terminated).<br \/>\n*<br \/>\n* The P_DATA payload represents encrypted, encapsulated tunnel<br \/>\n* packets which tend to be either IP packets or Ethernet frames.<br \/>\n* This is essentially the &#8220;payload&#8221; of the VPN.<br \/>\n*<br \/>\n* P_DATA message content:<br \/>\n*\u00a0\u00a0 HMAC of ciphertext IV + ciphertext (if not disabled by<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &#8211;auth none).<br \/>\n*\u00a0\u00a0 Ciphertext IV (size is cipher-dependent, if not disabled by<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &#8211;no-iv).<br \/>\n*\u00a0\u00a0 Tunnel packet ciphertext.<br \/>\n*<br \/>\n* P_DATA plaintext<br \/>\n*\u00a0\u00a0 packet_id (4 or 8 bytes, if not disabled by &#8211;no-replay).<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 In SSL\/TLS mode, 4 bytes are used because the implementation<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 can force a TLS renegotation before 2^32 packets are sent.<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 In pre-shared key mode, 8 bytes are used (sequence number<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 and time_t value) to allow long-term key usage without<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 packet_id collisions.<br \/>\n*\u00a0\u00a0 User plaintext (n bytes).<br \/>\n*<br \/>\n* Notes:<br \/>\n*\u00a0\u00a0 (1) ACK messages can be encoded in either the dedicated<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 P_ACK record or they can be prepended to a P_CONTROL message.<br \/>\n*\u00a0\u00a0 (2) P_DATA and P_CONTROL\/P_ACK use independent packet-id<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 sequences because P_DATA is an unreliable channel while<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 P_CONTROL\/P_ACK is a reliable channel.\u00a0 Each use their<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 own independent HMAC keys.<br \/>\n*\u00a0\u00a0 (3) Note that when &#8211;tls-auth is used, all message types are<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 protected with an HMAC signature, even the initial packets<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 of the TLS handshake.\u00a0 This makes it easy for OpenVPN to<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 throw away bogus packets quickly, without wasting resources<br \/>\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 on attempting a TLS handshake which will ultimately fail.<br \/>\n*\/<\/p>\n<nav class=\"page-links\"><strong>\u9875\u9762\uff1a<\/strong> <a href=\"https:\/\/www.icocean.com\/blog\/?p=3699\" class=\"post-page-numbers\"><span class=\"page-num\">1<\/span><\/a> <a href=\"https:\/\/www.icocean.com\/blog\/?p=3699&#038;page=2\" class=\"post-page-numbers\"><span class=\"page-num\">2<\/span><\/a><\/nav>\n","protected":false},"excerpt":{"rendered":"<p>OpenVPN cryptographic layer This is a technical overvie <a href='https:\/\/www.icocean.com\/blog\/?p=3699' class='excerpt-more'>[&#8230;]<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[3074,2481,3681],"class_list":["post-3699","post","type-post","status-publish","format-standard","hentry","category-4","tag-openvpn","tag-security","tag-tls","category-4-id","post-seq-1","post-parity-odd","meta-position-corners","fix"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.icocean.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/3699","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.icocean.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.icocean.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.icocean.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.icocean.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3699"}],"version-history":[{"count":9,"href":"https:\/\/www.icocean.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/3699\/revisions"}],"predecessor-version":[{"id":3711,"href":"https:\/\/www.icocean.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/3699\/revisions\/3711"}],"wp:attachment":[{"href":"https:\/\/www.icocean.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3699"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.icocean.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3699"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.icocean.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3699"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}