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