1 /*
2 * TLS 1.3 key schedule
3 *
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6 */
7
8 #include "common.h"
9
10 #if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)
11
12 #include "mbedtls/hkdf.h"
13 #include "mbedtls/ssl_internal.h"
14 #include "ssl_tls13_keys.h"
15 #include "psa/crypto_sizes.h"
16
17 #include <stdint.h>
18 #include <string.h>
19
20 #define MBEDTLS_SSL_TLS1_3_LABEL(name, string) \
21 .name = string,
22
23 #define TLS1_3_EVOLVE_INPUT_SIZE (PSA_HASH_MAX_SIZE > PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE) ? \
24 PSA_HASH_MAX_SIZE : PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE
25
26 struct mbedtls_ssl_tls1_3_labels_struct const mbedtls_ssl_tls1_3_labels =
27 {
28 /* This seems to work in C, despite the string literal being one
29 * character too long due to the 0-termination. */
30 MBEDTLS_SSL_TLS1_3_LABEL_LIST
31 };
32
33 #undef MBEDTLS_SSL_TLS1_3_LABEL
34
35 /*
36 * This function creates a HkdfLabel structure used in the TLS 1.3 key schedule.
37 *
38 * The HkdfLabel is specified in RFC 8446 as follows:
39 *
40 * struct HkdfLabel {
41 * uint16 length; // Length of expanded key material
42 * opaque label<7..255>; // Always prefixed by "tls13 "
43 * opaque context<0..255>; // Usually a communication transcript hash
44 * };
45 *
46 * Parameters:
47 * - desired_length: Length of expanded key material
48 * Even though the standard allows expansion to up to
49 * 2**16 Bytes, TLS 1.3 never uses expansion to more than
50 * 255 Bytes, so we require `desired_length` to be at most
51 * 255. This allows us to save a few Bytes of code by
52 * hardcoding the writing of the high bytes.
53 * - (label, llen): label + label length, without "tls13 " prefix
54 * The label length MUST be less than or equal to
55 * MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_LABEL_LEN
56 * It is the caller's responsibility to ensure this.
57 * All (label, label length) pairs used in TLS 1.3
58 * can be obtained via MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN().
59 * - (ctx, clen): context + context length
60 * The context length MUST be less than or equal to
61 * MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_CONTEXT_LEN
62 * It is the caller's responsibility to ensure this.
63 * - dst: Target buffer for HkdfLabel structure,
64 * This MUST be a writable buffer of size
65 * at least SSL_TLS1_3_KEY_SCHEDULE_MAX_HKDF_LABEL_LEN Bytes.
66 * - dlen: Pointer at which to store the actual length of
67 * the HkdfLabel structure on success.
68 */
69
70 static const char tls1_3_label_prefix[6] = "tls13 ";
71
72 #define SSL_TLS1_3_KEY_SCHEDULE_HKDF_LABEL_LEN(label_len, context_len) \
73 (2 /* expansion length */ \
74 + 1 /* label length */ \
75 + label_len \
76 + 1 /* context length */ \
77 + context_len)
78
79 #define SSL_TLS1_3_KEY_SCHEDULE_MAX_HKDF_LABEL_LEN \
80 SSL_TLS1_3_KEY_SCHEDULE_HKDF_LABEL_LEN( \
81 sizeof(tls1_3_label_prefix) + \
82 MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_LABEL_LEN, \
83 MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_CONTEXT_LEN)
84
ssl_tls1_3_hkdf_encode_label(size_t desired_length,const unsigned char * label,size_t llen,const unsigned char * ctx,size_t clen,unsigned char * dst,size_t * dlen)85 static void ssl_tls1_3_hkdf_encode_label(
86 size_t desired_length,
87 const unsigned char *label, size_t llen,
88 const unsigned char *ctx, size_t clen,
89 unsigned char *dst, size_t *dlen)
90 {
91 size_t total_label_len =
92 sizeof(tls1_3_label_prefix) + llen;
93 size_t total_hkdf_lbl_len =
94 SSL_TLS1_3_KEY_SCHEDULE_HKDF_LABEL_LEN(total_label_len, clen);
95
96 unsigned char *p = dst;
97
98 /* Add the size of the expanded key material.
99 * We're hardcoding the high byte to 0 here assuming that we never use
100 * TLS 1.3 HKDF key expansion to more than 255 Bytes. */
101 #if MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_EXPANSION_LEN > 255
102 #error "The implementation of ssl_tls1_3_hkdf_encode_label() is not fit for the \
103 value of MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_EXPANSION_LEN"
104 #endif
105
106 *p++ = 0;
107 *p++ = MBEDTLS_BYTE_0(desired_length);
108
109 /* Add label incl. prefix */
110 *p++ = MBEDTLS_BYTE_0(total_label_len);
111 memcpy(p, tls1_3_label_prefix, sizeof(tls1_3_label_prefix));
112 p += sizeof(tls1_3_label_prefix);
113 memcpy(p, label, llen);
114 p += llen;
115
116 /* Add context value */
117 *p++ = MBEDTLS_BYTE_0(clen);
118 if (clen != 0) {
119 memcpy(p, ctx, clen);
120 }
121
122 /* Return total length to the caller. */
123 *dlen = total_hkdf_lbl_len;
124 }
125
mbedtls_ssl_tls1_3_hkdf_expand_label(mbedtls_md_type_t hash_alg,const unsigned char * secret,size_t slen,const unsigned char * label,size_t llen,const unsigned char * ctx,size_t clen,unsigned char * buf,size_t blen)126 int mbedtls_ssl_tls1_3_hkdf_expand_label(
127 mbedtls_md_type_t hash_alg,
128 const unsigned char *secret, size_t slen,
129 const unsigned char *label, size_t llen,
130 const unsigned char *ctx, size_t clen,
131 unsigned char *buf, size_t blen)
132 {
133 const mbedtls_md_info_t *md;
134 unsigned char hkdf_label[SSL_TLS1_3_KEY_SCHEDULE_MAX_HKDF_LABEL_LEN];
135 size_t hkdf_label_len;
136
137 if (llen > MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_LABEL_LEN) {
138 /* Should never happen since this is an internal
139 * function, and we know statically which labels
140 * are allowed. */
141 return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
142 }
143
144 if (clen > MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_CONTEXT_LEN) {
145 /* Should not happen, as above. */
146 return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
147 }
148
149 if (blen > MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_EXPANSION_LEN) {
150 /* Should not happen, as above. */
151 return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
152 }
153
154 md = mbedtls_md_info_from_type(hash_alg);
155 if (md == NULL) {
156 return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
157 }
158
159 ssl_tls1_3_hkdf_encode_label(blen,
160 label, llen,
161 ctx, clen,
162 hkdf_label,
163 &hkdf_label_len);
164
165 return mbedtls_hkdf_expand(md,
166 secret, slen,
167 hkdf_label, hkdf_label_len,
168 buf, blen);
169 }
170
171 /*
172 * The traffic keying material is generated from the following inputs:
173 *
174 * - One secret value per sender.
175 * - A purpose value indicating the specific value being generated
176 * - The desired lengths of key and IV.
177 *
178 * The expansion itself is based on HKDF:
179 *
180 * [sender]_write_key = HKDF-Expand-Label( Secret, "key", "", key_length )
181 * [sender]_write_iv = HKDF-Expand-Label( Secret, "iv" , "", iv_length )
182 *
183 * [sender] denotes the sending side and the Secret value is provided
184 * by the function caller. Note that we generate server and client side
185 * keys in a single function call.
186 */
mbedtls_ssl_tls1_3_make_traffic_keys(mbedtls_md_type_t hash_alg,const unsigned char * client_secret,const unsigned char * server_secret,size_t slen,size_t key_len,size_t iv_len,mbedtls_ssl_key_set * keys)187 int mbedtls_ssl_tls1_3_make_traffic_keys(
188 mbedtls_md_type_t hash_alg,
189 const unsigned char *client_secret,
190 const unsigned char *server_secret,
191 size_t slen, size_t key_len, size_t iv_len,
192 mbedtls_ssl_key_set *keys)
193 {
194 int ret = 0;
195
196 ret = mbedtls_ssl_tls1_3_hkdf_expand_label(hash_alg,
197 client_secret, slen,
198 MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN(key),
199 NULL, 0,
200 keys->client_write_key, key_len);
201 if (ret != 0) {
202 return ret;
203 }
204
205 ret = mbedtls_ssl_tls1_3_hkdf_expand_label(hash_alg,
206 server_secret, slen,
207 MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN(key),
208 NULL, 0,
209 keys->server_write_key, key_len);
210 if (ret != 0) {
211 return ret;
212 }
213
214 ret = mbedtls_ssl_tls1_3_hkdf_expand_label(hash_alg,
215 client_secret, slen,
216 MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN(iv),
217 NULL, 0,
218 keys->client_write_iv, iv_len);
219 if (ret != 0) {
220 return ret;
221 }
222
223 ret = mbedtls_ssl_tls1_3_hkdf_expand_label(hash_alg,
224 server_secret, slen,
225 MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN(iv),
226 NULL, 0,
227 keys->server_write_iv, iv_len);
228 if (ret != 0) {
229 return ret;
230 }
231
232 keys->key_len = key_len;
233 keys->iv_len = iv_len;
234
235 return 0;
236 }
237
mbedtls_ssl_tls1_3_derive_secret(mbedtls_md_type_t hash_alg,const unsigned char * secret,size_t slen,const unsigned char * label,size_t llen,const unsigned char * ctx,size_t clen,int ctx_hashed,unsigned char * dstbuf,size_t buflen)238 int mbedtls_ssl_tls1_3_derive_secret(
239 mbedtls_md_type_t hash_alg,
240 const unsigned char *secret, size_t slen,
241 const unsigned char *label, size_t llen,
242 const unsigned char *ctx, size_t clen,
243 int ctx_hashed,
244 unsigned char *dstbuf, size_t buflen)
245 {
246 int ret;
247 unsigned char hashed_context[MBEDTLS_MD_MAX_SIZE];
248
249 const mbedtls_md_info_t *md;
250 md = mbedtls_md_info_from_type(hash_alg);
251 if (md == NULL) {
252 return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
253 }
254
255 if (ctx_hashed == MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED) {
256 ret = mbedtls_md(md, ctx, clen, hashed_context);
257 if (ret != 0) {
258 return ret;
259 }
260 clen = mbedtls_md_get_size(md);
261 } else {
262 if (clen > sizeof(hashed_context)) {
263 /* This should never happen since this function is internal
264 * and the code sets `ctx_hashed` correctly.
265 * Let's double-check nonetheless to not run at the risk
266 * of getting a stack overflow. */
267 return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
268 }
269
270 memcpy(hashed_context, ctx, clen);
271 }
272
273 return mbedtls_ssl_tls1_3_hkdf_expand_label(hash_alg,
274 secret, slen,
275 label, llen,
276 hashed_context, clen,
277 dstbuf, buflen);
278 }
279
mbedtls_ssl_tls1_3_evolve_secret(mbedtls_md_type_t hash_alg,const unsigned char * secret_old,const unsigned char * input,size_t input_len,unsigned char * secret_new)280 int mbedtls_ssl_tls1_3_evolve_secret(
281 mbedtls_md_type_t hash_alg,
282 const unsigned char *secret_old,
283 const unsigned char *input, size_t input_len,
284 unsigned char *secret_new)
285 {
286 int ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
287 size_t hlen, ilen;
288 unsigned char tmp_secret[PSA_MAC_MAX_SIZE] = { 0 };
289 unsigned char tmp_input[TLS1_3_EVOLVE_INPUT_SIZE] = { 0 };
290
291 const mbedtls_md_info_t *md;
292 md = mbedtls_md_info_from_type(hash_alg);
293 if (md == NULL) {
294 return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
295 }
296
297 hlen = mbedtls_md_get_size(md);
298
299 /* For non-initial runs, call Derive-Secret( ., "derived", "")
300 * on the old secret. */
301 if (secret_old != NULL) {
302 ret = mbedtls_ssl_tls1_3_derive_secret(
303 hash_alg,
304 secret_old, hlen,
305 MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN(derived),
306 NULL, 0, /* context */
307 MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED,
308 tmp_secret, hlen);
309 if (ret != 0) {
310 goto cleanup;
311 }
312 }
313
314 if (input != NULL) {
315 memcpy(tmp_input, input, input_len);
316 ilen = input_len;
317 } else {
318 ilen = hlen;
319 }
320
321 /* HKDF-Extract takes a salt and input key material.
322 * The salt is the old secret, and the input key material
323 * is the input secret (PSK / ECDHE). */
324 ret = mbedtls_hkdf_extract(md,
325 tmp_secret, hlen,
326 tmp_input, ilen,
327 secret_new);
328 if (ret != 0) {
329 goto cleanup;
330 }
331
332 ret = 0;
333
334 cleanup:
335
336 mbedtls_platform_zeroize(tmp_secret, sizeof(tmp_secret));
337 mbedtls_platform_zeroize(tmp_input, sizeof(tmp_input));
338 return ret;
339 }
340
341 #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */
342