Giblets IPsec, we measure against TLS 1.3, GOST and Go

Greetings! I'd like to tell you about the device of the modern IPsec stack of the ESPv3 and IKEv2 protocols . IPsec, it seems to me, undeservedly bypasses many sides and I have not seen a detailed analysis of its work, its protocols and capabilities in Russian. Also, I'll do something weird - compare IPsec ESPv3 and IKEv2 (both 2005) with the modern, trendy, state-of-art TLS 1.3 of 2018.





Why am I so passionate about IPsec - arguably the most complex protocol stack for securing networks? After all, complexity is the main enemy of reliability and safety! Firstly, the more you learn about its protocols, especially IKEv2, the more you understand how many possibilities were put into it and you are impressed by its thoughtfulness, in contrast to the popular approach of developers "a crutch drives a crutch" and solving serious problems "until the thunder breaks out". Secondly, IPsec protocols are well thought out from a cryptographic point of view, and even the old ESP / IKEv1, in fact, are the only industrial mass-used protocols in which there were no serious vulnerabilities. The same SSL (1995th year) became decently thought out only from version 1.3. And many people dislike IPsec due to the monstrous complexity of IKEv1,which is no longer in v2.



Ideally, if the developers of operating systems did not slow down in their time with the implementation and implementation of IPsec and IPv6 (for the availability of computers, so that no NAT), then no SSL / TLS should have appeared in principle. The world turned out to be not perfect, but now IPsec out of the box (at least SA / SP + ESP part of the stack) is available in any at least some widespread OS (personally, I only know DragonFly BSD , which drank IPsec due to a lack of developers to support it), and IPv6 in some developed countries is immediately available to the vast majority of people.



IPsec is a stack of protocols, API calls, framework so that applications and / or the administrator can tell what security they need during communication and it would be transparently ensured at the network level ( IP security). We can talk about both IP packets of only one socket (for example, TCP connections), and about traffic between entire networks.



Traffic security means: ensuring the confidentiality of data, its authenticity / integrity and protection against replay attacks . Like almost all protocols, IPsec has a transport part that secures IP packets, and a handshake part related to key negotiation, parameters, configuration and authentication of the parties.



TLS 1.3 : only provides per-socket data protection for TCP connections. DTLS can provide protection for datagrams (DTLS 1.3 is not a standard yet), but not every library supports this.



Transport protocols



IPsec transport uses IP protocols:



  • AH (authentication headers). I will not talk about AH further, since it does not provide data confidentiality and, as far as I heard, it was made solely to somehow "put up" with the laws of some countries in the 1990s on restrictions on the use of encryption. Encryption is so lightweight relative to everything else that it doesn't make sense to sacrifice it. But almost everywhere ESP is mentioned, AH is also meant.
  • ESP (encapsulating security payloads). ESP has evolved slightly over time and is now using its ESPv3 version, which is often backward compatible and does not differ from the previous version.


IP traffic is secured only by the transport layer. And since we can talk about many millions of packets per second, de facto ESP is implemented at the kernel level of the operating system, in its network stack, at least in order not to make expensive context switching between the kernel and userspace (as it usually happens with TLS , SSH, OpenVPN, and others).



I emphasize that AH and ESP are IP-layer protocols, network, not transport. Why not UDP? The checksum is redundant and burns the CPU, and cryptography will ensure the integrity anyway. But, if your NAT knows nothing about ESP (and he does not know), then all this will not work for him. Later they came up with NAT-T crutches (NAT traversal), when IPsec traffic is wrapped in a UDP packet on port 4500 and will be able to pass through NAT, but this is an unnecessary overhead and the need to edit the IPsec stack in the kernel, because it should already understand these special UDP packets and extract ESP from them for it regular processing.



SP, SA, SPI and our first IPsec encryption



How does the kernel know what to do with an IP packet: whether to encrypt it using some key, decrypt the incoming ESP, or let it pass without touching it? To do this, the kernel has Security Policies ( SP ). These are rules like in a firewall. In addition to them, the core contains Security Associations ( SA ): contexts for performing cryptographic operations (keys, counters, window replay, etc.). In general, neither SPs are IPsec-specific, nor SAs β€” they can be used for other tasks / protocols (eg OSPF).



SP / SA can be configured either through a special API ( PF_KEYv2 ), or by hand through some setkey utility. For example, if we want to tell the kernel that all IP packets coming fromfc :: 123 addresses on fc :: 321 must be secured via ESP, then this can be easily done by calling from the command line:



$ echo "spdadd fc00::123 fc00::321 any -P out ipsec esp/transport//require;" | setkey -c


Before this command, we saw pings:



IP6 fc00::123 > fc00::321: ICMP6, echo request, seq 0, length 16
IP6 fc00::321 > fc00::123: ICMP6, echo reply, seq 0, length 16
IP6 fc00::123 > fc00::321: ICMP6, echo request, seq 1, length 16
IP6 fc00::321 > fc00::123: ICMP6, echo reply, seq 1, length 16


We won't see it later, since the kernel does not yet know "what" to encrypt. You need to add SA, and this can also be done manually, setting the AEAD encryption algorithm and a random 160-bit key for simplicity AES-GCM-16 :



echo "add fc00::123 fc00::321 esp 0xdeadbabe -E aes-gcm-16 0x0c09d1d90f804b0b4cef80e255e29c0894db1928 ;" | setkey -c


If we execute the same commands on the remote host (just not forgetting to specify -P in ), we will see:



IP6 fc00::123 > fc00::321: ESP(spi=0xdeadbabe,seq=0x1), length 52
IP6 fc00::321 > fc00::123: ICMP6, echo reply, seq 0, length 16
IP6 fc00::123 > fc00::321: ESP(spi=0xdeadbabe,seq=0x2), length 52
IP6 fc00::321 > fc00::123: ICMP6, echo reply, seq 1, length 16


Request is encrypted by ESP, but reply is not. Because ESP works in "one way" by default and for two-way communication it is necessary to add another SP / SA for the opposite direction.



0xdeadbabe in this example is the Security Parameters Index ( SPI ) - a unique identifier for the ESP "tunnel" between two IP addresses, at which the kernel can find the corresponding SA context and take the decryption key from it. And esp / transport // require is a requirement to use ESP in transport mode (more on that below).



Giblets ESP



The ESP package is schematically structured as follows:



  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---
|               Security Parameters Index (SPI)                 | ^
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | A
|                      Sequence Number                          | | u
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | t
~                       IV (variable)                           ~ | h
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | e -----
|                    Payload Data  (variable)                   | | n   ^ E
~                                                               ~ | t   | n
|                                                               | | i   | c
+               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | c   | r
|               |         TFC Padding * (optional, variable)    | | a   | y
+-+-+-+-+-+-+-+-+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | t   | p
|                         |        Padding (0-255 bytes)        | | e   | t
+-+-+-+-+-+-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | d   | e
|                               |  Pad Length   | Next Header   | v     v d
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---------
~         Integrity Check Value-ICV   (variable)                ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


  • SPI - 32-bit unique identifier for the ESP session / tunnel / connection between IP addresses. Typically, {SrcIP, DstIP, SPI} is the SA and the cryptographic context.
  • SeqNum β€” 32- . . , replay attack.
  • payload β€” ESP, .
  • TFC padding β€” (Traffic Flow Confidentiality), , - , . TFC , , payload , . , payload IP , . TFC - , .
  • Padding β€” ESP payload 32- , . , ( CBC) . . .
  • Pad Length β€” 8- Padding .
  • Next Header β€” 8- IP payload. Β«no next headerΒ», ESP- β€” , . TFC β€” .
  • ICV β€” Integrity Check Value, (MAC).


The entire part of the packet from payload to Next Header is encrypted. Everything except the MAC is authenticated. The length of the ICV, the presence of an IV (initialization vector) depends on the encryption and authentication modes / algorithms used.



TLS 1.3 : optional padding of data to a given size appeared only in version 1.3. Otherwise, encryption and authentication are completely similar. TLS 1.3 obliges to use only AEAD algorithms, which is correct and good. ESP supports AEAD, but there is a choice of more archaic solutions. Type fields SPI or SeqNumno, since TCP guarantees sequence and delivery, in addition, in practice, no initialization vector is explicitly transmitted - the TLS record layer packet is therefore slightly shorter. DTLS already contains SeqNum as well as message fragmentation data.



The 32-bit packet number may be too short in practice. This is just 4+ billion IP packets, which at 10+ Mpps speeds can fly in minutes. What happens when the counter overflows? It will reset to zero. But, this will mean that the SPI + SeqNum value will start repeating for us and the previously intercepted ESP packets can be used for replaying the attack. To solve this problem, ESN was invented(Extended Sequence Number). This is a 64-bit counter, but only the "lower" 32-bits of which are transferred to the SeqNum field, and the upper 32-bits are stored in memory. The full value of the ESN is authenticated - therefore the parties are obliged to agree on the use of the ESN in advance.



ESP encryption



How exactly does the encryption / authentication of an ESP packet take place, for example, when using AES-GCM-16? To work with ESP, it uses a 64-bit initialization vector located at the beginning of payload . It also uses 32-bit salt as part of the key material. In the example for setkey, I provided not a 128-bit key, but a 128 + 32-bit key. There may be situations where the key is reused and the IV is filled with a bad pseudo random number generator (PRNG) whose values ​​can be repeated. The salt is designed to protect against this most dangerous case, which potentially leads to decryption of intercepted packets. The ESP encryption / authentication itself in AES-128-GCM-16-ESP mode is as follows:



AES-GCM(
    key             = 128-bit key,
    plaintext       = 64-bit IV || payload || TFC || pad || padLen || NH,
    nonce           = 32-bit salt || IV,
    associated-data = SPI || {ESN  SeqNum},
) -> encrypted-payload || 128-bit ICV

ESP = SPI || SeqNum || IV || encrypted-payload || ICV


For Russian GOST algorithms (Magma or Grasshopper ciphers), the input data is similar. Both ciphers are used in MGM mode (I would say an improved version of GCM ), and regular ESPTREE key material rotation is applied using HMAC-Stribog-256. This reduces the load on the key. Mainly in the context of IPsec, this is not so much to increase its use time as to reduce the attack surface through side channels. For example, due to key meshing (a similar technology of constant key rotation), GOST 28147-89 block cipher with 64-bit block size turned out to be invulnerable to SWEET32 attacks.



From a safety point of view, there are no complaints about ESP with AEAD algorithms. But for AEAD algorithms, IV is just a 64-bit counter, explicitly passed with each packet that wastes space in the packet. SeqNum is too short, and ESN is not fully transmitted, although it would completely fit as an IV. For non-AEAD algorithms, IV may already be necessary and carry an unpredictable value, but by no means a counter. This is legacy, eating away precious space in the package and weight does not affect reliability here.







If IV for AEADs could have values ​​from 128-bits, then it would be possible to use algorithms like XSalsa20 / XChaCha20 with 192-bit nonce, 128-bit of which is pseudo-randomly generated at startup, and the remaining 64-bits can be used for the counter ... This could be a lifesaver for systems that have lost their counter state, but want to continue using existing keys.



TLS 1.3 : XOR is used as a nonce between the message counter and the initialization vector generated with the key. Since neither the meter nor the IV is explicitly transmitted, TLS 1.3 is a little more compact. If ESP uses non-AEAD algorithms, then they may require generating an unpredictable IV, which can be noticeably CPU-intensive.



Tunnel and transport modes



What is included in the payload of the package? It depends on whether the ESP is operating in transport mode or tunnel mode . Transport mode replaces the payload of the transmitted IP packet with ESP with this payload. That is, it was:



---------------------------------------
| orig IP hdr |[ext hdrs]| TCP | Data |
---------------------------------------


became:



---------------------------------------------------------
| orig |hop-by-hop,dest*,|   |dest|   |    | ESP   | ESP|
|IP hdr|routing,fragment.|ESP|opt*|TCP|Data|Trailer| ICV|
---------------------------------------------------------
                             |<--- encryption ---->|
                         |<---- authenticity ----->|


In tunnel mode, the entire IP packet is completely wrapped in ESP and a new IP packet is formed, usually with new headers and SrcIP / DstIP addresses. This mode is used to tunnel packets between networks.



----------------------------------------------------------
| new* |new ext|   | orig*|orig ext|   |    | ESP   | ESP|
|IP hdr| hdrs* |ESP|IP hdr| hdrs * |TCP|Data|Trailer| ICV|
----------------------------------------------------------
                   |<--------- encryption --------->|
               |<---------- authenticity ---------->|


For example, through setkey I can specify that all packets between 2001: ac :: / 64 and 2001: dc :: / 64 networks should pass encrypted through two endpoints of tunnels with addresses 2001 :: 123 , 2001 :: 321 ...



spdadd 2001:ac::/64 2001:dc::/64 any -P out ipsec esp/tunnel/2001::123-2001::321/require ;
spdadd 2001:dc::/64 2001:ac::/64 any -P in  ipsec esp/tunnel/2001::321-2001::123/require ;


Transport mode is often referred to as a host-to-host connection. If some GRE or IPv * -over-IPv * protocol is used for tunneling, which is already working between two endpoints, then it makes no sense, in this case, to use the tunneling mode at the IPsec level. However, transport mode does not authenticate the IP header. As a rule, this is not important and not critical, but if you want to make sure that no extended IPv6 headers or flow labels of packets have been changed, then you should use tunnel mode, even if between two hosts, at the cost of overhead.



ISAKMP



What happens if I reboot computers, SA with all the counter values ​​disappear from their memory, and I again load the old SP / SA commands with my hands? Firstly, packets that match the IV can be decrypted, since this is tantamount to using the cipher pad twice. Secondly, since SPI / salt / ESN / SeqNum match, then all previously intercepted packets will be validly authenticated and you can replay them. Reusing such setkey SAs is disastrous for security. Thirdly, especially if ESN is not used (for example, in FreeBSD at the time of this writing, it is not yet supported), with long SA operation, you may not notice that the counter is "used up".



All this means that we need to regularly change ESP keys. And also negotiate an encryption algorithm, the presence of ESN, TFC, transport / tunnel mode, SPI values. De facto, the ISAKMP protocol (Internet Security Association and Key Management Protocol) is used for this . Although, you can easily screw some IM with OTR / PGP / OMEMO authenticated encryption and just send the shell script setkey commands to the server, in which the keys are generated by reading / dev / urandom . It doesn't matter to the kernel how it was agreed. As in OpenVPN: X.509 authentication with certificates and key negotiation generally take place over TLS, and the VPN transport protocol itself is already its own.



In its "pure" form, ISAKMP is not used, since there is no cryptography in it. To authenticate interlocutors and generate key material, a third-party protocol is used that encapsulates ISAKMP inside itself. I know:



  • KINK - Kerberized Internet Negotiation of Keys , where a third trusted Kerberos KDC is used for authentication and negotiation. In addition to the description from Wikipedia, I do not know anything more about KINK and have not seen it live.
  • IKE (v1) - Internet Key Exchange . Probably still the most popular protocol, even though it was created in 1998.
  • IKEv2 is the second version of IKE, 2005, which I will talk about.


IKE protocols are very extensible due to the large number of different payload types. IKEv1 has a large number of options for configuring just one tunnel to work. More than a dozen RFCs describing the whole bunch of ISAKMP and IKEv1 with common payloads. Intimidating complexity. Plus the ability to easily screw up non-fool-proof configurations and the well-known, partly deservedly true, myth that IKEv1 is guaranteed to work only if, almost completely, copy the configuration file.



Fortunately, IKEv2 has appeared: one convenient RFC (for most features), a significantly simplified protocol for negotiating parameters and, accordingly, its configuration. As a rule, it has fewer round-trips for the entire handshake and key agreement process than in IKEv1. Therefore, only he will be considered, since there is no longer any sense in IKEv1 (but it is hardly worth chasing to replace already running and working instances, since they are working). IKEv2, unlike IKEv1, uses absolutely similar algorithms and approaches to encrypt its own messages as ESP does. It also introduced EAP authentication and the ability for each party to authenticate with different methods (for example, the client uses PSK, and the X.509 server uses certificates).



IKE daemon



      +-------------+
      |  |
      +-------------+
       |           |
       |           |
       |           |      /userspace
=====[PF_KEY]====[PF_INET]====================
       |           |                    
+-----------+   +-------------+
| |   |TCP/IP,      |
|  SA  SP  |---| IPsec|
+-----------+   +-------------+
                     |
                 +-----------+
                 |    |
                 |  |
                 +-----------+


This part of the IPsec stack is already running, usually in userspace. Firstly, these are not heavily loaded daemons: they can communicate with each other at least once a day, and the initial handshake takes a few round-trips over UDP. Secondly, the number of ISAKMP / IKE capabilities is such that there are hundreds of times more code than in the full SA / SP / ESP implementation. There are many implementations of ISAKMP daemons: strongSwan (IKEv1 / v2) (as well as Openswan , Libreswan ), isakmpd (IKEv1), OpenIKED (IKEv2), racoon (IKEv1), racoon2 (IKEv1 / v2, KINK) and others.



Note: correct to write and speak "DaemonsΒ» ( daemons), as I have seen in translations of fiction. But in technical Russian-speaking circles "demons" have already taken root.



TLS 1.3 : in general, the entire TLS stack is library functions that work in each individual application and store key material in its own memory. All cryptography is done with switching to userspace, which is a huge overhead. However, at least FreeBSD and Linux already have kernel offload implementations of TLS, when, similarly to IPsec, the transport part is processed entirely in the kernel, and the handshake takes place in userspace.



IKEv2 runs over UDP, by default on port 500 ( isakmpservice). Daemons create a secure channel, authenticate each other, negotiate / create / delete ESP SA / SPs, update keys, do heartbeat (Dead Peer Detection ( DPD )), and more. All communication between daemons takes place in the form of an exchange of a pair of request / response messages. Any request must be answered. Since this is UDP, what to do if a packet is lost? Take this into account in your state, resend requests after timeout for which no responses have been received, resend responses to repeated requests, ignore repeated responses. Packets can arrive in a chaotic order, they can disappear unpredictably - a lot is taken into account in the IKEv2 standard and it is described how to behave under various race conditions.



TLS 1.3: The TCP nature of TLS takes care of the order and delivery of messages. But TCP takes up significant resources in the OS kernel and a huge number of TCP sessions can be a problem (unlike UDP). But in DTLS all similar problems will arise in the same way as in IKE, plus hemorrhoids with the processing of fragmented messages will be added. Changing IP addresses of endpoints for UDP is not a problem. IKE connections, as a rule, are very long-lived (the IKE state is small and is stored only in the memory of the userspace daemon) and therefore require a handshake less often, whereas in TLS, after losing a TCP connection, you will have to do it (although there are also accelerated methods of continuing sessions if the state was not lost, for example when restarting the program). Since the IKE daemon is one for the entire system (as a rule), then if some application wants to securely communicate with thatwith someone who already has an IKE connection, he can either immediately use it or the daemon, in one round-trip, will create an additional ESP SA for the application.



Giblets IKE



The first exchange (request-response) of the daemons will be IKE_SA_INIT , which creates an IKE SA for further secure communication. Note that the ESP SA is "stored" in the kernel, and the IKE SA is in the userspace daemon. Then comes the IKE_AUTH exchange, where the parties are authenticated. In the same exchange, the creation of a child SA ( Child SA ) takes place , which is used for ESP SA. In general, these two exchanges are enough to authenticate the parties and negotiate ESP SA parameters with the keys and then drive encrypted ESP traffic between computers. In this case, a working IKE SA remains between the daemons for a long time. Further, at any time, they can make CREATE_CHILD_SA exchange, to create more child SAs, as well as INFORMATIONALexchange (a variety of purposes).



All IKEv2 message headers have the following structure:



                     1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       IKE SA Initiator's SPI                  |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       IKE SA Responder's SPI                  |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Next Payload |    Version    | Exchange Type |     Flags     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          Message ID                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                            Length                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


  • SPIi - 64-bit IKE SA Initiator SPI. An identifier randomly generated by the initiator of the IKE session.
  • SPIr - 64-bit IKE SA Responder SPI. Likewise, but only SPI from the responder side. In the very first message from the initiator, this field is filled with zero bytes.
  • NP - 8-bit Next payload. The identifier for the payload following the header.
  • Version - 8-bit version of the IKE protocol.
  • ExchType - 8-bit type of IKE exchange: IKE_SA_INIT , IKE_AUTH , CREATE_CHILD_SA, or INFORMATIONAL .
  • Flags β€” 8- . .
  • MsgID β€” 32- . , , replay-. β€” request/response MsgID. , .
  • Len β€” 32- ( + ).


SPIi + SPIr are 128-bit. Why so much when ESP only has 32 bits? Firstly, since they do not match, but are generated pseudo-randomly, 64-bit for one side will be enough to avoid collisions. Secondly, ESP is also tied to IP addresses, while an IKE session is generally not - the parties can easily change their IP addresses (mobile client) and continue to communicate.



TLS 1.3: Changing the IP address will disconnect the connection. You will need to do rehandshake, even with iPSK, saving on resources for asymmetric cryptography, this is 1.5 round-trips plus round-trips to establish a TCP connection. The creation of child ESP SAs on new IP addresses, in an already established IKE connection (unbound to addresses), will take only one round-trip (+ round-trip to remove old ones, but this will already happen in the background of a new working ESP SA).



The IKE header is followed by one or more payloads. Each payload has a general format header, followed by content specific to its type. Content is 32-bit aligned. A common header for all:



                     1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Next Payload  |C|  RESERVED   |         Payload Length        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


  • Next Payload β€” 8- . payload- . payload. payload IKE . Encrypted Payload, payload- NP ( payload IKE ), payload- .
  • C β€” «» payload. IKEv2 payload , IKE . payload . IKE vendor-specific , .
  • Len β€” 16- payload ( + ).


Thus, IKE messages consist of an IKE header and payloads linked together in a chain. Daemons can ignore non-critical and unknown payloads. The payload content of the Nonce type (after the header) is just a random set of data, not a fixed size. But there are also much more complex structures. In IKE standards, short designations for payload types are accepted (for example, N * for nonce messages, where "*" is either "i" (initiator) or "r" (responder)).



SIGMA



From a cryptographic point of view, IKEv1 / IKEv2 belong to the STS, ISO / IEC IS 9798-3, and SIGMA (SIGn-and-MAc) class of authenticated key exchange protocols. These are very well researched and mathematically verified (SIGMA) solutions. In my "P2P F2F E2EE IM in one evening" article I have already described the principle of operation and implementation of the SIGMA-I protocol. IKEv2 is completely similar. When we discuss the security of the handshake protocol, what are we expecting?



  • confidentiality of transmitted messages;
  • authenticity and integrity of transmitted messages - their change must be detected;
  • protection against replay attacks - the fact of loss or replay of messages must be detected;
  • ;

    perfect forward secrecy (PFS) β€” PSK ( IKE ESP SA). ;

    / ( ) IKE . / ( ) ;

    , , . .



After such an IKE_SA_INIT exchange, the daemons have each other's addresses, SPIi + SPIr the value of the IKE session, the SA negotiated algorithms (in the case of IKE, these are key agreement ( DH ), message encryption / authentication ( ENCR ), key generation ( PRF ) algorithms ), the public key (DH) of the opposite side. This is enough to save the state in memory and perform key agreement (Diffie-Hellman, GOST R 34.10-VKO, curve25519, etc.), generating a symmetric key to encrypt the payload of subsequent IKE messages.



TLS 1.3: the format of the handshake messages is very different, there is a lot of legacy, but fundamentally nothing stands out The random field is used instead of nonce. Instead of payloads, numerous extensions. Instead of a complex SA proposal structure, ciphersuites identifiers are used, which is more compact and simpler. In my opinion, the flexibility of SA proposals is excessive, but in IKEv2 this is still not a problem and values ​​similar to ciphersuite are written in the configuration file. Only with TLS 1.3 version DH exchange becomes mandatory.



IKE key material



After IKE_SA_INIT , SKEYSEED is generated :

SKEYSEED = PRF (Ni [: 8] || Nr [: 8], DH-KEY)


The PRF algorithm is selected in the IKE SA. For example, for GOST IKEv2, this is the HMAC-Stribog-512 function. The PRF key is a 64-bit chunk from each nonce.



It looks frivolous, because nonces are transmitted openly, which means that the key for this PRF is known to anyone who intercepted the traffic. But PRF is used here exclusively to generate a key from the DH-KEY result of the calculation of DH , already unknown to the attacker . The result of the DH function can be a huge and unevenly entropy value, it can be a point on an elliptic curve - all this cannot be used as a short high-entropy symmetric key. Therefore, you need to extract the entropy from DH-KEY (this is just SKEYSEED ), and then expand (expand ) it to the required number of keys:



PRF+(SKEYSEED, Ni || Nr || SPIi || SPIr) ->
    SK_d || SK_ai || SK_ar || SK_ei || SK_er || SK_pi || SK_pr

PRF+(K,S) = T1 || T2 || T3 || T4 || ...
T1 = PRF(K,       S || 0x01)
T2 = PRF(K, T1 || S || 0x02)
T3 = PRF(K, T2 || S || 0x03)
T4 = PRF(K, T3 || S || 0x04)


This is all a classic key derivation operation with extract / expand stages, similar to the HKDF function. But if HKDF assumes the use of hash functions, then this PRF / PRF + construction can be used simply with symmetric ciphers - in the case of the common AES-GCM + AES-XCBC-PRF, we will not use a hash function anywhere at all, but a small number used primitives are always good.



The following keys are generated:



  • SK_d key to generate keys for child ESP SAs.
  • SK_a [ir] keys for IKE message authentication. Not generated / not used if the AEAD algorithm is agreed (AES-GCM, Grasshopper / Magma-MGM, ChaCha20-Poly1305, etc.).
  • SK_e[ir] IKE .
  • SK_p[ir] AUTH.


TLS 1.3: has a much more complex key scheduling. The entropy is squeezed out of the entire handshake messages at once, rather than individual fields. The generated extended sequence is not only cut into a number of keys (+ salt for them when required), but also accompanied by HMAC transformations with labels (labels) for each context of use of these keys or generated IVs. Using textual label / application / context for any kind of generated value is good modern practice and is easier to always do than to wonder if you need it. Hashing everything that comes across is also a very good practice, "it won't get any worse." However, this does not mean that the security of IKEv2 is worse, or that one can easily come up with at least a remotely theoretical situation where the absence of a label could be in the hands of an attacker.In IKEv2, the approach is minimal, while in TLS 1.3 it is "better to override" (because how many jambs or difficulties were done in previous versions of the protocol!). IKEv2 still uses proven approaches and primitives, authenticates everything that is needed, squeezes / takes into account all the transferred entropy, uses different keys for each side and task.



IKE_AUTH



Next, an IKE_AUTH exchange is performed , authenticating both parties and negotiating the ESP SA:



    SK{IDi, [CERT, ...], [CERTREQ], [IDr], AUTH, SAi2, TSi, TSr} -->
<-- SK{IDr, [CERT, ...],                   AUTH, SAr2, TSi, TSr}


  • IKE messages contain an encrypted ( SK ) payload, which contains all the others.
  • The initiator provides its identifier ( IDi ), authenticator ( AUTH ), SA offer for ESP ( SAi2 ) and an initiator / responder pair, so called traffic selectors ( TS * ). It can also optionally send the expected responder identifier, which can be considered a kind of SNI analog from TLS.
  • In response, it receives the responder's identifier, the negotiated ESP SA proposal, validated traffic selectors, and an authenticator.
  • After that, both parties consider each other authenticated, have an agreement on ESP SA, traffic that must belong to this ESP, and can already issue a command to the kernel to create SA and, possibly, SP (there are daemons that do not deal with SP at all).


Now in more detail about these payloads:



  • ID - party identifier. Contains the identification type and data specific to it. Parties can be identified in a lot of ways: IPv4 / IPv6 address, FQDN (fully qualified domain name, just a string, the most popular way), RFC822 email address, ASN.1 DER Distinguished Name (the most common way when using X.509 certificates) or General Name as well as vendor-specific.
  • AUTH β€” . PRF ( MAC-), (pre-shared key (PSK)), . (TBS*):



    TBSi = Msg0 || Nr || PRF(SK_pi, IDi)
    TBSr = Msg1 || Ni || PRF(SK_pr, IDr)
    


    (Msg0), nonce (Nr), (IDi), «» . , SK_pi ( ). «».



    / . . ( Ni Nr), . , , .



    , . ( ), . , - . round-trip-. SIGMA- , IKEv2, ESP SA, . , , . SIGMA MAC c ( SK_*). IKEv2 PRF, . , PRF(ID*) , brute-force ( ) .



    PSK, :



    AUTHi = PRF(PRF(PSK, "Key Pad for IKEv2"), TBSi)
    AUTHr = PRF(PRF(PSK, "Key Pad for IKEv2"), TBSr)
    


    PRF(PSK) PSK ? PSK PRF . PSK , /. PRF() «» . PRF(PSK) PSK PSK , ( Argon2, Balloon ).

  • SA*2 β€” SA , ESP .
  • TS* β€” . : IPv4/IPv6 , IP (), / (), / . :



    TSi = ((proto=17, port=100, fc::123 - fc::123),
           (proto=17, port=200, fc::123 - fc::123))
    TSr = ((proto=17, port=300, :: - ffff:..:ffff),
           (proto=17, port=400, :: - ffff:..:ffff))
    


    , UDP ( = 17), 100- 200- fc::123 , UDP 300 400. , IP . , , IP , ( , ICMP ). , .



    UDP . , , , 100 300-, ESP SA .



    The responding party sends its confirmed selection of selectors, which either matches or may have narrower selection ranges.


All these payloads are encrypted on the key generated by the IKE SA after the first message exchange. Encryption is necessary to hide the transmitted identifiers of the parties, their certificates and other private information in the open. However, an active attacker can wedge into the first IKE_SA_INIT exchange and see this information, although he is no longer able to continue the session.



TLS 1.3 :



  • application ( ServerHello ||… || Finished, , , ), (Client Finished). IKEv2 ESP SA round-trip-, TCP/SCTP handshake.
  • , (IDr ), SNI, ClientHello . IKEv2 . ESNI, , DNS, DPI.
  • IKEv2 , «»/«» ( ), PSK, , EAP. TLS 1.3 X.509 . TLS 1.3 X.509 . RFC TLS 1.3 «» . IKEv2 / .
  • TLS 1.3 , , application ClientHello (EarlyData), application Client Finished . TLS 1.3 EarlyData .
  • TLS (session resumption), iPSK , , . IKEv2 , RFC 5723 . IKE , , ( TCP/SCTP/whatever ) IP .
  • TLS . IKEv2 IKE SA ESP SA . , () high-grade , . , , , . - ChaCha20-Poly1305, AES-256-GCM-16, -MGM . IKE SA ESP - NIST-.


The encryption of SK payload AEAD ciphers is not tricky and is completely similar to ESP, for example, for AES-GCM (in which, similarly to AES-GCM-ESP, the salt is part of the key material):



AES-GCM(
    key             = SK_*e,
    plaintext       = 64-bit IV || payloads || pad || 8-bit padLen,
    nonce           = 32-bit salt || IV,
    associated-data = IKEHdr || unencrypted payloads
) -> ciphertext


Authentication with EDS



What if any party wants to authenticate with signature and X.509 certificates? For this, already in IKE_SA_INIT , a CERTREQ payload can be sent , requesting the opposite side to provide a certificate in the form of CERT payloads. CERT and CERTREQ contain the certificate format identifier and format specific content. Typically, certificates can be presented as ASN.1 DER or as SHA1 hash of the certificate + URL from where it can be downloaded. Since the size of UDP is limited by MTU, and the sizes of certificates can be much larger, the hash + URL option is salutary here (although it can be considered a crutch).



The IKEv2 RFC alone lists, in addition to DER encoded X.509 certificates and SHA1 + URLs: PKCS # 7 wrapped X.509 certificate, PGP certificate, DNS signed key, SPKI certificate, X.509 Attribute certificate, raw public keys. If you want to use IPsec in the same way as the most common use-case TLS: a server authenticated by an X.509 certificate and an anonymous client, then in IKEv2 there is no way not to authenticate one of the parties. But RFC 5386 describes a Better-Than-Nothing-Security approach where the "client" can use the bare public key and the server can treat it as anonymous.



In addition, EAP authentication is standardly supported, adding round-trips to IKE_AUTHexchange. EAP can both say whether the party is authenticated or not, as well as generate a key that IKEv2 will take into account and use. I will only show you a diagram of how EAP can work:



                 SAi1, KEi, Ni  -->
                                <--  SAr1, KEr, Nr
SK{IDi, [IDr], SAi2, TSi, TSr}  -->
                                <--  SK{IDr, AUTH, EAP}
                       SK{EAP}  -->
                                <--  SK{EAP(success)}
                      SK{AUTH}  -->
                                <--  SK{AUTH, SAr2, TSi, TSr}


TLS 1.3 : in it, the signature (or MAC in the Finished message) is placed above the hash from all seen messages that participated in the handshake. Also a simple and reliable good approach. There is no variety of authentication methods. But I would like to see some strong Authenticated Password Key Agreement (PAKE) protocol, such as the Russian SESPAKE or OPAQUE .



ESP SA key material and its renewal



So, we have verified the authentication, verified the key agreement was correct, negotiated the ESP SA and traffic selectors. It remains to generate symmetric keys for ESP and the required SA / SP can be installed in the kernel:

PRF + (SK_d, Ni || Nr) -> KEYMAT0 || KEYMAT1


Two-way communication requires two ESP SAs, so IKEv2 generates two key materials at once, which are already transmitted directly to the core in the corresponding SA. The length of the material depends on the used ESP algorithm (for example, AES-GCM-ESP requires, in addition to the key, also 32-bit salt). The SPI value is the SPI value specified by each party in the ESP SA proposals.



What if we need to agree on several ESP SA / SPs, for example, because not all wishes can be specified in a single TSi / TSr pair ? For this, CREATE_CHILD_SA exchanges are used that occur at any time after IKE_AUTH . The creation of a child SA occurs in the following exchange:



    SK {SA, Ni, [KEi], TSi, TSr} ->
<- SK {SA, Nr, [KEr], TSi, TSr}


SA offer is made, nonces, traffic selectors are sent. Everything is as before. The key material is already generated using these new nonces. Optionally, you can use key exchange payloads, which add entropy and force the parties to use even more asymmetric cryptography. It may be necessary to constantly observe the PFS property (in the OTR protocol, ephemeral DH keys are sent with each message). The key material in this case will be worked out as follows:



PRF + (SK_d, DH-KEY || Ni || Nr) -> KEYMAT0 || KEYMAT1


What if we want to renew the IKE SA of the connection? We do the following CREATE_CHILD_SA exchange:



    SK {SA, Ni, KEi} ->
<- SK {SA, Nr, KEr}


where SA will already contain IKE SA proposals and a new SKEYSEED will be developed :



PRF (SK_d_old, DH-KEY || Ni || Nr) -> SKEYSEED


The ESP SA key is updated either by creating a new ESP SA (with a different SPI) and deleting the old one, or by sending a special notification (about it below). Switching traffic to using the new ESP SA will be transparent and lossless. For a short time, the parties will have two active ESP SAs, which will allow them to process traffic that is still in transit on communication channels.



Deleting an ESP SA is done by sending a DELETE payload in subsequent INFORMATIONAL exchanges that list the SPIs to be deleted. Since all ESP SAs exist in pairs (for bi-directional communication), each side sends SPI values ​​only to the ESP SAs responsible for outgoing traffic. In response, the SPI values ​​of the ESP SA for incoming traffic are received.



    SK {D (SPIi)} ->
<- SK {D (SPIr)}


Deleting an IKE SA is also done via DELETE , but with IKE SPI and accepting an empty authenticated response:



    SK {D} ->
<- SK {}


TLS 1.3 : there is a mechanism for rotating keys through KeyUpdate messages, but there is no possibility of adding additional entropy or performing DH. TLS is clearly not designed for very long lived connections. At best, you can only break the session and continue / create a new one with iPSK-ECDHE handshake.



IKEv1 has both a separate IKE key renewal procedure and a separate one for re-authentication. There is no re-authentication in IKEv2. To do this, a new IKE SA is simply created from scratch, the old one is deleted via DELETE .



TLS 1.3 : has post-handshake client authentication capability when at any point after the handshake ( Finishedmessages from both sides), the server can send a request for client authentication using an X.509 certificate. For example, a client, wandering around the site, went to the page of his personal account. In IKEv2, this is not possible - authentication is performed only at the time of the handshake.



NOTIFY



So how are tunnel / transport modes negotiated, TFC? For this, payloads of "notifications" NOTIFY ( N ) are added to the request . There are dozens of types of notifications in the IKEv2 RFC alone. Alerts are used to signal errors, SA negotiation issues, traffic selectors, etc ...



To signal the desire to use transport mode in a negotiated ESP SA, an N (USE_TRANSPORT_MODE) notification is added by both initiator and responder to confirm mode negotiation. N (ESP_TFC_PADDING_NOT_SUPPORTED) alert signals that TFC is not supported. And N (HTTP_CERT_LOOKUP_SUPPORTED) indicates that downloading a certificate from a URL is supported.



The ability to update the ESP SA key, without creating new ESP SAs, is similar to the procedure for creating a child ESP SA, but the initiator adds an N (REKEY_SA) alert containing the SPI of the current ESP SA:

    SK {N (REKEY_SA), SA, Ni, [KEi], TSi, TSr} ->
<- SK {SA, Nr, [KEr], TSi, TSr}





DPD



INFORMATIONAL exchange with empty SK is used for dead peer detection ( DPD ), as a heartbeat between daemons. If the IKE daemon is unavailable for a long time, then most likely it has lost its state and therefore no one is watching the ESP SA on the opposite side, or they are no longer active. Therefore, when it is clear that the peer is unavailable, it makes sense to remove all associated ESP / IKE SAs. An empty SK means that there is no payload in it, but it has authenticated data (at least IKE headers with counters), so the authentication of such a packet is a trusted sign of life.



    SK {} ->
<- SK {}


But what if one side quickly restarted, lost state, and started establishing an IKE connection from scratch? The opposite side might not even notice that the other was unavailable, and it would think that it decided to either re-authenticate or create new child SAs in another IKE connection. Nothing catastrophic will be, but the old ESP SA can still live for a decent time. An initiator MAY place an N (INITIAL_CONTACT) alert in its IKE_AUTH exchange, signaling that it is the only known IKE connection to that side. Seeing such an authenticated notification, you can delete all old IKE / ESP SAs with a clear conscience.



DoS and bad KE



Already at the very beginning of IKE_SA_INIT, a KEi payload with an ephemeral public key DH is sent . But the initiator has not yet exchanged the IKE SA, and how does he know which algorithm the receiving side supports? It can only make a guess or remember in long-term memory what was previously used to associate with this address. If the responder does not support the algorithm, then it will send N (INVALID_KEY_PAYLOAD) a notification, which will indicate the identifier of the preferred DH algorithm. The initiator will have to repeat his request, but with a new KEi .



TLS 1.3: can send several ephemeral public keys at once using different algorithms, maybe some will do. But these are resources and traffic. He may not send the public key at all and the server will reply to him with HelloRetryRequest with its preferences - the plus is that expensive asymmetric cryptography is not used at all until the preferred server algorithms are known, but at the cost of an extra round-trip. If the client initially provided an inappropriate public key algorithm, then, as in IKEv2, it will receive a HelloRetryRequest with the algorithms to choose from.



But what if you send the same initial packet from the initiator? It is possible to generate a new SPIi every time... The responder will, at a minimum, perform DH computations honestly and respond with IKE_AUTH . DH is a very resource-intensive operation, burning up the CPU and the source of entropy - therefore, the transponder can be disabled.



In IKEv2 (but not IKEv1) there is a protection against this, in the form of a response N (COOKIE) with an alert containing a cookie string, after which the initiator must repeat his request, but adding this N (COOKIE) payload to it:



           SAi1, KEi, Ni -->
                         <-- N(COOKIE)
SAi1, KEi, Ni, N(COOKIE) -->
                         <-- SAr1, KEr, Nr, [CERTREQ]


The request must have identical SPI / Ni as the first. It is enough to simply supplement it with payload. The responder can save the state about the connection between the request and the cookie sent to it, and only after they match, after completing this work on adding the cookie to the request by the initiator, the responder can continue the IKE_AUTH exchange in a regular manner .



But it is possible to store the state right inside the cookie, making it "self-authenticating". It can carry the fact that the respondent saw the request from the initiator ( Ni and SPIi saw it , at least):

Cookie = MAC (some-secret, Ni || SPIi || timestamp)


Thus, the DoS lover will have to store the state and recycle his repeated messages, which makes the attack much more expensive. It only makes sense to enable cookie protection when there is a suspicion of a DoS attack, so as not to force everyone to perform an extra round-trip.



TLS 1.3 : Has similar optional security. The server MAY respond with HelloRetryRequest with a message containing the Cookie extension, which the client should insert into its repeated ClientHello2 .



CP



IKEv2 allows you to negotiate the configuration of IP networks / addresses. Configuration payload ( CP ) allows you to make a request to receive a configuration ( CFG_REQUEST / CFG_REPLY packet types) and set the configuration to the opposite side ( CFG_SET / CFG_ACK types). The configuration request contains the attributes that the party wants to know / set. Attributes can be: "internal" address, DNS address, DHCP, subnet knowledge, or other types described in related RFCs. For example, the initiator in the IKE_AUTH exchange can make a request to issue him an intranet address (connecting to the company's network) and a DNS server:



    SK{IDi, [IDr], AUTH, CP(CFG_REQUEST), SAi2, TSi, TSr} -->
<-- SK{IDr,        AUTH, CP(CFG_REPLY),   SAr2, TSi, TSr}

CP(CFG_REQUEST) =
  INTERNAL_IP6_ADDRESS()
  INTERNAL_IP6_DNS()
TSi = (proto=0, port=0-65535, :: - ffff:...:ffff)
TSr = (proto=0, port=0-65535, :: - ffff:...:ffff)

CP(CFG_REPLY) =
  INTERNAL_IP6_ADDRESS(2001:db8::5/64)
  INTERNAL_IP6_DNS(2001:db8::1)
  INTERNAL_IP6_SUBNET(2001:db8:abcd::/64)
TSi = (proto=0, port=0-65535, 2001:db8::5 - 2001:db8::5)
TSr = (proto=0, port=0-65535, 2001:db8::0 - 2001:db8::ffff:ffff:ffff:ffff)


  • The 2001: db8 :: 5 address is allocated to the initiator .
  • ESP SA 2001:db8::/64 .
  • 2001:db8::1 DNS .
  • 2001:db8:abcd::/64 , , ESP SA, 2001:db8:: .


Go?



To test modern domestic implementations of the IPsec stack with GOST algorithms, we decided to write a completely independent (from Linux, FreeBSD, strongSwan and other stacks) implementation. And for speed and ease of development in the Go language, with the already existing implementation of GOST algorithms GoGOST library. Before, I already had experience of integrating GOST into TLS 1.3 implementation of crypto / tls and crypto / x509 Go libraries.



The gostipsec project is free software consisting of two daemons: ESPER (ESPv3) and IKER (IKEv2):



          β”Œβ”€β”€β”€β”€β”€β”€β”          β”Œβ”€β”€β”€β”€β”          β”Œβ”€β”€β”€β”€β”€β”          β”Œβ”€β”€β”€β”€β”
          β”‚remoteβ”‚          β”‚ikerβ”‚          β”‚esperβ”‚          β”‚ipfwβ”‚
          β””β”€β”€β”¬β”€β”€β”€β”˜          β””β”€β”¬β”€β”€β”˜          β””β”€β”€β”¬β”€β”€β”˜          β””β”€β”¬β”€β”€β”˜
             β”‚                β”‚                β”‚               β”‚
╔══════╀═════β•ͺ════════════════β•ͺ════════════╗   β”‚               β”‚
β•‘ UDP  β”‚     β”‚                β”‚            β•‘   β”‚               β”‚
β•Ÿβ”€β”€β”€β”€β”€β”€β”˜     β”‚    IKEv2...    β”‚            β•‘   β”‚               β”‚
β•‘            β”‚ <───────────────            β•‘   β”‚               β”‚
β•‘            β”‚                β”‚            β•‘   β”‚               β”‚
β•‘            β”‚    IKEv2...    β”‚            β•‘   β”‚               β”‚
β•‘            β”‚ ───────────────>            β•‘   β”‚               β”‚
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•ͺ════════════════β•ͺ════════════╝   β”‚               β”‚
             β”‚                β”‚                β”‚               β”‚
             β”‚                β”‚                β”‚               β”‚
             β”‚    ╔═══════════β•ͺ══╀═════════════β•ͺ════════════╗  β”‚
             β”‚    β•‘ UNIX-SOCKET  β”‚             β”‚            β•‘  β”‚
             β”‚    β•Ÿβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€setkey-commandsβ”‚            β•‘  β”‚
             β”‚    β•‘           β”‚ ───────────────>            β•‘  β”‚
             β”‚    β•šβ•β•β•β•β•β•β•β•β•β•β•β•ͺ════════════════β•ͺ════════════╝  β”‚
             β”‚                β”‚                β”‚               β”‚
             β”‚                β”‚                β”‚               β”‚
             β”‚                β”‚   ╔════════════β•ͺ═══╀═══════════β•ͺ════════════╗
             β”‚                β”‚   β•‘ DIVERT-SOCKET  β”‚           β”‚            β•‘
             β”‚                β”‚   β•Ÿβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€encrypted ESP β”‚            β•‘
             β”‚                β”‚   β•‘            β”‚ <──────────────            β•‘
             β”‚                β”‚   β•‘            β”‚               β”‚            β•‘
             β”‚                β”‚   β•‘            β”‚ decrypted ESP β”‚            β•‘
             β”‚                β”‚   β•‘            β”‚ ──────────────>            β•‘
             β”‚                β”‚   β•‘            β”‚               β”‚            β•‘
             β”‚                β”‚   β•‘            β”‚ unencrypted IPβ”‚            β•‘
             β”‚                β”‚   β•‘            β”‚ <──────────────            β•‘
             β”‚                β”‚   β•‘            β”‚               β”‚            β•‘
             β”‚                β”‚   β•‘            β”‚  encrypted IP β”‚            β•‘
             β”‚                β”‚   β•‘            β”‚ ──────────────>            β•‘
             β”‚                β”‚   β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•ͺ═══════════════β•ͺ════════════╝
             β”‚                β”‚                β”‚               β”‚


At the moment, ESPER only works with DIVERT sockets (I did not find anything as simple under Linux), therefore it is supported only on FreeBSD (probably OpenBSD, did not check) OS. ESPER, like IKER, does not use PF_KEYv2 , which would require C-bindings, as an interface between ESP <-> IKE bindings, but the textual setkey -like interface already mentioned at the beginning of the article. IKER can therefore be used to negotiate the keys of a kernel ESP implementation by invoking the real setkey command. These commands for ESPER look like this:



add fc00::ac fc00::dc esp 0x12345678 -u 123 -E aes-gcm-16 0xd3537e657fde5599a2804fbb52d1aaed94b65d3e ;
add fc00::dc fc00::ac esp 0x12345679 -u 234 -E aes-gcm-16 0x9a2dae68e475eacb39d41f23c3cbef890e9f6276 tfc:1320 ;

spdadd fc00::ac/128 fc00::dc/128 all -P in ipsec esp/transport//unique:123 ;
spdadd fc00::dc/128 fc00::ac/128 all -P out ipsec esp/transport//unique:234 ;


ESPER supports: AES-128/256-GCM-16, Magma / Grasshopper-MGM, ESN, TFC, transport / tunnel modes, IPv6 / IPv4 (support for the latter, much more complex, has not been thoroughly tested, and who needs IPv4 for new projects?), protection against replay attacks. IKER allows you to match: AES-128/256-GCM-16 + AES-XCBC + curve25519, Magma / Grasshopper-MGM + HMAC-Stribog-512 + GOST R 34.10-2012-VKO-256/512, ESN / TFC / transport / tunnel-modes, authenticate using PSK and X.509 digital signatures (ECDSA, GOST R 34.10-2012). Configured by a single Hjson file:



{
    IKEAlgos: [
        gost128-vko512
        aes256gcm16-aesxcbc-curve25519
        aes128gcm16-aesxcbc-curve25519
    ]
    ESPAlgos: [
        gost128-esn
        gost64-esn
        aes256gcm16-esn
        aes256gcm16-noesn
        aes128gcm16-esn
        aes128gcm16-noesn
    ]
    SigHashes: [
        streebog512
        streebog256
        sha512
        sha256
    ]
    DPDTimeout: 300
    Peers: [
        {
            Autostart: true
            OurIP: fc00::dc
            TheirIP: fc00::ac
            OurId: our.company.net
            TheirId: CN=example.com
            OurTSS: [
                fc00::dc/128[tcp]
                fc00::dc/128[udp/53]
            ]
            TheirTSS: [
                fc00::ac/128
            ]
            Mode: transport
            # Won't be used, because of X.509 signature authentication
            PSK: DEADBABE
            TheirCertHash: a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447
            OurCert: our.company.net.cer.pem
            OurPrvKey: our.company.net.key.pem
            TFC: 1200
        }
    ]
}


In this example, we have set the only member we know of:



  • Which daemon will automatically connect to
  • Do dead peer detection every five minutes
  • ESN, fallback- , TFC 1200 .
  • TCP DNS fc00::dc fc00::ac .
  • X.509 , CN=example.com subject- SHA256 SubjectPublicKeyInfo . OurId OurCert .
  • OurCert/OurPrvKey , PSK FQDN OurId.


IKER does not yet support the full set of all IKEv2 features ( CREATE_CHILD_SA , rekeying), does not monitor the loss of packets and does not care about the DON'T PANIC principle. Therefore, it cannot yet be considered as a candidate for "industrial" use.



Tarball gostipsec already contains all dependencies, compiled .info documentation, and targets for the redo build system , although building executables is easily done with a regular go build call.



Hjson?



Holywar theme, but I'll give my phi anyway:



  • INI does not allow you to specify such sweeping structures, and there is no standard for .ini files.
  • capabilities database , termcap-like, BSD , (, , ), C. IKER .
  • XML β€” .
  • JSON β€” , Python Go . , . - !
  • YAML β€” , , . , . , YAML , , , . . . - . YAML ( ) - ( StrictYAML ).
  • TOML β€” : , , , . , :



    [[foo.bar]]
    baz = 123
    
    [[foo.bar]]
    abc = 123
    




    :



    {
      "foo": {
        "bar": [
          {"baz": 123 },
          {"abc": 123 }
        ]
      }
    }
    


    «» / , . , TOML, NNCP , . , , .
  • Hjson β€” JSON ( , ), Hjson. github.com/hjson/hjson-go Hjson JSON, . . , . , JSON Hjson.




In general, if you implement a subset of capabilities similar to TLS 1.3 (authentication only using PSK and X.509 certificates, no serious rekeying), then ESPv3 with IKEv2 and IPv6 (it is much easier to work with it!), From the point of view of the programmer, will be slightly more difficult in implementation. The RFC does not even oblige to support CREATE_CHILD_SA exchanges. Security will be excellent, without the controversial and dangerous possible modes of operation of TLS 1.3. The performance of an IPsec solution will generally be higher due to transport at the nuclear level and long-lived IKE sessions.



It can be seen that in IPsec everything is sharpened to protect the colossal amount of traffic between entire networks, but BTNS(better than nothing security) the IETF working group has written several RFCs demonstrating that IPsec can be used without problems for per-socket connections, where one of the parties (the client) is anonymous, thereby completely questioning the advisability of using TLS. Connection latching, in this case, would allow any network application, by making a trivial system call like setsockopt , to indicate that it needs an ESP to the FQDN = bank.com address, presenting itself as an X.509 certificate (or remaining anonymous), and then transparently, quickly and safely working with this bank.com , without crutches in the form of userspace transport per-application libraries.



Sergey Matveev , cypherpunk, Python / Go / C-developer, chief specialist of FGUP STC Atlas.



All Articles