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
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>.
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
20 #include <bio/bio_writer.h>
21 #include <crypto/prf_plus.h>
23 typedef struct private_tls_hkdf_t private_tls_hkdf_t
;
25 typedef struct cached_secrets_t
{
30 typedef enum hkdf_phase
{
37 struct private_tls_hkdf_t
{
40 * Public tls_hkdf_t interface.
42 struct tls_hkdf_t
public;
50 * Pseudorandom function used.
60 * (EC)DHE as IKM to switch from phase 1 to phase 2
62 chunk_t shared_secret
;
75 * Handshake traffic secrets.
77 cached_secrets_t handshake_traffic_secrets
;
80 * Current traffic secrets.
82 cached_secrets_t traffic_secrets
;
85 static char *hkdf_labels
[] = {
99 * Step 1: Extract, as defined in RFC 5869, section 2.2:
100 * HKDF-Extract(salt, IKM) -> PRK
102 static bool extract(private_tls_hkdf_t
*this, chunk_t salt
, chunk_t ikm
,
105 if (!this->prf
->set_key(this->prf
, salt
))
107 DBG1(DBG_TLS
, "unable to set PRF secret to salt");
111 if(!this->prf
->allocate_bytes(this->prf
, ikm
, prk
))
113 DBG1(DBG_TLS
, "unable to allocate PRF result");
117 DBG4(DBG_TLS
, "PRK: %B", prk
);
123 * Step 2: Expand as defined in RFC 5869, section 2.3:
124 * HKDF-Expand(PRK, info, L) -> OKM
126 static bool expand(private_tls_hkdf_t
*this, chunk_t prk
, chunk_t info
,
127 size_t length
, chunk_t
*okm
)
129 prf_plus_t
*prf_plus
;
131 if (!this->prf
->set_key(this->prf
, prk
))
133 DBG1(DBG_TLS
, "unable to set PRF secret to PRK");
136 prf_plus
= prf_plus_create(this->prf
, TRUE
, info
);
137 if (!prf_plus
|| !prf_plus
->allocate_bytes(prf_plus
, length
, okm
))
139 DBG1(DBG_TLS
, "unable to allocate PRF+ result");
140 DESTROY_IF(prf_plus
);
143 prf_plus
->destroy(prf_plus
);
145 DBG4(DBG_TLS
, "OKM: %B", okm
);
151 * Expand-Label as defined in RFC 8446, section 7.1:
152 * HKDF-Expand-Label(Secret, Label, Context, Length) -> OKM
154 static bool expand_label(private_tls_hkdf_t
*this, chunk_t secret
,
155 chunk_t label
, chunk_t context
, uint16_t length
,
160 if (!label
.len
|| label
.len
> 249 || context
.len
> 255)
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
);
172 success
= expand(this, secret
, writer
->get_buf(writer
), length
, key
);
173 writer
->destroy(writer
);
178 * Derive-Secret as defined in RFC 8446, section 7.1:
179 * Derive-Secret(Secret, Label, Message) -> OKM
181 static bool derive_secret(private_tls_hkdf_t
*this, chunk_t secret
,
182 chunk_t label
, chunk_t messages
, chunk_t
*okm
)
187 if (!this->hasher
->allocate_hash(this->hasher
, messages
, &context
))
192 success
= expand_label(this, secret
, label
, context
,
193 this->hasher
->get_hash_size(this->hasher
), okm
);
194 chunk_free(&context
);
199 * Move to phase 1 (Early Secret)
204 * PSK -> HKDF-Extract = Early Secret
206 * +-----> Derive-Secret(., "ext binder" | "res binder", "")
209 * +-----> Derive-Secret(., "c e traffic", ClientHello)
210 * | = client_early_traffic_secret
212 * +-----> Derive-Secret(., "e exp master", ClientHello)
213 * | = early_exporter_master_secret
216 static bool move_to_phase_1(private_tls_hkdf_t
*this)
218 chunk_t salt_zero
, psk
= this->psk
;
223 salt_zero
= chunk_alloca(this->hasher
->get_hash_size(this->hasher
));
224 chunk_copy_pad(salt_zero
, chunk_empty
, 0);
229 if (!extract(this, salt_zero
, psk
, &this->prk
))
231 DBG1(DBG_TLS
, "unable to extract PRK");
234 this->phase
= HKDF_PHASE_1
;
239 DBG1(DBG_TLS
, "invalid HKDF phase");
245 * Move to phase 2 (Handshake Secret)
247 * Derive-Secret(., "derived", "")
250 * (EC)DHE -> HKDF-Extract = Handshake Secret
252 * +-----> Derive-Secret(., "c hs traffic",
253 * | ClientHello...ServerHello)
254 * | = client_handshake_traffic_secret
256 * +-----> Derive-Secret(., "s hs traffic",
257 * | ClientHello...ServerHello)
258 * | = server_handshake_traffic_secret
261 static bool move_to_phase_2(private_tls_hkdf_t
*this)
268 if (!move_to_phase_1(this))
270 DBG1(DBG_TLS
, "unable to move to phase 1");
275 if (!derive_secret(this, this->prk
, chunk_from_str("derived"),
278 DBG1(DBG_TLS
, "unable to derive secret");
282 if (!this->shared_secret
.ptr
)
284 DBG1(DBG_TLS
, "no shared secret set");
289 if (!extract(this, okm
, this->shared_secret
, &this->prk
))
291 DBG1(DBG_TLS
, "unable extract PRK");
296 this->phase
= HKDF_PHASE_2
;
301 DBG1(DBG_TLS
, "invalid HKDF phase");
307 * Move to phase 3 (Master Secret)
309 * Derive-Secret(., "derived", "")
312 * 0 -> HKDF-Extract = Master Secret
314 * +-----> Derive-Secret(., "c ap traffic",
315 * | ClientHello...server Finished)
316 * | = client_application_traffic_secret_0
318 * +-----> Derive-Secret(., "s ap traffic",
319 * | ClientHello...server Finished)
320 * | = server_application_traffic_secret_0
322 * +-----> Derive-Secret(., "exp master",
323 * | ClientHello...server Finished)
324 * | = exporter_master_secret
326 * +-----> Derive-Secret(., "res master",
327 * ClientHello...client Finished)
328 * = resumption_master_secret
330 static bool move_to_phase_3(private_tls_hkdf_t
*this)
332 chunk_t okm
, ikm_zero
;
338 if (!move_to_phase_2(this))
340 DBG1(DBG_TLS
, "unable to move to phase 2");
345 /* prepare okm for next extract */
346 if (!derive_secret(this, this->prk
, chunk_from_str("derived"),
349 DBG1(DBG_TLS
, "unable to derive secret");
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
))
357 DBG1(DBG_TLS
, "unable extract PRK");
362 this->phase
= HKDF_PHASE_3
;
367 DBG1(DBG_TLS
, "invalid HKDF phase");
372 METHOD(tls_hkdf_t
, set_shared_secret
, void,
373 private_tls_hkdf_t
*this, chunk_t shared_secret
)
375 this->shared_secret
= chunk_clone(shared_secret
);
378 METHOD(tls_hkdf_t
, generate_secret
, bool,
379 private_tls_hkdf_t
*this, tls_hkdf_label_t label
, chunk_t messages
,
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))
392 DBG1(DBG_TLS
, "unable to move to phase 1");
396 case TLS_HKDF_C_HS_TRAFFIC
:
397 case TLS_HKDF_S_HS_TRAFFIC
:
398 if (!move_to_phase_2(this))
400 DBG1(DBG_TLS
, "unable to move to phase 2");
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))
410 DBG1(DBG_TLS
, "unable to move to phase 3");
414 case TLS_HKDF_UPD_C_TRAFFIC
:
415 case TLS_HKDF_UPD_S_TRAFFIC
:
416 if (this->phase
!= HKDF_PHASE_3
)
418 DBG1(DBG_TLS
, "unable to update traffic keys");
423 DBG1(DBG_TLS
, "invalid HKDF label");
427 if (label
== TLS_HKDF_UPD_C_TRAFFIC
|| label
== TLS_HKDF_UPD_S_TRAFFIC
)
429 chunk_t previous
= this->traffic_secrets
.client
;
431 if (label
== TLS_HKDF_UPD_S_TRAFFIC
)
433 previous
= this->traffic_secrets
.server
;
436 if (!expand_label(this, previous
, chunk_from_str("traffic upd"),
437 chunk_empty
, this->hasher
->get_hash_size(this->hasher
),
440 DBG1(DBG_TLS
, "unable to update secret");
446 if (!derive_secret(this, this->prk
, chunk_from_str(hkdf_labels
[label
]),
449 DBG1(DBG_TLS
, "unable to derive secret");
456 case TLS_HKDF_C_HS_TRAFFIC
:
457 chunk_clear(&this->handshake_traffic_secrets
.client
);
458 this->handshake_traffic_secrets
.client
= chunk_clone(okm
);
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
);
465 case TLS_HKDF_S_HS_TRAFFIC
:
466 chunk_clear(&this->handshake_traffic_secrets
.server
);
467 this->handshake_traffic_secrets
.server
= chunk_clone(okm
);
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
);
490 * Derive keys/IVs from the current traffic secrets.
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
)
496 chunk_t result
= chunk_empty
, secret
;
498 secret
= server ? secrets
->server
: secrets
->client
;
500 if (!expand_label(this, secret
, label
, chunk_empty
, length
, &result
))
502 DBG1(DBG_TLS
, "unable to derive labeled secret");
503 chunk_clear(&result
);
513 chunk_clear(&result
);
518 METHOD(tls_hkdf_t
, derive_key
, bool,
519 private_tls_hkdf_t
*this, bool is_server
, size_t length
, chunk_t
*key
)
521 return get_shared_label_keys(this, chunk_from_str("key"),
522 &this->traffic_secrets
, is_server
, length
, key
);
525 METHOD(tls_hkdf_t
, derive_iv
, bool,
526 private_tls_hkdf_t
*this, bool is_server
, size_t length
, chunk_t
*iv
)
528 return get_shared_label_keys(this, chunk_from_str("iv"),
529 &this->traffic_secrets
, is_server
, length
, iv
);
532 METHOD(tls_hkdf_t
, derive_finished
, bool,
533 private_tls_hkdf_t
*this, bool server
, chunk_t
*finished
)
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
),
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
)
545 chunk_t exporter_master
, exporter
, hash
= chunk_empty
;
547 if (this->phase
!= HKDF_PHASE_3
)
549 DBG1(DBG_TLS
, "unable to export key material");
554 * Export key material according to RFC 8446, section 7.5:
556 * TLS-Exporter(label, context_value, key_length) =
557 * HKDF-Expand-Label(Derive-Secret(Secret, label, ""),
558 * "exporter", Hash(context_value), key_length)
560 if (!generate_secret(this, TLS_HKDF_EXP_MASTER
, messages
, &exporter_master
))
562 DBG1(DBG_TLS
, "unable to derive exporter master secret");
566 if (!derive_secret(this, exporter_master
, chunk_from_str(label
),
567 chunk_empty
, &exporter
))
569 DBG1(DBG_TLS
, "unable to derive exporter secret");
570 chunk_clear(&exporter_master
);
573 chunk_clear(&exporter_master
);
575 if (!this->hasher
->allocate_hash(this->hasher
, context
, &hash
) ||
576 !expand_label(this, exporter
, chunk_from_str("exporter"), hash
,
579 DBG1(DBG_TLS
, "unable to expand key material");
580 chunk_clear(&exporter
);
584 chunk_clear(&exporter
);
589 METHOD(tls_hkdf_t
, allocate_bytes
, bool,
590 private_tls_hkdf_t
*this, chunk_t key
, chunk_t seed
,
593 return this->prf
->set_key(this->prf
, key
) &&
594 this->prf
->allocate_bytes(this->prf
, seed
, out
);
600 static void destroy_secrets(cached_secrets_t
*secrets
)
602 chunk_clear(&secrets
->client
);
603 chunk_clear(&secrets
->server
);
606 METHOD(tls_hkdf_t
, destroy
, void,
607 private_tls_hkdf_t
*this)
609 chunk_clear(&this->psk
);
610 chunk_clear(&this->prk
);
611 chunk_clear(&this->shared_secret
);
612 destroy_secrets(&this->handshake_traffic_secrets
);
613 destroy_secrets(&this->traffic_secrets
);
614 DESTROY_IF(this->prf
);
615 DESTROY_IF(this->hasher
);
619 tls_hkdf_t
*tls_hkdf_create(hash_algorithm_t hash_algorithm
, chunk_t psk
)
621 private_tls_hkdf_t
*this;
622 pseudo_random_function_t prf_algorithm
;
624 switch (hash_algorithm
)
627 prf_algorithm
= PRF_HMAC_SHA2_256
;
630 prf_algorithm
= PRF_HMAC_SHA2_384
;
633 DBG1(DBG_TLS
, "unsupported hash algorithm %N", hash_algorithm_names
,
640 .set_shared_secret
= _set_shared_secret
,
641 .generate_secret
= _generate_secret
,
642 .derive_key
= _derive_key
,
643 .derive_iv
= _derive_iv
,
644 .derive_finished
= _derive_finished
,
646 .allocate_bytes
= _allocate_bytes
,
649 .phase
= HKDF_PHASE_0
,
650 .psk
= psk
.ptr ?
chunk_clone(psk
) : chunk_empty
,
651 .prf
= lib
->crypto
->create_prf(lib
->crypto
, prf_algorithm
),
652 .hasher
= lib
->crypto
->create_hasher(lib
->crypto
, hash_algorithm
),
655 if (!this->prf
|| !this->hasher
)
659 DBG1(DBG_TLS
, "%N not supported", pseudo_random_function_names
,
664 DBG1(DBG_TLS
, "%N not supported", hash_algorithm_names
,
667 DBG1(DBG_TLS
, "unable to initialise HKDF");
671 return &this->public;