Internet-Draft CORE Authenticated Key Exchange (CAKE) November 2024
Schanzenbach Expires 17 May 2025 [Page]
Workgroup:
Independent Stream
Internet-Draft:
draft-schanzen-cake-00
Published:
Intended Status:
Informational
Expires:
Author:
M. Schanzenbach
Fraunhofer AISEC

CORE Authenticated Key Exchange (CAKE)

Abstract

This document contains the GNUnet CORE AKE (CAKE).

This document defines the normative wire format of the protocol, cryptographic routines and security considerations for use by implementers.

This specification was developed outside the IETF and does not have IETF consensus. It is published here to inform readers about the function of GNUnet communicators, guide future implementations, and ensure interoperability including with the pre-existing GNUnet implementation.

Status of This Memo

This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.

Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.

Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."

This Internet-Draft will expire on 17 May 2025.

Table of Contents

1. Introduction

This specification was developed outside the IETF and does not have IETF consensus. It is published here to guide implementers of GNS and to ensure interoperability among implementations.

1.1. Requirements Notation

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

2. Conventions and Terminology

While some of the terminology is explicitly re-defined here, the reader is expected to be familiar with TLS 1.3 ([RFC8446]), DTLS 1.3 ([RFC9147]) and HPKE ([RFC9180]).

inititator:
See client in [RFC9147] Section 2.
receiver:
See server in [RFC9147] Section 2.
epoch:
See [RFC9147] Section 2.
IATS:
Initiator Application Traffic Secret Key
RATS:
Receiver Application Traffic Secret Key
ES:
Early Secret Key
ETS:
Early Traffic Secret Key
HS:
Handshake Secret Key
MS:
Main Secret Key
ES:
Early Secret Key
IHTS:
Initiator Handshake Secret Key
RHTS:
Receiver Handshake Secret Key
Foo...Bar:
means the transcript of received/send messages from Foo until Bar. Note that the transcript refers to what is seen on the wire (i.e. potentially encryption) but as shorthand, we only refer to the plaintext message.
'{}'
indicates encryption with a handshake traffic key and [RFC8439], the ChaCha20-Poly1305 Authenticated Encryption with Associated Data (AEAD) construction.
'[]'
indicates encryption with an application traffic key and [RFC8439], the ChaCha20-Poly1305 Authenticated Encryption with Associated Data (AEAD) construction.

3. Design Rationale

The design rationale for CAKE is similar to DTLS 1.3 (cf. Section 3 of [RFC9147]). Except that CAKE does not consider Fragmentation as this is expected to be provided by the transport underlay layer of GNUnet.

4. Protocol Flow

This protocol is heavily inspired by [KEMTLS].

We assume that the peers have semi-static (as opposed to ephemeral) key pairs. Let (pkA,skA) be the key pair of peer PIDA and (pkB,skB) the key pair of peer PIDB.

For any secure handshake protocol, we have to dermine an initiator and a receiver in the protocol. We use GNUNET_CRYPTO_hash_cmp to determine which peer is the receiver R and which peer the initiator I:


if (GNUNET_CRYPTO_hash_cmp (pk_A, pk_B))
{
  pk_I = pk_A
  pk_R = pk_B
}
else
{
  pk_I = pk_B
  pk_R = pk_A
}

It is possible that the designated initiator does not initiate the handshake. After a pre-determined timeout, the respective other peer may initiate. We assume that the initiator knows pkR (pre-distributed through HELLO, for example).

Below is a swimlane of the protocol messages. On the left and right side of the swimlanes the secrets known to the Initiator and Receiver are shown respectively. If a private key of a key pair is known it is implied that the public key is also known. Messages in brackets are optional. Messages in braces are encrypted with the key after "*".

         Initiator                                Receiver
sk_I     |                                               | sk_R
pk_R     |                                               |
sk_e     |                                               |
ES,ETS   |                                               |
         |                                               |
         |               InitiatorHello:                 |
         |                 EphemeralKey                  |
         |                 ReceiverKemChallenge          |
         |                 InitiatorNonce                |
         |                 InitiatorPkHash               |
         |                 {pk_I}                        |
         |                 {ServicesInfo}                |
         +---------------------------------------------->|
         |                                               | pk_I
         |                                               | ES,ETS
         |                                               | dES
         |                                               | (d)HS
         |                                               | MS
         |                                               | [I,R]HTS
         |                                               | RATS
         |               ReceiverHello:                  |
         |                 HandshakeKemCiphertext        |
         |                 ReceiverNonce                 |
         |                 {ServicesInfo}                |
         |                 {InitiatorKemChallenge}       |
         |                 {ReceiverFinished}            |
         |               *[Application Payload]          |
         |<----------------------------------------------+
dES      |                                               |
(d)HS    |                                               |
MS       |                                               |
[I,R]HTS |                                               |
[I,R]ATS |                                               |
         |               InitiatorDone:                  |
         |                 {InitiatorFinished}           |
         |               *[Application Payload]          |
         +---------------------------------------------->|
         |                                               | IATS
         |                                               |
         |                                               |
         |                                               |
         |               [Application Payload]           |
         |<--------------------------------------------->|
         |                                               |
         v                                               v
Figure 1: Overview over the Handshake Protocol Flow.

Notice how we do not need any acknowledgement messages until after InitiatorFinished (after 1.5 RTT). The InitiatorHello message is a single flight that is implicitly ack'ed with ReceiverHello. ReceiverHello is a single flight that is implicitly ack'ed with InitiatorFinished. InitiatorFinished requires an explicit ack; at this time R and I have already established a secure channel and R can use an EncryptedMessage to send the ack. The reason why this works is because CAKE groups the messages in row 3 of Table 1 in Section 5.7 of [RFC9147] into a single message (ReceiverHello). Hence the only message that is sent without any expected response (and consequently requiring an explicit ACK) is InitiatorFinished (and KeyUpdate).

The Initiator creates the InitiatorHello message which includes the encrypted tuple (pkI,ServicesInfo). The fields are encrypted using a key derived from the ETS according to Figure 1 and Figure 2. The ReceiverKemChallenge is computed as:

  1. (ssR,cR) <- Encaps(pkR)

R processes the InitiatorHello as follows:

  1. Verify that the message type is CORE_INITIATOR_HELLO
  2. (ssR,cR) <- Decaps(skR, cR)
  3. (sse,ce) <- Encaps(pke)
  4. Generate ETS from Section 5 and decrypt pkI.
  5. (ssI,cI) <- Encaps(pkI)
  6. Generate RHTS and RATS from Section 5.

The ETS, the Handshake and Master Secrets are generated according to Figure 2. Note that IATS cannot be derived (yet) at this point. R may now generate its ReceiverHello message:

  1. rR <- RandomUInt64()
  2. Create ReceiverFinished as per Section 6.
  3. Encrypt ServicesInfo, cI and ReceiverFinished with a key derived from RHTS.
  4. Optionally, R may now already send application data encrypted with RATS.

I processes the message received by R:

  1. Verify that the message type is CORE_RECEIVER_HELLO
  2. sse <- Decaps(ske,ce)
  3. Generate IHTS and RHTS from Section 5 and decrypt ServicesInfo, cI and ReceiverFinished.
  4. ssI <- Decaps(skI,cI).
  5. Create ReceiverFinished as per Section 6 and check against decrypted payload.
  6. Create IteratorFinished as per Section 6.
  7. Send InteratorFinished message encrypted with the key derived from IHTS to R

At this point we have a secure channel.

Note that for the handshake we do not use epochs or sequence numbers. The reason for this is simple: DTLS uses epoch 0 for plaintext messages. Epoch 1 is reserved for payload encrypted with a key derived from ETS. However, we only have a single message that contains such a payload: InitiatorHello. Epoch 2 is reserved for payload encrypted with a key derived from *HTS. But we only have a single message that contains a payload encrypted with a key derived from RHTS: ReceiverHello. We also only have a single message that contains a payload encrypted with a key derived from AHTS: InitiatorFinished. Consequently, we do not need any signalling of Epochs until we encrypt data using *ATS secrets. The optional application data that may already be sent by the receiver after its first handshake message or by the initiator after its second handshake message, are already wrapped inside an EncryptedMessage and have both Epoch and sequence numbers set.

5. Key Schedule

The key schedule is very similar to [RFC8446] Section 7.1:

             0
             |
             v
ss_R ->  HKDF-Extract = Early Secret (ES)
             |
             +-----> HKDF-Expand(., "early data", InitiatorHello)
             |                     = Early Transport Secret (ETS)
             |
             v
       HKDF-Expand(., "derived", "") = derived Early Secret (dES)
             |
             v
ss_e -> HKDF-Extract = Handshake Secret (HS)
             |
             +-----> HKDF-Expand(., "i hs traffic",
             |                     InitiatorHello...ReceiverHello)
             |                     = IHTS
             |
             +-----> HKDF-Expand(., "r hs traffic",
             |                     InitiatorHello...ReceiverHello)
             |                     = RHTS
             v
       HKDF-Expand(., "derived", "") = derived Handshake Secret (dHS)
             |
             v
ss_I -> HKDF-Extract = Master Secret (MS)
             |
             +-----> HKDF-Expand(., "i ap traffic",
             |                   InitiatorHello...InitiatorDone)
             |                     = IATS_0
             |
             +-----> HKDF-Expand(., "r ap traffic",
                                 InitiatorHello...ReceiverHello)
                                   = RATS_0
Figure 2: The Key Schedule.

When a traffic secret (*TS) is used to encrypt data, the respective encryption key and starting nonce is generated as follows:

key = HKDF-Expand [I,R][A,H]TS, "key", 64)
nonce = HKDF-Expand ([I,R][A,H]TS, "iv", 12)
Figure 3: Traffic Key Generation.

After a successful initial handshake, both initiator and receiver may update the application traffic secrets ([A,I]ATS) and generate new keys. Let [I,R]ATS0 be the initial secrets with index 0. The next secret is derived as:

[I,R]ATS_N+1 = HKDF-Expand ([I,R]ATS_N, "traffic_upd", secret_len)
Figure 4: Traffic Secret Update.

When a peer wants to update keys, it sends a key update message Section 6.10. Implementations SHOULD delete old traffic secrets and their derived keys.

6. The CAKE Handshake Protocol

This section is named and structured to mimic Section 5 of [RFC9147].

6.1. Timeout and Retransmission

CAKE reuses the logic for timeout and retransmission from Section 5.8 of [RFC9147]. It differs in that large flight sizes are not of concern for CAKE. Similarly, the only Post-Handshake message relevant for CAKE is the KeyUpdate message.

6.2. Cryptographic Label Prefix

Section 7.1 of [RFC8446] specifies that HKDF-Expand-Label uses a label prefix of "tls13 ". For CAKE, that label SHALL be "cake ". This ensures key separation between CAKE, DTLS 1.3 and TLS 1.3.

6.3. ServicesInfo Field

The ServicesInfo is a string consisting of key-value pairs separated by a separator indicating supported services and their versions. E.g. "dht:1.1;cadet:0.4". The ServicesInfo is zero terminated.

6.4. Finished Field

The HandshakeFinished field contains either InitiatorFinished or ReceiverFinished value:

  1. fkI <- HKDF-Expand(MS, "i finished", NULL)
  2. InitiatorFinished <- HMAC(fkI, InitiatorHello...Hello)
  1. fkR <- HKDF-Expand(MS, "r finished", NULL)
  2. ReceiverFinished <- HMAC(fkR, InitiatorHello...InitiatorDone)

6.5. CAKE Message Format

Any sent message starts with a MessageHeader:

          0     8     16    24    32    40    48    56
          +-----+-----+-----+-----+-----+-----+-----+-----+
          |         Size          |       Type (0xXX)     |
          +-----+-----+-----+-----+-----+-----+-----+-----+
Figure 5: The Wire Format of the Message Header.
size:
The size of the message including the Size and Type fields.
type:
The message type.

The possible types of messages are:

  • InitiatorHello
  • ReceiverHello
  • HandshakeFinished
  • EncryptedMessage

An encrypted message also always starts with a MessageHeader and the allowed types are:

  • KeyUpdate
  • Ack
  • ApplicationData

6.6. InitiatorHello Message

The InitiatorHello:

          0     8     16    24    32    40    48    56
          +-----+-----+-----+-----+-----+-----+-----+-----+
          |                  EphemeralKey                 |
          |                                               |
          |                                               |
          +-----+-----+-----+-----+-----+-----+-----+-----+
          |                  InitiatorKemChallenge        |
          |                                               |
          |                                               |
          |                                               |
          +-----+-----+-----+-----+-----+-----+-----+-----+
          |                ReceiverPeerID Hash (512 bit)  |
          /                                               /
          |                                               |
          +-----+-----+-----+-----+-----+-----+-----+-----+
          |                     Nonce                     |
          +-----+-----+-----+-----+-----+-----+-----+-----+
          /             {pk_I,ServicesInfo}               /
Figure 6: The Wire Format of the InitiatorHello.

The InitiatorKemChallenge is generated according to Figure 2 using:

  1. (ssR,cR) <- Encaps(pkR)

The pkI and ServiceInfo are encrypted using ChaCha20-Poly1305 [RFC8439] with key and IV derived from the ETS.

6.7. ReceiverHello Message

The ReceiverHello:

          0     8     16    24    32    40    48    56
          +-----+-----+-----+-----+-----+-----+-----+-----+
          |                  HandshakeKemCiphertext       |
          |                                               |
          |                                               |
          |                                               |
          +-----+-----+-----+-----+-----+-----+-----+-----+
          |                     Nonce                     |
          +-----+-----+-----+-----+-----+-----+-----+-----+
          / {ServicesInfo,ReceiverKemCiphertext,Finished} /
Figure 7: The Wire Format of the ReceiverHello.

The protected fields after the nonce are encrypted using a key derived from AHTS. They are not encrypted individually but as a single payload.

6.8. InitiatorDone Message

The InitiatorDone message contains the InitiatorFinished field encrypted with a key derived from the IHTS. The message type MUST be CORE_INITIATOR_DONE.

6.9. EncryptedMessage

The EncryptedMessage follows a message header with type CORE_ENCRYPTED_MESSAGE:

0     8     16    24    32    40    48    56
+-----+-----+-----+-----+-----+-----+-----+-----+
|   Epoch   |             Sequence Number       |
+-----+-----+-----+-----+-----+-----+-----+-----+
|                   Timestamp                   |
+-----+-----+-----+-----+-----+-----+-----+-----+
|                     Tag                       |
|                                               |
+-----+-----+-----+-----+-----+-----+-----+-----+
Figure 8: The Wire Format of the EncryptedMessage header.

The epoch starts at 0 after the handshake with the first *ATS secret. The sequence number is encrypted with the output as defined in Section 4.2.3 of [RFC9147] for ChaCha20-based AEAD schemes. For clarity, the XOR-based encryption using the 64 byte output of ChaCha20 is as follows: The sequence number is padded to the left such that it is exactly 8 bytes (as if the Epoch field was still present). Then, the first 8 bytes of the output of ChaCha20 are XORed with the resulting byte string. The first 16 bits can be ignored (zeroed). Note that an implementation may simply XOR the first 8 byte of the EncryptedMessage. However, this will include the Epoch field and whatever value it was set to so after the XOR this value will have to be reconstructed or otherwise masked beforehand.

The tag is followed by encrypted application data. The length of the data is included in the size field of the MessageHeader preceeding the EncryptedMessage header.

The per-message nonce is not transmitted and instead generated as defined in Section 5.3 of [RFC8446].

6.10. KeyUpdate

The KeyUpdate message is a simple MessageHeader inside an EncryptedMessage with type CORE_KEY_UPDATE followed by an UpdateRequested indicator. This means that for every received EncryptedMessage the peer MUST check if this is a KeyUpdate. A KeyUpdate message indicates that the sender has switched its traffic secrets according to the key schedule in Section 5. If any bit in the UpdateRequested field is set, this means that the receiver of the KeyUpdate MUST send its own KeyUpdate message. Any bytes following the UpdateRequested field are updated ServicesInfo (Section 6.3). ServicesInfo updates are optional.

0     8     16    24    32
+-----+-----+-----+-----+
|      UpdateRequested  |
+-----+-----+-----+-----+
|      ServicesInfo     /
/                       /
Figure 9: The Wire Format of the EncryptedMessage header.

6.11. ACK

The ACK message: See Section 7 of [RFC9147].

7. Open Issues

We must include ACK handling. In general we need to take a look at DTLS and port whatever it does to ensure failure tolerance with out-of-order and unreliable transmissions. This includes ACKs as well as retransmission (timers).

We must discuss EdDSA vs X25519 KEM usage. Maybe see Communicator draft for this.

We must discuss ChaCha20 vs XChaCha20. For XChaCha20 (currently implemented) we can use fresh nonces when the key is re-used. With ChaCha20, we should increment the nonce. We could probably increment both. Incrementing may allow us to derive a starting nonce from the key schedule. We can get away with ChaCha20 (TLS, IETF) and its 32-bit internal counter because our messages are <= 216-1 bytes and the counter cannot overflow.

The Initiator/Receiver selection logic may require a timed fallback: The designates Initiator may never initiate (NAT, already has sufficient connections, learns about receiver later than receiver about initiator etc.). This may result in edge cases where the Initiator initiates a handshake and the Receiver also initiates a handshake at the same time switching roles. In such cases we may simply do both key exchanges. If both succeed, we drop the key exchange that was not initiated by the designated initiator on both peers. Otherwise we use the successful key exchange and the roles are swapped.

8. Security and Privacy Considerations

TODO

9. GANA Considerations

-

10. Normative References

[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/info/rfc2119>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/info/rfc8174>.
[RFC8439]
Nir, Y. and A. Langley, "ChaCha20 and Poly1305 for IETF Protocols", RFC 8439, DOI 10.17487/RFC8439, , <https://www.rfc-editor.org/info/rfc8439>.
[RFC8446]
Rescorla, E., "The Transport Layer Security (TLS) Protocol Version 1.3", RFC 8446, DOI 10.17487/RFC8446, , <https://www.rfc-editor.org/info/rfc8446>.
[RFC9147]
Rescorla, E., Tschofenig, H., and N. Modadugu, "The Datagram Transport Layer Security (DTLS) Protocol Version 1.3", RFC 9147, DOI 10.17487/RFC9147, , <https://www.rfc-editor.org/info/rfc9147>.
[RFC9180]
Barnes, R., Bhargavan, K., Lipp, B., and C. Wood, "Hybrid Public Key Encryption", RFC 9180, DOI 10.17487/RFC9180, , <https://www.rfc-editor.org/info/rfc9180>.

11. Informative References

[KEMTLS]
Wiggers, T., "Post-Quantum TLS", , <https://thomwiggers.nl/publication/thesis/>.

Author's Address

Martin Schanzenbach
Fraunhofer AISEC
Lichtenbergstrasse 11
85748 Garching
Germany