summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaiki Ueno <dueno@redhat.com>2020-02-02 14:44:05 +0100
committerDaiki Ueno <dueno@redhat.com>2020-02-04 10:29:36 +0100
commit623058337490b847d27b736c67b6e710efb980a7 (patch)
treebebc7927a88e16439d60834312729ca0ca0fb403
parentb4c52d8ad4a063d05100980f895e330ff6076de5 (diff)
downloadgnutls-623058337490b847d27b736c67b6e710efb980a7.tar.gz
crypto-api: add generic crypto functions for KDF
This exposes HKDF and PBKDF2 functions from the library. Instead of defining a single KDF interface as in PKCS #11, this patch defines 3 distinct functions for HKDF-Extract, HKDF-Expand, and PBKDF2 derivation, so that we can take advantage of compile time checking of necesssary parameters. Signed-off-by: Daiki Ueno <dueno@redhat.com>
-rw-r--r--.gitignore1
-rw-r--r--NEWS9
-rw-r--r--devel/libgnutls-latest-x86_64.abi3
-rw-r--r--devel/symbols.last4
-rw-r--r--doc/Makefile.am6
-rw-r--r--doc/manpages/Makefile.am3
-rw-r--r--lib/crypto-api.c95
-rw-r--r--lib/crypto-backend.h16
-rw-r--r--lib/includes/gnutls/crypto.h18
-rw-r--r--lib/libgnutls.map8
-rw-r--r--lib/nettle/mac.c75
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/kdf-api.c160
13 files changed, 399 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index 34d9af38a5..6c716933fa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -436,6 +436,7 @@ tests/insecure_key
tests/iov
tests/ip-check
tests/ip-utils
+tests/kdf-api
tests/key-export-pkcs8
tests/key-id/Makefile
tests/key-id/Makefile.in
diff --git a/NEWS b/NEWS
index 2dcdfe049e..11c860e428 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,15 @@ Copyright (C) 2000-2016 Free Software Foundation, Inc.
Copyright (C) 2013-2019 Nikos Mavrogiannopoulos
See the end for copying conditions.
+* Version 3.6.13 (unreleased)
+
+** libgnutls: Added new APIs to access KDF algorithms (#813).
+
+** API and ABI modifications:
+gnutls_hkdf_extract: Added
+gnutls_hkdf_expand: Added
+gnutls_pbkdf2: Added
+
* Version 3.6.12 (released 2020-02-01)
** libgnutls: Introduced TLS session flag (gnutls_session_get_flags())
diff --git a/devel/libgnutls-latest-x86_64.abi b/devel/libgnutls-latest-x86_64.abi
index cab31da9a8..23d346aefa 100644
--- a/devel/libgnutls-latest-x86_64.abi
+++ b/devel/libgnutls-latest-x86_64.abi
@@ -319,6 +319,8 @@
<elf-symbol name='gnutls_hex_decode' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_hex_encode2' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_hex_encode' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='gnutls_hkdf_expand' version='GNUTLS_3_6_13' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='gnutls_hkdf_extract' version='GNUTLS_3_6_13' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_hmac' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_hmac_copy' version='GNUTLS_3_6_9' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_hmac_deinit' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -465,6 +467,7 @@
<elf-symbol name='gnutls_openpgp_set_recv_key_function' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_packet_deinit' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_packet_get' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='gnutls_pbkdf2' version='GNUTLS_3_6_13' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_pcert_deinit' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_pcert_export_openpgp' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_pcert_export_x509' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
diff --git a/devel/symbols.last b/devel/symbols.last
index 1e0e56d5c0..5159447705 100644
--- a/devel/symbols.last
+++ b/devel/symbols.last
@@ -2,6 +2,7 @@ GNUTLS_3_4@GNUTLS_3_4
GNUTLS_3_6_0@GNUTLS_3_6_0
GNUTLS_3_6_10@GNUTLS_3_6_10
GNUTLS_3_6_12@GNUTLS_3_6_12
+GNUTLS_3_6_13@GNUTLS_3_6_13
GNUTLS_3_6_2@GNUTLS_3_6_2
GNUTLS_3_6_3@GNUTLS_3_6_3
GNUTLS_3_6_4@GNUTLS_3_6_4
@@ -285,6 +286,8 @@ gnutls_hex_decode2@GNUTLS_3_4
gnutls_hex_decode@GNUTLS_3_4
gnutls_hex_encode2@GNUTLS_3_4
gnutls_hex_encode@GNUTLS_3_4
+gnutls_hkdf_expand@GNUTLS_3_6_13
+gnutls_hkdf_extract@GNUTLS_3_6_13
gnutls_hmac@GNUTLS_3_4
gnutls_hmac_copy@GNUTLS_3_6_9
gnutls_hmac_deinit@GNUTLS_3_4
@@ -431,6 +434,7 @@ gnutls_openpgp_send_cert@GNUTLS_3_4
gnutls_openpgp_set_recv_key_function@GNUTLS_3_4
gnutls_packet_deinit@GNUTLS_3_4
gnutls_packet_get@GNUTLS_3_4
+gnutls_pbkdf2@GNUTLS_3_6_13
gnutls_pcert_deinit@GNUTLS_3_4
gnutls_pcert_export_openpgp@GNUTLS_3_4
gnutls_pcert_export_x509@GNUTLS_3_4
diff --git a/doc/Makefile.am b/doc/Makefile.am
index aa3984ffe1..234cbf315d 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -1121,6 +1121,10 @@ FUNCS += functions/gnutls_hex_encode
FUNCS += functions/gnutls_hex_encode.short
FUNCS += functions/gnutls_hex_encode2
FUNCS += functions/gnutls_hex_encode2.short
+FUNCS += functions/gnutls_hkdf_expand
+FUNCS += functions/gnutls_hkdf_expand.short
+FUNCS += functions/gnutls_hkdf_extract
+FUNCS += functions/gnutls_hkdf_extract.short
FUNCS += functions/gnutls_hmac
FUNCS += functions/gnutls_hmac.short
FUNCS += functions/gnutls_hmac_copy
@@ -1277,6 +1281,8 @@ FUNCS += functions/gnutls_packet_deinit
FUNCS += functions/gnutls_packet_deinit.short
FUNCS += functions/gnutls_packet_get
FUNCS += functions/gnutls_packet_get.short
+FUNCS += functions/gnutls_pbkdf2
+FUNCS += functions/gnutls_pbkdf2.short
FUNCS += functions/gnutls_pcert_deinit
FUNCS += functions/gnutls_pcert_deinit.short
FUNCS += functions/gnutls_pcert_export_openpgp
diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am
index 85d0f7f0e4..f11b070fe0 100644
--- a/doc/manpages/Makefile.am
+++ b/doc/manpages/Makefile.am
@@ -362,6 +362,8 @@ APIMANS += gnutls_hex_decode.3
APIMANS += gnutls_hex_decode2.3
APIMANS += gnutls_hex_encode.3
APIMANS += gnutls_hex_encode2.3
+APIMANS += gnutls_hkdf_expand.3
+APIMANS += gnutls_hkdf_extract.3
APIMANS += gnutls_hmac.3
APIMANS += gnutls_hmac_copy.3
APIMANS += gnutls_hmac_deinit.3
@@ -440,6 +442,7 @@ APIMANS += gnutls_openpgp_privkey_sign_hash.3
APIMANS += gnutls_openpgp_send_cert.3
APIMANS += gnutls_packet_deinit.3
APIMANS += gnutls_packet_get.3
+APIMANS += gnutls_pbkdf2.3
APIMANS += gnutls_pcert_deinit.3
APIMANS += gnutls_pcert_export_openpgp.3
APIMANS += gnutls_pcert_export_x509.3
diff --git a/lib/crypto-api.c b/lib/crypto-api.c
index 4db6812c29..45be64ed1f 100644
--- a/lib/crypto-api.c
+++ b/lib/crypto-api.c
@@ -1401,3 +1401,98 @@ void gnutls_aead_cipher_deinit(gnutls_aead_cipher_hd_t handle)
_gnutls_aead_cipher_deinit(handle);
gnutls_free(handle);
}
+
+extern gnutls_crypto_kdf_st _gnutls_kdf_ops;
+
+/**
+ * gnutls_hkdf_extract:
+ * @mac: the mac algorithm used internally
+ * @key: the initial keying material
+ * @salt: the optional salt
+ * @output: the output value of the extract operation
+ *
+ * This function will derive a fixed-size key using the HKDF-Extract
+ * function as defined in RFC 5869.
+ *
+ * Returns: Zero or a negative error code on error.
+ *
+ * Since: 3.6.13
+ */
+int
+gnutls_hkdf_extract(gnutls_mac_algorithm_t mac,
+ const gnutls_datum_t *key,
+ const gnutls_datum_t *salt,
+ void *output)
+{
+ /* MD5 is only allowed internally for TLS */
+ if (is_mac_algo_forbidden(mac))
+ return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
+
+ return _gnutls_kdf_ops.hkdf_extract(mac, key->data, key->size,
+ salt ? salt->data : NULL,
+ salt ? salt->size : 0,
+ output);
+}
+
+/**
+ * gnutls_hkdf_expand:
+ * @mac: the mac algorithm used internally
+ * @key: the pseudorandom key created with HKDF-Extract
+ * @info: the optional informational data
+ * @output: the output value of the expand operation
+ * @length: the desired length of the output key
+ *
+ * This function will derive a variable length keying material from
+ * the pseudorandom key using the HKDF-Expand function as defined in
+ * RFC 5869.
+ *
+ * Returns: Zero or a negative error code on error.
+ *
+ * Since: 3.6.13
+ */
+int
+gnutls_hkdf_expand(gnutls_mac_algorithm_t mac,
+ const gnutls_datum_t *key,
+ const gnutls_datum_t *info,
+ void *output, size_t length)
+{
+ /* MD5 is only allowed internally for TLS */
+ if (is_mac_algo_forbidden(mac))
+ return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
+
+ return _gnutls_kdf_ops.hkdf_expand(mac, key->data, key->size,
+ info->data, info->size,
+ output, length);
+}
+
+/**
+ * gnutls_pbkdf2:
+ * @mac: the mac algorithm used internally
+ * @key: the initial keying material
+ * @salt: the salt
+ * @iter_count: the iteration count
+ * @output: the output value
+ * @length: the desired length of the output key
+ *
+ * This function will derive a variable length keying material from
+ * a password according to PKCS #5 PBKDF2.
+ *
+ * Returns: Zero or a negative error code on error.
+ *
+ * Since: 3.6.13
+ */
+int
+gnutls_pbkdf2(gnutls_mac_algorithm_t mac,
+ const gnutls_datum_t *key,
+ const gnutls_datum_t *salt,
+ unsigned iter_count,
+ void *output, size_t length)
+{
+ /* MD5 is only allowed internally for TLS */
+ if (is_mac_algo_forbidden(mac))
+ return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
+
+ return _gnutls_kdf_ops.pbkdf2(mac, key->data, key->size,
+ salt->data, salt->size, iter_count,
+ output, length);
+}
diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h
index c083b16498..33005e73dd 100644
--- a/lib/crypto-backend.h
+++ b/lib/crypto-backend.h
@@ -75,6 +75,22 @@ typedef struct {
int (*exists) (gnutls_digest_algorithm_t);
} gnutls_crypto_digest_st;
+typedef struct {
+ int (*hkdf_extract) (gnutls_mac_algorithm_t,
+ const void *key, size_t keysize,
+ const void *salt, size_t saltsize,
+ void *output);
+ int (*hkdf_expand) (gnutls_mac_algorithm_t,
+ const void *key, size_t keysize,
+ const void *info, size_t infosize,
+ void *output, size_t length);
+ int (*pbkdf2) (gnutls_mac_algorithm_t,
+ const void *key, size_t keysize,
+ const void *salt, size_t saltsize,
+ unsigned iter_count,
+ void *output, size_t length);
+} gnutls_crypto_kdf_st;
+
typedef struct gnutls_crypto_rnd {
int (*init) (void **ctx); /* called prior to first usage of randomness */
int (*rnd) (void *ctx, int level, void *data, size_t datasize);
diff --git a/lib/includes/gnutls/crypto.h b/lib/includes/gnutls/crypto.h
index 685d9d5d29..c878d7dfac 100644
--- a/lib/includes/gnutls/crypto.h
+++ b/lib/includes/gnutls/crypto.h
@@ -139,6 +139,24 @@ int gnutls_hash_fast(gnutls_digest_algorithm_t algorithm,
const void *text, size_t textlen, void *digest);
gnutls_hash_hd_t gnutls_hash_copy(gnutls_hash_hd_t handle);
+/* KDF API */
+
+int gnutls_hkdf_extract(gnutls_mac_algorithm_t mac,
+ const gnutls_datum_t *key,
+ const gnutls_datum_t *salt,
+ void *output);
+
+int gnutls_hkdf_expand(gnutls_mac_algorithm_t mac,
+ const gnutls_datum_t *key,
+ const gnutls_datum_t *info,
+ void *output, size_t length);
+
+int gnutls_pbkdf2(gnutls_mac_algorithm_t mac,
+ const gnutls_datum_t *key,
+ const gnutls_datum_t *salt,
+ unsigned iter_count,
+ void *output, size_t length);
+
/* register ciphers */
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index e1878bb00c..bf8fff8bc3 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1309,6 +1309,14 @@ GNUTLS_3_6_12
gnutls_hmac_get_key_size;
} GNUTLS_3_6_10;
+GNUTLS_3_6_13
+{
+ global:
+ gnutls_hkdf_extract;
+ gnutls_hkdf_expand;
+ gnutls_pbkdf2;
+} GNUTLS_3_6_12;
+
GNUTLS_FIPS140_3_4 {
global:
gnutls_cipher_self_test;
diff --git a/lib/nettle/mac.c b/lib/nettle/mac.c
index 25054dc267..f997cf3d46 100644
--- a/lib/nettle/mac.c
+++ b/lib/nettle/mac.c
@@ -32,6 +32,8 @@
#include <nettle/sha3.h>
#include <nettle/hmac.h>
#include <nettle/umac.h>
+#include <nettle/hkdf.h>
+#include <nettle/pbkdf2.h>
#if ENABLE_GOST
#include "gost/hmac-gost.h"
#ifndef HAVE_NETTLE_GOSTHASH94CP_UPDATE
@@ -825,6 +827,69 @@ wrap_nettle_hash_output(void *src_ctx, void *digest, size_t digestsize)
return 0;
}
+/* KDF functions based on MAC
+ */
+static int
+wrap_nettle_hkdf_extract (gnutls_mac_algorithm_t mac,
+ const void *key, size_t keysize,
+ const void *salt, size_t saltsize,
+ void *output)
+{
+ struct nettle_mac_ctx ctx;
+ int ret;
+
+ ret = _mac_ctx_init(mac, &ctx);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ctx.set_key(&ctx, saltsize, salt);
+ hkdf_extract(&ctx.ctx, ctx.update, ctx.digest, ctx.length,
+ keysize, key, output);
+
+ return 0;
+}
+
+static int
+wrap_nettle_hkdf_expand (gnutls_mac_algorithm_t mac,
+ const void *key, size_t keysize,
+ const void *info, size_t infosize,
+ void *output, size_t length)
+{
+ struct nettle_mac_ctx ctx;
+ int ret;
+
+ ret = _mac_ctx_init(mac, &ctx);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ctx.set_key(&ctx, keysize, key);
+ hkdf_expand(&ctx.ctx, ctx.update, ctx.digest, ctx.length,
+ infosize, info, length, output);
+
+ return 0;
+}
+
+static int
+wrap_nettle_pbkdf2 (gnutls_mac_algorithm_t mac,
+ const void *key, size_t keysize,
+ const void *salt, size_t saltsize,
+ unsigned iter_count,
+ void *output, size_t length)
+{
+ struct nettle_mac_ctx ctx;
+ int ret;
+
+ ret = _mac_ctx_init(mac, &ctx);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ctx.set_key(&ctx, keysize, key);
+ pbkdf2(&ctx.ctx, ctx.update, ctx.digest, ctx.length,
+ iter_count, saltsize, salt, length, output);
+
+ return 0;
+}
+
gnutls_crypto_mac_st _gnutls_mac_ops = {
.init = wrap_nettle_mac_init,
.setkey = wrap_nettle_mac_set_key,
@@ -846,3 +911,13 @@ gnutls_crypto_digest_st _gnutls_digest_ops = {
.exists = wrap_nettle_hash_exists,
.copy = wrap_nettle_hash_copy,
};
+
+/* These names are clashing with nettle's name mangling. */
+#undef hkdf_extract
+#undef hkdf_expand
+#undef pbkdf2
+gnutls_crypto_kdf_st _gnutls_kdf_ops = {
+ .hkdf_extract = wrap_nettle_hkdf_extract,
+ .hkdf_expand = wrap_nettle_hkdf_expand,
+ .pbkdf2 = wrap_nettle_pbkdf2,
+};
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4e12bc802e..764db8c33a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -217,7 +217,7 @@ ctests += mini-record-2 simple gnutls_hmac_fast set_pkcs12_cred cert certuniquei
tls-record-size-limit-asym dh-compute ecdh-compute sign-verify-data-newapi \
sign-verify-newapi sign-verify-deterministic iov aead-cipher-vec \
tls13-without-timeout-func buffer status-request-revoked \
- set_x509_ocsp_multi_cli
+ set_x509_ocsp_multi_cli kdf-api
if HAVE_SECCOMP_TESTS
ctests += dtls-with-seccomp tls-with-seccomp dtls-client-with-seccomp tls-client-with-seccomp
diff --git a/tests/kdf-api.c b/tests/kdf-api.c
new file mode 100644
index 0000000000..ec74f44ce8
--- /dev/null
+++ b/tests/kdf-api.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * Author: Daiki Ueno
+ *
+ * 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 <https://www.gnu.org/licenses/>
+ *
+ */
+
+#include "config.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "utils.h"
+
+#define MAX_BUF 1024
+
+static void
+test_hkdf(gnutls_mac_algorithm_t mac,
+ const char *ikm_hex,
+ const char *salt_hex,
+ const char *info_hex,
+ size_t length,
+ const char *prk_hex,
+ const char *okm_hex)
+{
+ gnutls_datum_t hex;
+ gnutls_datum_t ikm;
+ gnutls_datum_t salt;
+ gnutls_datum_t info;
+ gnutls_datum_t prk;
+ gnutls_datum_t okm;
+ uint8_t buf[MAX_BUF];
+
+ success("HKDF test with %s\n", gnutls_mac_get_name(mac));
+
+ /* Test HKDF-Extract */
+ hex.data = (void *)ikm_hex;
+ hex.size = strlen(ikm_hex);
+ assert(gnutls_hex_decode2(&hex, &ikm) >= 0);
+
+ hex.data = (void *)salt_hex;
+ hex.size = strlen(salt_hex);
+ assert(gnutls_hex_decode2(&hex, &salt) >= 0);
+
+ assert(gnutls_hkdf_extract(mac, &ikm, &salt, buf) >= 0);
+ gnutls_free(ikm.data);
+ gnutls_free(salt.data);
+
+ prk.data = buf;
+ prk.size = strlen(prk_hex) / 2;
+ assert(gnutls_hex_encode2(&prk, &hex) >= 0);
+
+ if (strcmp((char *)hex.data, prk_hex))
+ fail("prk doesn't match: %s != %s\n",
+ (char *)hex.data, prk_hex);
+
+ gnutls_free(hex.data);
+
+ /* Test HKDF-Expand */
+ hex.data = (void *)info_hex;
+ hex.size = strlen(info_hex);
+ assert(gnutls_hex_decode2(&hex, &info) >= 0);
+
+ assert(gnutls_hkdf_expand(mac, &prk, &info, buf, length) >= 0);
+ gnutls_free(info.data);
+
+ okm.data = buf;
+ okm.size = strlen(okm_hex) / 2;
+ assert(gnutls_hex_encode2(&okm, &hex) >= 0);
+
+ if (strcmp((char *)hex.data, okm_hex))
+ fail("okm doesn't match: %s != %s\n",
+ (char *)hex.data, okm_hex);
+
+ gnutls_free(hex.data);
+}
+
+static void
+test_pbkdf2(gnutls_mac_algorithm_t mac,
+ const char *ikm_hex,
+ const char *salt_hex,
+ unsigned iter_count,
+ size_t length,
+ const char *okm_hex)
+{
+ gnutls_datum_t hex;
+ gnutls_datum_t ikm;
+ gnutls_datum_t salt;
+ gnutls_datum_t okm;
+ uint8_t buf[MAX_BUF];
+
+ success("PBKDF2 test with %s\n", gnutls_mac_get_name(mac));
+
+ hex.data = (void *)ikm_hex;
+ hex.size = strlen(ikm_hex);
+ assert(gnutls_hex_decode2(&hex, &ikm) >= 0);
+
+ hex.data = (void *)salt_hex;
+ hex.size = strlen(salt_hex);
+ assert(gnutls_hex_decode2(&hex, &salt) >= 0);
+
+ assert(gnutls_pbkdf2(mac, &ikm, &salt, iter_count, buf, length) >= 0);
+ gnutls_free(ikm.data);
+ gnutls_free(salt.data);
+
+ okm.data = buf;
+ okm.size = length;
+ assert(gnutls_hex_encode2(&okm, &hex) >= 0);
+
+ if (strcmp((char *)hex.data, okm_hex))
+ fail("okm doesn't match: %s != %s\n",
+ (char *)hex.data, okm_hex);
+
+ gnutls_free(hex.data);
+}
+
+void
+doit(void)
+{
+ /* Test vector from RFC 5869. More thorough testing is done
+ * in nettle. */
+ test_hkdf(GNUTLS_MAC_SHA256,
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"
+ "0b0b0b0b0b0b",
+ "000102030405060708090a0b0c",
+ "f0f1f2f3f4f5f6f7f8f9",
+ 42,
+ "077709362c2e32df0ddc3f0dc47bba63"
+ "90b6c73bb50f9c3122ec844ad7c2b3e5",
+ "3cb25f25faacd57a90434f64d0362f2a"
+ "2d2d0a90cf1a5a4c5db02d56ecc4c5bf"
+ "34007208d5b887185865");
+
+ /* Test vector from RFC 6070. More thorough testing is done
+ * in nettle. */
+ test_pbkdf2(GNUTLS_MAC_SHA1,
+ "70617373776f7264", /* "password" */
+ "73616c74", /* "salt" */
+ 4096,
+ 20,
+ "4b007901b765489abead49d926f721d065a429c1");
+}