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