xref: /freebsd/crypto/openssl/ssl/quic/quic_record_util.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*
2  * Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include "internal/quic_record_util.h"
11 #include "internal/quic_record_rx.h"
12 #include "internal/quic_record_tx.h"
13 #include "internal/quic_wire_pkt.h"
14 #include "../ssl_local.h"
15 #include <openssl/kdf.h>
16 #include <openssl/core_names.h>
17 
18 /*
19  * QUIC Key Derivation Utilities
20  * =============================
21  */
ossl_quic_hkdf_extract(OSSL_LIB_CTX * libctx,const char * propq,const EVP_MD * md,const unsigned char * salt,size_t salt_len,const unsigned char * ikm,size_t ikm_len,unsigned char * out,size_t out_len)22 int ossl_quic_hkdf_extract(OSSL_LIB_CTX *libctx,
23     const char *propq,
24     const EVP_MD *md,
25     const unsigned char *salt, size_t salt_len,
26     const unsigned char *ikm, size_t ikm_len,
27     unsigned char *out, size_t out_len)
28 {
29     int ret = 0;
30     EVP_KDF *kdf = NULL;
31     EVP_KDF_CTX *kctx = NULL;
32     OSSL_PARAM params[8], *p = params;
33     int key_check = 0;
34     int mode = EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY;
35     const char *md_name;
36 
37     if ((md_name = EVP_MD_get0_name(md)) == NULL
38         || (kdf = EVP_KDF_fetch(libctx, OSSL_KDF_NAME_HKDF, propq)) == NULL
39         || (kctx = EVP_KDF_CTX_new(kdf)) == NULL)
40         goto err;
41 
42     /*
43      * According to RFC 9000, the length of destination connection ID must be
44      * at least 8 bytes. It means that the length of destination connection ID
45      * may be less than the minimum length for HKDF required by FIPS provider.
46      *
47      * Therefore, we need to set `key-check` to zero to allow using destination
48      * connection ID as IKM.
49      */
50     *p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_FIPS_KEY_CHECK, &key_check);
51     *p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &mode);
52     *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
53         (char *)md_name, 0);
54     *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
55         (unsigned char *)salt, salt_len);
56     *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
57         (unsigned char *)ikm, ikm_len);
58     *p++ = OSSL_PARAM_construct_end();
59 
60     ret = EVP_KDF_derive(kctx, out, out_len, params);
61 
62 err:
63     EVP_KDF_CTX_free(kctx);
64     EVP_KDF_free(kdf);
65     return ret;
66 }
67 
68 /* Constants used for key derivation in QUIC v1. */
69 static const unsigned char quic_client_in_label[] = {
70     0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x6e /* "client in" */
71 };
72 static const unsigned char quic_server_in_label[] = {
73     0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x69, 0x6e /* "server in" */
74 };
75 
76 /* Salt used to derive Initial packet protection keys (RFC 9001 Section 5.2). */
77 static const unsigned char quic_v1_initial_salt[] = {
78     0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17,
79     0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a
80 };
81 
ossl_quic_provide_initial_secret(OSSL_LIB_CTX * libctx,const char * propq,const QUIC_CONN_ID * dst_conn_id,int is_server,struct ossl_qrx_st * qrx,struct ossl_qtx_st * qtx)82 int ossl_quic_provide_initial_secret(OSSL_LIB_CTX *libctx,
83     const char *propq,
84     const QUIC_CONN_ID *dst_conn_id,
85     int is_server,
86     struct ossl_qrx_st *qrx,
87     struct ossl_qtx_st *qtx)
88 {
89     unsigned char initial_secret[32];
90     unsigned char client_initial_secret[32], server_initial_secret[32];
91     unsigned char *rx_secret, *tx_secret;
92     EVP_MD *sha256;
93 
94     if (qrx == NULL && qtx == NULL)
95         return 1;
96 
97     /* Initial encryption always uses SHA-256. */
98     if ((sha256 = EVP_MD_fetch(libctx, "SHA256", propq)) == NULL)
99         return 0;
100 
101     if (is_server) {
102         rx_secret = client_initial_secret;
103         tx_secret = server_initial_secret;
104     } else {
105         rx_secret = server_initial_secret;
106         tx_secret = client_initial_secret;
107     }
108 
109     /* Derive initial secret from destination connection ID. */
110     if (!ossl_quic_hkdf_extract(libctx, propq,
111             sha256,
112             quic_v1_initial_salt,
113             sizeof(quic_v1_initial_salt),
114             dst_conn_id->id,
115             dst_conn_id->id_len,
116             initial_secret,
117             sizeof(initial_secret)))
118         goto err;
119 
120     /* Derive "client in" secret. */
121     if (((qtx != NULL && tx_secret == client_initial_secret)
122             || (qrx != NULL && rx_secret == client_initial_secret))
123         && !tls13_hkdf_expand_ex(libctx, propq,
124             sha256,
125             initial_secret,
126             quic_client_in_label,
127             sizeof(quic_client_in_label),
128             NULL, 0,
129             client_initial_secret,
130             sizeof(client_initial_secret), 1))
131         goto err;
132 
133     /* Derive "server in" secret. */
134     if (((qtx != NULL && tx_secret == server_initial_secret)
135             || (qrx != NULL && rx_secret == server_initial_secret))
136         && !tls13_hkdf_expand_ex(libctx, propq,
137             sha256,
138             initial_secret,
139             quic_server_in_label,
140             sizeof(quic_server_in_label),
141             NULL, 0,
142             server_initial_secret,
143             sizeof(server_initial_secret), 1))
144         goto err;
145 
146     /* Setup RX EL. Initial encryption always uses AES-128-GCM. */
147     if (qrx != NULL
148         && !ossl_qrx_provide_secret(qrx, QUIC_ENC_LEVEL_INITIAL,
149             QRL_SUITE_AES128GCM,
150             sha256,
151             rx_secret,
152             sizeof(server_initial_secret)))
153         goto err;
154 
155     /*
156      * ossl_qrx_provide_secret takes ownership of our ref to SHA256, so if we
157      * are initialising both sides, get a new ref for the following call for the
158      * TX side.
159      */
160     if (qrx != NULL && qtx != NULL && !EVP_MD_up_ref(sha256)) {
161         sha256 = NULL;
162         goto err;
163     }
164 
165     /* Setup TX cipher. */
166     if (qtx != NULL
167         && !ossl_qtx_provide_secret(qtx, QUIC_ENC_LEVEL_INITIAL,
168             QRL_SUITE_AES128GCM,
169             sha256,
170             tx_secret,
171             sizeof(server_initial_secret)))
172         goto err;
173 
174     return 1;
175 
176 err:
177     EVP_MD_free(sha256);
178     return 0;
179 }
180 
181 /*
182  * QUIC Record Layer Ciphersuite Info
183  * ==================================
184  */
185 
186 struct suite_info {
187     const char *cipher_name, *md_name;
188     uint32_t secret_len, cipher_key_len, cipher_iv_len, cipher_tag_len;
189     uint32_t hdr_prot_key_len, hdr_prot_cipher_id;
190     uint64_t max_pkt, max_forged_pkt;
191 };
192 
193 static const struct suite_info suite_aes128gcm = {
194     "AES-128-GCM",
195     "SHA256",
196     32,
197     16,
198     12,
199     16,
200     16,
201     QUIC_HDR_PROT_CIPHER_AES_128,
202     ((uint64_t)1) << 23, /* Limits as prescribed by RFC 9001 */
203     ((uint64_t)1) << 52,
204 };
205 
206 static const struct suite_info suite_aes256gcm = {
207     "AES-256-GCM",
208     "SHA384",
209     48,
210     32,
211     12,
212     16,
213     32,
214     QUIC_HDR_PROT_CIPHER_AES_256,
215     ((uint64_t)1) << 23, /* Limits as prescribed by RFC 9001 */
216     ((uint64_t)1) << 52,
217 };
218 
219 static const struct suite_info suite_chacha20poly1305 = {
220     "ChaCha20-Poly1305",
221     "SHA256",
222     32,
223     32,
224     12,
225     16,
226     32,
227     QUIC_HDR_PROT_CIPHER_CHACHA,
228     /* Do not use UINT64_MAX here as this represents an invalid value */
229     UINT64_MAX - 1, /* No applicable limit for this suite (RFC 9001) */
230     ((uint64_t)1) << 36, /* Limit as prescribed by RFC 9001 */
231 };
232 
get_suite(uint32_t suite_id)233 static const struct suite_info *get_suite(uint32_t suite_id)
234 {
235     switch (suite_id) {
236     case QRL_SUITE_AES128GCM:
237         return &suite_aes128gcm;
238     case QRL_SUITE_AES256GCM:
239         return &suite_aes256gcm;
240     case QRL_SUITE_CHACHA20POLY1305:
241         return &suite_chacha20poly1305;
242     default:
243         return NULL;
244     }
245 }
246 
ossl_qrl_get_suite_cipher_name(uint32_t suite_id)247 const char *ossl_qrl_get_suite_cipher_name(uint32_t suite_id)
248 {
249     const struct suite_info *c = get_suite(suite_id);
250     return c != NULL ? c->cipher_name : NULL;
251 }
252 
ossl_qrl_get_suite_md_name(uint32_t suite_id)253 const char *ossl_qrl_get_suite_md_name(uint32_t suite_id)
254 {
255     const struct suite_info *c = get_suite(suite_id);
256     return c != NULL ? c->md_name : NULL;
257 }
258 
ossl_qrl_get_suite_secret_len(uint32_t suite_id)259 uint32_t ossl_qrl_get_suite_secret_len(uint32_t suite_id)
260 {
261     const struct suite_info *c = get_suite(suite_id);
262     return c != NULL ? c->secret_len : 0;
263 }
264 
ossl_qrl_get_suite_cipher_key_len(uint32_t suite_id)265 uint32_t ossl_qrl_get_suite_cipher_key_len(uint32_t suite_id)
266 {
267     const struct suite_info *c = get_suite(suite_id);
268     return c != NULL ? c->cipher_key_len : 0;
269 }
270 
ossl_qrl_get_suite_cipher_iv_len(uint32_t suite_id)271 uint32_t ossl_qrl_get_suite_cipher_iv_len(uint32_t suite_id)
272 {
273     const struct suite_info *c = get_suite(suite_id);
274     return c != NULL ? c->cipher_iv_len : 0;
275 }
276 
ossl_qrl_get_suite_cipher_tag_len(uint32_t suite_id)277 uint32_t ossl_qrl_get_suite_cipher_tag_len(uint32_t suite_id)
278 {
279     const struct suite_info *c = get_suite(suite_id);
280     return c != NULL ? c->cipher_tag_len : 0;
281 }
282 
ossl_qrl_get_suite_hdr_prot_cipher_id(uint32_t suite_id)283 uint32_t ossl_qrl_get_suite_hdr_prot_cipher_id(uint32_t suite_id)
284 {
285     const struct suite_info *c = get_suite(suite_id);
286     return c != NULL ? c->hdr_prot_cipher_id : 0;
287 }
288 
ossl_qrl_get_suite_hdr_prot_key_len(uint32_t suite_id)289 uint32_t ossl_qrl_get_suite_hdr_prot_key_len(uint32_t suite_id)
290 {
291     const struct suite_info *c = get_suite(suite_id);
292     return c != NULL ? c->hdr_prot_key_len : 0;
293 }
294 
ossl_qrl_get_suite_max_pkt(uint32_t suite_id)295 uint64_t ossl_qrl_get_suite_max_pkt(uint32_t suite_id)
296 {
297     const struct suite_info *c = get_suite(suite_id);
298     return c != NULL ? c->max_pkt : UINT64_MAX;
299 }
300 
ossl_qrl_get_suite_max_forged_pkt(uint32_t suite_id)301 uint64_t ossl_qrl_get_suite_max_forged_pkt(uint32_t suite_id)
302 {
303     const struct suite_info *c = get_suite(suite_id);
304     return c != NULL ? c->max_forged_pkt : UINT64_MAX;
305 }
306