summaryrefslogtreecommitdiffstats
path: root/providers/implementations/kdfs
diff options
context:
space:
mode:
authorRichard Levitte <levitte@openssl.org>2019-10-04 10:24:09 +0200
committerRichard Levitte <levitte@openssl.org>2019-10-10 14:12:15 +0200
commit5687e357c60b31dc274c6d14f1cd623d0cff469b (patch)
tree6cac9157790e44435359726e71aa033fb18d8701 /providers/implementations/kdfs
parentdec95d75897125133380c7ce3c6ce58c93c06f10 (diff)
Providers: move common exchange,kdfs,keymgmt,macs,signature
From providers/common/ to providers/implementations/ Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/10088)
Diffstat (limited to 'providers/implementations/kdfs')
-rw-r--r--providers/implementations/kdfs/build.info22
-rw-r--r--providers/implementations/kdfs/hkdf.c463
-rw-r--r--providers/implementations/kdfs/kbkdf.c303
-rw-r--r--providers/implementations/kdfs/pbkdf2.c336
-rw-r--r--providers/implementations/kdfs/pbkdf2.h14
-rw-r--r--providers/implementations/kdfs/pbkdf2_fips.c20
-rw-r--r--providers/implementations/kdfs/sskdf.c538
-rw-r--r--providers/implementations/kdfs/tls1_prf.c396
8 files changed, 2092 insertions, 0 deletions
diff --git a/providers/implementations/kdfs/build.info b/providers/implementations/kdfs/build.info
new file mode 100644
index 0000000000..8800b12f7e
--- /dev/null
+++ b/providers/implementations/kdfs/build.info
@@ -0,0 +1,22 @@
+# We make separate GOAL variables for each algorithm, to make it easy to
+# switch each to the Legacy provider when needed.
+
+$TLS1_PRF_GOAL=../../libimplementations.a
+$HKDF_GOAL=../../libimplementations.a
+$KBKDF_GOAL=../../libimplementations.a
+$PBKDF2_GOAL=../../libimplementations.a
+$SSKDF_GOAL=../../libimplementations.a
+
+SOURCE[$TLS1_PRF_GOAL]=tls1_prf.c
+
+SOURCE[$HKDF_GOAL]=hkdf.c
+
+SOURCE[$KBKDF_GOAL]=kbkdf.c
+
+SOURCE[$PBKDF2_GOAL]=pbkdf2.c
+# Extra code to satisfy the FIPS and non-FIPS separation.
+# When the PBKDF2 moves to legacy, this can be removed.
+SOURCE[../../libfips.a]=pbkdf2_fips.c
+SOURCE[../../libnonfips.a]=pbkdf2_fips.c
+
+SOURCE[$SSKDF_GOAL]=sskdf.c
diff --git a/providers/implementations/kdfs/hkdf.c b/providers/implementations/kdfs/hkdf.c
new file mode 100644
index 0000000000..041811f0e1
--- /dev/null
+++ b/providers/implementations/kdfs/hkdf.c
@@ -0,0 +1,463 @@
+/*
+ * Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+#include <openssl/kdf.h>
+#include <openssl/core_names.h>
+#include "internal/cryptlib.h"
+#include "internal/numbers.h"
+#include "crypto/evp.h"
+#include "internal/provider_ctx.h"
+#include "internal/providercommonerr.h"
+#include "internal/provider_algs.h"
+#include "internal/provider_util.h"
+#include "e_os.h"
+
+#define HKDF_MAXBUF 1024
+
+static OSSL_OP_kdf_newctx_fn kdf_hkdf_new;
+static OSSL_OP_kdf_freectx_fn kdf_hkdf_free;
+static OSSL_OP_kdf_reset_fn kdf_hkdf_reset;
+static OSSL_OP_kdf_derive_fn kdf_hkdf_derive;
+static OSSL_OP_kdf_settable_ctx_params_fn kdf_hkdf_settable_ctx_params;
+static OSSL_OP_kdf_set_ctx_params_fn kdf_hkdf_set_ctx_params;
+static OSSL_OP_kdf_gettable_ctx_params_fn kdf_hkdf_gettable_ctx_params;
+static OSSL_OP_kdf_get_ctx_params_fn kdf_hkdf_get_ctx_params;
+
+static int HKDF(const EVP_MD *evp_md,
+ const unsigned char *salt, size_t salt_len,
+ const unsigned char *key, size_t key_len,
+ const unsigned char *info, size_t info_len,
+ unsigned char *okm, size_t okm_len);
+static int HKDF_Extract(const EVP_MD *evp_md,
+ const unsigned char *salt, size_t salt_len,
+ const unsigned char *ikm, size_t ikm_len,
+ unsigned char *prk, size_t prk_len);
+static int HKDF_Expand(const EVP_MD *evp_md,
+ const unsigned char *prk, size_t prk_len,
+ const unsigned char *info, size_t info_len,
+ unsigned char *okm, size_t okm_len);
+
+typedef struct {
+ void *provctx;
+ int mode;
+ PROV_DIGEST digest;
+ unsigned char *salt;
+ size_t salt_len;
+ unsigned char *key;
+ size_t key_len;
+ unsigned char info[HKDF_MAXBUF];
+ size_t info_len;
+} KDF_HKDF;
+
+static void *kdf_hkdf_new(void *provctx)
+{
+ KDF_HKDF *ctx;
+
+ if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ else
+ ctx->provctx = provctx;
+ return ctx;
+}
+
+static void kdf_hkdf_free(void *vctx)
+{
+ KDF_HKDF *ctx = (KDF_HKDF *)vctx;
+
+ kdf_hkdf_reset(ctx);
+ OPENSSL_free(ctx);
+}
+
+static void kdf_hkdf_reset(void *vctx)
+{
+ KDF_HKDF *ctx = (KDF_HKDF *)vctx;
+
+ ossl_prov_digest_reset(&ctx->digest);
+ OPENSSL_free(ctx->salt);
+ OPENSSL_clear_free(ctx->key, ctx->key_len);
+ OPENSSL_cleanse(ctx->info, ctx->info_len);
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+static size_t kdf_hkdf_size(KDF_HKDF *ctx)
+{
+ int sz;
+ const EVP_MD *md = ossl_prov_digest_md(&ctx->digest);
+
+ if (ctx->mode != EVP_KDF_HKDF_MODE_EXTRACT_ONLY)
+ return SIZE_MAX;
+
+ if (md == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST);
+ return 0;
+ }
+ sz = EVP_MD_size(md);
+ if (sz < 0)
+ return 0;
+
+ return sz;
+}
+
+static int kdf_hkdf_derive(void *vctx, unsigned char *key, size_t keylen)
+{
+ KDF_HKDF *ctx = (KDF_HKDF *)vctx;
+ const EVP_MD *md = ossl_prov_digest_md(&ctx->digest);
+
+ if (md == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST);
+ return 0;
+ }
+ if (ctx->key == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
+ return 0;
+ }
+
+ switch (ctx->mode) {
+ case EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND:
+ return HKDF(md, ctx->salt, ctx->salt_len, ctx->key,
+ ctx->key_len, ctx->info, ctx->info_len, key,
+ keylen);
+
+ case EVP_KDF_HKDF_MODE_EXTRACT_ONLY:
+ return HKDF_Extract(md, ctx->salt, ctx->salt_len, ctx->key,
+ ctx->key_len, key, keylen);
+
+ case EVP_KDF_HKDF_MODE_EXPAND_ONLY:
+ return HKDF_Expand(md, ctx->key, ctx->key_len, ctx->info,
+ ctx->info_len, key, keylen);
+
+ default:
+ return 0;
+ }
+}
+
+static int kdf_hkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ const OSSL_PARAM *p;
+ KDF_HKDF *ctx = vctx;
+ OPENSSL_CTX *provctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx);
+ int n;
+
+ if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx))
+ return 0;
+
+ if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MODE)) != NULL) {
+ if (p->data_type == OSSL_PARAM_UTF8_STRING) {
+ if (strcasecmp(p->data, "EXTRACT_AND_EXPAND") == 0) {
+ ctx->mode = EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND;
+ } else if (strcasecmp(p->data, "EXTRACT_ONLY") == 0) {
+ ctx->mode = EVP_KDF_HKDF_MODE_EXTRACT_ONLY;
+ } else if (strcasecmp(p->data, "EXPAND_ONLY") == 0) {
+ ctx->mode = EVP_KDF_HKDF_MODE_EXPAND_ONLY;
+ } else {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
+ return 0;
+ }
+ } else if (OSSL_PARAM_get_int(p, &n)) {
+ if (n != EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND
+ && n != EVP_KDF_HKDF_MODE_EXTRACT_ONLY
+ && n != EVP_KDF_HKDF_MODE_EXPAND_ONLY) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
+ return 0;
+ }
+ ctx->mode = n;
+ } else {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
+ return 0;
+ }
+ }
+
+ if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL) {
+ OPENSSL_clear_free(ctx->key, ctx->key_len);
+ ctx->key = NULL;
+ if (!OSSL_PARAM_get_octet_string(p, (void **)&ctx->key, 0,
+ &ctx->key_len))
+ return 0;
+ }
+
+ if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) {
+ if (p->data_size != 0 && p->data != NULL) {
+ OPENSSL_free(ctx->salt);
+ ctx->salt = NULL;
+ if (!OSSL_PARAM_get_octet_string(p, (void **)&ctx->salt, 0,
+ &ctx->salt_len))
+ return 0;
+ }
+ }
+ /* The info fields concatenate, so process them all */
+ if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO)) != NULL) {
+ ctx->info_len = 0;
+ for (; p != NULL; p = OSSL_PARAM_locate_const(p + 1,
+ OSSL_KDF_PARAM_INFO)) {
+ const void *q = ctx->info + ctx->info_len;
+ size_t sz = 0;
+
+ if (p->data_size != 0
+ && p->data != NULL
+ && !OSSL_PARAM_get_octet_string(p, (void **)&q,
+ HKDF_MAXBUF - ctx->info_len,
+ &sz))
+ return 0;
+ ctx->info_len += sz;
+ }
+ }
+ return 1;
+}
+
+static const OSSL_PARAM *kdf_hkdf_settable_ctx_params(void)
+{
+ static const OSSL_PARAM known_settable_ctx_params[] = {
+ OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MODE, NULL, 0),
+ OSSL_PARAM_int(OSSL_KDF_PARAM_MODE, NULL),
+ OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0),
+ OSSL_PARAM_END
+ };
+ return known_settable_ctx_params;
+}
+
+static int kdf_hkdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+ KDF_HKDF *ctx = (KDF_HKDF *)vctx;
+ OSSL_PARAM *p;
+
+ if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL)
+ return OSSL_PARAM_set_size_t(p, kdf_hkdf_size(ctx));
+ return -2;
+}
+
+static const OSSL_PARAM *kdf_hkdf_gettable_ctx_params(void)
+{
+ static const OSSL_PARAM known_gettable_ctx_params[] = {
+ OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
+ OSSL_PARAM_END
+ };
+ return known_gettable_ctx_params;
+}
+
+const OSSL_DISPATCH kdf_hkdf_functions[] = {
+ { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_hkdf_new },
+ { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_hkdf_free },
+ { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_hkdf_reset },
+ { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_hkdf_derive },
+ { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS,
+ (void(*)(void))kdf_hkdf_settable_ctx_params },
+ { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_hkdf_set_ctx_params },
+ { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
+ (void(*)(void))kdf_hkdf_gettable_ctx_params },
+ { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_hkdf_get_ctx_params },
+ { 0, NULL }
+};
+
+/*
+ * Refer to "HMAC-based Extract-and-Expand Key Derivation Function (HKDF)"
+ * Section 2 (https://tools.ietf.org/html/rfc5869#section-2) and
+ * "Cryptographic Extraction and Key Derivation: The HKDF Scheme"
+ * Section 4.2 (https://eprint.iacr.org/2010/264.pdf).
+ *
+ * From the paper:
+ * The scheme HKDF is specified as:
+ * HKDF(XTS, SKM, CTXinfo, L) = K(1) | K(2) | ... | K(t)
+ *
+ * where:
+ * SKM is source key material
+ * XTS is extractor salt (which may be null or constant)
+ * CTXinfo is context information (may be null)
+ * L is the number of key bits to be produced by KDF
+ * k is the output length in bits of the hash function used with HMAC
+ * t = ceil(L/k)
+ * the value K(t) is truncated to its first d = L mod k bits.
+ *
+ * From RFC 5869:
+ * 2.2. Step 1: Extract
+ * HKDF-Extract(salt, IKM) -> PRK
+ * 2.3. Step 2: Expand
+ * HKDF-Expand(PRK, info, L) -> OKM
+ */
+static int HKDF(const EVP_MD *evp_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)
+{
+ unsigned char prk[EVP_MAX_MD_SIZE];
+ int ret, sz;
+ size_t prk_len;
+
+ sz = EVP_MD_size(evp_md);
+ if (sz < 0)
+ return 0;
+ prk_len = (size_t)sz;
+
+ /* Step 1: HKDF-Extract(salt, IKM) -> PRK */
+ if (!HKDF_Extract(evp_md, salt, salt_len, ikm, ikm_len, prk, prk_len))
+ return 0;
+
+ /* Step 2: HKDF-Expand(PRK, info, L) -> OKM */
+ ret = HKDF_Expand(evp_md, prk, prk_len, info, info_len, okm, okm_len);
+ OPENSSL_cleanse(prk, sizeof(prk));
+
+ return ret;
+}
+
+/*
+ * Refer to "HMAC-based Extract-and-Expand Key Derivation Function (HKDF)"
+ * Section 2.2 (https://tools.ietf.org/html/rfc5869#section-2.2).
+ *
+ * 2.2. Step 1: Extract
+ *
+ * HKDF-Extract(salt, IKM) -> PRK
+ *
+ * Options:
+ * Hash a hash function; HashLen denotes the length of the
+ * hash function output in octets
+ *
+ * Inputs:
+ * salt optional salt value (a non-secret random value);
+ * if not provided, it is set to a string of HashLen zeros.
+ * IKM input keying material
+ *
+ * Output:
+ * PRK a pseudorandom key (of HashLen octets)
+ *
+ * The output PRK is calculated as follows:
+ *
+ * PRK = HMAC-Hash(salt, IKM)
+ */
+static int HKDF_Extract(const EVP_MD *evp_md,
+ const unsigned char *salt, size_t salt_len,
+ const unsigned char *ikm, size_t ikm_len,
+ unsigned char *prk, size_t prk_len)
+{
+ int sz = EVP_MD_size(evp_md);
+
+ if (sz < 0)
+ return 0;
+ if (prk_len != (size_t)sz) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_OUTPUT_BUFFER_SIZE);
+ return 0;
+ }
+ /* calc: PRK = HMAC-Hash(salt, IKM) */
+ return HMAC(evp_md, salt, salt_len, ikm, ikm_len, prk, NULL) != NULL;
+}
+
+/*
+ * Refer to "HMAC-based Extract-and-Expand Key Derivation Function (HKDF)"
+ * Section 2.3 (https://tools.ietf.org/html/rfc5869#section-2.3).
+ *
+ * 2.3. Step 2: Expand
+ *
+ * HKDF-Expand(PRK, info, L) -> OKM
+ *
+ * Options:
+ * Hash a hash function; HashLen denotes the length of the
+ * hash function output in octets
+ *
+ * Inputs:
+ * PRK a pseudorandom key of at least HashLen octets
+ * (usually, the output from the extract step)
+ * info optional context and application specific information
+ * (can be a zero-length string)
+ * L length of output keying material in octets
+ * (<= 255*HashLen)
+ *
+ * Output:
+ * OKM output keying material (of L octets)
+ *
+ * The output OKM is calculated as follows:
+ *
+ * N = ceil(L/HashLen)
+ * T = T(1) | T(2) | T(3) | ... | T(N)
+ * OKM = first L octets of T
+ *
+ * where:
+ * T(0) = empty string (zero length)
+ * T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)
+ * T(2) = HMAC-Hash(PRK, T(1) | info | 0x02)
+ * T(3) = HMAC-Hash(PRK, T(2) | info | 0x03)
+ * ...
+ *
+ * (where the constant concatenated to the end of each T(n) is a
+ * single octet.)
+ */
+static int HKDF_Expand(const EVP_MD *evp_md,
+ const unsigned char *prk, size_t prk_len,
+ const unsigned char *info, size_t info_len,
+ unsigned char *okm, size_t okm_len)
+{
+ HMAC_CTX *hmac;
+ int ret = 0, sz;
+ unsigned int i;
+ unsigned char prev[EVP_MAX_MD_SIZE];
+ size_t done_len = 0, dig_len, n;
+
+ sz = EVP_MD_size(evp_md);
+ if (sz <= 0)
+ return 0;
+ dig_len = (size_t)sz;
+
+ /* calc: N = ceil(L/HashLen) */
+ n = okm_len / dig_len;
+ if (okm_len % dig_len)
+ n++;
+
+ if (n > 255 || okm == NULL)
+ return 0;
+
+ if ((hmac = HMAC_CTX_new()) == NULL)
+ return 0;
+
+ if (!HMAC_Init_ex(hmac, prk, prk_len, evp_md, NULL))
+ goto err;
+
+ for (i = 1; i <= n; i++) {
+ size_t copy_len;
+ const unsigned char ctr = i;
+
+ /* calc: T(i) = HMAC-Hash(PRK, T(i - 1) | info | i) */
+ if (i > 1) {
+ if (!HMAC_Init_ex(hmac, NULL, 0, NULL, NULL))
+ goto err;
+
+ if (!HMAC_Update(hmac, prev, dig_len))
+ goto err;
+ }
+
+ if (!HMAC_Update(hmac, info, info_len))
+ goto err;
+
+ if (!HMAC_Update(hmac, &ctr, 1))
+ goto err;
+
+ if (!HMAC_Final(hmac, prev, NULL))
+ goto err;
+
+ copy_len = (done_len + dig_len > okm_len) ?
+ okm_len - done_len :
+ dig_len;
+
+ memcpy(okm + done_len, prev, copy_len);
+
+ done_len += copy_len;
+ }
+ ret = 1;
+
+ err:
+ OPENSSL_cleanse(prev, sizeof(prev));
+ HMAC_CTX_free(hmac);
+ return ret;
+}
diff --git a/providers/implementations/kdfs/kbkdf.c b/providers/implementations/kdfs/kbkdf.c
new file mode 100644
index 0000000000..ffffef0b17
--- /dev/null
+++ b/providers/implementations/kdfs/kbkdf.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2019 Red Hat, Inc.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*
+ * This implements https://csrc.nist.gov/publications/detail/sp/800-108/final
+ * section 5.1 ("counter mode") in HMAC only. That document does not name the
+ * KDFs it defines; the name is derived from
+ * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/Key-Derivation
+ *
+ * Note that sections 5.2 ("feedback mode") and 5.3 ("double-pipeline mode")
+ * are not implemented, though it would be possible to do so in the future.
+ * CMAC mode is also not implemented; some plumbing would be required.
+ *
+ * These versions all assume the counter is used. It would be relatively
+ * straightforward to expose a configuration handle should the need arise.
+ *
+ * Variable names attempt to match those of SP800-108.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/core_names.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/kdf.h>
+#include <openssl/params.h>
+
+#include "internal/cryptlib.h"
+#include "crypto/evp.h"
+#include "internal/numbers.h"
+#include "internal/provider_algs.h"
+#include "internal/provider_ctx.h"
+#include "internal/provider_util.h"
+#include "internal/providercommonerr.h"
+
+#include "e_os.h"
+
+#define MIN(a, b) ((a) < (b)) ? (a) : (b)
+
+/* Our context structure. */
+typedef struct {
+ void *provctx;
+ EVP_MAC_CTX *ctx_init;
+
+ /* Names are lowercased versions of those found in SP800-108. */
+ unsigned char *ki;
+ size_t ki_len;
+ unsigned char *label;
+ size_t label_len;
+ unsigned char *context;
+ size_t context_len;
+} KBKDF;
+
+/* Definitions needed for typechecking. */
+static OSSL_OP_kdf_newctx_fn kbkdf_new;
+static OSSL_OP_kdf_freectx_fn kbkdf_free;
+static OSSL_OP_kdf_reset_fn kbkdf_reset;
+static OSSL_OP_kdf_derive_fn kbkdf_derive;
+static OSSL_OP_kdf_settable_ctx_params_fn kbkdf_settable_ctx_params;
+static OSSL_OP_kdf_set_ctx_params_fn kbkdf_set_ctx_params;
+
+/* Not all platforms have htobe32(). */
+static uint32_t be32(uint32_t host)
+{
+ uint32_t big = 0;
+ const union {
+ long one;
+ char little;
+ } is_endian = { 1 };
+
+ if (!is_endian.little)
+ return host;
+
+ big |= (host & 0xff000000) >> 24;
+ big |= (host & 0x00ff0000) >> 8;
+ big |= (host & 0x0000ff00) << 8;
+ big |= (host & 0x000000ff) << 24;
+ return big;
+}
+
+static void *kbkdf_new(void *provctx)
+{
+ KBKDF *ctx;
+
+ ctx = OPENSSL_zalloc(sizeof(*ctx));
+ if (ctx == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ ctx->provctx = provctx;
+ return ctx;
+}
+
+static void kbkdf_free(void *vctx)
+{
+ KBKDF *ctx = (KBKDF *)vctx;
+
+ kbkdf_reset(ctx);
+ OPENSSL_free(ctx);
+}
+
+static void kbkdf_reset(void *vctx)
+{
+ KBKDF *ctx = (KBKDF *)vctx;
+
+ EVP_MAC_CTX_free(ctx->ctx_init);
+ OPENSSL_clear_free(ctx->context, ctx->context_len);
+ OPENSSL_clear_free(ctx->label, ctx->label_len);
+ OPENSSL_clear_free(ctx->ki, ctx->ki_len);
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+/* SP800-108 section 5.1. */
+static int kbkdf_derive_counter(EVP_MAC_CTX *ctx_init,
+ unsigned char *label, size_t label_len,
+ unsigned char *context, size_t context_len,
+ unsigned char *k_i, size_t h, uint32_t l,
+ unsigned char *ko, size_t ko_len)
+{
+ int ret = 0;
+ EVP_MAC_CTX *ctx = NULL;
+ size_t written = 0, to_write;
+ const unsigned char zero = 0;
+ uint32_t counter, i;
+
+ for (counter = 1; written < ko_len; counter++) {
+ i = be32(counter);
+
+ ctx = EVP_MAC_CTX_dup(ctx_init);
+ if (ctx == NULL)
+ goto done;
+
+ if (!EVP_MAC_update(ctx, (unsigned char *)&i, 4)
+ || !EVP_MAC_update(ctx, label, label_len)
+ || !EVP_MAC_update(ctx, &zero, 1)
+ || !EVP_MAC_update(ctx, context, context_len)
+ || !EVP_MAC_update(ctx, (unsigned char *)&l, 4)
+ || !EVP_MAC_final(ctx, k_i, NULL, h))
+ goto done;
+
+ to_write = ko_len - written;
+ memcpy(ko + written, k_i, MIN(to_write, h));
+ written += h;
+
+ EVP_MAC_CTX_free(ctx);
+ ctx = NULL;
+ }
+
+ ret = 1;
+done:
+ EVP_MAC_CTX_free(ctx);
+ return ret;
+}
+
+static int kbkdf_derive(void *vctx, unsigned char *key, size_t keylen)
+{
+ KBKDF *ctx = (KBKDF *)vctx;
+ int ret = 0;
+ unsigned char *k_i = NULL;
+ uint32_t l = be32(keylen * 8);
+ size_t h = 0;
+
+ /* Label and Context are permitted to be empty. Check everything else. */
+ if (ctx->ctx_init == NULL) {
+ if (ctx->ki_len == 0 || ctx->ki == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET);
+ return 0;
+ }
+ /* Could either be missing MAC or missing message digest -
+ * arbitrarily, I pick this one. */
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MAC);
+ return 0;
+ }
+
+ h = EVP_MAC_size(ctx->ctx_init);
+ if (h == 0)
+ goto done;
+
+ k_i = OPENSSL_zalloc(h);
+ if (k_i == NULL)
+ goto done;
+
+ ret = kbkdf_derive_counter(
+ ctx->ctx_init, ctx->label, ctx->label_len, ctx->context,
+ ctx->context_len, k_i, h, l, key, keylen);
+done:
+ if (ret != 1)
+ OPENSSL_cleanse(key, keylen);
+ OPENSSL_clear_free(k_i, h);
+ return ret;
+}
+
+static int kbkdf_set_buffer(unsigned char **out, size_t *out_len,
+ const OSSL_PARAM *p)
+{
+ if (p->data == NULL || p->data_size == 0)
+ return 1;
+
+ OPENSSL_clear_free(*out, *out_len);
+ *out = NULL;
+ return OSSL_PARAM_get_octet_string(p, (void **)out, 0, out_len);
+}
+
+static int kbkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ KBKDF *ctx = (KBKDF *)vctx;
+ OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx);
+ const OSSL_PARAM *p;
+ OSSL_PARAM mparams[2];
+
+ if (!ossl_prov_macctx_load_from_params(&ctx->ctx_init, params, NULL,
+ NULL, NULL, libctx))
+ return 0;
+ else if (ctx->ctx_init != NULL
+ && !EVP_MAC_is_a(EVP_MAC_CTX_mac(ctx->ctx_init),
+ OSSL_MAC_NAME_HMAC)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MAC);
+ return 0;
+ }
+
+ p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY);
+ if (p != NULL && !kbkdf_set_buffer(&ctx->ki, &ctx->ki_len, p))
+ return 0;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT);
+ if (p != NULL && !kbkdf_set_buffer(&ctx->label, &ctx->label_len, p))
+ return 0;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO);
+ if (p != NULL && !kbkdf_set_buffer(&ctx->context, &ctx->context_len, p))
+ return 0;
+
+ /* Set up digest context, if we can. */
+ if (ctx->ctx_init != NULL && ctx->ki_len != 0) {
+ mparams[0] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
+ ctx->ki, ctx->ki_len);
+ mparams[1] = OSSL_PARAM_construct_end();
+
+ if (!EVP_MAC_CTX_set_params(ctx->ctx_init, mparams)
+ || !EVP_MAC_init(ctx->ctx_init))
+ return 0;
+ }
+
+ return 1;
+}
+
+static const OSSL_PARAM *kbkdf_settable_ctx_params(void)
+{
+ static const OSSL_PARAM known_settable_ctx_params[] = {
+ OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MAC, NULL, 0),
+
+ OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
+ OSSL_PARAM_END,
+ };
+ return known_settable_ctx_params;
+}
+
+static int kbkdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+ OSSL_PARAM *p;
+
+ p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE);
+ if (p == NULL)
+ return -2;
+
+ /* KBKDF can produce results as large as you like. */
+ return OSSL_PARAM_set_size_t(p, SIZE_MAX);
+}
+
+static const OSSL_PARAM *kbkdf_gettable_ctx_params(void)
+{
+ static const OSSL_PARAM known_gettable_ctx_params[] =
+ { OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), OSSL_PARAM_END };
+ return known_gettable_ctx_params;
+}
+
+const OSSL_DISPATCH kdf_kbkdf_functions[] = {
+ { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kbkdf_new },
+ { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kbkdf_free },
+ { OSSL_FUNC_KDF_RESET, (void(*)(void))kbkdf_reset },
+ { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kbkdf_derive },
+ { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS,
+ (void(*)(void))kbkdf_settable_ctx_params },
+ { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kbkdf_set_ctx_params },
+ { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
+ (void(*)(void))kbkdf_gettable_ctx_params },
+ { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kbkdf_get_ctx_params },
+ { 0, NULL },
+};
diff --git a/providers/implementations/kdfs/pbkdf2.c b/providers/implementations/kdfs/pbkdf2.c
new file mode 100644
index 0000000000..68aa0aa7c4
--- /dev/null
+++ b/providers/implementations/kdfs/pbkdf2.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2018-2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+#include <openssl/kdf.h>
+#include <openssl/core_names.h>
+#include "internal/cryptlib.h"
+#include "internal/numbers.h"
+#include "crypto/evp.h"
+#include "internal/provider_ctx.h"
+#include "internal/providercommonerr.h"
+#include "internal/provider_algs.h"
+#include "internal/provider_util.h"
+#include "pbkdf2.h"
+
+/* Constants specified in SP800-132 */
+#define KDF_PBKDF2_MIN_KEY_LEN_BITS 112
+#define KDF_PBKDF2_MAX_KEY_LEN_DIGEST_RATIO 0xFFFFFFFF
+#define KDF_PBKDF2_MIN_ITERATIONS 1000
+#define KDF_PBKDF2_MIN_SALT_LEN (128 / 8)
+
+static OSSL_OP_kdf_newctx_fn kdf_pbkdf2_new;
+static OSSL_OP_kdf_freectx_fn kdf_pbkdf2_free;
+static OSSL_OP_kdf_reset_fn kdf_pbkdf2_reset;
+static OSSL_OP_kdf_derive_fn kdf_pbkdf2_derive;
+static OSSL_OP_kdf_settable_ctx_params_fn kdf_pbkdf2_settable_ctx_params;
+static OSSL_OP_kdf_set_ctx_params_fn kdf_pbkdf2_set_ctx_params;
+
+static int pbkdf2_derive(const char *pass, size_t passlen,
+ const unsigned char *salt, int saltlen, uint64_t iter,
+ const EVP_MD *digest, unsigned char *key,
+ size_t keylen, int extra_checks);
+
+typedef struct {
+ void *provctx;
+ unsigned char *pass;
+ size_t pass_len;
+ unsigned char *salt;
+ size_t salt_len;
+ uint64_t iter;
+ PROV_DIGEST digest;
+ int lower_bound_checks;
+} KDF_PBKDF2;
+
+static void kdf_pbkdf2_init(KDF_PBKDF2 *ctx);
+
+static void *kdf_pbkdf2_new(void *provctx)
+{
+ KDF_PBKDF2 *ctx;
+
+ ctx = OPENSSL_zalloc(sizeof(*ctx));
+ if (ctx == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ ctx->provctx = provctx;
+ kdf_pbkdf2_init(ctx);
+ return ctx;
+}
+
+static void kdf_pbkdf2_cleanup(KDF_PBKDF2 *ctx)
+{
+ ossl_prov_digest_reset(&ctx->digest);
+ OPENSSL_free(ctx->salt);
+ OPENSSL_clear_free(ctx->pass, ctx->pass_len);
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+static void kdf_pbkdf2_free(void *vctx)
+{
+ KDF_PBKDF2 *ctx = (KDF_PBKDF2 *)vctx;
+
+ kdf_pbkdf2_cleanup(ctx);
+ OPENSSL_free(ctx);
+}
+
+static void kdf_pbkdf2_reset(void *vctx)
+{
+ KDF_PBKDF2 *ctx = (KDF_PBKDF2 *)vctx;
+
+ kdf_pbkdf2_cleanup(ctx);
+ kdf_pbkdf2_init(ctx);
+}
+
+static void kdf_pbkdf2_init(KDF_PBKDF2 *ctx)
+{
+ OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
+ OPENSSL_CTX *provctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx);
+
+ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
+ SN_sha1, 0);
+ if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx))
+ /* This is an error, but there is no way to indicate such directly */
+ ossl_prov_digest_reset(&ctx->digest);
+ ctx->iter = PKCS5_DEFAULT_ITER;
+ ctx->lower_bound_checks = kdf_pbkdf2_default_checks;
+}
+
+static int pbkdf2_set_membuf(unsigned char **buffer, size_t *buflen,
+ const OSSL_PARAM *p)
+{
+ OPENSSL_clear_free(*buffer, *buflen);
+ if (p->data_size == 0) {
+ if ((*buffer = OPENSSL_malloc(1)) == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ } else if (p->data != NULL) {
+ *buffer = NULL;
+ if (!OSSL_PARAM_get_octet_string(p, (void **)buffer, 0, buflen))
+ return 0;
+ }
+ return 1;
+}
+
+static int kdf_pbkdf2_derive(void *vctx, unsigned char *key,
+ size_t keylen)
+{
+ KDF_PBKDF2 *ctx = (KDF_PBKDF2 *)vctx;
+ const EVP_MD *md = ossl_prov_digest_md(&ctx->digest);
+
+ if (ctx->pass == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_PASS);
+ return 0;
+ }
+
+ if (ctx->salt == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SALT);
+ return 0;
+ }
+
+ return pbkdf2_derive((char *)ctx->pass, ctx->pass_len,
+ ctx->salt, ctx->salt_len, ctx->iter,
+ md, key, keylen, ctx->lower_bound_checks);
+}
+
+static int kdf_pbkdf2_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ const OSSL_PARAM *p;
+ KDF_PBKDF2 *ctx = vctx;
+ OPENSSL_CTX *provctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx);
+ int pkcs5;
+ uint64_t iter, min_iter;
+
+ if (!ossl_prov_digest