summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPauli <paul.dale@oracle.com>2020-08-11 10:29:02 +1000
committerPauli <paul.dale@oracle.com>2020-08-14 18:15:12 +1000
commitb7466c1303b2e16815092ae4ef6c97ae1f0f347d (patch)
treea2faf89d6620fe6274bb6d02b854efcd8fde0b12
parentc19e6da9a345b1e14caca23c50a0c7690309e0e4 (diff)
Move PKCS#12 KDF to provider.
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)
-rw-r--r--crypto/err/openssl.txt1
-rw-r--r--crypto/pkcs12/p12_key.c124
-rw-r--r--doc/man7/EVP_KDF-PKCS12KDF.pod86
-rw-r--r--doc/man7/OSSL_PROVIDER-default.pod2
-rw-r--r--include/openssl/core_names.h1
-rw-r--r--providers/common/include/prov/providercommonerr.h1
-rw-r--r--providers/common/provider_err.c2
-rw-r--r--providers/defltprov.c1
-rw-r--r--providers/implementations/include/prov/implementations.h1
-rw-r--r--providers/implementations/kdfs/build.info3
-rw-r--r--providers/implementations/kdfs/pkcs12kdf.c285
11 files changed, 424 insertions, 83 deletions
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 2fa2af529a..c07eee6e7e 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -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
diff --git a/crypto/pkcs12/p12_key.c b/crypto/pkcs12/p12_key.c
index 4849cbd5bc..a40ae4cbe8 100644
--- a/crypto/pkcs12/p12_key.c
+++ b/crypto/pkcs12/p12_key.c
@@ -12,11 +12,9 @@
#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
index 0000000000..68f987b050
--- /dev/null
+++ b/doc/man7/EVP_KDF-PKCS12KDF.pod
@@ -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
diff --git a/doc/man7/OSSL_PROVIDER-default.pod b/doc/man7/OSSL_PROVIDER-default.pod
index 5fe7dbde8c..f82f8d8551 100644
--- a/doc/man7/OSSL_PROVIDER-default.pod
+++ b/doc/man7/OSSL_PROVIDER-default.pod
@@ -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)>
diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h
index 53e68e778b..97c4d65949 100644
--- a/include/openssl/core_names.h
+++ b/include/openssl/core_names.h
@@ -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"
diff --git a/providers/common/include/prov/providercommonerr.h b/providers/common/include/prov/providercommonerr.h
index bdc39e4121..3f3c39ba52 100644
--- a/providers/common/include/prov/providercommonerr.h
+++ b/providers/common/include/prov/providercommonerr.h
@@ -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
diff --git a/providers/common/provider_err.c b/providers/common/provider_err.c
index e65ce96471..ad7ae57157 100644
--- a/providers/common/provider_err.c
+++ b/providers/common/provider_err.c
@@ -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"},
diff --git a/providers/defltprov.c b/providers/defltprov.c
index c34c539726..083373a066 100644
--- a/providers/defltprov.c
+++ b/providers/defltprov.c
@@ -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 },
diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h
index 76053e22b0..f4c2a5adf5 100644
--- a/providers/implementations/include/prov/implementations.h
+++ b/providers/implementations/include/prov/implementations.h
@@ -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
diff --git a/providers/implementations/kdfs/build.info b/providers/implementations/kdfs/build.info
index 3b3884436a..459005def5 100644
--- a/providers/implementations/kdfs/build.info
+++ b/providers/implementations/kdfs/build.info
@@ -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
index 0000000000..2cebc2d240
--- /dev/null
+++ b/providers/implementations/kdfs/pkcs12kdf.c
@@ -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 }
+};