LCOV - code coverage report
Current view: top level - waltz/quic/crypto - fd_quic_crypto_suites.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 24 24 100.0 %
Date: 2025-03-20 12:08:36 Functions: 2 34 5.9 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_waltz_quic_crypto_fd_quic_crypto_suites_h
       2             : #define HEADER_fd_src_waltz_quic_crypto_fd_quic_crypto_suites_h
       3             : 
       4             : #include "../fd_quic_enum.h"
       5             : #include "../../../ballet/aes/fd_aes_gcm.h"
       6             : 
       7             : /* Defines the crypto suites used by QUIC v1.
       8             : 
       9             :    QUIC v2 is defined here:
      10             :      https://www.rfc-editor.org/rfc/rfc9001.html#name-header-protection
      11             :      https://www.rfc-editor.org/rfc/rfc8446.html#page-133
      12             : 
      13             :    The suites are defined thusly:
      14             : 
      15             :        +------------------------------+-------------+
      16             :        | Description                  | Value       |
      17             :        +------------------------------+-------------+
      18             :        | TLS_AES_128_GCM_SHA256       | {0x13,0x01} |
      19             :        | TLS_AES_256_GCM_SHA384       | {0x13,0x02} |
      20             :        | TLS_CHACHA20_POLY1305_SHA256 | {0x13,0x03} |
      21             :        | TLS_AES_128_CCM_SHA256       | {0x13,0x04} |
      22             :        | TLS_AES_128_CCM_8_SHA256     | {0x13,0x05} |
      23             :        +------------------------------+-------------+
      24             : 
      25             :    Notes:
      26             :      TLS_AES_128_CCM_SHA256 does not seem to be mentioned in rfc9001, so is excluded
      27             :      TLS_AES_128_CCM_8_SHA256 has no packet-header encryption defined, and so must be excluded
      28             : 
      29             :      The remainder are defined below */
      30             : 
      31             : typedef struct fd_quic_crypto_keys    fd_quic_crypto_keys_t;
      32             : typedef struct fd_quic_crypto_secrets fd_quic_crypto_secrets_t;
      33             : 
      34   125081379 : #define FD_QUIC_CRYPTO_TAG_SZ    16
      35    13845961 : #define FD_QUIC_CRYPTO_SAMPLE_SZ 16
      36    13845961 : #define FD_QUIC_CRYPTO_SAMPLE_OFFSET_FROM_PKT_NUM_START 4
      37             : 
      38             : struct fd_quic_crypto_keys {
      39             :   /* packet protection: */
      40             :   uchar pkt_key[FD_AES_128_KEY_SZ];
      41             :   uchar iv     [FD_AES_GCM_IV_SZ ];
      42             :   uchar hp_key [FD_AES_128_KEY_SZ];
      43             : };
      44             : 
      45             : /* define enums for encryption levels */
      46   106891602 : #define fd_quic_enc_level_initial_id    0
      47             : #define fd_quic_enc_level_early_data_id 1
      48   106250305 : #define fd_quic_enc_level_handshake_id  2
      49   203671418 : #define fd_quic_enc_level_appdata_id    3
      50             : #define FD_QUIC_NUM_ENC_LEVELS          4
      51             : 
      52             : /* labels defined in rfc9001 */
      53       24588 : #define FD_QUIC_CRYPTO_LABEL_CLIENT_IN "client in"
      54       24588 : #define FD_QUIC_CRYPTO_LABEL_SERVER_IN "server in"
      55             : 
      56      193920 : #define FD_QUIC_CRYPTO_LABEL_QUIC_KEY "quic key"
      57      193920 : #define FD_QUIC_CRYPTO_LABEL_QUIC_IV  "quic iv"
      58      145416 : #define FD_QUIC_CRYPTO_LABEL_QUIC_HP  "quic hp"
      59             : 
      60       48504 : #define FD_QUIC_CRYPTO_LABEL_KEY_UPDATE "quic ku"
      61             : 
      62             : /* each of these has "-1" to avoid counting the implied terminating NUL byte */
      63       12294 : #define FD_QUIC_CRYPTO_LABEL_CLIENT_IN_LEN ( sizeof( FD_QUIC_CRYPTO_LABEL_CLIENT_IN ) - 1 )
      64       12294 : #define FD_QUIC_CRYPTO_LABEL_SERVER_IN_LEN ( sizeof( FD_QUIC_CRYPTO_LABEL_SERVER_IN ) - 1 )
      65             : 
      66       96960 : #define FD_QUIC_CRYPTO_LABEL_QUIC_KEY_LEN  ( sizeof( FD_QUIC_CRYPTO_LABEL_QUIC_KEY ) - 1 )
      67       96960 : #define FD_QUIC_CRYPTO_LABEL_QUIC_IV_LEN   ( sizeof( FD_QUIC_CRYPTO_LABEL_QUIC_IV ) - 1 )
      68       72708 : #define FD_QUIC_CRYPTO_LABEL_QUIC_HP_LEN   ( sizeof( FD_QUIC_CRYPTO_LABEL_QUIC_HP ) - 1 )
      69             : 
      70       24252 : #define FD_QUIC_CRYPTO_LABEL_KEY_UPDATE_LEN ( sizeof( FD_QUIC_CRYPTO_LABEL_KEY_UPDATE ) - 1 )
      71             : 
      72             : struct fd_quic_crypto_secrets {
      73             :   uchar initial_secret[FD_QUIC_INITIAL_SECRET_SZ];
      74             : 
      75             :   /* secret[enc_level][dir][FD_QUIC_SECRET_SZ]
      76             :      a secret for each encryption level,
      77             :      and each direction (dir=0 is incoming, dir=1 is outgoing) */
      78             :   uchar secret[FD_QUIC_NUM_ENC_LEVELS][2][FD_QUIC_SECRET_SZ];
      79             : 
      80             :   /* new secret for switching keys during key update */
      81             :   uchar new_secret[2][FD_QUIC_SECRET_SZ];
      82             : };
      83             : 
      84             : /* fd_quic_gen_initial_secrets generates initial secrets for the given conn ID.
      85             :    Does not generate keys.  Sets secrets->initial_secrets, secrets->secret[0][0],
      86             :    (incoming secret) and secret->secret[0][1] (outgoing secret).  is_server is
      87             :    1 if the current QUIC instance runs from the perspective of the server, 0
      88             :    otherwise.
      89             : 
      90             :    Key schedule:
      91             : 
      92             :      initial_salt (hardcoded constant)
      93             :       |
      94             :       v
      95             :      initial_secret = HKDF-Extract(.,conn_id)
      96             :       |
      97             :       +---> initial_client_secret = HKDF-Expand-Label(., "client in", "", 32)
      98             :       |
      99             :       +---> initial_server_secret = HKDF-Expand-Label(., "server in", "", 32) */
     100             : 
     101             : void
     102             : fd_quic_gen_initial_secrets(
     103             :     fd_quic_crypto_secrets_t * secrets,
     104             :     uchar const *              conn_id,
     105             :     ulong                      conn_id_sz,
     106             :     int                        is_server );
     107             : 
     108             : /* fd_quic_gen_keys derives the IV, a header protection key, and a packet
     109             :    protection key from a secret.  Thus *keys is fully initialized.  This
     110             :    function is called twice per encryption level (for incoming and for
     111             :    outgoing keys).
     112             : 
     113             :    Key schedule:
     114             : 
     115             :      secret
     116             :       |
     117             :       +---> header protection key = HKDF-Expand-Label(.,"quic-hp")
     118             :       +---> packet protection IV  = HKDF-Expand-Label(.,"quic-iv")
     119             :       +---> packet protection key = HKDF-Expand-Label(.,"quic-key") */
     120             : 
     121             : void
     122             : fd_quic_gen_keys(
     123             :     fd_quic_crypto_keys_t * keys,
     124             :     uchar const             secret[ 32 ] );
     125             : 
     126             : /* fd_quic_key_update_derive derives the IVs and packet protection keys
     127             :    for the next key update.  Header protection keys are not updated.
     128             :    Key updates are periodic key rotations that some QUIC peers do out of
     129             :    caution.  Key updates are deterministic and can be computed infinitely
     130             :    far in advance if the client and server secrets are known.
     131             : 
     132             :    Key schedule:
     133             : 
     134             :      client/server secret n
     135             :       |
     136             :       v
     137             :      client/server secret n+1 = HKDF-Expand-Label(.,"quic-ku")
     138             :       |
     139             :       +---> server packet protection IV  = HKDF-Expand-Label(.,"quic-iv")
     140             :       +---> server packet protection key = HKDF-Expand-Label(.,"quic-key") */
     141             : 
     142             : void
     143             : fd_quic_key_update_derive( fd_quic_crypto_secrets_t * secrets,
     144             :                            fd_quic_crypto_keys_t      new_keys[2] );
     145             : 
     146             : 
     147             : /* encrypt a packet according to rfc9001 packet protection and header protection
     148             : 
     149             :    may fail in the following scenarios:
     150             :      the receiving buffer is too small
     151             :      the decryption functions report failure (fd_tls)
     152             : 
     153             :    returns
     154             :      FD_QUIC_SUCCESS   if the operation succeeded
     155             :      FD_QUIC_FAILED    otherwise
     156             : 
     157             :    args
     158             :     out       destination for the full packet
     159             :     out_sz    size of the output buffer, and also returned size of the written bytes
     160             :     hdr       the input plain text header
     161             :     hdr_sz    the size of the input header
     162             :     pkt       the input plain text payload
     163             :     pkt_sz    the size of the input payload
     164             :     keys      the keys to use
     165             :    */
     166             : int
     167             : fd_quic_crypto_encrypt(
     168             :     uchar *                        const out,
     169             :     ulong *                        const out_sz,
     170             :     uchar const *                  const hdr,
     171             :     ulong                          const hdr_sz,
     172             :     uchar const *                  const pkt,
     173             :     ulong                          const pkt_sz,
     174             :     fd_quic_crypto_keys_t const *  const pkt_keys,
     175             :     fd_quic_crypto_keys_t const *  const hp_keys,
     176             :     ulong                          const pkt_number );
     177             : 
     178             : 
     179             : /* decrypt a quic protected packet
     180             : 
     181             :    may fail in the following scenarios:
     182             :      the receiving buffer is too small
     183             :      the decryption functions report failure (fd_tls)
     184             :      the decrypted data is corrupt
     185             : 
     186             :    returns
     187             :      FD_QUIC_SUCCESS   if the operation succeeded
     188             :      FD_QUIC_FAILED    otherwise
     189             : 
     190             :    args
     191             :      buf                buffer containing a QUIC packet with a decrypted
     192             :                         header, and encrypted payload, and the auth tag
     193             :                         of size FD_QUIC_CRYPTO_TAG_SZ.  On return, the
     194             :                         payload will be decrypted.
     195             :      buf_sz             the size of the QUIC packet
     196             :      pkt_number_off     the offset of the packet number within the cipher text
     197             :                         this must be determined from unprotected header data
     198             :      keys               the keys needed to decrypt */
     199             : 
     200             : int
     201             : fd_quic_crypto_decrypt(
     202             :     uchar *                        buf,
     203             :     ulong                          buf_sz,
     204             :     ulong                          pkt_number_off,
     205             :     ulong                          pkt_number,
     206             :     fd_quic_crypto_keys_t const *  keys );
     207             : 
     208             : 
     209             : /* decrypt a quic protected packet header
     210             : 
     211             :    this removes header protection (HP)
     212             : 
     213             :    may fail in the following scenarios:
     214             :      the receiving buffer is too small
     215             :      the decryption functions report failure (fd_tls)
     216             :      the decrypted data is corrupt
     217             : 
     218             :    returns
     219             :      FD_QUIC_SUCCESS   if the operation succeeded
     220             :      FD_QUIC_FAILED    otherwise
     221             : 
     222             :    args
     223             :      buf                buffer containing an encrypted QUIC packet.
     224             :                         On return, the header is decrypted, the rest
     225             :                         still encrypted
     226             :      buf_sz             size of the QUIC packet
     227             :      pkt_number_off     the offset of the packet number within the cipher text
     228             :                         this must be determined from unprotected header data
     229             :      keys               the keys needed to decrypt */
     230             : 
     231             : int
     232             : fd_quic_crypto_decrypt_hdr(
     233             :     uchar *                        buf,
     234             :     ulong                          buf_sz,
     235             :     ulong                          pkt_number_off,
     236             :     fd_quic_crypto_keys_t const *  keys );
     237             : 
     238             : /* nonce is quic-iv XORed with 62-bits of byte-order packet-number */
     239             : static inline void
     240             : fd_quic_get_nonce(
     241             :     uchar *       nonce,
     242             :     uchar const * iv,
     243    39686132 :     ulong         pkt_number ) {
     244    39686132 :   #define MASK_LOWER_62 0x3fffffffffffffffu
     245    39686132 :   memcpy( nonce, iv, 4 );
     246    39686132 :   FD_STORE( ulong, nonce + 4, FD_LOAD( ulong, iv + 4 ) ^ fd_ulong_bswap( pkt_number & MASK_LOWER_62 ) );
     247    39686132 :   #undef MASK_LOWER_62
     248    39686132 : }
     249             : 
     250             : #endif /* HEADER_fd_src_waltz_quic_crypto_fd_quic_crypto_suites_h */

Generated by: LCOV version 1.14