diff options
-rw-r--r-- | lib/crypto-backend.h | 8 | ||||
-rw-r--r-- | lib/nettle/Makefile.am | 5 | ||||
-rw-r--r-- | lib/nettle/int/tls1-prf.c | 169 | ||||
-rw-r--r-- | lib/nettle/int/tls1-prf.h | 50 | ||||
-rw-r--r-- | lib/nettle/prf.c | 100 | ||||
-rw-r--r-- | lib/prf.c | 220 |
6 files changed, 336 insertions, 216 deletions
diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h index d60a5745c2..ef555d7382 100644 --- a/lib/crypto-backend.h +++ b/lib/crypto-backend.h @@ -380,4 +380,12 @@ int gnutls_crypto_pk_register(int priority, const gnutls_crypto_pk_st * s); int gnutls_crypto_bigint_register(int priority, const gnutls_crypto_bigint_st * s); +/* Provided by crypto-backend */ +int +_gnutls_prf_raw(gnutls_mac_algorithm_t mac, + size_t master_size, const void *master, + size_t label_size, const char *label, + size_t seed_size, const uint8_t *seed, size_t outsize, + char *out); + #endif diff --git a/lib/nettle/Makefile.am b/lib/nettle/Makefile.am index ea62926e72..12d7f016ea 100644 --- a/lib/nettle/Makefile.am +++ b/lib/nettle/Makefile.am @@ -38,9 +38,10 @@ endif noinst_LTLIBRARIES = libcrypto.la libcrypto_la_SOURCES = pk.c mpi.c mac.c cipher.c init.c \ - gnettle.h rnd-common.h \ + gnettle.h rnd-common.h prf.c \ rnd.c int/rsa-fips.h int/rsa-keygen-fips186.c int/provable-prime.c \ - int/dsa-fips.h int/dsa-keygen-fips186.c int/dsa-validate.c + int/dsa-fips.h int/dsa-keygen-fips186.c int/dsa-validate.c \ + int/tls1-prf.c int/tls1-prf.h if WINDOWS libcrypto_la_SOURCES += sysrng-windows.c diff --git a/lib/nettle/int/tls1-prf.c b/lib/nettle/int/tls1-prf.c new file mode 100644 index 0000000000..94228c6d7c --- /dev/null +++ b/lib/nettle/int/tls1-prf.c @@ -0,0 +1,169 @@ +/* + * 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/> + * + */ + +/* Functions for the TLS PRF handling. + */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gnutls_int.h> + +#include <stdlib.h> +#include <string.h> + +#include <nettle/hmac.h> +#include <nettle/memxor.h> +#include "int/tls1-prf.h" +#include <nettle/sha1.h> +#include <nettle/md5.h> + + +/* The RFC2246 P_hash() function. The mac_ctx is expected to + * be initialized and key set to be the secret key. + */ +static void +P_hash( void *mac_ctx, + nettle_hash_update_func *update, + nettle_hash_digest_func *digest, + size_t digest_size, + size_t seed_size, const uint8_t *seed, + size_t dst_length, + uint8_t *dst) +{ + uint8_t Atmp[MAX_HASH_SIZE]; + ssize_t left; + unsigned started = 0; + + /* round up */ + left = dst_length; + + while(left > 0) { + if (started == 0) { /* A(0) */ + update(mac_ctx, seed_size, seed); + started = 1; + } else { + update(mac_ctx, digest_size, Atmp); + } + digest(mac_ctx, digest_size, Atmp); /* store A(i) */ + + update(mac_ctx, digest_size, Atmp); /* hash A(i) */ + update(mac_ctx, seed_size, seed); /* hash seed */ + + if (left < (ssize_t)digest_size) + digest_size = left; + + digest(mac_ctx, digest_size, dst); + + left -= digest_size; + dst += digest_size; + } + + return; +} + +int +tls10_prf(size_t secret_size, const uint8_t *secret, + size_t label_size, const char *label, + size_t seed_size, const uint8_t *seed, + size_t length, uint8_t *dst) +{ + int l_s, cseed_size = seed_size + label_size; + const uint8_t *s1, *s2; + struct hmac_md5_ctx md5_ctx; + struct hmac_sha1_ctx sha1_ctx; + uint8_t o1[MAX_PRF_BYTES]; + uint8_t cseed[MAX_SEED_SIZE]; + + if (cseed_size > MAX_SEED_SIZE || length > MAX_PRF_BYTES) + return 0; + + memcpy(cseed, label, label_size); + memcpy(&cseed[label_size], seed, seed_size); + + l_s = secret_size / 2; + s1 = &secret[0]; + s2 = &secret[l_s]; + if (secret_size % 2 != 0) { + l_s++; + } + + hmac_md5_set_key(&md5_ctx, l_s, s1); + + P_hash(&md5_ctx, (nettle_hash_update_func*)hmac_md5_update, + (nettle_hash_digest_func*)hmac_md5_digest, + MD5_DIGEST_SIZE, + cseed_size, cseed, length, o1); + + hmac_sha1_set_key(&sha1_ctx, l_s, s2); + + P_hash(&sha1_ctx, (nettle_hash_update_func*)hmac_sha1_update, + (nettle_hash_digest_func*)hmac_sha1_digest, + SHA1_DIGEST_SIZE, + cseed_size, cseed, length, dst); + + memxor(dst, o1, length); + + return 1; +} + +/*- + * tls12_prf: + * @mac_ctx: a MAC context initialized with key being the secret + * @update: a MAC update function + * @digest: a MAC digest function + * @digest_size: the MAC output size + * @label_size: the size of the label + * @label: the label to apply + * @seed_size: the seed size + * @seed: the seed + * @length: size of desired PRF output + * @dst: the location to store output + * + * The TLS 1.2 Pseudo-Random-Function (PRF). + * + * Returns: zero on failure, non zero on success. + -*/ +int +tls12_prf(void *mac_ctx, + nettle_hash_update_func *update, + nettle_hash_digest_func *digest, + size_t digest_size, + size_t label_size, const char *label, + size_t seed_size, const uint8_t *seed, + size_t length, uint8_t *dst) +{ + size_t cseed_size = seed_size + label_size; + uint8_t cseed[MAX_SEED_SIZE]; + + if (cseed_size > MAX_SEED_SIZE) + return 0; + + memcpy(cseed, label, label_size); + memcpy(&cseed[label_size], seed, seed_size); + + P_hash(mac_ctx, update, digest, digest_size, + cseed_size, cseed, length, dst); + + return 1; +} diff --git a/lib/nettle/int/tls1-prf.h b/lib/nettle/int/tls1-prf.h new file mode 100644 index 0000000000..a455377571 --- /dev/null +++ b/lib/nettle/int/tls1-prf.h @@ -0,0 +1,50 @@ +/* + * 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 TLS_PRF_H_INCLUDED +#define TLS_PRF_H_INCLUDED + +#include <nettle/nettle-meta.h> + +#define MAX_SEED_SIZE 200 +#define MAX_PRF_BYTES 200 + +/* Namespace mangling */ +#define tls10_prf nettle_tls10_prf +#define tls12_prf nettle_tls12_prf + +int +tls10_prf(size_t secret_size, const uint8_t *secret, + size_t label_size, const char *label, + size_t seed_size, const uint8_t *seed, + size_t length, uint8_t *dst); + +int +tls12_prf(void *mac_ctx, + nettle_hash_update_func *update, + nettle_hash_digest_func *digest, + size_t digest_size, + size_t label_size, const char *label, + size_t seed_size, const uint8_t *seed, + size_t length, uint8_t *dst); + +#endif /* TLS_PRF_H_INCLUDED */ diff --git a/lib/nettle/prf.c b/lib/nettle/prf.c new file mode 100644 index 0000000000..762fd653bb --- /dev/null +++ b/lib/nettle/prf.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2017 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library 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/> + * + */ + +#include <gnutls_int.h> +#include "int/tls1-prf.h" +#include <nettle/hmac.h> + +/*- + * _gnutls_prf_raw: + * @mac: the MAC algorithm to use, set to %GNUTLS_MAC_MD5_SHA1 for the TLS1.0 mac + * @master_size: length of the @master variable. + * @master: the master secret used in PRF computation + * @label_size: length of the @label variable. + * @label: label used in PRF computation, typically a short string. + * @seed_size: length of the @seed variable. + * @seed: optional extra data to seed the PRF with. + * @outsize: size of pre-allocated output buffer to hold the output. + * @out: pre-allocated buffer to hold the generated data. + * + * Apply the TLS Pseudo-Random-Function (PRF) on the master secret + * and the provided data. + * + * Returns: %GNUTLS_E_SUCCESS on success, or an error code. + -*/ +int +_gnutls_prf_raw(gnutls_mac_algorithm_t mac, + size_t master_size, const void *master, + size_t label_size, const char *label, + size_t seed_size, const uint8_t *seed, size_t outsize, char *out) +{ + int ret; + + switch (mac) { + case GNUTLS_MAC_MD5_SHA1: + tls10_prf(master_size, (uint8_t*)master, label_size, label, + seed_size, seed, outsize, (uint8_t*)out); + return 0; + case GNUTLS_MAC_SHA256:{ + struct hmac_sha256_ctx ctx; + hmac_sha256_set_key(&ctx, master_size, (uint8_t*)master); + + ret = tls12_prf(&ctx, + (nettle_hash_update_func *) + hmac_sha256_update, + (nettle_hash_digest_func *) + hmac_sha256_digest, SHA256_DIGEST_SIZE, + label_size, label, seed_size, + seed, outsize, + (uint8_t*)out); + + if (unlikely(ret != 1)) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + break; + } + case GNUTLS_MAC_SHA384:{ + struct hmac_sha384_ctx ctx; + hmac_sha384_set_key(&ctx, master_size, master); + + ret = tls12_prf(&ctx, + (nettle_hash_update_func *) + hmac_sha384_update, + (nettle_hash_digest_func *) + hmac_sha384_digest, SHA384_DIGEST_SIZE, + label_size, label, seed_size, + seed, outsize, + (uint8_t*)out); + + if (unlikely(ret != 1)) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + break; + } + default: + gnutls_assert(); + _gnutls_debug_log("unhandled PRF %s\n", + gnutls_mac_get_name(mac)); + return GNUTLS_E_INVALID_REQUEST; + + } + + return 0; +} @@ -1,6 +1,7 @@ /* * Copyright (C) 2002-2015 Free Software Foundation, Inc. * Copyright (C) 2014-2015 Nikos Mavrogiannopoulos + * Copyright (C) 2016-2017 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * @@ -30,172 +31,6 @@ #include <state.h> #include <algorithms.h> -#define MAX_PRF_BYTES 200 -#define MAX_SEED_SIZE 200 - -inline static int -_gnutls_cal_PRF_A(const mac_entry_st * me, - const void *secret, int secret_size, - const void *seed, int seed_size, void *result) -{ - int ret; - - ret = - _gnutls_mac_fast(me->id, secret, secret_size, seed, seed_size, - result); - if (ret < 0) - return gnutls_assert_val(ret); - - return 0; -} - -/* Produces "total_bytes" bytes using the hash algorithm specified. - * (used in the PRF function) - */ -static int -P_hash(gnutls_mac_algorithm_t algorithm, - const uint8_t * secret, int secret_size, - const uint8_t * seed, int seed_size, int total_bytes, uint8_t * ret) -{ - - mac_hd_st td2; - int i, times, how, blocksize, A_size; - uint8_t final[MAX_HASH_SIZE], Atmp[MAX_SEED_SIZE]; - int output_bytes, result; - const mac_entry_st *me = mac_to_entry(algorithm); - - blocksize = _gnutls_mac_get_algo_len(me); - - if (seed_size > MAX_SEED_SIZE || total_bytes <= 0 || blocksize == 0) { - gnutls_assert(); - return GNUTLS_E_INTERNAL_ERROR; - } - - output_bytes = 0; - do { - output_bytes += blocksize; - } - while (output_bytes < total_bytes); - - /* calculate A(0) */ - - memcpy(Atmp, seed, seed_size); - A_size = seed_size; - - times = output_bytes / blocksize; - - for (i = 0; i < times; i++) { - result = _gnutls_mac_init(&td2, me, secret, secret_size); - if (result < 0) { - gnutls_assert(); - return result; - } - - /* here we calculate A(i+1) */ - if ((result = - _gnutls_cal_PRF_A(me, secret, secret_size, Atmp, - A_size, Atmp)) < 0) { - gnutls_assert(); - _gnutls_mac_deinit(&td2, final); - return result; - } - - A_size = blocksize; - - _gnutls_mac(&td2, Atmp, A_size); - _gnutls_mac(&td2, seed, seed_size); - _gnutls_mac_deinit(&td2, final); - - if ((1 + i) * blocksize < total_bytes) { - how = blocksize; - } else { - how = total_bytes - (i) * blocksize; - } - - if (how > 0) { - memcpy(&ret[i * blocksize], final, how); - } - } - - return 0; -} - -/* This function operates as _gnutls_PRF(), but does not require - * a pointer to the current session. It takes the @mac algorithm - * explicitly. For legacy TLS/SSL sessions before TLS 1.2 the MAC - * must be set to %GNUTLS_MAC_MD5_SHA1. - */ -static int -_gnutls_PRF_raw(gnutls_mac_algorithm_t mac, - const uint8_t * secret, unsigned int secret_size, - const char *label, int label_size, const uint8_t * seed, - int seed_size, int total_bytes, void *ret) -{ - int l_s, s_seed_size; - const uint8_t *s1, *s2; - uint8_t s_seed[MAX_SEED_SIZE]; - uint8_t o1[MAX_PRF_BYTES], o2[MAX_PRF_BYTES]; - int result; - - if (total_bytes > MAX_PRF_BYTES) { - gnutls_assert(); - return GNUTLS_E_INTERNAL_ERROR; - } - /* label+seed = s_seed */ - s_seed_size = seed_size + label_size; - - if (s_seed_size > MAX_SEED_SIZE) { - gnutls_assert(); - return GNUTLS_E_INTERNAL_ERROR; - } - - memcpy(s_seed, label, label_size); - memcpy(&s_seed[label_size], seed, seed_size); - - if (mac != GNUTLS_MAC_MD5_SHA1) { - result = - P_hash(mac, secret, secret_size, - s_seed, s_seed_size, - total_bytes, ret); - if (result < 0) { - gnutls_assert(); - return result; - } - } else { - l_s = secret_size / 2; - - s1 = &secret[0]; - s2 = &secret[l_s]; - - if (secret_size % 2 != 0) { - l_s++; - } - - result = - P_hash(GNUTLS_MAC_MD5, s1, l_s, s_seed, s_seed_size, - total_bytes, o1); - if (result < 0) { - gnutls_assert(); - return result; - } - - result = - P_hash(GNUTLS_MAC_SHA1, s2, l_s, s_seed, s_seed_size, - total_bytes, o2); - if (result < 0) { - gnutls_assert(); - return result; - } - - memxor(o1, o2, total_bytes); - - memcpy(ret, o1, total_bytes); - } - - return 0; /* ok */ -} - - /* The PRF function expands a given secret * needed by the TLS specification. ret must have a least total_bytes * available. @@ -206,55 +41,12 @@ _gnutls_PRF(gnutls_session_t session, const char *label, int label_size, const uint8_t * seed, int seed_size, int total_bytes, void *ret) { - return _gnutls_PRF_raw( - session->security_parameters.prf_mac, - secret, secret_size, - label, label_size, - seed, seed_size, - total_bytes, - ret); -} - -#ifdef ENABLE_FIPS140 -int -_gnutls_prf_raw(gnutls_mac_algorithm_t mac, - size_t master_size, const void *master, - size_t label_size, const char *label, - size_t seed_size, const char *seed, size_t outsize, - char *out); - -/*- - * _gnutls_prf_raw: - * @mac: the MAC algorithm to use, set to %GNUTLS_MAC_MD5_SHA1 for the TLS1.0 mac - * @master_size: length of the @master variable. - * @master: the master secret used in PRF computation - * @label_size: length of the @label variable. - * @label: label used in PRF computation, typically a short string. - * @seed_size: length of the @seed variable. - * @seed: optional extra data to seed the PRF with. - * @outsize: size of pre-allocated output buffer to hold the output. - * @out: pre-allocated buffer to hold the generated data. - * - * Apply the TLS Pseudo-Random-Function (PRF) on the master secret - * and the provided data. - * - * Returns: %GNUTLS_E_SUCCESS on success, or an error code. - -*/ -int -_gnutls_prf_raw(gnutls_mac_algorithm_t mac, - size_t master_size, const void *master, - size_t label_size, const char *label, - size_t seed_size, const char *seed, size_t outsize, - char *out) -{ - return _gnutls_PRF_raw(mac, - master, master_size, - label, label_size, - (uint8_t *) seed, seed_size, - outsize, out); - + return _gnutls_prf_raw(session->security_parameters.prf_mac, + secret_size, secret, + label_size, label, + seed_size, seed, + total_bytes, ret); } -#endif /** * gnutls_prf_raw: |