From b5838d7080ee5a864c0b87c3930367662f6e3532 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Fri, 24 Nov 2017 11:07:20 +0100 Subject: gnutls_prf_rfc5705: calculate exporter using HKDF if TLS 1.3 Signed-off-by: Daiki Ueno --- lib/prf.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 18 deletions(-) (limited to 'lib/prf.c') diff --git a/lib/prf.c b/lib/prf.c index 7ac1090d92..b5dd8888fa 100644 --- a/lib/prf.c +++ b/lib/prf.c @@ -27,10 +27,13 @@ #include "gnutls_int.h" #include "errors.h" +#include "secrets.h" #include #include #include +#define EXPORTER_LABEL "exporter" + /** * gnutls_prf_raw: * @session: is a #gnutls_session_t type. @@ -44,6 +47,10 @@ * Apply the TLS Pseudo-Random-Function (PRF) on the master secret * and the provided data. * + * This function only works with the TLS versions prior to 1.3. In + * TLS 1.3, the use of PRF is replaced with HKDF (HMAC-based Key + * Derivation Function) based on the multi-stage key scheduling. + * * The @label variable usually contains a string denoting the purpose * for the generated data. The @seed usually contains data such as the * client and server random, perhaps together with some additional @@ -88,15 +95,18 @@ gnutls_prf_raw(gnutls_session_t session, * @outsize: size of pre-allocated output buffer to hold the output. * @out: pre-allocated buffer to hold the generated data. * - * Applies the TLS Pseudo-Random-Function (PRF) on the master secret - * and the provided data, seeded with the client and server random fields, + * Exports keyring material from TLS/DTLS session to an application, * as specified in RFC5705. * + * In the TLS versions prior to 1.3, it applies the TLS + * Pseudo-Random-Function (PRF) on the master secret and the provided + * data, seeded with the client and server random fields. + * + * In TLS 1.3, it applies HKDF on the exporter master secret derived + * from the master secret. + * * The @label variable usually contains a string denoting the purpose - * for the generated data. The @server_random_first indicates whether - * the client random field or the server random field should be first - * in the seed. Non-zero indicates that the server random field is first, - * 0 that the client random field is first. + * for the generated data. * * The @context variable can be used to add more data to the seed, after * the random variables. It can be used to make sure the @@ -118,7 +128,7 @@ gnutls_prf_rfc5705(gnutls_session_t session, size_t context_size, const char *context, size_t outsize, char *out) { - char *pctx = NULL; + const version_entry_st *vers = get_version(session); int ret; if (context != NULL && context_size > 65535) { @@ -126,22 +136,52 @@ gnutls_prf_rfc5705(gnutls_session_t session, return GNUTLS_E_INVALID_REQUEST; } - if (context != NULL) { - pctx = gnutls_malloc(context_size+2); - if (!pctx) { + if (vers && vers->tls13_sem) { + uint8_t secret[MAX_HASH_SIZE]; + uint8_t digest[MAX_HASH_SIZE]; + unsigned digest_size = session->security_parameters.prf->output_size; + + /* exporter_master_secret might not be set, when + * handshake is in progress */ + if (session->internals.handshake_in_progress) { gnutls_assert(); - return GNUTLS_E_MEMORY_ERROR; + return GNUTLS_E_INVALID_REQUEST; } - memcpy(pctx+2, context, context_size); - _gnutls_write_uint16(context_size, (void*)pctx); - context_size += 2; - } + ret = _tls13_derive_secret(session, label, label_size, NULL, 0, + session->key.ap_expkey, secret); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = gnutls_hash_fast((gnutls_digest_algorithm_t)session->security_parameters.prf->id, + context, context_size, digest); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = _tls13_expand_secret(session, EXPORTER_LABEL, sizeof(EXPORTER_LABEL)-1, + digest, digest_size, + secret, outsize, out); + } else { + char *pctx = NULL; - ret = gnutls_prf(session, label_size, label, 0, - context_size, pctx, outsize, out); + if (context != NULL) { + pctx = gnutls_malloc(context_size+2); + if (!pctx) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + memcpy(pctx+2, context, context_size); + _gnutls_write_uint16(context_size, (void*)pctx); + context_size += 2; + } + + ret = gnutls_prf(session, label_size, label, 0, + context_size, pctx, outsize, out); + + gnutls_free(pctx); + } - gnutls_free(pctx); return ret; } @@ -160,6 +200,10 @@ gnutls_prf_rfc5705(gnutls_session_t session, * and the provided data, seeded with the client and server random fields. * For the key expansion specified in RFC5705 see gnutls_prf_rfc5705(). * + * This function only works with the TLS versions prior to 1.3. In + * TLS 1.3, the use of PRF is replaced with HKDF (HMAC-based Key + * Derivation Function) based on the multi-stage key scheduling. + * * The @label variable usually contains a string denoting the purpose * for the generated data. The @server_random_first indicates whether * the client random field or the server random field should be first -- cgit v1.2.1