]> git.ipfire.org Git - thirdparty/openssl.git/blob - ssl/quic/quic_record_shared.c
QUIC Record Layer (Refactor and TX Side)
[thirdparty/openssl.git] / ssl / quic / quic_record_shared.c
1 #include "quic_record_shared.h"
2 #include "internal/quic_record_util.h"
3 #include "internal/common.h"
4 #include "../ssl_local.h"
5
6 /* Constants used for key derivation in QUIC v1. */
7 static const unsigned char quic_v1_iv_label[] = {
8 0x71, 0x75, 0x69, 0x63, 0x20, 0x69, 0x76 /* "quic iv" */
9 };
10 static const unsigned char quic_v1_key_label[] = {
11 0x71, 0x75, 0x69, 0x63, 0x20, 0x6b, 0x65, 0x79 /* "quic key" */
12 };
13 static const unsigned char quic_v1_hp_label[] = {
14 0x71, 0x75, 0x69, 0x63, 0x20, 0x68, 0x70 /* "quic hp" */
15 };
16
17 OSSL_QRL_ENC_LEVEL *ossl_qrl_enc_level_set_get(OSSL_QRL_ENC_LEVEL_SET *els,
18 uint32_t enc_level,
19 int require_valid)
20 {
21 OSSL_QRL_ENC_LEVEL *el;
22
23 if (!ossl_assert(enc_level < QUIC_ENC_LEVEL_NUM))
24 return NULL;
25
26 el = &els->el[enc_level];
27
28 if (require_valid && (el->cctx == NULL || el->discarded))
29 return NULL;
30
31 return el;
32 }
33
34 int ossl_qrl_enc_level_set_have_el(OSSL_QRL_ENC_LEVEL_SET *els,
35 uint32_t enc_level)
36 {
37 OSSL_QRL_ENC_LEVEL *el = ossl_qrl_enc_level_set_get(els, enc_level, 0);
38
39 if (el == NULL)
40 return 0;
41 if (el->cctx != NULL)
42 return 1;
43 if (el->discarded)
44 return -1;
45 return 0;
46 }
47
48 /*
49 * Sets up cryptographic state for a given encryption level and direction by
50 * deriving "quic iv", "quic key" and "quic hp" values from a given secret.
51 *
52 * md is a hash function used for key derivation. If it is NULL, this function
53 * fetches the necessary hash function itself. If it is non-NULL, this function
54 * can reuse the caller's reference to a suitable EVP_MD; the EVP_MD provided
55 * must match the suite.
56 *
57 * On success where md is non-NULL, takes ownership of the caller's reference to
58 * md.
59 */
60 int ossl_qrl_enc_level_set_provide_secret(OSSL_QRL_ENC_LEVEL_SET *els,
61 OSSL_LIB_CTX *libctx,
62 const char *propq,
63 uint32_t enc_level,
64 uint32_t suite_id,
65 EVP_MD *md,
66 const unsigned char *secret,
67 size_t secret_len)
68 {
69 OSSL_QRL_ENC_LEVEL *el = ossl_qrl_enc_level_set_get(els, enc_level, 0);
70 unsigned char key[EVP_MAX_KEY_LENGTH], hpr_key[EVP_MAX_KEY_LENGTH];
71 size_t key_len = 0, hpr_key_len = 0, iv_len = 0;
72 const char *cipher_name = NULL, *md_name = NULL;
73 EVP_CIPHER *cipher = NULL;
74 EVP_CIPHER_CTX *cctx = NULL;
75 int own_md = 0, have_hpr = 0;
76
77 if (el == NULL || el->discarded)
78 /* Should not be trying to reinitialise an EL which was discarded. */
79 return 0;
80
81 cipher_name = ossl_qrl_get_suite_cipher_name(suite_id);
82 iv_len = ossl_qrl_get_suite_cipher_iv_len(suite_id);
83 key_len = ossl_qrl_get_suite_cipher_key_len(suite_id);
84 hpr_key_len = ossl_qrl_get_suite_hdr_prot_key_len(suite_id);
85 if (cipher_name == NULL)
86 return 0;
87
88 if (secret_len != ossl_qrl_get_suite_secret_len(suite_id))
89 return 0;
90
91 if (md == NULL) {
92 md_name = ossl_qrl_get_suite_md_name(suite_id);
93
94 if ((md = EVP_MD_fetch(libctx, md_name, propq)) == NULL)
95 return 0;
96
97 own_md = 1;
98 }
99
100 /* Derive "quic iv" key. */
101 if (!tls13_hkdf_expand_ex(libctx, propq,
102 md,
103 secret,
104 quic_v1_iv_label,
105 sizeof(quic_v1_iv_label),
106 NULL, 0,
107 el->iv, iv_len, 0))
108 goto err;
109
110 /* Derive "quic key" key. */
111 if (!tls13_hkdf_expand_ex(libctx, propq,
112 md,
113 secret,
114 quic_v1_key_label,
115 sizeof(quic_v1_key_label),
116 NULL, 0,
117 key, key_len, 0))
118 goto err;
119
120 /* Derive "quic hp" key. */
121 if (!tls13_hkdf_expand_ex(libctx, propq,
122 md,
123 secret,
124 quic_v1_hp_label,
125 sizeof(quic_v1_hp_label),
126 NULL, 0,
127 hpr_key, hpr_key_len, 0))
128 goto err;
129
130 /* Free any old context which is using old keying material. */
131 if (el->cctx != NULL) {
132 ossl_quic_hdr_protector_destroy(&el->hpr);
133 EVP_CIPHER_CTX_free(el->cctx);
134 el->cctx = NULL;
135 }
136
137 /* Setup header protection context. */
138 if (!ossl_quic_hdr_protector_init(&el->hpr,
139 libctx,
140 propq,
141 ossl_qrl_get_suite_hdr_prot_cipher_id(suite_id),
142 hpr_key,
143 hpr_key_len))
144 goto err;
145
146 have_hpr = 1;
147
148 /* Create and initialise cipher context. */
149 if ((cipher = EVP_CIPHER_fetch(libctx, cipher_name, propq)) == NULL)
150 goto err;
151
152 if (!ossl_assert(iv_len == (size_t)EVP_CIPHER_get_iv_length(cipher))
153 || !ossl_assert(key_len == (size_t)EVP_CIPHER_get_key_length(cipher)))
154 goto err;
155
156 if ((cctx = EVP_CIPHER_CTX_new()) == NULL)
157 goto err;
158
159 /* IV will be changed on RX/TX so we don't need to use a real value here. */
160 if (!EVP_CipherInit_ex(cctx, cipher, NULL, key, el->iv, 0))
161 goto err;
162
163 el->suite_id = suite_id;
164 el->cctx = cctx;
165 el->md = md;
166 el->tag_len = ossl_qrl_get_suite_cipher_tag_len(suite_id);
167 el->op_count = 0;
168
169 /* Zeroize intermediate keys. */
170 OPENSSL_cleanse(key, sizeof(key));
171 OPENSSL_cleanse(hpr_key, sizeof(hpr_key));
172 EVP_CIPHER_free(cipher);
173 return 1;
174
175 err:
176 if (have_hpr)
177 ossl_quic_hdr_protector_destroy(&el->hpr);
178 EVP_CIPHER_CTX_free(cctx);
179 EVP_CIPHER_free(cipher);
180 if (own_md)
181 EVP_MD_free(md);
182 return 0;
183 }
184
185 /* Drops keying material for a given encryption level. */
186 void ossl_qrl_enc_level_set_discard(OSSL_QRL_ENC_LEVEL_SET *els,
187 uint32_t enc_level, int is_final)
188 {
189 OSSL_QRL_ENC_LEVEL *el = ossl_qrl_enc_level_set_get(els, enc_level, 0);
190
191 if (el == NULL || el->discarded)
192 return;
193
194 if (el->cctx != NULL) {
195 ossl_quic_hdr_protector_destroy(&el->hpr);
196
197 EVP_CIPHER_CTX_free(el->cctx);
198 el->cctx = NULL;
199
200 EVP_MD_free(el->md);
201 el->md = NULL;
202 }
203
204 /* Zeroise IV. */
205 OPENSSL_cleanse(el->iv, sizeof(el->iv));
206
207 if (is_final)
208 el->discarded = 1;
209 }