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
#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,
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) {
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;
}
--- /dev/null
+=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
=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)>
#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"
# 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
{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"},
{ "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 },
/* 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
$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
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
--- /dev/null
+/*
+ * 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 }
+};