From 7f908ffbb7375a0f1da25c9f5f0affb58dcf5e7f Mon Sep 17 00:00:00 2001
From: Nikos Mavrogiannopoulos <nmav@redhat.com>
Date: Tue, 16 May 2017 12:57:12 +0200
Subject: [PATCH 4/6] Added the TLS 1.0 PRF and test vectors

Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
---
 Makefile.in                |   4 +-
 nettle-types.h             |   3 +
 testsuite/.test-rules.make |   3 +
 testsuite/Makefile.in      |   2 +-
 testsuite/tls10-prf-test.c |  42 +++++++++++++
 tls1-prf.c                 | 151 +++++++++++++++++++++++++++++++++++++++++++++
 tls1-prf.h                 |  57 +++++++++++++++++
 7 files changed, 259 insertions(+), 3 deletions(-)
 create mode 100644 testsuite/tls10-prf-test.c
 create mode 100644 tls1-prf.c
 create mode 100644 tls1-prf.h

diff --git a/Makefile.in b/Makefile.in
index 7e8f29c..5f07bee 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -106,7 +106,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c \
 		 gosthash94.c gosthash94-meta.c \
 		 hmac.c hmac-md5.c hmac-ripemd160.c hmac-sha1.c \
 		 hmac-sha224.c hmac-sha256.c hmac-sha384.c hmac-sha512.c \
-		 knuth-lfib.c \
+		 knuth-lfib.c tls1-prf.c \
 		 md2.c md2-meta.c md4.c md4-meta.c \
 		 md5.c md5-compress.c md5-compat.c md5-meta.c \
 		 memeql-sec.c memxor.c memxor3.c \
@@ -191,7 +191,7 @@ HEADERS = aes.h arcfour.h arctwo.h asn1.h blowfish.h \
 	  cbc.h ccm.h chacha.h chacha-poly1305.h ctr.h \
 	  curve25519.h des.h des-compat.h dsa.h dsa-compat.h eax.h \
 	  ecc-curve.h ecc.h ecdsa.h eddsa.h \
-	  gcm.h gosthash94.h hmac.h \
+	  gcm.h gosthash94.h hmac.h tls1-prf.h \
 	  knuth-lfib.h \
 	  macros.h \
 	  md2.h md4.h \
diff --git a/nettle-types.h b/nettle-types.h
index 475937d..32fb302 100644
--- a/nettle-types.h
+++ b/nettle-types.h
@@ -63,6 +63,9 @@ typedef void *nettle_realloc_func(void *ctx, void *p, size_t length);
 /* Ciphers */
 typedef void nettle_set_key_func(void *ctx, const uint8_t *key);
 
+/* MACs */
+typedef void nettle_hmac_set_key_func(void *ctx, size_t length, const uint8_t *key);
+
 /* For block ciphers, const context. */
 typedef void nettle_cipher_func(const void *ctx,
 				size_t length, uint8_t *dst,
diff --git a/testsuite/.test-rules.make b/testsuite/.test-rules.make
index 1b9c3fa..dbeb7a1 100644
--- a/testsuite/.test-rules.make
+++ b/testsuite/.test-rules.make
@@ -61,6 +61,9 @@ ripemd160-test$(EXEEXT): ripemd160-test.$(OBJEXT)
 salsa20-test$(EXEEXT): salsa20-test.$(OBJEXT)
 	$(LINK) salsa20-test.$(OBJEXT) $(TEST_OBJS) -o salsa20-test$(EXEEXT)
 
+tls10-prf-test$(EXEEXT): tls10-prf-test.$(OBJEXT)
+	$(LINK) tls10-prf-test.$(OBJEXT) $(TEST_OBJS) -o tls10-prf-test$(EXEEXT)
+
 sha1-test$(EXEEXT): sha1-test.$(OBJEXT)
 	$(LINK) sha1-test.$(OBJEXT) $(TEST_OBJS) -o sha1-test$(EXEEXT)
 
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
index 590691c..9e85c9f 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -18,7 +18,7 @@ TS_NETTLE_SOURCES = aes-test.c arcfour-test.c arctwo-test.c \
 		    md2-test.c md4-test.c md5-test.c md5-compat-test.c \
 		    memeql-test.c memxor-test.c gosthash94-test.c \
 		    ripemd160-test.c \
-		    salsa20-test.c \
+		    salsa20-test.c tls10-prf-test.c \
 		    sha1-test.c sha224-test.c sha256-test.c \
 		    sha384-test.c sha512-test.c sha512-224-test.c sha512-256-test.c \
 		    sha3-permute-test.c sha3-224-test.c sha3-256-test.c \
diff --git a/testsuite/tls10-prf-test.c b/testsuite/tls10-prf-test.c
new file mode 100644
index 0000000..1d763ae
--- /dev/null
+++ b/testsuite/tls10-prf-test.c
@@ -0,0 +1,42 @@
+#include "testutils.h"
+#include "tls1-prf.h"
+
+static
+void test_tls10_prf(const struct tstring *secret, const struct tstring *seed,
+	const struct tstring *label, const struct tstring *output)
+{
+	uint8_t *buffer = xalloc(output->length);
+
+	tls10_prf(secret->length, secret->data, label->length, (char*)label->data,
+		  seed->length, seed->data, output->length, buffer);
+
+	if (MEMEQ(output->length, output->data, buffer) == 0) {
+		fprintf(stdout, "\nGot:\n");
+		print_hex(output->length, buffer);
+		fprintf(stdout, "\nExpected:\n");
+		print_hex(output->length, output->data);
+		abort();
+	}
+	free(buffer);
+}
+
+void
+test_main(void)
+{
+  /* TLS 1.0 PRF vectors generated by _gnutls_prf_raw() */
+  test_tls10_prf(SHEX("263bdbbb6f6d4c664e058d0aa9d321be"), SHEX("b920573b199601024f04d6dc61966e65"),
+  	SDATA("test label"), SHEX("6617993765fa6ca703d19ec70dd5dd160ffcc07725fafb714a9f815a2a30bfb7e3bbfb7eee574b3b613eb7fe80eec9691d8c1b0e2d9b3c8b4b02b6b6d6db88e2094623ef6240607eda7abe3c846e82a3"));
+
+  test_tls10_prf(SHEX("bf31fe6c78ebf0ff9ce8bb5dd9d1f83d"), SHEX("7fc4583d19871d962760f358a18696c8"),
+  	SDATA("test label"), SHEX("8318f382c49fd5af7d6fdb4cbb31dfef"));
+
+  test_tls10_prf(SHEX("0addfc84435b9ac1ef523ef44791a784bf55757dea17837c1a72beec1bdb1850"),
+  	SHEX("74e849d11ad8a98d9bc2291dbceec26ff9"),
+  	SDATA("test label"), SHEX("3c221520c48bcb3a0eb3734a"));
+
+  test_tls10_prf(SHEX("4074939b440a08a285bc7208485c531f0bbd4c101d71bdba33ec066791e4678c"),
+  	SHEX("8aff0c770c1d60455ee48f220c9adb471e5fee27c88c1f33"),
+  	SDATA("test label"), SHEX("3a9aee040bbf3cf7009210e64bbdad1775ccf1b46b3a965d5f15168e9ddaa7cc6a7c0c117848"));
+
+}
+
diff --git a/tls1-prf.c b/tls1-prf.c
new file mode 100644
index 0000000..f825b69
--- /dev/null
+++ b/tls1-prf.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2002-2017 Free Software Foundation, Inc.
+ * Copyright (C) 2014-2017 Nikos Mavrogiannopoulos
+ * 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 <assert.h>
+/* Needed for alloca on freebsd */
+#include <stdlib.h>
+#include <string.h>
+
+#include "hmac.h"
+
+#include "memxor.h"
+#include "nettle-internal.h"
+#include "tls1-prf.h"
+#include "sha1.h"
+#include "md5.h"
+
+/* The RFC2246 P_hash() function.
+ */
+static void
+P_hash( void *mac_ctx,
+	nettle_hmac_set_key_func *set_key,
+	nettle_hash_update_func *update,
+	nettle_hash_digest_func *digest,
+	size_t digest_size,
+	size_t secret_size, const uint8_t *secret,
+	size_t seed_size, const uint8_t *seed,
+	size_t dst_length,
+	uint8_t *dst)
+{
+	uint8_t Atmp[NETTLE_MAX_HASH_DIGEST_SIZE];
+	ssize_t left;
+	unsigned started = 0;
+
+	/* round up */
+	left = dst_length;
+
+	while(left > 0) {
+		set_key(mac_ctx, secret_size, secret);
+		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) */
+
+		set_key(mac_ctx, secret_size, secret);
+		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;
+}
+
+/*-
+ * tls10_prf:
+ * @secret_size: the size of secret
+ * @secret: the secret data
+ * @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.0 Pseudo-Random-Function (PRF).
+ *
+ * Returns: zero on failure, non zero on success.
+ -*/
+void
+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;
+	const uint8_t *s1, *s2;
+	struct hmac_md5_ctx md5_ctx;
+	struct hmac_sha1_ctx sha1_ctx;
+
+	TMP_DECL(o1, uint8_t, MAX_PRF_BYTES);
+	TMP_DECL(cseed, uint8_t, MAX_SEED_SIZE);
+
+	/* label+seed = cseed */
+	cseed_size = seed_size + label_size;
+
+	TMP_ALLOC (o1, length);
+	TMP_ALLOC (cseed, cseed_size);
+
+	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++;
+	}
+
+	P_hash(&md5_ctx, (nettle_hmac_set_key_func*)hmac_md5_set_key,
+		(nettle_hash_update_func*)hmac_md5_update,
+		(nettle_hash_digest_func*)hmac_md5_digest,
+		MD5_DIGEST_SIZE,
+		l_s, s1, cseed_size, cseed, length, o1);
+
+	P_hash(&sha1_ctx, (nettle_hmac_set_key_func*)hmac_sha1_set_key,
+		(nettle_hash_update_func*)hmac_sha1_update,
+		(nettle_hash_digest_func*)hmac_sha1_digest,
+		SHA1_DIGEST_SIZE,
+		l_s, s2, cseed_size, cseed, length, dst);
+
+	memxor(dst, o1, length);
+
+	return;
+}
diff --git a/tls1-prf.h b/tls1-prf.h
new file mode 100644
index 0000000..fdcef1d
--- /dev/null
+++ b/tls1-prf.h
@@ -0,0 +1,57 @@
+/* hmac.h
+
+   TLS PRF code (RFC-5246, RFC-2246).
+
+   Copyright (C) 2017 Nikos Mavrogiannopoulos
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle 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
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_PRF_H_INCLUDED
+#define NETTLE_PRF_H_INCLUDED
+
+#include "nettle-meta.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Namespace mangling */
+#define tls10_prf nettle_tls10_prf
+
+void
+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);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_PRF_H_INCLUDED */
-- 
2.9.3

