summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-05-31 13:52:03 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2017-06-01 08:52:58 +0200
commita46b5cb535a2ccb7a6ffa7672399182e094923c5 (patch)
treefdc9680f5ef54c061985f1285f02e6d51d2005c1
parent18f42d025c229ef5066245578f45c1771e1b6ec7 (diff)
downloadgnutls-a46b5cb535a2ccb7a6ffa7672399182e094923c5.tar.gz
prf: implement the TLS 1.0 and 1.2 PRFs using nettle
That simplifies the existing PRF code and moves it in the crypto-backend component. Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r--lib/crypto-backend.h8
-rw-r--r--lib/nettle/Makefile.am5
-rw-r--r--lib/nettle/int/tls1-prf.c169
-rw-r--r--lib/nettle/int/tls1-prf.h50
-rw-r--r--lib/nettle/prf.c100
-rw-r--r--lib/prf.c220
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;
+}
diff --git a/lib/prf.c b/lib/prf.c
index 517fac90d9..e7265d9a0d 100644
--- a/lib/prf.c
+++ b/lib/prf.c
@@ -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: