tests/iov
tests/ip-check
tests/ip-utils
+tests/kdf-api
tests/key-export-pkcs8
tests/key-id/Makefile
tests/key-id/Makefile.in
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())
<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'/>
<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'/>
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
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
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
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
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
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
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
_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);
+}
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);
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 */
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;
#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
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,
.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,
+};
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
--- /dev/null
+/*
+ * 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");
+}