xref: /openssl/ssl/quic/quic_record_util.c (revision 7ed6de99)
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 destionation
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", "SHA256", 32, 16, 12, 16, 16,
195     QUIC_HDR_PROT_CIPHER_AES_128,
196     ((uint64_t)1) << 23, /* Limits as prescribed by RFC 9001 */
197     ((uint64_t)1) << 52,
198 };
199 
200 static const struct suite_info suite_aes256gcm = {
201     "AES-256-GCM", "SHA384", 48, 32, 12, 16, 32,
202     QUIC_HDR_PROT_CIPHER_AES_256,
203     ((uint64_t)1) << 23, /* Limits as prescribed by RFC 9001 */
204     ((uint64_t)1) << 52,
205 };
206 
207 static const struct suite_info suite_chacha20poly1305 = {
208     "ChaCha20-Poly1305", "SHA256", 32, 32, 12, 16, 32,
209     QUIC_HDR_PROT_CIPHER_CHACHA,
210     /* Do not use UINT64_MAX here as this represents an invalid value */
211     UINT64_MAX - 1,         /* No applicable limit for this suite (RFC 9001) */
212     ((uint64_t)1) << 36,    /* Limit as prescribed by RFC 9001 */
213 };
214 
get_suite(uint32_t suite_id)215 static const struct suite_info *get_suite(uint32_t suite_id)
216 {
217     switch (suite_id) {
218         case QRL_SUITE_AES128GCM:
219             return &suite_aes128gcm;
220         case QRL_SUITE_AES256GCM:
221             return &suite_aes256gcm;
222         case QRL_SUITE_CHACHA20POLY1305:
223             return &suite_chacha20poly1305;
224         default:
225             return NULL;
226     }
227 }
228 
ossl_qrl_get_suite_cipher_name(uint32_t suite_id)229 const char *ossl_qrl_get_suite_cipher_name(uint32_t suite_id)
230 {
231     const struct suite_info *c = get_suite(suite_id);
232     return c != NULL ? c->cipher_name : NULL;
233 }
234 
ossl_qrl_get_suite_md_name(uint32_t suite_id)235 const char *ossl_qrl_get_suite_md_name(uint32_t suite_id)
236 {
237     const struct suite_info *c = get_suite(suite_id);
238     return c != NULL ? c->md_name : NULL;
239 }
240 
ossl_qrl_get_suite_secret_len(uint32_t suite_id)241 uint32_t ossl_qrl_get_suite_secret_len(uint32_t suite_id)
242 {
243     const struct suite_info *c = get_suite(suite_id);
244     return c != NULL ? c->secret_len : 0;
245 }
246 
ossl_qrl_get_suite_cipher_key_len(uint32_t suite_id)247 uint32_t ossl_qrl_get_suite_cipher_key_len(uint32_t suite_id)
248 {
249     const struct suite_info *c = get_suite(suite_id);
250     return c != NULL ? c->cipher_key_len : 0;
251 }
252 
ossl_qrl_get_suite_cipher_iv_len(uint32_t suite_id)253 uint32_t ossl_qrl_get_suite_cipher_iv_len(uint32_t suite_id)
254 {
255     const struct suite_info *c = get_suite(suite_id);
256     return c != NULL ? c->cipher_iv_len : 0;
257 }
258 
ossl_qrl_get_suite_cipher_tag_len(uint32_t suite_id)259 uint32_t ossl_qrl_get_suite_cipher_tag_len(uint32_t suite_id)
260 {
261     const struct suite_info *c = get_suite(suite_id);
262     return c != NULL ? c->cipher_tag_len : 0;
263 }
264 
ossl_qrl_get_suite_hdr_prot_cipher_id(uint32_t suite_id)265 uint32_t ossl_qrl_get_suite_hdr_prot_cipher_id(uint32_t suite_id)
266 {
267     const struct suite_info *c = get_suite(suite_id);
268     return c != NULL ? c->hdr_prot_cipher_id : 0;
269 }
270 
ossl_qrl_get_suite_hdr_prot_key_len(uint32_t suite_id)271 uint32_t ossl_qrl_get_suite_hdr_prot_key_len(uint32_t suite_id)
272 {
273     const struct suite_info *c = get_suite(suite_id);
274     return c != NULL ? c->hdr_prot_key_len : 0;
275 }
276 
ossl_qrl_get_suite_max_pkt(uint32_t suite_id)277 uint64_t ossl_qrl_get_suite_max_pkt(uint32_t suite_id)
278 {
279     const struct suite_info *c = get_suite(suite_id);
280     return c != NULL ? c->max_pkt : UINT64_MAX;
281 }
282 
ossl_qrl_get_suite_max_forged_pkt(uint32_t suite_id)283 uint64_t ossl_qrl_get_suite_max_forged_pkt(uint32_t suite_id)
284 {
285     const struct suite_info *c = get_suite(suite_id);
286     return c != NULL ? c->max_forged_pkt : UINT64_MAX;
287 }
288