Annotation of embedaddon/strongswan/src/libtls/tls_hkdf.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2020 Tobias Brunner
3: * Copyright (C) 2020 Pascal Knecht
4: * Copyright (C) 2020 Méline Sieber
5: * HSR Hochschule fuer Technik Rapperswil
6: *
7: * This program is free software; you can redistribute it and/or modify it
8: * under the terms of the GNU General Public License as published by the
9: * Free Software Foundation; either version 2 of the License, or (at your
10: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11: *
12: * This program is distributed in the hope that it will be useful, but
13: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15: * for more details.
16: */
17:
18: #include "tls_hkdf.h"
19:
20: #include <bio/bio_writer.h>
21: #include <crypto/prf_plus.h>
22:
23: typedef struct private_tls_hkdf_t private_tls_hkdf_t;
24:
25: typedef struct cached_secrets_t {
26: chunk_t client;
27: chunk_t server;
28: } cached_secrets_t;
29:
30: typedef enum hkdf_phase {
31: HKDF_PHASE_0,
32: HKDF_PHASE_1,
33: HKDF_PHASE_2,
34: HKDF_PHASE_3,
35: } hkdf_phase;
36:
37: struct private_tls_hkdf_t {
38:
39: /**
40: * Public tls_hkdf_t interface.
41: */
42: struct tls_hkdf_t public;
43:
44: /**
45: * Phase we are in.
46: */
47: hkdf_phase phase;
48:
49: /**
50: * Pseudorandom function used.
51: */
52: prf_t *prf;
53:
54: /**
55: * Hasher used.
56: */
57: hasher_t *hasher;
58:
59: /**
60: * (EC)DHE as IKM to switch from phase 1 to phase 2
61: */
62: chunk_t shared_secret;
63:
64: /**
65: * PSK used.
66: */
67: chunk_t psk;
68:
69: /**
70: * PRK used.
71: */
72: chunk_t prk;
73:
74: /**
75: * Handshake traffic secrets.
76: */
77: cached_secrets_t handshake_traffic_secrets;
78:
79: /**
80: * Current traffic secrets.
81: */
82: cached_secrets_t traffic_secrets;
83: };
84:
85: static char *hkdf_labels[] = {
86: "ext binder",
87: "res binder",
88: "c e traffic",
89: "e exp master",
90: "c hs traffic",
91: "s hs traffic",
92: "c ap traffic",
93: "s ap traffic",
94: "exp master",
95: "res master",
96: };
97:
98: /**
99: * Step 1: Extract, as defined in RFC 5869, section 2.2:
100: * HKDF-Extract(salt, IKM) -> PRK
101: */
102: static bool extract(private_tls_hkdf_t *this, chunk_t salt, chunk_t ikm,
103: chunk_t *prk)
104: {
105: if (!this->prf->set_key(this->prf, salt))
106: {
107: DBG1(DBG_TLS, "unable to set PRF secret to salt");
108: return FALSE;
109: }
110: chunk_clear(prk);
111: if(!this->prf->allocate_bytes(this->prf, ikm, prk))
112: {
113: DBG1(DBG_TLS, "unable to allocate PRF result");
114: return FALSE;
115: }
116:
117: DBG4(DBG_TLS, "PRK: %B", prk);
118:
119: return TRUE;
120: }
121:
122: /**
123: * Step 2: Expand as defined in RFC 5869, section 2.3:
124: * HKDF-Expand(PRK, info, L) -> OKM
125: */
126: static bool expand(private_tls_hkdf_t *this, chunk_t prk, chunk_t info,
127: size_t length, chunk_t *okm)
128: {
129: prf_plus_t *prf_plus;
130:
131: if (!this->prf->set_key(this->prf, prk))
132: {
133: DBG1(DBG_TLS, "unable to set PRF secret to PRK");
134: return FALSE;
135: }
136: prf_plus = prf_plus_create(this->prf, TRUE, info);
137: if (!prf_plus || !prf_plus->allocate_bytes(prf_plus, length, okm))
138: {
139: DBG1(DBG_TLS, "unable to allocate PRF+ result");
140: DESTROY_IF(prf_plus);
141: return FALSE;
142: }
143: prf_plus->destroy(prf_plus);
144:
145: DBG4(DBG_TLS, "OKM: %B", okm);
146:
147: return TRUE;
148: }
149:
150: /**
151: * Expand-Label as defined in RFC 8446, section 7.1:
152: * HKDF-Expand-Label(Secret, Label, Context, Length) -> OKM
153: */
154: static bool expand_label(private_tls_hkdf_t *this, chunk_t secret,
155: chunk_t label, chunk_t context, uint16_t length,
156: chunk_t *key)
157: {
158: bool success;
159:
160: if (!label.len || label.len > 249 || context.len > 255)
161: {
162: return FALSE;
163: }
164:
165: /* HKDFLabel as defined in RFC 8446, section 7.1 */
166: bio_writer_t *writer = bio_writer_create(0);
167: writer->write_uint16(writer, length);
168: label = chunk_cata("cc", chunk_from_str("tls13 "), label);
169: writer->write_data8(writer, label);
170: writer->write_data8(writer, context);
171:
172: success = expand(this, secret, writer->get_buf(writer), length, key);
173: writer->destroy(writer);
174: return success;
175: }
176:
177: /**
178: * Derive-Secret as defined in RFC 8446, section 7.1:
179: * Derive-Secret(Secret, Label, Message) -> OKM
180: */
181: static bool derive_secret(private_tls_hkdf_t *this, chunk_t secret,
182: chunk_t label, chunk_t messages, chunk_t *okm)
183: {
184: chunk_t context;
185: bool success;
186:
187: if (!this->hasher->allocate_hash(this->hasher, messages, &context))
188: {
189: return FALSE;
190: }
191:
192: success = expand_label(this, secret, label, context,
193: this->hasher->get_hash_size(this->hasher), okm);
194: chunk_free(&context);
195: return success;
196: }
197:
198: /**
199: * Move to phase 1 (Early Secret)
200: *
201: * 0
202: * |
203: * v
204: * PSK -> HKDF-Extract = Early Secret
205: * |
206: * +-----> Derive-Secret(., "ext binder" | "res binder", "")
207: * | = binder_key
208: * |
209: * +-----> Derive-Secret(., "c e traffic", ClientHello)
210: * | = client_early_traffic_secret
211: * |
212: * +-----> Derive-Secret(., "e exp master", ClientHello)
213: * | = early_exporter_master_secret
214: * v
215: */
216: static bool move_to_phase_1(private_tls_hkdf_t *this)
217: {
218: chunk_t salt_zero, psk = this->psk;
219:
220: switch (this->phase)
221: {
222: case HKDF_PHASE_0:
223: salt_zero = chunk_alloca(this->hasher->get_hash_size(this->hasher));
224: chunk_copy_pad(salt_zero, chunk_empty, 0);
225: if (!psk.ptr)
226: {
227: psk = salt_zero;
228: }
229: if (!extract(this, salt_zero, psk, &this->prk))
230: {
231: DBG1(DBG_TLS, "unable to extract PRK");
232: return FALSE;
233: }
234: this->phase = HKDF_PHASE_1;
235: return TRUE;
236: case HKDF_PHASE_1:
237: return TRUE;
238: default:
239: DBG1(DBG_TLS, "invalid HKDF phase");
240: return FALSE;
241: }
242: }
243:
244: /**
245: * Move to phase 2 (Handshake Secret)
246: *
247: * Derive-Secret(., "derived", "")
248: * |
249: * v
250: * (EC)DHE -> HKDF-Extract = Handshake Secret
251: * |
252: * +-----> Derive-Secret(., "c hs traffic",
253: * | ClientHello...ServerHello)
254: * | = client_handshake_traffic_secret
255: * |
256: * +-----> Derive-Secret(., "s hs traffic",
257: * | ClientHello...ServerHello)
258: * | = server_handshake_traffic_secret
259: * v
260: */
261: static bool move_to_phase_2(private_tls_hkdf_t *this)
262: {
263: chunk_t okm;
264:
265: switch (this->phase)
266: {
267: case HKDF_PHASE_0:
268: if (!move_to_phase_1(this))
269: {
270: DBG1(DBG_TLS, "unable to move to phase 1");
271: return FALSE;
272: }
273: /* fall-through */
274: case HKDF_PHASE_1:
275: if (!derive_secret(this, this->prk, chunk_from_str("derived"),
276: chunk_empty, &okm))
277: {
278: DBG1(DBG_TLS, "unable to derive secret");
279: return FALSE;
280: }
281:
282: if (!this->shared_secret.ptr)
283: {
284: DBG1(DBG_TLS, "no shared secret set");
285: chunk_clear(&okm);
286: return FALSE;
287: }
288:
289: if (!extract(this, okm, this->shared_secret, &this->prk))
290: {
291: DBG1(DBG_TLS, "unable extract PRK");
292: chunk_clear(&okm);
293: return FALSE;
294: }
295: chunk_clear(&okm);
296: this->phase = HKDF_PHASE_2;
297: return TRUE;
298: case HKDF_PHASE_2:
299: return TRUE;
300: default:
301: DBG1(DBG_TLS, "invalid HKDF phase");
302: return FALSE;
303: }
304: }
305:
306: /**
307: * Move to phase 3 (Master Secret)
308: *
309: * Derive-Secret(., "derived", "")
310: * |
311: * v
312: * 0 -> HKDF-Extract = Master Secret
313: * |
314: * +-----> Derive-Secret(., "c ap traffic",
315: * | ClientHello...server Finished)
316: * | = client_application_traffic_secret_0
317: * |
318: * +-----> Derive-Secret(., "s ap traffic",
319: * | ClientHello...server Finished)
320: * | = server_application_traffic_secret_0
321: * |
322: * +-----> Derive-Secret(., "exp master",
323: * | ClientHello...server Finished)
324: * | = exporter_master_secret
325: * |
326: * +-----> Derive-Secret(., "res master",
327: * ClientHello...client Finished)
328: * = resumption_master_secret
329: */
330: static bool move_to_phase_3(private_tls_hkdf_t *this)
331: {
332: chunk_t okm, ikm_zero;
333:
334: switch (this->phase)
335: {
336: case HKDF_PHASE_0:
337: case HKDF_PHASE_1:
338: if (!move_to_phase_2(this))
339: {
340: DBG1(DBG_TLS, "unable to move to phase 2");
341: return FALSE;
342: }
343: /* fall-through */
344: case HKDF_PHASE_2:
345: /* prepare okm for next extract */
346: if (!derive_secret(this, this->prk, chunk_from_str("derived"),
347: chunk_empty, &okm))
348: {
349: DBG1(DBG_TLS, "unable to derive secret");
350: return FALSE;
351: }
352:
353: ikm_zero = chunk_alloca(this->hasher->get_hash_size(this->hasher));
354: chunk_copy_pad(ikm_zero, chunk_empty, 0);
355: if (!extract(this, okm, ikm_zero, &this->prk))
356: {
357: DBG1(DBG_TLS, "unable extract PRK");
358: chunk_clear(&okm);
359: return FALSE;
360: }
361: chunk_clear(&okm);
362: this->phase = HKDF_PHASE_3;
363: return TRUE;
364: case HKDF_PHASE_3:
365: return TRUE;
366: default:
367: DBG1(DBG_TLS, "invalid HKDF phase");
368: return FALSE;
369: }
370: }
371:
372: METHOD(tls_hkdf_t, set_shared_secret, void,
373: private_tls_hkdf_t *this, chunk_t shared_secret)
374: {
375: this->shared_secret = chunk_clone(shared_secret);
376: }
377:
378: METHOD(tls_hkdf_t, generate_secret, bool,
379: private_tls_hkdf_t *this, tls_hkdf_label_t label, chunk_t messages,
380: chunk_t *secret)
381: {
382: chunk_t okm;
383:
384: switch (label)
385: {
386: case TLS_HKDF_EXT_BINDER:
387: case TLS_HKDF_RES_BINDER:
388: case TLS_HKDF_C_E_TRAFFIC:
389: case TLS_HKDF_E_EXP_MASTER:
390: if (!move_to_phase_1(this))
391: {
392: DBG1(DBG_TLS, "unable to move to phase 1");
393: return FALSE;
394: }
395: break;
396: case TLS_HKDF_C_HS_TRAFFIC:
397: case TLS_HKDF_S_HS_TRAFFIC:
398: if (!move_to_phase_2(this))
399: {
400: DBG1(DBG_TLS, "unable to move to phase 2");
401: return FALSE;
402: }
403: break;
404: case TLS_HKDF_C_AP_TRAFFIC:
405: case TLS_HKDF_S_AP_TRAFFIC:
406: case TLS_HKDF_EXP_MASTER:
407: case TLS_HKDF_RES_MASTER:
408: if (!move_to_phase_3(this))
409: {
410: DBG1(DBG_TLS, "unable to move to phase 3");
411: return FALSE;
412: }
413: break;
414: case TLS_HKDF_UPD_C_TRAFFIC:
415: case TLS_HKDF_UPD_S_TRAFFIC:
416: if (this->phase != HKDF_PHASE_3)
417: {
418: DBG1(DBG_TLS, "unable to update traffic keys");
419: return FALSE;
420: }
421: break;
422: default:
423: DBG1(DBG_TLS, "invalid HKDF label");
424: return FALSE;
425: }
426:
427: if (label == TLS_HKDF_UPD_C_TRAFFIC || label == TLS_HKDF_UPD_S_TRAFFIC)
428: {
429: chunk_t previous = this->traffic_secrets.client;
430:
431: if (label == TLS_HKDF_UPD_S_TRAFFIC)
432: {
433: previous = this->traffic_secrets.server;
434: }
435:
436: if (!expand_label(this, previous, chunk_from_str("traffic upd"),
437: chunk_empty, this->hasher->get_hash_size(this->hasher),
438: &okm))
439: {
440: DBG1(DBG_TLS, "unable to update secret");
441: return FALSE;
442: }
443: }
444: else
445: {
446: if (!derive_secret(this, this->prk, chunk_from_str(hkdf_labels[label]),
447: messages, &okm))
448: {
449: DBG1(DBG_TLS, "unable to derive secret");
450: return FALSE;
451: }
452: }
453:
454: switch (label)
455: {
456: case TLS_HKDF_C_HS_TRAFFIC:
457: chunk_clear(&this->handshake_traffic_secrets.client);
458: this->handshake_traffic_secrets.client = chunk_clone(okm);
459: /* fall-through */
460: case TLS_HKDF_C_AP_TRAFFIC:
461: case TLS_HKDF_UPD_C_TRAFFIC:
462: chunk_clear(&this->traffic_secrets.client);
463: this->traffic_secrets.client = chunk_clone(okm);
464: break;
465: case TLS_HKDF_S_HS_TRAFFIC:
466: chunk_clear(&this->handshake_traffic_secrets.server);
467: this->handshake_traffic_secrets.server = chunk_clone(okm);
468: /* fall-through */
469: case TLS_HKDF_S_AP_TRAFFIC:
470: case TLS_HKDF_UPD_S_TRAFFIC:
471: chunk_clear(&this->traffic_secrets.server);
472: this->traffic_secrets.server = chunk_clone(okm);
473: break;
474: default:
475: break;
476: }
477:
478: if (secret)
479: {
480: *secret = okm;
481: }
482: else
483: {
484: chunk_clear(&okm);
485: }
486: return TRUE;
487: }
488:
489: /**
490: * Derive keys/IVs from the current traffic secrets.
491: */
492: static bool get_shared_label_keys(private_tls_hkdf_t *this, chunk_t label,
493: cached_secrets_t *secrets,
494: bool server, size_t length, chunk_t *key)
495: {
496: chunk_t result = chunk_empty, secret;
497:
498: secret = server ? secrets->server : secrets->client;
499:
500: if (!expand_label(this, secret, label, chunk_empty, length, &result))
501: {
502: DBG1(DBG_TLS, "unable to derive labeled secret");
503: chunk_clear(&result);
504: return FALSE;
505: }
506:
507: if (key)
508: {
509: *key = result;
510: }
511: else
512: {
513: chunk_clear(&result);
514: }
515: return TRUE;
516: }
517:
518: METHOD(tls_hkdf_t, derive_key, bool,
519: private_tls_hkdf_t *this, bool is_server, size_t length, chunk_t *key)
520: {
521: return get_shared_label_keys(this, chunk_from_str("key"),
522: &this->traffic_secrets, is_server, length, key);
523: }
524:
525: METHOD(tls_hkdf_t, derive_iv, bool,
526: private_tls_hkdf_t *this, bool is_server, size_t length, chunk_t *iv)
527: {
528: return get_shared_label_keys(this, chunk_from_str("iv"),
529: &this->traffic_secrets, is_server, length, iv);
530: }
531:
532: METHOD(tls_hkdf_t, derive_finished, bool,
533: private_tls_hkdf_t *this, bool server, chunk_t *finished)
534: {
535: return get_shared_label_keys(this, chunk_from_str("finished"),
536: &this->handshake_traffic_secrets, server,
537: this->hasher->get_hash_size(this->hasher),
538: finished);
539: }
540:
541: METHOD(tls_hkdf_t, export, bool,
542: private_tls_hkdf_t *this, char *label, chunk_t context,
543: chunk_t messages, size_t length, chunk_t *key)
544: {
545: chunk_t exporter_master, exporter, hash = chunk_empty;
546:
547: if (this->phase != HKDF_PHASE_3)
548: {
549: DBG1(DBG_TLS, "unable to export key material");
550: return FALSE;
551: }
552:
553: /**
554: * Export key material according to RFC 8446, section 7.5:
555: *
556: * TLS-Exporter(label, context_value, key_length) =
557: * HKDF-Expand-Label(Derive-Secret(Secret, label, ""),
558: * "exporter", Hash(context_value), key_length)
559: */
560: if (!generate_secret(this, TLS_HKDF_EXP_MASTER, messages, &exporter_master))
561: {
562: DBG1(DBG_TLS, "unable to derive exporter master secret");
563: return FALSE;
564: }
565:
566: if (!derive_secret(this, exporter_master, chunk_from_str(label),
567: chunk_empty, &exporter))
568: {
569: DBG1(DBG_TLS, "unable to derive exporter secret");
570: chunk_clear(&exporter_master);
571: return FALSE;
572: }
573: chunk_clear(&exporter_master);
574:
575: if (!this->hasher->allocate_hash(this->hasher, context, &hash) ||
576: !expand_label(this, exporter, chunk_from_str("exporter"), hash,
577: length, key))
578: {
579: DBG1(DBG_TLS, "unable to expand key material");
580: chunk_clear(&exporter);
581: chunk_free(&hash);
582: return FALSE;
583: }
584: chunk_clear(&exporter);
585: chunk_free(&hash);
586: return TRUE;
587: }
588:
589: METHOD(tls_hkdf_t, resume, bool,
590: private_tls_hkdf_t *this, chunk_t messages, chunk_t nonce, chunk_t *key)
591: {
592: chunk_t resumption_master;
593:
594: if (this->phase != HKDF_PHASE_3)
595: {
596: DBG1(DBG_TLS, "unable to generate resumption key material");
597: return FALSE;
598: }
599: if (!nonce.len)
600: {
601: DBG1(DBG_TLS, "no nonce provided");
602: return FALSE;
603: }
604:
605: /**
606: * PSK associated with the ticket according to RFC 8446, section 4.6.1
607: *
608: * HKDF-Expand-Label(resumption_master_secret,
609: * "resumption", ticket_nonce, Hash.length)
610: */
611: if (!generate_secret(this, TLS_HKDF_RES_MASTER, messages,
612: &resumption_master))
613: {
614: DBG1(DBG_TLS, "unable to derive resumption master secret");
615: return FALSE;
616: }
617:
618: if (!expand_label(this, resumption_master, chunk_from_str("resumption"),
619: nonce, this->hasher->get_hash_size(this->hasher), key))
620: {
621: chunk_clear(&resumption_master);
622: DBG1(DBG_TLS, "unable to expand key material");
623: return FALSE;
624: }
625: chunk_clear(&resumption_master);
626: return TRUE;
627: }
628:
629: METHOD(tls_hkdf_t, binder, bool,
630: private_tls_hkdf_t *this, chunk_t seed, chunk_t *out)
631: {
632: chunk_t binder_key, finished_key;
633:
634: if (!generate_secret(this, TLS_HKDF_RES_BINDER, chunk_empty, &binder_key))
635: {
636: DBG1(DBG_TLS, "unable to derive binder key");
637: return FALSE;
638: }
639:
640: if (!expand_label(this, binder_key, chunk_from_str("finished"), chunk_empty,
641: this->hasher->get_hash_size(this->hasher), &finished_key))
642: {
643: chunk_clear(&binder_key);
644: return FALSE;
645: }
646: chunk_clear(&binder_key);
647:
648: if (!this->prf->set_key(this->prf, finished_key) ||
649: !this->prf->allocate_bytes(this->prf, seed, out))
650: {
651: chunk_clear(&finished_key);
652: return FALSE;
653: }
654: chunk_clear(&finished_key);
655: return TRUE;
656: }
657:
658: METHOD(tls_hkdf_t, allocate_bytes, bool,
659: private_tls_hkdf_t *this, chunk_t key, chunk_t seed,
660: chunk_t *out)
661: {
662: return this->prf->set_key(this->prf, key) &&
663: this->prf->allocate_bytes(this->prf, seed, out);
664: }
665:
666: /**
667: * Clean up secrets
668: */
669: static void destroy_secrets(cached_secrets_t *secrets)
670: {
671: chunk_clear(&secrets->client);
672: chunk_clear(&secrets->server);
673: }
674:
675: METHOD(tls_hkdf_t, destroy, void,
676: private_tls_hkdf_t *this)
677: {
678: chunk_clear(&this->psk);
679: chunk_clear(&this->prk);
680: chunk_clear(&this->shared_secret);
681: destroy_secrets(&this->handshake_traffic_secrets);
682: destroy_secrets(&this->traffic_secrets);
683: DESTROY_IF(this->prf);
684: DESTROY_IF(this->hasher);
685: free(this);
686: }
687:
688: tls_hkdf_t *tls_hkdf_create(hash_algorithm_t hash_algorithm, chunk_t psk)
689: {
690: private_tls_hkdf_t *this;
691: pseudo_random_function_t prf_algorithm;
692:
693: switch (hash_algorithm)
694: {
695: case HASH_SHA256:
696: prf_algorithm = PRF_HMAC_SHA2_256;
697: break;
698: case HASH_SHA384:
699: prf_algorithm = PRF_HMAC_SHA2_384;
700: break;
701: default:
702: DBG1(DBG_TLS, "unsupported hash algorithm %N", hash_algorithm_names,
703: hash_algorithm);
704: return NULL;
705: }
706:
707: INIT(this,
708: .public = {
709: .set_shared_secret = _set_shared_secret,
710: .generate_secret = _generate_secret,
711: .derive_key = _derive_key,
712: .derive_iv = _derive_iv,
713: .derive_finished = _derive_finished,
714: .export = _export,
715: .resume = _resume,
716: .binder = _binder,
717: .allocate_bytes = _allocate_bytes,
718: .destroy = _destroy,
719: },
720: .phase = HKDF_PHASE_0,
721: .psk = psk.ptr ? chunk_clone(psk) : chunk_empty,
722: .prf = lib->crypto->create_prf(lib->crypto, prf_algorithm),
723: .hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm),
724: );
725:
726: if (!this->prf || !this->hasher)
727: {
728: if (!this->prf)
729: {
730: DBG1(DBG_TLS, "%N not supported", pseudo_random_function_names,
731: prf_algorithm);
732: }
733: if (!this->hasher)
734: {
735: DBG1(DBG_TLS, "%N not supported", hash_algorithm_names,
736: hash_algorithm);
737: }
738: DBG1(DBG_TLS, "unable to initialise HKDF");
739: destroy(this);
740: return NULL;
741: }
742: return &this->public;
743: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>