]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Move PKCS#12 KDF to provider.
authorPauli <paul.dale@oracle.com>
Tue, 11 Aug 2020 00:29:02 +0000 (10:29 +1000)
committerPauli <paul.dale@oracle.com>
Fri, 14 Aug 2020 08:15:12 +0000 (18:15 +1000)
This KDF is defined in RFC7292 in appendix B.  It is widely used in PKCS#12
and should be provided.

Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/12624)

crypto/err/openssl.txt
crypto/pkcs12/p12_key.c
doc/man7/EVP_KDF-PKCS12KDF.pod [new file with mode: 0644]
doc/man7/OSSL_PROVIDER-default.pod
include/openssl/core_names.h
providers/common/include/prov/providercommonerr.h
providers/common/provider_err.c
providers/defltprov.c
providers/implementations/include/prov/implementations.h
providers/implementations/kdfs/build.info
providers/implementations/kdfs/pkcs12kdf.c [new file with mode: 0644]

index 2fa2af529a683c3a011ec79f2e0ea9d7c19f9af4..c07eee6e7e33fb284c0b84429ad11e810a917390 100644 (file)
@@ -2874,6 +2874,7 @@ PROV_R_INVALID_CUSTOM_LENGTH:111:invalid custom length
 PROV_R_INVALID_DATA:115:invalid data
 PROV_R_INVALID_DIGEST:122:invalid digest
 PROV_R_INVALID_DIGEST_LENGTH:166:invalid digest length
+PROV_R_INVALID_DIGEST_SIZE:218:invalid digest size
 PROV_R_INVALID_ITERATION_COUNT:123:invalid iteration count
 PROV_R_INVALID_IVLEN:116:invalid ivlen
 PROV_R_INVALID_IV_LENGTH:109:invalid iv length
index 4849cbd5bc2452fb28780fa2141c5e92258a9f04..a40ae4cbe89a65f4c46f3d5362d7203d0dae32db 100644 (file)
 #include <openssl/pkcs12.h>
 #include <openssl/bn.h>
 #include <openssl/trace.h>
-
-/* PKCS12 compatible key/IV generation */
-#ifndef min
-# define min(a,b) ((a) < (b) ? (a) : (b))
-#endif
+#include <openssl/kdf.h>
+#include <openssl/core_names.h>
+#include "internal/provider.h"
 
 int PKCS12_key_gen_asc(const char *pass, int passlen, unsigned char *salt,
                        int saltlen, int id, int iter, int n,
@@ -68,16 +66,37 @@ int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt,
                        int saltlen, int id, int iter, int n,
                        unsigned char *out, const EVP_MD *md_type)
 {
-    unsigned char *B = NULL, *D = NULL, *I = NULL, *p = NULL, *Ai = NULL;
-    int Slen, Plen, Ilen;
-    int i, j, u, v;
-    int ret = 0;
-    EVP_MD_CTX *ctx = NULL;
-    unsigned char *tmpout = out;
-    int tmpn = n;
+    int res = 0;
+    EVP_KDF *kdf;
+    EVP_KDF_CTX *ctx;
+    OSSL_PARAM params[6], *p = params;
+
+    if (n <= 0)
+        return 0;
 
-    ctx = EVP_MD_CTX_new();
+    /*
+     * The parameter query isn't available but the library context can be
+     * extracted from the passed digest.
+     */
+    kdf = EVP_KDF_fetch(ossl_provider_library_context(EVP_MD_provider(md_type)),
+                        "PKCS12KDF", NULL);
+    if (kdf == NULL)
+        return 0;
+    ctx = EVP_KDF_CTX_new(kdf);
+    EVP_KDF_free(kdf);
     if (ctx == NULL)
+        return 0;
+
+    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
+                                            (char *)EVP_MD_name(md_type), 0);
+    *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD,
+                                             pass, passlen);
+    *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
+                                             salt, saltlen);
+    *p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_PKCS12_ID, &id);
+    *p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_ITER, &iter);
+    *p = OSSL_PARAM_construct_end();
+    if (!EVP_KDF_CTX_set_params(ctx, params))
         goto err;
 
     OSSL_TRACE_BEGIN(PKCS12_KEYGEN) {
@@ -89,77 +108,16 @@ int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt,
         BIO_hex_string(trc_out, 0, saltlen, salt, saltlen);
         BIO_printf(trc_out, "\n");
     } OSSL_TRACE_END(PKCS12_KEYGEN);
-    v = EVP_MD_block_size(md_type);
-    u = EVP_MD_size(md_type);
-    if (u < 0 || v <= 0)
-        goto err;
-    D = OPENSSL_malloc(v);
-    Ai = OPENSSL_malloc(u);
-    B = OPENSSL_malloc(v + 1);
-    Slen = v * ((saltlen + v - 1) / v);
-    if (passlen)
-        Plen = v * ((passlen + v - 1) / v);
-    else
-        Plen = 0;
-    Ilen = Slen + Plen;
-    I = OPENSSL_malloc(Ilen);
-    if (D == NULL || Ai == NULL || B == NULL || I == NULL)
-        goto err;
-    for (i = 0; i < v; i++)
-        D[i] = id;
-    p = I;
-    for (i = 0; i < Slen; i++)
-        *p++ = salt[i % saltlen];
-    for (i = 0; i < Plen; i++)
-        *p++ = pass[i % passlen];
-    for (;;) {
-        if (!EVP_DigestInit_ex(ctx, md_type, NULL)
-            || !EVP_DigestUpdate(ctx, D, v)
-            || !EVP_DigestUpdate(ctx, I, Ilen)
-            || !EVP_DigestFinal_ex(ctx, Ai, NULL))
-            goto err;
-        for (j = 1; j < iter; j++) {
-            if (!EVP_DigestInit_ex(ctx, md_type, NULL)
-                || !EVP_DigestUpdate(ctx, Ai, u)
-                || !EVP_DigestFinal_ex(ctx, Ai, NULL))
-                goto err;
-        }
-        memcpy(out, Ai, min(n, u));
-        if (u >= n) {
-            OSSL_TRACE_BEGIN(PKCS12_KEYGEN) {
-                BIO_printf(trc_out, "Output KEY (length %d)\n", tmpn);
-                BIO_hex_string(trc_out, 0, tmpn, tmpout, tmpn);
-                BIO_printf(trc_out, "\n");
-            } OSSL_TRACE_END(PKCS12_KEYGEN);
-            ret = 1;
-            goto end;
-        }
-        n -= u;
-        out += u;
-        for (j = 0; j < v; j++)
-            B[j] = Ai[j % u];
-        for (j = 0; j < Ilen; j += v) {
-            int k;
-            unsigned char *Ij = I + j;
-            uint16_t c = 1;
 
-            /* Work out Ij = Ij + B + 1 */
-            for (k = v - 1; k >= 0; k--) {
-                c += Ij[k] + B[k];
-                Ij[k] = (unsigned char)c;
-                c >>= 8;
-            }
-        }
+    if (EVP_KDF_derive(ctx, out, (size_t)n)) {
+        res = 1;
+        OSSL_TRACE_BEGIN(PKCS12_KEYGEN) {
+            BIO_printf(trc_out, "Output KEY (length %d)\n", n);
+            BIO_hex_string(trc_out, 0, n, out, n);
+            BIO_printf(trc_out, "\n");
+        } OSSL_TRACE_END(PKCS12_KEYGEN);
     }
-
  err:
-    PKCS12err(PKCS12_F_PKCS12_KEY_GEN_UNI, ERR_R_MALLOC_FAILURE);
-
- end:
-    OPENSSL_free(Ai);
-    OPENSSL_free(B);
-    OPENSSL_free(D);
-    OPENSSL_free(I);
-    EVP_MD_CTX_free(ctx);
-    return ret;
+    EVP_KDF_CTX_free(ctx);
+    return res;
 }
diff --git a/doc/man7/EVP_KDF-PKCS12KDF.pod b/doc/man7/EVP_KDF-PKCS12KDF.pod
new file mode 100644 (file)
index 0000000..68f987b
--- /dev/null
@@ -0,0 +1,86 @@
+=pod
+
+=head1 NAME
+
+EVP_KDF-PKCS12KDF - The PKCS#12 EVP_KDF implementation
+
+=head1 DESCRIPTION
+
+Support for computing the B<PKCS#12> password-based KDF through the B<EVP_KDF>
+API.
+
+The EVP_KDF-PKCS12KDF algorithm implements the PKCS#12 password-based key
+derivation function, as described in appendix B of RFC 7292 (PKCS #12:
+Personal Information Exchange Syntax); it derives a key from a password
+using a salt, iteration count and the intended usage.
+
+=head2 Identity
+
+"PKCS12KDF" is the name for this implementation; it
+can be used with the EVP_KDF_fetch() function.
+
+=head2 Supported parameters
+
+The supported parameters are:
+
+=over 4
+
+=item "pass" (B<OSSL_KDF_PARAM_PASSWORD>) <octet string>
+
+=item "salt" (B<OSSL_KDF_PARAM_SALT>) <octet string>
+
+=item "iter" (B<OSSL_KDF_PARAM_ITER>) <unsigned integer>
+
+=item "properties" (B<OSSL_KDF_PARAM_PROPERTIES>) <UTF8 string>
+
+=item "digest" (B<OSSL_KDF_PARAM_DIGEST>) <UTF8 string>
+
+These parameters work as described in L<EVP_KDF(3)/PARAMETERS>.
+
+=item "id" (B<OSSL_KDF_PARAM_PKCS12_ID>) <integer>
+
+This parameter is used to specify the intended usage of the output bits, as per
+RFC 7292 section B.3.
+
+=back
+
+=head1 NOTES
+
+A typical application of this algorithm is to derive keying material for an
+encryption algorithm from a password in the "pass", a salt in "salt",
+and an iteration count.
+
+Increasing the "iter" parameter slows down the algorithm which makes it
+harder for an attacker to perform a brute force attack using a large number
+of candidate passwords.
+
+No assumption is made regarding the given password; it is simply treated as a
+byte sequence.
+
+=head1 CONFORMING TO
+
+RFC7292
+
+=head1 SEE ALSO
+
+L<EVP_KDF(3)>,
+L<EVP_KDF_CTX_new(3)>,
+L<EVP_KDF_CTX_free(3)>,
+L<EVP_KDF_CTX_set_params(3)>,
+L<EVP_KDF_derive(3)>,
+L<EVP_KDF(3)/PARAMETERS>
+
+=head1 HISTORY
+
+This functionality was added to OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2020 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
+L<https://www.openssl.org/source/license.html>.
+
+=cut
index 5fe7dbde8c354299dd97dfa44b04c8390d059b11..f82f8d8551bba243a92d3b04ea8473823dbedc2f 100644 (file)
@@ -124,6 +124,8 @@ The OpenSSL default provider supports these operations and algorithms:
 
 =item PBKDF2, see L<EVP_KDF-PBKDF2(7)>
 
+=item PKCS12KDF, see L<EVP_KDF-PKCS12KDF(7)>
+
 =item SSHKDF, see L<EVP_KDF-SSHKDF(7)>
 
 =item TLS1-PRF, see L<EVP_KDF-TLS1_PRF(7)>
index 53e68e778b7ed3be52fe98bc95bc49aba83c425c..97c4d65949d114f80330067143aa5ace228311b5 100644 (file)
@@ -178,6 +178,7 @@ extern "C" {
 #define OSSL_KDF_PARAM_SIZE         "size"      /* size_t */
 #define OSSL_KDF_PARAM_CIPHER       OSSL_ALG_PARAM_CIPHER     /* utf8 string */
 #define OSSL_KDF_PARAM_CONSTANT     "constant"  /* octet string */
+#define OSSL_KDF_PARAM_PKCS12_ID    "id"        /* int */
 
 /* Known KDF names */
 #define OSSL_KDF_NAME_HKDF          "HKDF"
index bdc39e4121de0c2cb4e488fa77a97f82a66b1d4f..3f3c39ba52320607816cbf7410169d370097a710 100644 (file)
@@ -88,6 +88,7 @@ int ERR_load_PROV_strings(void);
 # define PROV_R_INVALID_DATA                              115
 # define PROV_R_INVALID_DIGEST                            122
 # define PROV_R_INVALID_DIGEST_LENGTH                     166
+# define PROV_R_INVALID_DIGEST_SIZE                       218
 # define PROV_R_INVALID_ITERATION_COUNT                   123
 # define PROV_R_INVALID_IVLEN                             116
 # define PROV_R_INVALID_IV_LENGTH                         109
index e65ce96471a9ef555f5303e52b8352d9da241228..ad7ae571572b4f046054649b61687d33243c02eb 100644 (file)
@@ -79,6 +79,8 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_DIGEST), "invalid digest"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_DIGEST_LENGTH),
     "invalid digest length"},
+    {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_DIGEST_SIZE),
+    "invalid digest size"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_ITERATION_COUNT),
     "invalid iteration count"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_IVLEN), "invalid ivlen"},
index c34c5397260eff641bfcee99af7aabe7eca0f6a0..083373a0666b69f742b06e244ab06ece3a00e312 100644 (file)
@@ -316,6 +316,7 @@ static const OSSL_ALGORITHM deflt_kdfs[] = {
     { "HKDF", "provider=default", kdf_hkdf_functions },
     { "SSKDF", "provider=default", kdf_sskdf_functions },
     { "PBKDF2", "provider=default", kdf_pbkdf2_functions },
+    { "PKCS12KDF", "provider=default", kdf_pkcs12_functions },
     { "SSHKDF", "provider=default", kdf_sshkdf_functions },
     { "X963KDF", "provider=default", kdf_x963_kdf_functions },
     { "TLS1-PRF", "provider=default", kdf_tls1_prf_functions },
index 76053e22b086049dc4331cf4397978de51ef57e7..f4c2a5adf5453e88a84bc07c77a40e959480b68f 100644 (file)
@@ -244,6 +244,7 @@ extern const OSSL_DISPATCH poly1305_functions[];
 
 /* KDFs / PRFs */
 extern const OSSL_DISPATCH kdf_pbkdf2_functions[];
+extern const OSSL_DISPATCH kdf_pkcs12_functions[];
 #ifndef OPENSSL_NO_SCRYPT
 extern const OSSL_DISPATCH kdf_scrypt_functions[];
 #endif
index 3b3884436a4cde5d5cfa261cb7631f7ed2052d9e..459005def5e3f6724842ac21a9aaa3c41c3fcc57 100644 (file)
@@ -6,6 +6,7 @@ $HKDF_GOAL=../../libimplementations.a
 $KBKDF_GOAL=../../libimplementations.a
 $KRB5KDF_GOAL=../../libimplementations.a
 $PBKDF2_GOAL=../../libimplementations.a
+$PKCS12KDF_GOAL=../../libimplementations.a
 $SSKDF_GOAL=../../libimplementations.a
 $SCRYPT_GOAL=../../libimplementations.a
 $SSHKDF_GOAL=../../libimplementations.a
@@ -25,6 +26,8 @@ SOURCE[$PBKDF2_GOAL]=pbkdf2.c
 SOURCE[../../libfips.a]=pbkdf2_fips.c
 SOURCE[../../libnonfips.a]=pbkdf2_fips.c
 
+SOURCE[$PKCS12KDF_GOAL]=pkcs12kdf.c
+
 SOURCE[$SSKDF_GOAL]=sskdf.c
 
 SOURCE[$SCRYPT_GOAL]=scrypt.c
diff --git a/providers/implementations/kdfs/pkcs12kdf.c b/providers/implementations/kdfs/pkcs12kdf.c
new file mode 100644 (file)
index 0000000..2cebc2d
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Copyright 1999-2020 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 <openssl/trace.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.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 "prov/provider_ctx.h"
+#include "prov/providercommonerr.h"
+#include "prov/implementations.h"
+#include "prov/provider_util.h"
+
+static OSSL_FUNC_kdf_newctx_fn kdf_pkcs12_new;
+static OSSL_FUNC_kdf_freectx_fn kdf_pkcs12_free;
+static OSSL_FUNC_kdf_reset_fn kdf_pkcs12_reset;
+static OSSL_FUNC_kdf_derive_fn kdf_pkcs12_derive;
+static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_pkcs12_settable_ctx_params;
+static OSSL_FUNC_kdf_set_ctx_params_fn kdf_pkcs12_set_ctx_params;
+static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_pkcs12_gettable_ctx_params;
+static OSSL_FUNC_kdf_get_ctx_params_fn kdf_pkcs12_get_ctx_params;
+
+typedef struct {
+    void *provctx;
+    PROV_DIGEST digest;
+    unsigned char *pass;
+    size_t pass_len;
+    unsigned char *salt;
+    size_t salt_len;
+    uint64_t iter;
+    int id;
+} KDF_PKCS12;
+
+/* PKCS12 compatible key/IV generation */
+
+static int pkcs12kdf_derive(const unsigned char *pass, size_t passlen,
+                            const unsigned char *salt, size_t saltlen,
+                            int id, uint64_t iter, const EVP_MD *md_type,
+                            unsigned char *out, size_t n)
+{
+    unsigned char *B = NULL, *D = NULL, *I = NULL, *p = NULL, *Ai = NULL;
+    size_t Slen, Plen, Ilen;
+    size_t i, j, k, u, v;
+    uint64_t iter_cnt;
+    int ret = 0, ui, vi;
+    EVP_MD_CTX *ctx = NULL;
+
+    ctx = EVP_MD_CTX_new();
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        goto end;
+    }
+    vi = EVP_MD_block_size(md_type);
+    ui = EVP_MD_size(md_type);
+    if (ui < 0 || vi <= 0) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_SIZE);
+        goto end;
+    }
+    u = (size_t)ui;
+    v = (size_t)vi;
+    D = OPENSSL_malloc(v);
+    Ai = OPENSSL_malloc(u);
+    B = OPENSSL_malloc(v + 1);
+    Slen = v * ((saltlen + v - 1) / v);
+    if (passlen != 0)
+        Plen = v * ((passlen + v - 1) / v);
+    else
+        Plen = 0;
+    Ilen = Slen + Plen;
+    I = OPENSSL_malloc(Ilen);
+    if (D == NULL || Ai == NULL || B == NULL || I == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        goto end;
+    }
+    for (i = 0; i < v; i++)
+        D[i] = id;
+    p = I;
+    for (i = 0; i < Slen; i++)
+        *p++ = salt[i % saltlen];
+    for (i = 0; i < Plen; i++)
+        *p++ = pass[i % passlen];
+    for (;;) {
+        if (!EVP_DigestInit_ex(ctx, md_type, NULL)
+            || !EVP_DigestUpdate(ctx, D, v)
+            || !EVP_DigestUpdate(ctx, I, Ilen)
+            || !EVP_DigestFinal_ex(ctx, Ai, NULL))
+            goto end;
+        for (iter_cnt = 1; iter_cnt < iter; iter_cnt++) {
+            if (!EVP_DigestInit_ex(ctx, md_type, NULL)
+                || !EVP_DigestUpdate(ctx, Ai, u)
+                || !EVP_DigestFinal_ex(ctx, Ai, NULL))
+                goto end;
+        }
+        memcpy(out, Ai, n < u ? n : u);
+        if (u >= n) {
+            ret = 1;
+            break;
+        }
+        n -= u;
+        out += u;
+        for (j = 0; j < v; j++)
+            B[j] = Ai[j % u];
+        for (j = 0; j < Ilen; j += v) {
+            unsigned char *Ij = I + j;
+            uint16_t c = 1;
+
+            /* Work out Ij = Ij + B + 1 */
+            for (k = v; k > 0;) {
+                k--;
+                c += Ij[k] + B[k];
+                Ij[k] = (unsigned char)c;
+                c >>= 8;
+            }
+        }
+    }
+
+ end:
+    OPENSSL_free(Ai);
+    OPENSSL_free(B);
+    OPENSSL_free(D);
+    OPENSSL_free(I);
+    EVP_MD_CTX_free(ctx);
+    return ret;
+}
+
+static void *kdf_pkcs12_new(void *provctx)
+{
+    KDF_PKCS12 *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 kdf_pkcs12_cleanup(KDF_PKCS12 *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_pkcs12_free(void *vctx)
+{
+    KDF_PKCS12 *ctx = (KDF_PKCS12 *)vctx;
+
+    if (ctx != NULL) {
+        kdf_pkcs12_cleanup(ctx);
+        OPENSSL_free(ctx);
+    }
+}
+
+static void kdf_pkcs12_reset(void *vctx)
+{
+    KDF_PKCS12 *ctx = (KDF_PKCS12 *)vctx;
+    void *provctx = ctx->provctx;
+
+    kdf_pkcs12_cleanup(ctx);
+    ctx->provctx = provctx;
+}
+
+static int pkcs12kdf_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_pkcs12_derive(void *vctx, unsigned char *key,
+                             size_t keylen)
+{
+    KDF_PKCS12 *ctx = (KDF_PKCS12 *)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 pkcs12kdf_derive(ctx->pass, ctx->pass_len, ctx->salt, ctx->salt_len,
+                            ctx->id, ctx->iter, md, key, keylen);
+}
+
+static int kdf_pkcs12_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+    const OSSL_PARAM *p;
+    KDF_PKCS12 *ctx = vctx;
+    OPENSSL_CTX *provctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx);
+
+    if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx))
+        return 0;
+
+    if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PASSWORD)) != NULL)
+        if (!pkcs12kdf_set_membuf(&ctx->pass, &ctx->pass_len, p))
+            return 0;
+
+    if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL)
+        if (!pkcs12kdf_set_membuf(&ctx->salt, &ctx->salt_len,p))
+            return 0;
+
+    if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PKCS12_ID)) != NULL)
+        if (!OSSL_PARAM_get_int(p, &ctx->id))
+            return 0;
+
+    if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_ITER)) != NULL)
+        if (!OSSL_PARAM_get_uint64(p, &ctx->iter))
+            return 0;
+    return 1;
+}
+
+static const OSSL_PARAM *kdf_pkcs12_settable_ctx_params(void *provctx)
+{
+    static const OSSL_PARAM known_settable_ctx_params[] = {
+        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_PASSWORD, NULL, 0),
+        OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0),
+        OSSL_PARAM_uint64(OSSL_KDF_PARAM_ITER, NULL),
+        OSSL_PARAM_int(OSSL_KDF_PARAM_PKCS12_ID, NULL),
+        OSSL_PARAM_END
+    };
+    return known_settable_ctx_params;
+}
+
+static int kdf_pkcs12_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+    OSSL_PARAM *p;
+
+    if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL)
+        return OSSL_PARAM_set_size_t(p, SIZE_MAX);
+    return -2;
+}
+
+static const OSSL_PARAM *kdf_pkcs12_gettable_ctx_params(void *provctx)
+{
+    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_pkcs12_functions[] = {
+    { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_pkcs12_new },
+    { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_pkcs12_free },
+    { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_pkcs12_reset },
+    { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_pkcs12_derive },
+    { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS,
+      (void(*)(void))kdf_pkcs12_settable_ctx_params },
+    { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_pkcs12_set_ctx_params },
+    { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
+      (void(*)(void))kdf_pkcs12_gettable_ctx_params },
+    { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_pkcs12_get_ctx_params },
+    { 0, NULL }
+};