blob: d4314d7cb4ca6fff6dd2051e10536872c30ecf7e [file] [log] [blame]
Frédéric Lécaillea7e7ce92020-11-23 14:14:04 +01001#include <string.h>
2
3#include <openssl/ssl.h>
4
5#if defined(OPENSSL_IS_BORINGSSL)
6#include <openssl/hkdf.h>
7#else
8#include <openssl/evp.h>
9#include <openssl/kdf.h>
10#endif
11
12#include <haproxy/buf.h>
13#include <haproxy/chunk.h>
14//#include <haproxy/quic_tls-t.h>
15#include <haproxy/xprt_quic.h>
16
17
Frédéric Lécaillefc768ec2021-11-23 21:02:04 +010018DECLARE_POOL(pool_head_quic_tls_secret, "quic_tls_secret", QUIC_TLS_SECRET_LEN);
19DECLARE_POOL(pool_head_quic_tls_iv, "quic_tls_iv", QUIC_TLS_IV_LEN);
20DECLARE_POOL(pool_head_quic_tls_key, "quic_tls_key", QUIC_TLS_KEY_LEN);
21
Frédéric Lécaillea7e7ce92020-11-23 14:14:04 +010022__attribute__((format (printf, 3, 4)))
23void hexdump(const void *buf, size_t buflen, const char *title_fmt, ...);
24
Frédéric Lécaillea7e7ce92020-11-23 14:14:04 +010025/* Dump the RX/TX secrets of <secs> QUIC TLS secrets. */
Amaury Denoyelle4fd53d72021-12-21 14:28:26 +010026void quic_tls_keys_hexdump(struct buffer *buf,
27 const struct quic_tls_secrets *secs)
Frédéric Lécaillea7e7ce92020-11-23 14:14:04 +010028{
29 int i;
30 size_t aead_keylen = (size_t)EVP_CIPHER_key_length(secs->aead);
31 size_t aead_ivlen = (size_t)EVP_CIPHER_iv_length(secs->aead);
32 size_t hp_len = (size_t)EVP_CIPHER_key_length(secs->hp);
33
34 chunk_appendf(buf, "\n key=");
35 for (i = 0; i < aead_keylen; i++)
36 chunk_appendf(buf, "%02x", secs->key[i]);
37 chunk_appendf(buf, "\n iv=");
38 for (i = 0; i < aead_ivlen; i++)
39 chunk_appendf(buf, "%02x", secs->iv[i]);
40 chunk_appendf(buf, "\n hp=");
41 for (i = 0; i < hp_len; i++)
42 chunk_appendf(buf, "%02x", secs->hp_key[i]);
43}
44
45/* Dump <secret> TLS secret. */
46void quic_tls_secret_hexdump(struct buffer *buf,
47 const unsigned char *secret, size_t secret_len)
48{
49 int i;
50
51 chunk_appendf(buf, " secret=");
52 for (i = 0; i < secret_len; i++)
53 chunk_appendf(buf, "%02x", secret[i]);
54}
55
56#if defined(OPENSSL_IS_BORINGSSL)
57int quic_hkdf_extract(const EVP_MD *md,
58 unsigned char *buf, size_t *buflen,
59 const unsigned char *key, size_t keylen,
Frédéric Lécaille2fc76cf2021-08-31 19:10:40 +020060 const unsigned char *salt, size_t saltlen)
Frédéric Lécaillea7e7ce92020-11-23 14:14:04 +010061{
62 return HKDF_extract(buf, buflen, md, key, keylen, salt, saltlen);
63}
64
65int quic_hkdf_expand(const EVP_MD *md,
66 unsigned char *buf, size_t buflen,
67 const unsigned char *key, size_t keylen,
68 const unsigned char *label, size_t labellen)
69{
70 return HKDF_expand(buf, buflen, md, key, keylen, label, labellen);
71}
72#else
73int quic_hkdf_extract(const EVP_MD *md,
74 unsigned char *buf, size_t *buflen,
75 const unsigned char *key, size_t keylen,
Frédéric Lécaille2fc76cf2021-08-31 19:10:40 +020076 const unsigned char *salt, size_t saltlen)
Frédéric Lécaillea7e7ce92020-11-23 14:14:04 +010077{
78 EVP_PKEY_CTX *ctx;
79
80 ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
81 if (!ctx)
82 return 0;
83
84 if (EVP_PKEY_derive_init(ctx) <= 0 ||
85 EVP_PKEY_CTX_hkdf_mode(ctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) <= 0 ||
86 EVP_PKEY_CTX_set_hkdf_md(ctx, md) <= 0 ||
87 EVP_PKEY_CTX_set1_hkdf_salt(ctx, salt, saltlen) <= 0 ||
88 EVP_PKEY_CTX_set1_hkdf_key(ctx, key, keylen) <= 0 ||
89 EVP_PKEY_derive(ctx, buf, buflen) <= 0)
90 goto err;
91
92 EVP_PKEY_CTX_free(ctx);
93 return 1;
94
95 err:
96 EVP_PKEY_CTX_free(ctx);
97 return 0;
98}
99
100int quic_hkdf_expand(const EVP_MD *md,
101 unsigned char *buf, size_t buflen,
102 const unsigned char *key, size_t keylen,
103 const unsigned char *label, size_t labellen)
104{
105 EVP_PKEY_CTX *ctx;
106
107 ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
108 if (!ctx)
109 return 0;
110
111 if (EVP_PKEY_derive_init(ctx) <= 0 ||
112 EVP_PKEY_CTX_hkdf_mode(ctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) <= 0 ||
113 EVP_PKEY_CTX_set_hkdf_md(ctx, md) <= 0 ||
114 EVP_PKEY_CTX_set1_hkdf_key(ctx, key, keylen) <= 0 ||
115 EVP_PKEY_CTX_add1_hkdf_info(ctx, label, labellen) <= 0 ||
116 EVP_PKEY_derive(ctx, buf, &buflen) <= 0)
117 goto err;
118
119 EVP_PKEY_CTX_free(ctx);
120 return 1;
121
122 err:
123 EVP_PKEY_CTX_free(ctx);
124 return 0;
125}
126#endif
127
128/* https://quicwg.org/base-drafts/draft-ietf-quic-tls.html#protection-keys
129 * refers to:
130 *
131 * https://tools.ietf.org/html/rfc8446#section-7.1:
132 * 7.1. Key Schedule
133 *
134 * The key derivation process makes use of the HKDF-Extract and
135 * HKDF-Expand functions as defined for HKDF [RFC5869], as well as the
136 * functions defined below:
137 *
138 * HKDF-Expand-Label(Secret, Label, Context, Length) =
139 * HKDF-Expand(Secret, HkdfLabel, Length)
140 *
141 * Where HkdfLabel is specified as:
142 *
143 * struct {
144 * uint16 length = Length;
145 * opaque label<7..255> = "tls13 " + Label;
146 * opaque context<0..255> = Context;
147 * } HkdfLabel;
148 *
149 * Derive-Secret(Secret, Label, Messages) =
150 * HKDF-Expand-Label(Secret, Label,
151 * Transcript-Hash(Messages), Hash.length)
152 *
153 */
154int quic_hkdf_expand_label(const EVP_MD *md,
155 unsigned char *buf, size_t buflen,
156 const unsigned char *key, size_t keylen,
157 const unsigned char *label, size_t labellen)
158{
159 unsigned char hdkf_label[256], *pos;
160 const unsigned char hdkf_label_label[] = "tls13 ";
161 size_t hdkf_label_label_sz = sizeof hdkf_label_label - 1;
162
163 pos = hdkf_label;
164 *pos++ = buflen >> 8;
165 *pos++ = buflen & 0xff;
166 *pos++ = hdkf_label_label_sz + labellen;
167 memcpy(pos, hdkf_label_label, hdkf_label_label_sz);
168 pos += hdkf_label_label_sz;
169 memcpy(pos, label, labellen);
170 pos += labellen;
171 *pos++ = '\0';
172
173 return quic_hkdf_expand(md, buf, buflen,
174 key, keylen, hdkf_label, pos - hdkf_label);
175}
176
177/*
178 * This function derives two keys from <secret> is <ctx> as TLS cryptographic context.
179 * ->key is the TLS key to be derived to encrypt/decrypt data at TLS level.
180 * ->iv is the initialization vector to be used with ->key.
181 * ->hp_key is the key to be derived for header protection.
182 * Obviouly these keys have the same size becaused derived with the same TLS cryptographic context.
183 */
184int quic_tls_derive_keys(const EVP_CIPHER *aead, const EVP_CIPHER *hp,
185 const EVP_MD *md,
186 unsigned char *key, size_t keylen,
187 unsigned char *iv, size_t ivlen,
188 unsigned char *hp_key, size_t hp_keylen,
189 const unsigned char *secret, size_t secretlen)
190{
191 size_t aead_keylen = (size_t)EVP_CIPHER_key_length(aead);
192 size_t aead_ivlen = (size_t)EVP_CIPHER_iv_length(aead);
Frédéric Lécaille6e351d62021-11-30 11:06:41 +0100193 size_t hp_len = hp ? (size_t)EVP_CIPHER_key_length(hp) : 0;
Frédéric Lécaillea7e7ce92020-11-23 14:14:04 +0100194 const unsigned char key_label[] = "quic key";
195 const unsigned char iv_label[] = "quic iv";
196 const unsigned char hp_key_label[] = "quic hp";
197
198 if (aead_keylen > keylen || aead_ivlen > ivlen || hp_len > hp_keylen)
199 return 0;
200
201 if (!quic_hkdf_expand_label(md, key, aead_keylen, secret, secretlen,
202 key_label, sizeof key_label - 1) ||
203 !quic_hkdf_expand_label(md, iv, aead_ivlen, secret, secretlen,
204 iv_label, sizeof iv_label - 1) ||
Frédéric Lécaille6e351d62021-11-30 11:06:41 +0100205 (hp_key && !quic_hkdf_expand_label(md, hp_key, hp_len, secret, secretlen,
206 hp_key_label, sizeof hp_key_label - 1)))
Frédéric Lécaillea7e7ce92020-11-23 14:14:04 +0100207 return 0;
208
209 return 1;
210}
211
212/*
213 * Derive the initial secret from <secret> and QUIC version dependent salt.
214 * Returns the size of the derived secret if succeeded, 0 if not.
215 */
216int quic_derive_initial_secret(const EVP_MD *md,
Frédéric Lécaille2fc76cf2021-08-31 19:10:40 +0200217 const unsigned char *initial_salt, size_t initial_salt_sz,
Frédéric Lécaillea7e7ce92020-11-23 14:14:04 +0100218 unsigned char *initial_secret, size_t initial_secret_sz,
219 const unsigned char *secret, size_t secret_sz)
220{
221 if (!quic_hkdf_extract(md, initial_secret, &initial_secret_sz, secret, secret_sz,
Frédéric Lécaille2fc76cf2021-08-31 19:10:40 +0200222 initial_salt, initial_salt_sz))
Frédéric Lécaillea7e7ce92020-11-23 14:14:04 +0100223 return 0;
224
225 return 1;
226}
227
228/*
229 * Derive the client initial secret from the initial secret.
230 * Returns the size of the derived secret if succeeded, 0 if not.
231 */
232int quic_tls_derive_initial_secrets(const EVP_MD *md,
233 unsigned char *rx, size_t rx_sz,
234 unsigned char *tx, size_t tx_sz,
235 const unsigned char *secret, size_t secret_sz,
236 int server)
237{
238 const unsigned char client_label[] = "client in";
239 const unsigned char server_label[] = "server in";
240 const unsigned char *tx_label, *rx_label;
241 size_t rx_label_sz, tx_label_sz;
242
243 if (server) {
244 rx_label = client_label;
245 rx_label_sz = sizeof client_label;
246 tx_label = server_label;
247 tx_label_sz = sizeof server_label;
248 }
249 else {
250 rx_label = server_label;
251 rx_label_sz = sizeof server_label;
252 tx_label = client_label;
253 tx_label_sz = sizeof client_label;
254 }
255
256 if (!quic_hkdf_expand_label(md, rx, rx_sz, secret, secret_sz,
257 rx_label, rx_label_sz - 1) ||
258 !quic_hkdf_expand_label(md, tx, tx_sz, secret, secret_sz,
259 tx_label, tx_label_sz - 1))
260 return 0;
261
262 return 1;
263}
264
Frédéric Lécaille39484de2021-11-30 10:10:24 +0100265/* Update <sec> secret key into <new_sec> according to RFC 9001 6.1.
266 * Always succeeds.
267 */
268int quic_tls_sec_update(const EVP_MD *md,
269 unsigned char *new_sec, size_t new_seclen,
270 const unsigned char *sec, size_t seclen)
271{
272 const unsigned char ku_label[] = "quic ku";
273
274 return quic_hkdf_expand_label(md, new_sec, new_seclen, sec, seclen,
275 ku_label, sizeof ku_label - 1);
276}
277
Frédéric Lécaillea7e7ce92020-11-23 14:14:04 +0100278/*
279 * Build an IV into <iv> buffer with <ivlen> as size from <aead_iv> with
280 * <aead_ivlen> as size depending on <pn> packet number.
281 * This is the function which must be called to build an AEAD IV for the AEAD cryptographic algorithm
282 * used to encrypt/decrypt the QUIC packet payloads depending on the packet number <pn>.
283 * This function fails and return 0 only if the two buffer lengths are different, 1 if not.
284 */
285int quic_aead_iv_build(unsigned char *iv, size_t ivlen,
286 unsigned char *aead_iv, size_t aead_ivlen, uint64_t pn)
287{
288 int i;
289 unsigned int shift;
290 unsigned char *pos = iv;
291
292 if (ivlen != aead_ivlen)
293 return 0;
294
295 for (i = 0; i < ivlen - sizeof pn; i++)
296 *pos++ = *aead_iv++;
297
298 /* Only the remaining (sizeof pn) bytes are XOR'ed. */
299 shift = 56;
300 for (i = aead_ivlen - sizeof pn; i < aead_ivlen ; i++, shift -= 8)
301 *pos++ = *aead_iv++ ^ (pn >> shift);
302
303 return 1;
304}
305
306/*
307 * https://quicwg.org/base-drafts/draft-ietf-quic-tls.html#aead
308 *
309 * 5.3. AEAD Usage
310 *
311 * Packets are protected prior to applying header protection (Section 5.4).
312 * The unprotected packet header is part of the associated data (A). When removing
313 * packet protection, an endpoint first removes the header protection.
314 * (...)
315 * These ciphersuites have a 16-byte authentication tag and produce an output 16
316 * bytes larger than their input.
317 * The key and IV for the packet are computed as described in Section 5.1. The nonce,
318 * N, is formed by combining the packet protection IV with the packet number. The 62
319 * bits of the reconstructed QUIC packet number in network byte order are left-padded
320 * with zeros to the size of the IV. The exclusive OR of the padded packet number and
321 * the IV forms the AEAD nonce.
322 *
323 * The associated data, A, for the AEAD is the contents of the QUIC header, starting
324 * from the flags byte in either the short or long header, up to and including the
325 * unprotected packet number.
326 *
327 * The input plaintext, P, for the AEAD is the payload of the QUIC packet, as described
328 * in [QUIC-TRANSPORT].
329 *
330 * The output ciphertext, C, of the AEAD is transmitted in place of P.
331 *
332 * Some AEAD functions have limits for how many packets can be encrypted under the same
333 * key and IV (see for example [AEBounds]). This might be lower than the packet number limit.
334 * An endpoint MUST initiate a key update (Section 6) prior to exceeding any limit set for
335 * the AEAD that is in use.
336 */
337
338int quic_tls_encrypt(unsigned char *buf, size_t len,
339 const unsigned char *aad, size_t aad_len,
340 const EVP_CIPHER *aead, const unsigned char *key, const unsigned char *iv)
341{
342 EVP_CIPHER_CTX *ctx;
343 int ret, outlen;
344
345 ret = 0;
346 ctx = EVP_CIPHER_CTX_new();
347 if (!ctx)
348 return 0;
349
350 if (!EVP_EncryptInit_ex(ctx, aead, NULL, key, iv) ||
351 !EVP_EncryptUpdate(ctx, NULL, &outlen, aad, aad_len) ||
352 !EVP_EncryptUpdate(ctx, buf, &outlen, buf, len) ||
353 !EVP_EncryptFinal_ex(ctx, buf + outlen, &outlen) ||
354 !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, QUIC_TLS_TAG_LEN, buf + len))
355 goto out;
356
357 ret = 1;
358
359 out:
360 EVP_CIPHER_CTX_free(ctx);
361
362 return ret;
363}
364
365int quic_tls_decrypt(unsigned char *buf, size_t len,
366 unsigned char *aad, size_t aad_len,
367 const EVP_CIPHER *aead, const unsigned char *key, const unsigned char *iv)
368{
369 int ret, outlen;
370 size_t off;
371 EVP_CIPHER_CTX *ctx;
372
373 ret = 0;
374 off = 0;
375 ctx = EVP_CIPHER_CTX_new();
376 if (!ctx)
377 return 0;
378
379 if (!EVP_DecryptInit_ex(ctx, aead, NULL, key, iv) ||
380 !EVP_DecryptUpdate(ctx, NULL, &outlen, aad, aad_len) ||
381 !EVP_DecryptUpdate(ctx, buf, &outlen, buf, len - QUIC_TLS_TAG_LEN))
382 goto out;
383
384 off += outlen;
385
386 if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, QUIC_TLS_TAG_LEN,
387 buf + len - QUIC_TLS_TAG_LEN) ||
388 !EVP_DecryptFinal_ex(ctx, buf + off, &outlen))
389 goto out;
390
391 off += outlen;
392
393 ret = off;
394
395 out:
396 EVP_CIPHER_CTX_free(ctx);
397 return ret;
398}
Amaury Denoyelle6efec292022-01-11 11:57:00 +0100399
400/* Generate the AEAD tag for the Retry packet <pkt> of <pkt_len> bytes and
401 * write it to <tag>. The tag is written just after the <pkt> area. It should
402 * be at least 16 bytes longs. <odcid> is the CID of the Initial packet
403 * received which triggers the Retry.
404 *
405 * Returns non-zero on success else zero.
406 */
407int quic_tls_generate_retry_integrity_tag(unsigned char *odcid,
408 unsigned char odcid_len,
409 unsigned char *pkt, size_t pkt_len)
410{
411 const EVP_CIPHER *evp = EVP_aes_128_gcm();
412 EVP_CIPHER_CTX *ctx;
413
414 /* key/nonce from rfc9001 5.8. Retry Packet Integrity */
415 const unsigned char key[] = {
416 0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a,
417 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e,
418 };
419 const unsigned char nonce[] = {
420 0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb,
421 };
422
423 /* encryption buffer - not used as only AEAD tag generation is proceed */
424 unsigned char *out = NULL;
425 /* address to store the AEAD tag */
426 unsigned char *tag = pkt + pkt_len;
427 int outlen, ret = 0;
428
429 ctx = EVP_CIPHER_CTX_new();
430 if (!ctx)
431 return 0;
432
433 /* rfc9001 5.8. Retry Packet Integrity
434 *
435 * AEAD is proceed over a pseudo-Retry packet used as AAD. It contains
436 * the ODCID len + data and the Retry packet itself.
437 */
438 if (!EVP_EncryptInit_ex(ctx, evp, NULL, key, nonce) ||
439 /* specify pseudo-Retry as AAD */
440 !EVP_EncryptUpdate(ctx, NULL, &outlen, &odcid_len, sizeof(odcid_len)) ||
441 !EVP_EncryptUpdate(ctx, NULL, &outlen, odcid, odcid_len) ||
442 !EVP_EncryptUpdate(ctx, NULL, &outlen, pkt, pkt_len) ||
443 /* finalize */
444 !EVP_EncryptFinal_ex(ctx, out, &outlen) ||
445 /* store the tag */
446 !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, QUIC_TLS_TAG_LEN, tag)) {
447 goto out;
448 }
449 ret = 1;
450
451 out:
452 EVP_CIPHER_CTX_free(ctx);
453 return ret;
454}