On Tue, 2017-05-16 at 22:47 +0200, Niels Möller wrote:

> >  and a comment in .bootstrap for the
> > testsuite/.test-rules.make which I always seem to forget and spend
> > an
> > hour figuring out what is going on. Ideally .test-rules.make should
> > depend on Makefile.in.
> 
> Have you tested if it works to just add that dependency? 

It seems to do. The first patch attached does just that.


+void
> > +hkdf_extract(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 salt_size, const uint8_t *salt,
> > +        size_t secret_size, const uint8_t *secret,
> > +        uint8_t *dst)
> > +{
> > +   set_key(mac_ctx, salt_size, salt);
> > +
> > +   update(mac_ctx, secret_size, secret);
> > +   digest(mac_ctx, digest_size, dst);
> > +}
> 
> This looks like a plain application of a mac, digest = MAC(salt,
> secret), is this really useful?

I've kept it because it makes the mapping from RFC to hkdf.h simpler.
Let me know if you would prefer a macro or inline function.

> Not sure about the typedef nettle_hmac_set_key_func, there's nothing
> hmac specific, besides key size being variable? And it's identical to
> nettle_hash_update_func, right?

No longer there.

> > +   while(left > 0) {
> > +           /* T(i) */
> > +           set_key(mac_ctx, prk_size, prk);
> > +           if (started != 0) {
> > +                   update(mac_ctx, digest_size, Ttmp);
> > +           } else {
> > +                   started = 1;
> > +           }
> > +           if (info_size)
> > +                   update(mac_ctx, info_size, info);
> > +           update(mac_ctx, 1, &i);
> > +
> > +           if (left < digest_size)
> > +                   digest_size = left;
> > +
> > +           digest(mac_ctx, digest_size, dst);
> > +           Ttmp = dst;
> > +
> > +           left -= digest_size;
> > +           dst += digest_size;
> > +           i++;
> > +   }
> 
> I think this loop would clearer if Ttmp was replaced by (dst -
> digest_size), and maybe it would make sense to take out the first
> and/or final iterations.

Patch 0005 unrolls the first loop and does that change. I find that
longer and not as easy to follow, but I may have not caught what you
meant.

The last patch adds documentation for the added functions.

regards,
Nikos
From 9ce6041c3fb03c6b0afc650fdec3a86c87216a93 Mon Sep 17 00:00:00 2001
From: Nikos Mavrogiannopoulos <[email protected]>
Date: Wed, 17 May 2017 15:45:40 +0200
Subject: [PATCH 1/6] testsuite/Makefile.in: ensure .test-rules.make is
 regenerated

That is, regenerate when Makefile.in is modified.

Signed-off-by: Nikos Mavrogiannopoulos <[email protected]>
---
 testsuite/Makefile.in | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
index 590691c..8f18f84 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -96,7 +96,9 @@ dlopen-test$(EXEEXT): dlopen-test.$(OBJEXT) testutils.$(OBJEXT)
 	$(LINK) dlopen-test.$(OBJEXT) -ldl -o dlopen-test$(EXEEXT)
 
 .PHONY: test-rules
-test-rules:
+test-rules: .test-rules.make
+
+.test-rules.make: Makefile.in
 	(for f in $(TS_NETTLE) $(TS_HOGWEED) $(EXTRA_TARGETS) ; do \
 	  echo $$f'$$(EXEEXT): '$$f'.$$(OBJEXT)' ; \
 	  echo '	$$(LINK) '$$f'.$$(OBJEXT) $$(TEST_OBJS) -o '$$f'$$(EXEEXT)' ; \
@@ -107,6 +109,10 @@ test-rules:
 	  echo '	$$(LINK_CXX) '$$f'.$$(OBJEXT) $$(TEST_OBJS) -o '$$f'$$(EXEEXT)' ; \
 	  echo ; \
 	done) > $(srcdir)/.test-rules.make
+	@echo "******************************************************************"
+	@echo "testsuite Makefile rules have been regenerated; please re-run make"
+	@echo "******************************************************************"
+	false
 
 include $(srcdir)/.test-rules.make
 
-- 
2.9.3

From 9150be6bd21639cd0b2a2e86ecd670cd91b1a2c9 Mon Sep 17 00:00:00 2001
From: Nikos Mavrogiannopoulos <[email protected]>
Date: Tue, 16 May 2017 12:57:12 +0200
Subject: [PATCH 2/6] Added the TLS 1.0 PRF and test vectors

Signed-off-by: Nikos Mavrogiannopoulos <[email protected]>
---
 Makefile.in                |   4 +-
 testsuite/.test-rules.make |   3 +
 testsuite/Makefile.in      |   2 +-
 testsuite/tls10-prf-test.c |  42 ++++++++++++++
 tls1-prf.c                 | 133 +++++++++++++++++++++++++++++++++++++++++++++
 tls1-prf.h                 |  57 +++++++++++++++++++
 6 files changed, 238 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/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 8f18f84..3deee1c 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..3c5172e
--- /dev/null
+++ b/tls1-prf.c
@@ -0,0 +1,133 @@
+/*
+ * 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. 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[NETTLE_MAX_HASH_DIGEST_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;
+}
+
+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, NETTLE_MAX_HASH_BLOCK_SIZE);
+	TMP_DECL(cseed, uint8_t, NETTLE_MAX_HASH_BLOCK_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++;
+	}
+
+	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;
+}
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

From 1fde71cf6954c04a0da0f35afafb7774643e13d2 Mon Sep 17 00:00:00 2001
From: Nikos Mavrogiannopoulos <[email protected]>
Date: Tue, 16 May 2017 13:11:29 +0200
Subject: [PATCH 3/6] Added the TLS 1.2 PRF and test vectors

Signed-off-by: Nikos Mavrogiannopoulos <[email protected]>
---
 testsuite/.test-rules.make |  3 +++
 testsuite/Makefile.in      |  2 +-
 testsuite/tls12-prf-test.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++
 tls1-prf.c                 | 44 +++++++++++++++++++++++++++++++++++++++++
 tls1-prf.h                 |  9 +++++++++
 5 files changed, 106 insertions(+), 1 deletion(-)
 create mode 100644 testsuite/tls12-prf-test.c

diff --git a/testsuite/.test-rules.make b/testsuite/.test-rules.make
index dbeb7a1..d09a68b 100644
--- a/testsuite/.test-rules.make
+++ b/testsuite/.test-rules.make
@@ -64,6 +64,9 @@ salsa20-test$(EXEEXT): salsa20-test.$(OBJEXT)
 tls10-prf-test$(EXEEXT): tls10-prf-test.$(OBJEXT)
 	$(LINK) tls10-prf-test.$(OBJEXT) $(TEST_OBJS) -o tls10-prf-test$(EXEEXT)
 
+tls12-prf-test$(EXEEXT): tls12-prf-test.$(OBJEXT)
+	$(LINK) tls12-prf-test.$(OBJEXT) $(TEST_OBJS) -o tls12-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 3deee1c..d8c312b 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 tls10-prf-test.c \
+		    salsa20-test.c tls10-prf-test.c tls12-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/tls12-prf-test.c b/testsuite/tls12-prf-test.c
new file mode 100644
index 0000000..eae8421
--- /dev/null
+++ b/testsuite/tls12-prf-test.c
@@ -0,0 +1,49 @@
+#include "testutils.h"
+#include "tls1-prf.h"
+#include "hmac.h"
+
+static
+void test_tls12_sha256_prf(const struct tstring *secret, const struct tstring *seed,
+	const struct tstring *label, const struct tstring *output)
+{
+	struct hmac_sha256_ctx ctx;
+	uint8_t *buffer = xalloc(output->length);
+
+	hmac_sha256_set_key(&ctx, secret->length, secret->data);
+	tls12_prf(&ctx, (nettle_hash_update_func*)hmac_sha256_update,
+		  (nettle_hash_digest_func*)hmac_sha256_digest, SHA256_DIGEST_SIZE,
+		  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.2 SHA256-PRF vectors generated by _gnutls_prf_raw() */
+  test_tls12_sha256_prf(SHEX("0450b0ea9ecd3602ee0d76c5c3c86f4a"),
+  	SHEX("207acc0254b867f5b925b45a33601d8b"),
+  	SDATA("test label"), SHEX("ae679e0e714f5975763768b166979e1d"));
+
+  test_tls12_sha256_prf(SHEX("34204a9df0be6eb4e925a8027cf6c602"),
+  	SHEX("98b2c40bcd664c83bb920c18201a6395"),
+  	SDATA("test label"), SHEX("afa9312453c22fa83d2b511b372d73a402a2a62873239a51fade45082faf3fd2bb7ffb3e9bf36e28b3141aaba484005332a9f9e388a4d329f1587a4b317da07708ea1ba95a53f8786724bd83ce4b03af"));
+
+  test_tls12_sha256_prf(SHEX("a3691aa1f6814b80592bf1cf2acf1697"),
+  	SHEX("5523d41e320e694d0c1ff5734d830b933e46927071c92621"),
+  	SDATA("test label"), SHEX("6ad0984fa06f78fe161bd46d7c261de43340d728dddc3d0ff0dd7e0d"));
+
+  test_tls12_sha256_prf(SHEX("210ec937069707e5465bc46bf779e104108b18fdb793be7b218dbf145c8641f3"), SHEX("1e351a0baf35c79945924394b881cfe31dae8f1c1ed54d3b"),
+  	SDATA("test label"), SHEX("7653fa809cde3b553c4a17e2cdbcc918f36527f22219a7d7f95d97243ff2d5dee8265ef0af03"));
+
+
+}
+
diff --git a/tls1-prf.c b/tls1-prf.c
index 3c5172e..f07395a 100644
--- a/tls1-prf.c
+++ b/tls1-prf.c
@@ -131,3 +131,47 @@ tls10_prf(size_t secret_size, const uint8_t *secret,
 
 	return;
 }
+
+/*-
+ * 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.
+ -*/
+void
+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;
+
+	TMP_DECL(cseed, uint8_t, MAX_SEED_SIZE);
+
+	/* label+seed = cseed */
+	cseed_size = seed_size + label_size;
+
+	TMP_ALLOC (cseed, cseed_size);
+
+	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;
+}
diff --git a/tls1-prf.h b/tls1-prf.h
index fdcef1d..da2739e 100644
--- a/tls1-prf.h
+++ b/tls1-prf.h
@@ -42,6 +42,7 @@ extern "C" {
 
 /* Namespace mangling */
 #define tls10_prf nettle_tls10_prf
+#define tls12_prf nettle_tls12_prf
 
 void
 tls10_prf(size_t secret_size, const uint8_t *secret,
@@ -49,6 +50,14 @@ tls10_prf(size_t secret_size, const uint8_t *secret,
 	  size_t seed_size, const uint8_t *seed,
 	  size_t length, uint8_t *dst);
 
+void
+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);
 
 #ifdef __cplusplus
 }
-- 
2.9.3

From ffec7df7a67c77536fdaca91a9c8cfab13fc6536 Mon Sep 17 00:00:00 2001
From: Nikos Mavrogiannopoulos <[email protected]>
Date: Tue, 16 May 2017 14:30:41 +0200
Subject: [PATCH 4/6] Added the HKDF key derivation function and test vectors

Signed-off-by: Nikos Mavrogiannopoulos <[email protected]>
---
 Makefile.in                |   4 +-
 hkdf.c                     | 103 ++++++++++++++++++++++++++++++++++++
 hkdf.h                     |  67 ++++++++++++++++++++++++
 testsuite/.test-rules.make |   3 ++
 testsuite/Makefile.in      |   2 +-
 testsuite/hkdf-test.c      | 128 +++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 304 insertions(+), 3 deletions(-)
 create mode 100644 hkdf.c
 create mode 100644 hkdf.h
 create mode 100644 testsuite/hkdf-test.c

diff --git a/Makefile.in b/Makefile.in
index 5f07bee..2e80772 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 tls1-prf.c \
+		 knuth-lfib.c tls1-prf.c hkdf.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 tls1-prf.h \
+	  gcm.h gosthash94.h hmac.h tls1-prf.h hkdf.h \
 	  knuth-lfib.h \
 	  macros.h \
 	  md2.h md4.h \
diff --git a/hkdf.c b/hkdf.c
new file mode 100644
index 0000000..48ac8ae
--- /dev/null
+++ b/hkdf.c
@@ -0,0 +1,103 @@
+/*
+ * 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 HKDF 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 "hkdf.h"
+
+/* hkdf_extract: Outputs a PRK of digest_size
+ * @mac_ctx: a MAC context initialized with key being the salt
+ * @update: a MAC update function
+ * @digest: a MAC digest function
+ * 
+ */
+void
+hkdf_extract(void *mac_ctx,
+	     nettle_hash_update_func *update,
+	     nettle_hash_digest_func *digest,
+	     size_t digest_size,
+	     size_t secret_size, const uint8_t *secret,
+	     uint8_t *dst)
+{
+	update(mac_ctx, secret_size, secret);
+	digest(mac_ctx, digest_size, dst);
+}
+
+/* hkdf_expand: Outputs an arbitrary key of size specified by length
+ * @mac_ctx: a MAC context initialized with key being the PRK (normally output of hkdf_extract)
+ * @update: a MAC update function
+ * @digest: a MAC digest function
+ * 
+ */
+void
+hkdf_expand(void *mac_ctx,
+	     nettle_hash_update_func *update,
+	     nettle_hash_digest_func *digest,
+	     size_t digest_size,
+	     size_t info_size, const uint8_t *info,
+	     size_t length, uint8_t *dst)
+{
+	uint8_t *Ttmp;
+	ssize_t left;
+	uint8_t i = 1;
+	unsigned started = 0;
+
+	left = length;
+
+	while(left > 0) {
+		/* T(i) */
+		if (started != 0) {
+			update(mac_ctx, digest_size, Ttmp);
+		} else {
+			started = 1;
+		}
+		if (info_size)
+			update(mac_ctx, info_size, info);
+		update(mac_ctx, 1, &i);
+
+		if (left < digest_size)
+			digest_size = left;
+
+		digest(mac_ctx, digest_size, dst);
+		Ttmp = dst;
+
+		left -= digest_size;
+		dst += digest_size;
+		i++;
+	}
+
+	return;
+}
diff --git a/hkdf.h b/hkdf.h
new file mode 100644
index 0000000..2c8cfea
--- /dev/null
+++ b/hkdf.h
@@ -0,0 +1,67 @@
+/* hmac.h
+
+   TLS PRF code (RFC-5246, RFC-2246).
+
+   Copyright (C) 2017 Red Hat, Inc.
+
+   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_HKDF_H_INCLUDED
+#define NETTLE_HKDF_H_INCLUDED
+
+#include "nettle-meta.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Namespace mangling */
+#define hkdf_extract nettle_hkdf_extract
+#define hkdf_expand nettle_hkdf_expand
+
+void
+hkdf_extract(void *mac_ctx,
+	     nettle_hash_update_func *update,
+	     nettle_hash_digest_func *digest,
+	     size_t digest_size,
+	     size_t secret_size, const uint8_t *secret,
+	     uint8_t *dst);
+
+void
+hkdf_expand(void *mac_ctx,
+	     nettle_hash_update_func *update,
+	     nettle_hash_digest_func *digest,
+	     size_t digest_size,
+	     size_t info_size, const uint8_t *info,
+	     size_t length, uint8_t *dst);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_HKDF_H_INCLUDED */
diff --git a/testsuite/.test-rules.make b/testsuite/.test-rules.make
index d09a68b..a419a09 100644
--- a/testsuite/.test-rules.make
+++ b/testsuite/.test-rules.make
@@ -58,6 +58,9 @@ gosthash94-test$(EXEEXT): gosthash94-test.$(OBJEXT)
 ripemd160-test$(EXEEXT): ripemd160-test.$(OBJEXT)
 	$(LINK) ripemd160-test.$(OBJEXT) $(TEST_OBJS) -o ripemd160-test$(EXEEXT)
 
+hkdf-test$(EXEEXT): hkdf-test.$(OBJEXT)
+	$(LINK) hkdf-test.$(OBJEXT) $(TEST_OBJS) -o hkdf-test$(EXEEXT)
+
 salsa20-test$(EXEEXT): salsa20-test.$(OBJEXT)
 	$(LINK) salsa20-test.$(OBJEXT) $(TEST_OBJS) -o salsa20-test$(EXEEXT)
 
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
index d8c312b..a67f180 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -17,7 +17,7 @@ TS_NETTLE_SOURCES = aes-test.c arcfour-test.c arctwo-test.c \
 		    des-test.c des3-test.c des-compat-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 \
+		    ripemd160-test.c hkdf-test.c \
 		    salsa20-test.c tls10-prf-test.c tls12-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 \
diff --git a/testsuite/hkdf-test.c b/testsuite/hkdf-test.c
new file mode 100644
index 0000000..f033946
--- /dev/null
+++ b/testsuite/hkdf-test.c
@@ -0,0 +1,128 @@
+#include "testutils.h"
+#include "hkdf.h"
+#include "hmac.h"
+
+static
+void test_hkdf_sha256(const struct tstring *ikm, const struct tstring *salt,
+	const struct tstring *info, const struct tstring *extract_output,
+	const struct tstring *expand_output)
+{
+	struct hmac_sha256_ctx ctx;
+	uint8_t prk[SHA256_DIGEST_SIZE];
+	uint8_t *buffer = xalloc(expand_output->length);
+
+	hmac_sha256_set_key(&ctx, salt->length, salt->data);
+	hkdf_extract(&ctx, (nettle_hash_update_func*)hmac_sha256_update,
+		  (nettle_hash_digest_func*)hmac_sha256_digest, SHA256_DIGEST_SIZE,
+		  ikm->length, ikm->data, prk);
+
+	if (MEMEQ(SHA256_DIGEST_SIZE, prk, extract_output->data) == 0) {
+		fprintf(stdout, "\nGot:\n");
+		print_hex(SHA256_DIGEST_SIZE, prk);
+		fprintf(stdout, "\nExpected:\n");
+		print_hex(extract_output->length, extract_output->data);
+		abort();
+	}
+
+	hmac_sha256_set_key(&ctx, SHA256_DIGEST_SIZE, prk);
+	hkdf_expand(&ctx, (nettle_hash_update_func*)hmac_sha256_update,
+		  (nettle_hash_digest_func*)hmac_sha256_digest, SHA256_DIGEST_SIZE,
+		  info->length, info->data,
+		  expand_output->length, buffer);
+
+	if (MEMEQ(expand_output->length, expand_output->data, buffer) == 0) {
+		fprintf(stdout, "\nGot:\n");
+		print_hex(expand_output->length, buffer);
+		fprintf(stdout, "\nExpected:\n");
+		print_hex(expand_output->length, expand_output->data);
+		abort();
+	}
+	free(buffer);
+}
+
+static
+void test_hkdf_sha1(const struct tstring *ikm, const struct tstring *salt,
+	const struct tstring *info, const struct tstring *extract_output,
+	const struct tstring *expand_output)
+{
+	struct hmac_sha1_ctx ctx;
+	uint8_t prk[SHA1_DIGEST_SIZE];
+	uint8_t *buffer = xalloc(expand_output->length);
+
+	hmac_sha1_set_key(&ctx, salt->length, salt->data);
+	hkdf_extract(&ctx, (nettle_hash_update_func*)hmac_sha1_update,
+		  (nettle_hash_digest_func*)hmac_sha1_digest, SHA1_DIGEST_SIZE,
+		  ikm->length, ikm->data,
+		  prk);
+
+	if (MEMEQ(SHA1_DIGEST_SIZE, prk, extract_output->data) == 0) {
+		fprintf(stdout, "\nGot:\n");
+		print_hex(SHA1_DIGEST_SIZE, prk);
+		fprintf(stdout, "\nExpected:\n");
+		print_hex(extract_output->length, extract_output->data);
+		abort();
+	}
+
+	hmac_sha1_set_key(&ctx, SHA1_DIGEST_SIZE, prk);
+	hkdf_expand(&ctx, (nettle_hash_update_func*)hmac_sha1_update,
+		  (nettle_hash_digest_func*)hmac_sha1_digest, SHA1_DIGEST_SIZE,
+		  info->length, info->data,
+		  expand_output->length, buffer);
+
+	if (MEMEQ(expand_output->length, expand_output->data, buffer) == 0) {
+		fprintf(stdout, "\nGot:\n");
+		print_hex(expand_output->length, buffer);
+		fprintf(stdout, "\nExpected:\n");
+		print_hex(expand_output->length, expand_output->data);
+		abort();
+	}
+	free(buffer);
+}
+
+void
+test_main(void)
+{
+  /* HKDF test vectors from RFC5869 */
+  test_hkdf_sha256(SHEX("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+  	SHEX("000102030405060708090a0b0c"),
+  	SHEX("f0f1f2f3f4f5f6f7f8f9"),
+  	SHEX("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5"),
+  	SHEX("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"));
+
+  test_hkdf_sha256(SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"),
+  	SHEX("606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf"),
+  	SHEX("b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+  	SHEX("06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244"),
+  	SHEX("b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87"));
+
+  test_hkdf_sha256(SHEX("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+  	SDATA(""),
+  	SDATA(""),
+  	SHEX("19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04"),
+  	SHEX("8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8"));
+
+  test_hkdf_sha1(SHEX("0b0b0b0b0b0b0b0b0b0b0b"),
+  	SHEX("000102030405060708090a0b0c"),
+  	SHEX("f0f1f2f3f4f5f6f7f8f9"),
+  	SHEX("9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243"),
+  	SHEX("085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896"));
+
+  test_hkdf_sha1(SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"),
+  	SHEX("606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf"),
+  	SHEX("b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+  	SHEX("8adae09a2a307059478d309b26c4115a224cfaf6"),
+  	SHEX("0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4"));
+
+  test_hkdf_sha1(SHEX("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+  	SDATA(""),
+  	SDATA(""),
+  	SHEX("da8c8a73c7fa77288ec6f5e7c297786aa0d32d01"),
+  	SHEX("0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918"));
+
+  test_hkdf_sha1(SHEX("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"),
+  	SHEX(""),
+  	SHEX(""),
+  	SHEX("2adccada18779e7c2077ad2eb19d3f3e731385dd"),
+  	SHEX("2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48"));
+}
+
-- 
2.9.3

From 9f7d668c6b763044bbb6b0fff5e19828ce015446 Mon Sep 17 00:00:00 2001
From: Nikos Mavrogiannopoulos <[email protected]>
Date: Wed, 17 May 2017 16:39:35 +0200
Subject: [PATCH 5/6] unrolled first loop of HKDF

Signed-off-by: Nikos Mavrogiannopoulos <[email protected]>
---
 hkdf.c | 38 +++++++++++++++++++++++++-------------
 1 file changed, 25 insertions(+), 13 deletions(-)

diff --git a/hkdf.c b/hkdf.c
index 48ac8ae..cf5311f 100644
--- a/hkdf.c
+++ b/hkdf.c
@@ -70,33 +70,45 @@ hkdf_expand(void *mac_ctx,
 	     size_t info_size, const uint8_t *info,
 	     size_t length, uint8_t *dst)
 {
-	uint8_t *Ttmp;
 	ssize_t left;
 	uint8_t i = 1;
-	unsigned started = 0;
+	size_t tohash;
 
 	left = length;
 
+	/* first loop */
+	if (info_size)
+		update(mac_ctx, info_size, info);
+	update(mac_ctx, 1, &i);
+
+	if (left < digest_size)
+		tohash = left;
+	else
+		tohash = digest_size;
+
+	digest(mac_ctx, tohash, dst);
+	left -= tohash;
+	dst += tohash;
+
 	while(left > 0) {
+		i++;
+
 		/* T(i) */
-		if (started != 0) {
-			update(mac_ctx, digest_size, Ttmp);
-		} else {
-			started = 1;
-		}
+		update(mac_ctx, digest_size, dst-digest_size);
 		if (info_size)
 			update(mac_ctx, info_size, info);
 		update(mac_ctx, 1, &i);
 
+		/* last loop */
 		if (left < digest_size)
-			digest_size = left;
+			tohash = left;
+		else
+			tohash = digest_size;
 
-		digest(mac_ctx, digest_size, dst);
-		Ttmp = dst;
+		digest(mac_ctx, tohash, dst);
 
-		left -= digest_size;
-		dst += digest_size;
-		i++;
+		left -= tohash;
+		dst += tohash;
 	}
 
 	return;
-- 
2.9.3

From f8cb1a2b40bfb1091652831a4a685ddbe39004fb Mon Sep 17 00:00:00 2001
From: Nikos Mavrogiannopoulos <[email protected]>
Date: Wed, 17 May 2017 16:29:40 +0200
Subject: [PATCH 6/6] doc: added HKDF and TLS-PRF documentation

Signed-off-by: Nikos Mavrogiannopoulos <[email protected]>
---
 nettle.texinfo | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 76 insertions(+), 5 deletions(-)

diff --git a/nettle.texinfo b/nettle.texinfo
index 1d7e4e3..0960e51 100644
--- a/nettle.texinfo
+++ b/nettle.texinfo
@@ -3366,12 +3366,7 @@ processing a new message.
 @node Key derivation functions, Public-key algorithms, Keyed hash functions, Reference
 @comment  node-name,  next,  previous,  up
 @section Key derivation Functions
-
 @cindex Key Derivation Function
-@cindex Password Based Key Derivation Function
-@cindex PKCS #5
-@cindex KDF
-@cindex PBKDF
 
 A @dfn{key derivation function} (@acronym{KDF}) is a function that from
 a given symmetric key derives other symmetric keys.  A sub-class of KDFs
@@ -3380,7 +3375,83 @@ which take as input a password or passphrase, and its purpose is
 typically to strengthen it and protect against certain pre-computation
 attacks by using salting and expensive computation.
 
+@subsection HKDF: HMAC-based Extract-and-Expand
+@cindex HKDF
+
+The key derivation function used in TLS 1.3 is HKDF, described
+in @cite{RFC 5869}, and is a derivation function based on HMAC.
+
+Nettle's @acronym{HKDF} functions are defined in
+@file{<nettle/hkdf.h>}.  There are two abstract functions for extract
+and expand operations that operate on any HMAC implemented via the @code{nettle_hash_update_func},
+@code{nettle_hash_digest_func} interfaces.
+
+@deftypefun void hkdf_extract (void *mac_ctx, nettle_hash_update_func *update, nettle_hash_digest_func *digest, size_t digest_size,size_t secret_size, const uint8_t *secret,  uint8_t *dst)
+Extract a Pseudorandom Key (PRK) from a secret and a salt according
+to HKDF. The HMAC must have been initialized, with its key being the
+salt for the Extract operation. This function will call the
+@var{update} and @var{digest} functions passing the @var{mac_ctx}
+context parameter as an argument in order to compute digest of size
+@var{digest_size}.  Inputs are the secret @var{secret} of length
+@var{secret_length}. The output length is fixed to @var{digest_size} octets,
+thus the output buffer @var{dst} must have room for at least @var{digest_size} octets.
+@end deftypefun
+
+@deftypefun void hkdf_expand (void *mac_ctx, nettle_hash_update_func *update, nettle_hash_digest_func *digest, size_t digest_size, size_t info_size, const uint8_t *info, size_t length, uint8_t *dst)
+Expand a Pseudorandom Key (PRK) to an arbitrary size according to HKDF.
+The HMAC must have been initialized, with its key being the
+PRK from the Extract operation. This function will call the
+@var{update} and @var{digest} functions passing the @var{mac_ctx}
+context parameter as an argument in order to compute digest of size
+@var{digest_size}.  Inputs are the info @var{info} of length
+@var{info_length}, and the desired derived output length @var{length}.
+The output buffer is @var{dst} which must have room for at least @var{length} octets.
+@end deftypefun
+
+
+@subsection TLS-PRF: TLS Pseudo Random Function
+@cindex PRF
+@cindex TLS-PRF
+
+The key derivation functions used in TLS 1.0 and TLS 1.2, described
+in @cite{RFC 2246}, and @cite{RFC 5246}, and are key derivation functions
+based on HMAC.
+
+Nettle's @acronym{TLS-PRF} functions are defined in
+@file{<nettle/tls1-prf.h>}.  There are two abstract functions for TLS 1.0,
+based on SHA1 and MD5, and TLS 1.2, that operates on any HMAC implemented via
+the @code{nettle_hash_update_func}, @code{nettle_hash_digest_func} interfaces.
+
+@deftypefun 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)
+Derive a Pseudorandom Key from a secret, label and a seed according
+to TLS 1.0.  Inputs are the secret @var{secret} of length
+@var{secret_length}, the label @var{label} of length
+@var{label_length}, the seed @var{seed} of length
+@var{seed_length} and the desired derived output length @var{length}.
+The output buffer is @var{dst} which must have room for at least @var{length} octets.
+@end deftypefun
+
+@deftypefun void 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)
+Derive a Pseudorandom Key from a secret, label and a seed according
+to TLS 1.2. The HMAC must have been initialized, with its key being the
+secret to be used. This function will call the @var{update} and @var{digest}
+functions passing the @var{mac_ctx} context parameter as an argument in order
+to compute digest of size @var{digest_size}.
+Inputs are the secret @var{secret} of length
+@var{secret_length}, the label @var{label} of length
+@var{label_length}, the seed @var{seed} of length
+@var{seed_length} and the desired derived output length @var{length}.
+The output buffer is @var{dst} which must have room for at least @var{length} octets.
+@end deftypefun
+
+
+
+
 @subsection @acronym{PBKDF2}
+@cindex Password Based Key Derivation Function
+@cindex PKCS #5
+@cindex KDF
+@cindex PBKDF
 The most well known PBKDF is the @code{PKCS #5 PBKDF2} described in
 @cite{RFC 2898} which uses a pseudo-random function such as
 @acronym{HMAC-SHA1}.
-- 
2.9.3

_______________________________________________
nettle-bugs mailing list
[email protected]
http://lists.lysator.liu.se/mailman/listinfo/nettle-bugs

Reply via email to