Add an HKDF (RFC 5869) implementation
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index be80332..4689f3a 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -4,7 +4,7 @@
* \brief Consistency checks for configuration options
*/
/*
- * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
+ * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -191,6 +191,10 @@
#error "MBEDTLS_HAVEGE_C defined, but not all prerequisites"
#endif
+#if defined(MBEDTLS_HKDF_C) && !defined(MBEDTLS_MD_C)
+#error "MBEDTLS_HKDF_C defined, but not all prerequisites"
+#endif
+
#if defined(MBEDTLS_HMAC_DRBG_C) && !defined(MBEDTLS_MD_C)
#error "MBEDTLS_HMAC_DRBG_C defined, but not all prerequisites"
#endif
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index 7c9acb2..9047a64 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -8,7 +8,7 @@
* memory footprint.
*/
/*
- * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -2092,6 +2092,21 @@
//#define MBEDTLS_HAVEGE_C
/**
+ * \def MBEDTLS_HKDF_C
+ *
+ * Enable HKDF algorithm.
+ *
+ * Module: library/hkdf.c
+ * Caller:
+
+ * Requires: MBEDTLS_MD_C
+ *
+ * This module adds support for the Hashed Message Authentication Code
+ * (HMAC)-based key derivation function (HKDF).
+ */
+#define MBEDTLS_HKDF_C
+
+/**
* \def MBEDTLS_HMAC_DRBG_C
*
* Enable the HMAC_DRBG random generator.
diff --git a/include/mbedtls/error.h b/include/mbedtls/error.h
index 8b4d3a8..a3d6bba 100644
--- a/include/mbedtls/error.h
+++ b/include/mbedtls/error.h
@@ -4,7 +4,7 @@
* \brief Error to string translation
*/
/*
- * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -88,6 +88,7 @@
* RSA 4 11
* ECP 4 9 (Started from top)
* MD 5 5
+ * HKDF 5 1
* CIPHER 6 8
* SSL 6 17 (Started from top)
* SSL 7 31
diff --git a/include/mbedtls/hkdf.h b/include/mbedtls/hkdf.h
new file mode 100644
index 0000000..419c34e
--- /dev/null
+++ b/include/mbedtls/hkdf.h
@@ -0,0 +1,115 @@
+/**
+ * \file hkdf.h
+ *
+ * \brief The HMAC-based Extract-and-Expand Key Derivation Function (HKDF)
+ *
+ */
+/*
+ * Copyright (C) 2016-2018, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_HKDF_H
+#define MBEDTLS_HKDF_H
+
+#include "md.h"
+
+/**
+ * \name HKDF Error codes
+ * \{
+ */
+#define MBEDTLS_ERR_HKDF_BAD_PARAM -0x5300 /**< Bad parameter */
+/* \} name */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief HMAC-based Extract-and-Expand Key Derivation Function
+ *
+ * \param md a hash function; md.size denotes the length of the hash
+ * function output in bytes
+ * \param salt optional salt value (a non-secret random value);
+ * if not provided, it is set to a string of md.size zeros.
+ * \param salt_len length in bytes of the optional \p salt
+ * \param ikm input keying material
+ * \param ikm_len length in bytes of \p ikm
+ * \param info optional context and application specific information
+ * (can be a zero-length string)
+ * \param info_len length of \p info in bytes
+ * \param okm output keying material (of \p okm_len bytes)
+ * \param okm_len length of output keying material in octets
+ * (<= 255*md.size)
+ *
+ * \return 0 on success or one of the failure codes from mbedtls_hkdf_extract
+ * or mbedtls_hkdf_expand
+ */
+int mbedtls_hkdf( const mbedtls_md_info_t *md, const unsigned char *salt,
+ size_t salt_len, const unsigned char *ikm, size_t ikm_len,
+ const unsigned char *info, size_t info_len,
+ unsigned char *okm, size_t okm_len );
+
+/**
+ * \brief Take the input keying material \p ikm and extract from it a
+ * fixed-length pseudorandom key \p prk
+ *
+ * \param md a hash function; md.size denotes the length of the
+ * hash function output in bytes
+ * \param salt optional salt value (a non-secret random value);
+ * if not provided, it is set to a string of md.size
+ * zeros.
+ * \param salt_len length in bytes of the optional \p salt
+ * \param ikm input keying material
+ * \param ikm_len length in bytes of \p ikm
+ * \param[out] prk a pseudorandom key of md.size bytes
+ *
+ * \return 0 on success, MBEDTLS_ERR_HKDF_BAD_PARAM or one of mbedtls_md_*
+ * error codes on failure
+ */
+int mbedtls_hkdf_extract( const mbedtls_md_info_t *md,
+ const unsigned char *salt, size_t salt_len,
+ const unsigned char *ikm, size_t ikm_len,
+ unsigned char *prk );
+
+/**
+ * \brief Expand the supplied \p prk into several additional pseudorandom keys
+ * (the output of the KDF).
+ *
+ * \param md a hash function; md.size denotes the length of the hash
+ * function output in bytes
+ * \param prk a pseudorandom key of at least md.size bytes; usually,
+ * the output from the extract step
+ * \param prk_len length of \p prk in bytes
+ * \param info optional context and application specific information
+ * (can be a zero-length string)
+ * \param info_len length of \p info in bytes
+ * \param okm output keying material (of \p okm_len bytes)
+ * \param okm_len length of output keying material in octets
+ * (<= 255*md.size)
+ *
+ * \return 0 on success, MBEDTLS_ERR_HKDF_BAD_PARAM or a failure code from the
+ * mbedtls_md_* family
+ */
+int mbedtls_hkdf_expand( const mbedtls_md_info_t *md, const unsigned char *prk,
+ size_t prk_len, const unsigned char *info,
+ size_t info_len, unsigned char *okm, size_t okm_len );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* hkdf.h */
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 6177ca2..b730d08 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -29,6 +29,7 @@
error.c
gcm.c
havege.c
+ hkdf.c
hmac_drbg.c
md.c
md2.c
diff --git a/library/Makefile b/library/Makefile
index b155c72..5721d7e 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -56,6 +56,7 @@
ecjpake.o ecp.o \
ecp_curves.o entropy.o entropy_poll.o \
error.o gcm.o havege.o \
+ hkdf.o \
hmac_drbg.o md.o md2.o \
md4.o md5.o md_wrap.o \
memory_buffer_alloc.o oid.o \
diff --git a/library/error.c b/library/error.c
index 222d85b..8dd90b2 100644
--- a/library/error.c
+++ b/library/error.c
@@ -101,6 +101,10 @@
#include "mbedtls/gcm.h"
#endif
+#if defined(MBEDTLS_HKDF_C)
+#include "mbedtls/hkdf.h"
+#endif
+
#if defined(MBEDTLS_HMAC_DRBG_C)
#include "mbedtls/hmac_drbg.h"
#endif
@@ -698,6 +702,11 @@
mbedtls_snprintf( buf, buflen, "GCM - Bad input parameters to function" );
#endif /* MBEDTLS_GCM_C */
+#if defined(MBEDTLS_HKDF_C)
+ if( use_ret == -(MBEDTLS_ERR_HKDF_BAD_PARAM) )
+ mbedtls_snprintf( buf, buflen, "HKDF - Bad parameter" );
+#endif /* MBEDTLS_HKDF_C */
+
#if defined(MBEDTLS_HMAC_DRBG_C)
if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG) )
mbedtls_snprintf( buf, buflen, "HMAC_DRBG - Too many random requested in single call" );
diff --git a/library/hkdf.c b/library/hkdf.c
new file mode 100644
index 0000000..ded555c
--- /dev/null
+++ b/library/hkdf.c
@@ -0,0 +1,164 @@
+/*
+ * HKDF implementation -- RFC 5869
+ *
+ * Copyright (C) 2016-2017, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_HKDF_C)
+
+#include <string.h>
+#include "mbedtls/hkdf.h"
+#include "mbedtls/platform_util.h"
+
+/* HKDF-Extract + HKDF-Expand */
+int mbedtls_hkdf( const mbedtls_md_info_t *md, const unsigned char *salt,
+ size_t salt_len, const unsigned char *ikm, size_t ikm_len,
+ const unsigned char *info, size_t info_len,
+ unsigned char *okm, size_t okm_len )
+{
+ int ret;
+ unsigned char prk[MBEDTLS_MD_MAX_SIZE];
+
+ ret = mbedtls_hkdf_extract( md, salt, salt_len, ikm, ikm_len, prk );
+
+ if ( ret == 0 ) {
+ ret = mbedtls_hkdf_expand( md, prk, mbedtls_md_get_size(md), info, info_len, okm, okm_len );
+ }
+
+ mbedtls_platform_zeroize( prk, sizeof( prk ) );
+
+ return( ret );
+}
+
+/* HKDF-Extract(salt, IKM) -> PRK */
+int mbedtls_hkdf_extract( const mbedtls_md_info_t *md,
+ const unsigned char *salt, size_t salt_len,
+ const unsigned char *ikm, size_t ikm_len,
+ unsigned char *prk )
+{
+ unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = { '\0' };
+
+ if ( salt == NULL ) {
+ size_t hash_len;
+
+ hash_len = mbedtls_md_get_size( md );
+
+ if ( hash_len == 0 ) {
+ return MBEDTLS_ERR_HKDF_BAD_PARAM;
+ }
+
+ salt = null_salt;
+ salt_len = hash_len;
+ }
+
+ return( mbedtls_md_hmac( md, salt, salt_len, ikm, ikm_len, prk ) );
+}
+
+/* HKDF-Expand(PRK, info, L) -> OKM */
+int mbedtls_hkdf_expand( const mbedtls_md_info_t *md, const unsigned char *prk,
+ size_t prk_len, const unsigned char *info,
+ size_t info_len, unsigned char *okm, size_t okm_len )
+{
+ size_t hash_len;
+ size_t where = 0;
+ size_t N;
+ size_t T_len = 0;
+ size_t i;
+ int ret = 0;
+ mbedtls_md_context_t ctx;
+ unsigned char T[MBEDTLS_MD_MAX_SIZE];
+
+ if ( okm == NULL ) {
+ return( MBEDTLS_ERR_HKDF_BAD_PARAM );
+ }
+
+ hash_len = mbedtls_md_get_size(md);
+
+ if ( (prk_len < hash_len) || (hash_len == 0) ) {
+ return( MBEDTLS_ERR_HKDF_BAD_PARAM );
+ }
+
+ if ( info == NULL ) {
+ info = (const unsigned char *) "";
+ info_len = 0;
+ }
+
+ N = okm_len / hash_len;
+
+ if ( (okm_len % hash_len) != 0 ) {
+ N++;
+ }
+
+ if ( N > 255 ) {
+ return( MBEDTLS_ERR_HKDF_BAD_PARAM );
+ }
+
+ mbedtls_md_init( &ctx );
+
+ if ( (ret = mbedtls_md_setup( &ctx, md, 1) ) != 0 ) {
+ goto exit;
+ }
+
+ /* Section 2.3. */
+ for ( i = 1; i <= N; i++ ) {
+ unsigned char c = i & 0xff;
+
+ ret = mbedtls_md_hmac_starts( &ctx, prk, prk_len );
+ if ( ret != 0 ) {
+ goto exit;
+ }
+
+ ret = mbedtls_md_hmac_update( &ctx, T, T_len );
+ if ( ret != 0 ) {
+ goto exit;
+ }
+
+ ret = mbedtls_md_hmac_update( &ctx, info, info_len );
+ if ( ret != 0 ) {
+ goto exit;
+ }
+
+ /* The constant concatenated to the end of each T(n) is a single octet.
+ * */
+ ret = mbedtls_md_hmac_update( &ctx, &c, 1 );
+ if ( ret != 0 ) {
+ goto exit;
+ }
+
+ ret = mbedtls_md_hmac_finish( &ctx, T );
+ if ( ret != 0 ) {
+ goto exit;
+ }
+
+ memcpy( okm + where, T, (i != N) ? hash_len : (okm_len - where) );
+ where += hash_len;
+ T_len = hash_len;
+ }
+
+exit:
+ mbedtls_md_free( &ctx );
+
+ return( ret );
+}
+
+#endif /* MBEDTLS_HKDF_C */
diff --git a/library/version_features.c b/library/version_features.c
index a452caf..1b0f180 100644
--- a/library/version_features.c
+++ b/library/version_features.c
@@ -579,6 +579,9 @@
#if defined(MBEDTLS_HAVEGE_C)
"MBEDTLS_HAVEGE_C",
#endif /* MBEDTLS_HAVEGE_C */
+#if defined(MBEDTLS_HKDF_C)
+ "MBEDTLS_HKDF_C",
+#endif /* MBEDTLS_HKDF_C */
#if defined(MBEDTLS_HMAC_DRBG_C)
"MBEDTLS_HMAC_DRBG_C",
#endif /* MBEDTLS_HMAC_DRBG_C */
diff --git a/scripts/generate_errors.pl b/scripts/generate_errors.pl
index ac0fbff..7290b87 100755
--- a/scripts/generate_errors.pl
+++ b/scripts/generate_errors.pl
@@ -31,7 +31,7 @@
my @low_level_modules = qw( AES ARC4 ASN1 BASE64 BIGNUM BLOWFISH
CAMELLIA CCM CMAC CTR_DRBG DES
- ENTROPY GCM HMAC_DRBG MD2 MD4 MD5
+ ENTROPY GCM HKDF HMAC_DRBG MD2 MD4 MD5
NET OID PADLOCK PBKDF2 RIPEMD160
SHA1 SHA256 SHA512 THREADING XTEA );
my @high_level_modules = qw( CIPHER DHM ECP MD
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 16e19a9..bcd97a0 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -81,6 +81,7 @@
add_test_suite(gcm gcm.aes192_de)
add_test_suite(gcm gcm.aes256_de)
add_test_suite(gcm gcm.camellia)
+add_test_suite(hkdf)
add_test_suite(hmac_drbg hmac_drbg.misc)
add_test_suite(hmac_drbg hmac_drbg.no_reseed)
add_test_suite(hmac_drbg hmac_drbg.nopr)
diff --git a/tests/Makefile b/tests/Makefile
index d85617f..e127809 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -70,6 +70,7 @@
test_suite_gcm.aes192_en$(EXEXT) \
test_suite_gcm.aes256_en$(EXEXT) \
test_suite_gcm.camellia$(EXEXT) \
+ test_suite_hkdf$(EXEXT) \
test_suite_hmac_drbg.misc$(EXEXT) \
test_suite_hmac_drbg.no_reseed$(EXEXT) \
test_suite_hmac_drbg.nopr$(EXEXT) \
@@ -177,6 +178,10 @@
echo " Gen $@"
perl scripts/generate_code.pl suites test_suite_gcm test_suite_gcm.camellia
+test_suite_hkdf.c : suites/test_suite_hkdf.function suites/test_suite_hkdf.data scripts/generate_code.pl suites/helpers.function suites/main_test.function
+ echo " Gen $@"
+ perl scripts/generate_code.pl suites test_suite_hkdf test_suite_hkdf
+
test_suite_hmac_drbg.misc.c : suites/test_suite_hmac_drbg.function suites/test_suite_hmac_drbg.misc.data scripts/generate_code.pl suites/helpers.function suites/main_test.function
echo " Gen $@"
perl scripts/generate_code.pl suites test_suite_hmac_drbg test_suite_hmac_drbg.misc
@@ -341,6 +346,10 @@
echo " CC $<"
$(CC) $(LOCAL_CFLAGS) $(CFLAGS) $< $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
+test_suite_hkdf$(EXEXT): test_suite_hkdf.c $(DEP)
+ echo " CC $<"
+ $(CC) $(LOCAL_CFLAGS) $(CFLAGS) $< $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
+
test_suite_hmac_drbg.misc$(EXEXT): test_suite_hmac_drbg.misc.c $(DEP)
echo " CC $<"
$(CC) $(LOCAL_CFLAGS) $(CFLAGS) $< $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
diff --git a/tests/suites/test_suite_hkdf.data b/tests/suites/test_suite_hkdf.data
new file mode 100644
index 0000000..b58ec93
--- /dev/null
+++ b/tests/suites/test_suite_hkdf.data
@@ -0,0 +1,27 @@
+HKDF RFC5869 Test Vector #1
+depends_on:MBEDTLS_SHA256_C
+test_hkdf:6:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":"000102030405060708090a0b0c":"f0f1f2f3f4f5f6f7f8f9":"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"
+
+HKDF RFC5869 Test Vector #2
+depends_on:MBEDTLS_SHA256_C
+test_hkdf:6:"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f":"606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf":"b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff":"b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87"
+
+HKDF RFC5869 Test Vector #3
+depends_on:MBEDTLS_SHA256_C
+test_hkdf:6:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":"":"":"8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8"
+
+HKDF RFC5869 Test Vector #4
+depends_on:MBEDTLS_SHA1_C
+test_hkdf:4:"0b0b0b0b0b0b0b0b0b0b0b":"000102030405060708090a0b0c":"f0f1f2f3f4f5f6f7f8f9":"085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896"
+
+HKDF RFC5869 Test Vector #5
+depends_on:MBEDTLS_SHA1_C
+test_hkdf:4:"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f":"606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf":"b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff":"0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4"
+
+HKDF RFC5869 Test Vector #6
+depends_on:MBEDTLS_SHA1_C
+test_hkdf:4:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":"":"":"0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918"
+
+HKDF RFC5869 Test Vector #7
+depends_on:MBEDTLS_SHA1_C
+test_hkdf:4:"0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c":"":"":"2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48"
diff --git a/tests/suites/test_suite_hkdf.function b/tests/suites/test_suite_hkdf.function
new file mode 100644
index 0000000..21a9447
--- /dev/null
+++ b/tests/suites/test_suite_hkdf.function
@@ -0,0 +1,39 @@
+/* BEGIN_HEADER */
+#include "mbedtls/hkdf.h"
+/* END_HEADER */
+
+/* BEGIN_DEPENDENCIES
+ * depends_on:MBEDTLS_HKDF_C
+ * END_DEPENDENCIES
+ */
+
+/* BEGIN_CASE */
+void test_hkdf(int md_alg, char *hex_ikm_string, char *hex_salt_string,
+ char *hex_info_string, char *hex_okm_string)
+{
+ int ret;
+ size_t ikm_len, salt_len, info_len, okm_len;
+ unsigned char ikm[1024] = {'\0'};
+ unsigned char salt[1024] = {'\0'};
+ unsigned char info[1024] = {'\0'};
+ unsigned char expected_okm[1024] = {'\0'};
+ unsigned char okm[1024] = {'\0'};
+ unsigned char okm_string[1000] = {'\0'};
+
+ const mbedtls_md_info_t *md = mbedtls_md_info_from_type(md_alg);
+ TEST_ASSERT(md != NULL);
+
+ ikm_len = unhexify(ikm, hex_ikm_string);
+ salt_len = unhexify(salt, hex_salt_string);
+ info_len = unhexify(info, hex_info_string);
+ okm_len = unhexify(expected_okm, hex_okm_string);
+
+ ret = mbedtls_hkdf(md, salt, salt_len, ikm, ikm_len, info, info_len, okm,
+ okm_len);
+ TEST_ASSERT(ret == 0);
+
+ // Run hexify on it so that it looks nicer if the assertion fails
+ hexify(okm_string, okm, okm_len);
+ TEST_ASSERT(!strcmp((char *)okm_string, hex_okm_string));
+}
+/* END_CASE */
diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj
index 802cce7..4c5c480 100644
--- a/visualc/VS2010/mbedTLS.vcxproj
+++ b/visualc/VS2010/mbedTLS.vcxproj
@@ -178,6 +178,7 @@
<ClInclude Include="..\..\include\mbedtls\error.h" />
<ClInclude Include="..\..\include\mbedtls\gcm.h" />
<ClInclude Include="..\..\include\mbedtls\havege.h" />
+ <ClInclude Include="..\..\include\mbedtls\hkdf.h" />
<ClInclude Include="..\..\include\mbedtls\hmac_drbg.h" />
<ClInclude Include="..\..\include\mbedtls\md.h" />
<ClInclude Include="..\..\include\mbedtls\md2.h" />
@@ -248,6 +249,7 @@
<ClCompile Include="..\..\library\error.c" />
<ClCompile Include="..\..\library\gcm.c" />
<ClCompile Include="..\..\library\havege.c" />
+ <ClCompile Include="..\..\library\hkdf.c" />
<ClCompile Include="..\..\library\hmac_drbg.c" />
<ClCompile Include="..\..\library\md.c" />
<ClCompile Include="..\..\library\md2.c" />