diff options
-rw-r--r-- | lib/Makefile.am | 4 | ||||
-rw-r--r-- | lib/gnutls_int.h | 5 | ||||
-rw-r--r-- | lib/handshake.h | 12 | ||||
-rw-r--r-- | lib/secrets.c | 171 | ||||
-rw-r--r-- | lib/secrets.h | 40 |
5 files changed, 230 insertions, 2 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 3ea1c6cebb..3442a6c443 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -79,7 +79,7 @@ COBJECTS = range.c record.c compress.c debug.c cipher.c \ safe-memfuncs.c system/inet_pton.c atfork.c atfork.h randomart.c \ system-keys.h urls.c urls.h prf.c auto-verify.c dh-session.c \ cert-session.c handshake-checks.c dtls-sw.c dh-primes.c openpgp_compat.c \ - crypto-selftests.c crypto-selftests-pk.c + crypto-selftests.c crypto-selftests-pk.c secrets.c if WINDOWS COBJECTS += system/keys-win.c @@ -110,7 +110,7 @@ HFILES = abstract_int.h debug.h cipher.h \ srp.h auth/srp_kx.h auth/srp_passwd.h \ file.h supplemental.h crypto.h random.h system.h\ locks.h mbuffers.h ecc.h pin.h fips.h \ - priority_options.h + priority_options.h secrets.h if ENABLE_PKCS11 HFILES += pkcs11_int.h pkcs11x.h diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 004c28e908..ae2e7cba08 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -402,6 +402,11 @@ struct gnutls_key_st { gnutls_pk_params_st kshare_ecdhx_params; gnutls_pk_params_st kshare_dh_params; + /* the current (depending on state) secret, can be + * early_secret, client_early_traffic_secret, ... */ + uint8_t temp_secret[MAX_CIPHER_KEY_SIZE]; + unsigned temp_secret_size; + /* For ECDH KX */ gnutls_pk_params_st ecdh_params; /* private part */ diff --git a/lib/handshake.h b/lib/handshake.h index 3f9b55faa0..6934b0d6fd 100644 --- a/lib/handshake.h +++ b/lib/handshake.h @@ -76,4 +76,16 @@ int _gnutls_handshake_get_session_hash(gnutls_session_t session, gnutls_datum_t int _gnutls_check_id_for_change(gnutls_session_t session); int _gnutls_check_if_cert_hash_is_same(gnutls_session_t session, gnutls_certificate_credentials_t cred); +#define EARLY_TRAFFIC_LABEL "c e traffic" +#define EXT_BINDER_LABEL "ext binder" +#define RES_BINDER_LABEL "res binder" +#define EARLY_EXPORTER_LABEL "e exp master" +#define HANDSHAKE_CLIENT_TRAFFIC_LABEL "c hs traffic" +#define HANDSHAKE_SERVER_TRAFFIC_LABEL "s hs traffic" +#define DERIVED_LABEL "derived" +#define APPLICATION_CLIENT_TRAFFIC_LABEL "c ap traffic" +#define APPLICATION_SERVER_TRAFFIC_LABEL "s ap traffic" +#define EXPORTER_LABEL "exp master" +#define RES_LABEL "res master" + #endif diff --git a/lib/secrets.c b/lib/secrets.c new file mode 100644 index 0000000000..adffd8b6bb --- /dev/null +++ b/lib/secrets.c @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2017 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +/* TLS 1.3 secret key derivation handling. + */ + +#include <config.h> +#include "gnutls_int.h" +#include "nettle/int/hkdf.h" +#include <nettle/hmac.h> +#include "secrets.h" + +/* HKDF-Extract(0,0) or HKDF-Extract(0, PSK) */ +int _tls13_init_secret(gnutls_session_t session, const uint8_t *psk, size_t psk_size) +{ + char buf[128]; + + session->key.temp_secret_size = gnutls_hmac_get_len(session->security_parameters.prf_mac); + + /* when no PSK, use the zero-value */ + if (psk == NULL) { + psk_size = session->key.temp_secret_size; + if (unlikely(psk_size >= sizeof(buf))) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + memset(buf, 0, psk_size); + psk = (uint8_t*)buf; + } + + return gnutls_hmac_fast(session->security_parameters.prf_mac, + "", 0, + psk, psk_size, + session->key.temp_secret); +} + +/* HKDF-Extract(Prev-Secret, key) */ +int _tls13_update_secret(gnutls_session_t session, const uint8_t *key, size_t key_size) +{ + return gnutls_hmac_fast(session->security_parameters.prf_mac, + session->key.temp_secret, session->key.temp_secret_size, + key, key_size, + session->key.temp_secret); +} + +static +int _tls13_expand_hash_secret(gnutls_session_t session, + const char *label, unsigned label_size, + const uint8_t *tbh, size_t tbh_size, + const uint8_t secret[MAX_CIPHER_KEY_SIZE], + unsigned out_size, + void *out) +{ + uint8_t digest[MAX_HASH_SIZE]; + int ret; + unsigned digest_size = gnutls_hmac_get_len(session->security_parameters.prf_mac); + + if (unlikely(label_size >= sizeof(digest))) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + ret = gnutls_hash_fast((gnutls_digest_algorithm_t)session->security_parameters.prf_mac, + tbh, tbh_size, digest); + if (ret < 0) + return gnutls_assert_val(ret); + + return _tls13_expand_secret(session, label, label_size, digest, digest_size, secret, out_size, out); +} + +/* HKDF-Expand-Label(Secret, Label, HashValue, Length) */ +int _tls13_expand_secret(gnutls_session_t session, + const char *label, unsigned label_size, + const uint8_t *msg, size_t msg_size, + const uint8_t secret[MAX_CIPHER_KEY_SIZE], + unsigned out_size, + void *out) +{ + uint8_t tmp[256] = "tls13 "; + gnutls_buffer_st str; + int ret; + + if (unlikely(label_size >= sizeof(tmp)-6)) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + _gnutls_buffer_init(&str); + + ret = _gnutls_buffer_append_prefix(&str, 16, out_size); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + memcpy(&tmp[6], label, label_size); + ret = _gnutls_buffer_append_data_prefix(&str, 8, tmp, label_size+6); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = _gnutls_buffer_append_data_prefix(&str, 8, msg, msg_size); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + switch(session->security_parameters.prf_mac) { + case GNUTLS_MAC_SHA256:{ + struct hmac_sha256_ctx ctx; + + hmac_sha256_set_key(&ctx, SHA256_DIGEST_SIZE, secret); + hkdf_expand(&ctx, (nettle_hash_update_func*)hmac_sha256_update, + (nettle_hash_digest_func*)hmac_sha256_digest, SHA256_DIGEST_SIZE, + str.length, str.data, out_size, out); + break; + } + case GNUTLS_MAC_SHA384:{ + struct hmac_sha384_ctx ctx; + + hmac_sha384_set_key(&ctx, SHA384_DIGEST_SIZE, secret); + hkdf_expand(&ctx, (nettle_hash_update_func*)hmac_sha384_update, + (nettle_hash_digest_func*)hmac_sha384_digest, SHA384_DIGEST_SIZE, + str.length, str.data, out_size, out); + break; + } + default: + gnutls_assert(); + ret = GNUTLS_E_INTERNAL_ERROR; + goto cleanup; + } + +#if 0 + _gnutls_hard_log("INT: secret expanded for '%.*s': %d,%s\n", + (int)label_size, label, out_size, + _gnutls_bin2hex(out, out_size, + (char*)tmp, sizeof(tmp), NULL)); +#endif + + ret = 0; + cleanup: + _gnutls_buffer_clear(&str); + return ret; +} + +/* Derive-Secret(Secret, Label, Messages) */ +int _tls13_derive_secret(gnutls_session_t session, + const char *label, unsigned label_size, + const uint8_t *msg, size_t msg_size, + void *out) +{ + return _tls13_expand_hash_secret(session, label, label_size, msg, msg_size, + session->key.temp_secret, + session->key.temp_secret_size, + out); +} diff --git a/lib/secrets.h b/lib/secrets.h new file mode 100644 index 0000000000..b80af974a6 --- /dev/null +++ b/lib/secrets.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef SECRETS_H +#define SECRETS_H + +int _tls13_init_secret(gnutls_session_t session, const uint8_t *psk, size_t psk_size); +int _tls13_update_secret(gnutls_session_t session, const uint8_t *key, size_t key_size); +int _tls13_derive_secret(gnutls_session_t session, + const char *label, unsigned label_size, + const uint8_t *msg, size_t msg_size, + void *out /* of enough length to hold PRF MAC */); + +int _tls13_expand_secret(gnutls_session_t session, + const char *label, unsigned label_size, + const uint8_t *msg, size_t msg_size, + const uint8_t secret[MAX_CIPHER_KEY_SIZE], + unsigned out_size, + void *out); + +#endif |