[openssl] master update

Dr. Paul Dale pauli at openssl.org
Tue Sep 28 08:10:19 UTC 2021


The branch master has been updated
       via  2d34e5b2ecf6a5db982c53bb56c62249b7791051 (commit)
       via  c8ffd2201b8685e149dd3244d6772339263d4a17 (commit)
       via  5fae7b432e3e2e14916bdcd1ad0fe594a27628c6 (commit)
       via  4eb27149f066d567393771986f01267707982a7e (commit)
       via  4667b0f0731a8bb8d6236ea18b8c0591016f53d7 (commit)
       via  fc9eda53bcf7d41c8159b7161c663db86dda5481 (commit)
       via  1ffac6ca174d25a61f2e1e70dd0fd1eb7eaacbf5 (commit)
       via  722fe8edf224ecc0921481b47fdd06a54d82e4ff (commit)
      from  8ba65c35ea3af347c3b2adc8e665066b541a1c35 (commit)


- Log -----------------------------------------------------------------
commit 2d34e5b2ecf6a5db982c53bb56c62249b7791051
Author: Pauli <pauli at openssl.org>
Date:   Mon Sep 27 09:20:20 2021 +1000

    test: add some PVK KDF unit test cases
    
    These cases were generated using OpenSSL.
    
    Reviewed-by: Tomas Mraz <tomas at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15968)

commit c8ffd2201b8685e149dd3244d6772339263d4a17
Author: Pauli <pauli at openssl.org>
Date:   Mon Sep 27 09:06:01 2021 +1000

    changes: note that PVK KDF has moved to the legacy provider
    
    Reviewed-by: Tomas Mraz <tomas at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15968)

commit 5fae7b432e3e2e14916bdcd1ad0fe594a27628c6
Author: Pauli <pauli at openssl.org>
Date:   Mon Sep 27 09:05:32 2021 +1000

    doc: note that these KDFs require the legacy provider to be available
    
    Reviewed-by: Tomas Mraz <tomas at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15968)

commit 4eb27149f066d567393771986f01267707982a7e
Author: Pauli <pauli at openssl.org>
Date:   Thu Jul 1 14:48:49 2021 +1000

    doc: include PVK KDFdocumentation in build.info
    
    Reviewed-by: Tomas Mraz <tomas at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15968)

commit 4667b0f0731a8bb8d6236ea18b8c0591016f53d7
Author: Pauli <pauli at openssl.org>
Date:   Thu Jul 1 14:40:44 2021 +1000

    include PVK KDF in legacy provider algorithm list
    
    Reviewed-by: Tomas Mraz <tomas at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15968)

commit fc9eda53bcf7d41c8159b7161c663db86dda5481
Author: Pauli <pauli at openssl.org>
Date:   Thu Jul 1 14:40:27 2021 +1000

    doc: add page for PVK KDF
    
    Reviewed-by: Tomas Mraz <tomas at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15968)

commit 1ffac6ca174d25a61f2e1e70dd0fd1eb7eaacbf5
Author: Pauli <pauli at openssl.org>
Date:   Thu Jul 1 14:11:17 2021 +1000

    pvk: use PVK KDF
    
    Reviewed-by: Tomas Mraz <tomas at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15968)

commit 722fe8edf224ecc0921481b47fdd06a54d82e4ff
Author: Pauli <pauli at openssl.org>
Date:   Thu Jul 1 14:10:04 2021 +1000

    kdf: Add PVK KDF to providers.
    
    Add PIN Verification Key key derevation function to providers.
    
    Reviewed-by: Tomas Mraz <tomas at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15968)

-----------------------------------------------------------------------

Summary of changes:
 CHANGES.md                                         |   6 +
 crypto/pem/pvkfmt.c                                |  45 ++--
 doc/build.info                                     |   6 +
 doc/man7/EVP_KDF-PBKDF1.pod                        |   5 +-
 .../{EVP_KDF-PBKDF1.pod => EVP_KDF-PVKKDF.pod}     |  29 +--
 doc/man7/OSSL_PROVIDER-legacy.pod                  |   2 +
 .../implementations/include/prov/implementations.h |   1 +
 providers/implementations/include/prov/names.h     |   1 +
 providers/implementations/kdfs/build.info          |   3 +
 providers/implementations/kdfs/pvkkdf.c            | 227 +++++++++++++++++++++
 providers/legacyprov.c                             |   1 +
 test/recipes/30-test_evp_data/evpkdf_pvkkdf.txt    |  36 ++++
 12 files changed, 322 insertions(+), 40 deletions(-)
 copy doc/man7/{EVP_KDF-PBKDF1.pod => EVP_KDF-PVKKDF.pod} (59%)
 create mode 100644 providers/implementations/kdfs/pvkkdf.c
 create mode 100644 test/recipes/30-test_evp_data/evpkdf_pvkkdf.txt

diff --git a/CHANGES.md b/CHANGES.md
index dc3008f814..c14bec916d 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -24,6 +24,12 @@ OpenSSL 3.1
 
 ### Changes between 3.0 and 3.1 [xx XXX xxxx]
 
+ * The PVK key derivation function has been moved from b2i_PVK_bio_ex() into
+   the legacy crypto provider as an EVP_KDF. Applications requiring this KDF
+   will need to load the legacy crypto provider.
+
+   *Paul Dale*
+
  * The various OBJ_* functions have been made thread safe.
 
    *Paul Dale*
diff --git a/crypto/pem/pvkfmt.c b/crypto/pem/pvkfmt.c
index 11ac0a7c40..6f5207abd1 100644
--- a/crypto/pem/pvkfmt.c
+++ b/crypto/pem/pvkfmt.c
@@ -23,6 +23,8 @@
 #include <openssl/bn.h>
 #include <openssl/dsa.h>
 #include <openssl/rsa.h>
+#include <openssl/kdf.h>
+#include <openssl/core_names.h>
 #include "internal/cryptlib.h"
 #include "crypto/pem.h"
 #include "crypto/evp.h"
@@ -790,29 +792,34 @@ int ossl_do_PVK_header(const unsigned char **in, unsigned int length,
 }
 
 #ifndef OPENSSL_NO_RC4
-static int derive_pvk_key(unsigned char *key,
+static int derive_pvk_key(unsigned char *key, size_t keylen,
                           const unsigned char *salt, unsigned int saltlen,
                           const unsigned char *pass, int passlen,
                           OSSL_LIB_CTX *libctx, const char *propq)
 {
-    EVP_MD_CTX *mctx = EVP_MD_CTX_new();
-    int rv = 0;
-    EVP_MD *sha1 = NULL;
+    EVP_KDF *kdf;
+    EVP_KDF_CTX *ctx;
+    OSSL_PARAM params[5], *p = params;
+    int rv;
 
-    if ((sha1 = EVP_MD_fetch(libctx, SN_sha1, propq)) == NULL)
-        goto err;
-
-    if (mctx == NULL
-        || !EVP_DigestInit_ex(mctx, sha1, NULL)
-        || !EVP_DigestUpdate(mctx, salt, saltlen)
-        || !EVP_DigestUpdate(mctx, pass, passlen)
-        || !EVP_DigestFinal_ex(mctx, key, NULL))
-        goto err;
+    if ((kdf = EVP_KDF_fetch(libctx, "PVKKDF", propq)) == NULL)
+        return 0;
+    ctx = EVP_KDF_CTX_new(kdf);
+    EVP_KDF_free(kdf);
+    if (ctx == NULL)
+        return 0;
 
-    rv = 1;
-err:
-    EVP_MD_CTX_free(mctx);
-    EVP_MD_free(sha1);
+    *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
+                                             (void *)salt, saltlen);
+    *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD,
+                                             (void *)pass, passlen);
+    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, SN_sha1, 0);
+    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_PROPERTIES,
+                                            (char *)propq, 0);
+    *p = OSSL_PARAM_construct_end();
+
+    rv = EVP_KDF_derive(ctx, key, keylen, params);
+    EVP_KDF_CTX_free(ctx);
     return rv;
 }
 #endif
@@ -852,7 +859,7 @@ static void *do_PVK_body_key(const unsigned char **in,
             ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE);
             goto err;
         }
-        if (!derive_pvk_key(keybuf, p, saltlen,
+        if (!derive_pvk_key(keybuf, sizeof(keybuf), p, saltlen,
                             (unsigned char *)psbuf, inlen, libctx, propq))
             goto err;
         p += saltlen;
@@ -1058,7 +1065,7 @@ static int i2b_PVK(unsigned char **out, const EVP_PKEY *pk, int enclevel,
             ERR_raise(ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ);
             goto error;
         }
-        if (!derive_pvk_key(keybuf, salt, PVK_SALTLEN,
+        if (!derive_pvk_key(keybuf, sizeof(keybuf), salt, PVK_SALTLEN,
                             (unsigned char *)psbuf, inlen, libctx, propq))
             goto error;
         if ((rc4 = EVP_CIPHER_fetch(libctx, "RC4", propq)) == NULL)
diff --git a/doc/build.info b/doc/build.info
index fcf2c1cacf..5f446e3868 100644
--- a/doc/build.info
+++ b/doc/build.info
@@ -4119,6 +4119,10 @@ DEPEND[html/man7/EVP_KDF-PKCS12KDF.html]=man7/EVP_KDF-PKCS12KDF.pod
 GENERATE[html/man7/EVP_KDF-PKCS12KDF.html]=man7/EVP_KDF-PKCS12KDF.pod
 DEPEND[man/man7/EVP_KDF-PKCS12KDF.7]=man7/EVP_KDF-PKCS12KDF.pod
 GENERATE[man/man7/EVP_KDF-PKCS12KDF.7]=man7/EVP_KDF-PKCS12KDF.pod
+DEPEND[html/man7/EVP_KDF-PVKKDF.html]=man7/EVP_KDF-PVKKDF.pod
+GENERATE[html/man7/EVP_KDF-PVKKDF.html]=man7/EVP_KDF-PVKKDF.pod
+DEPEND[man/man7/EVP_KDF-PVKKDF.7]=man7/EVP_KDF-PVKKDF.pod
+GENERATE[man/man7/EVP_KDF-PVKKDF.7]=man7/EVP_KDF-PVKKDF.pod
 DEPEND[html/man7/EVP_KDF-SCRYPT.html]=man7/EVP_KDF-SCRYPT.pod
 GENERATE[html/man7/EVP_KDF-SCRYPT.html]=man7/EVP_KDF-SCRYPT.pod
 DEPEND[man/man7/EVP_KDF-SCRYPT.7]=man7/EVP_KDF-SCRYPT.pod
@@ -4563,6 +4567,7 @@ html/man7/EVP_KDF-KRB5KDF.html \
 html/man7/EVP_KDF-PBKDF1.html \
 html/man7/EVP_KDF-PBKDF2.html \
 html/man7/EVP_KDF-PKCS12KDF.html \
+html/man7/EVP_KDF-PVKKDF.html \
 html/man7/EVP_KDF-SCRYPT.html \
 html/man7/EVP_KDF-SS.html \
 html/man7/EVP_KDF-SSHKDF.html \
@@ -4687,6 +4692,7 @@ man/man7/EVP_KDF-KRB5KDF.7 \
 man/man7/EVP_KDF-PBKDF1.7 \
 man/man7/EVP_KDF-PBKDF2.7 \
 man/man7/EVP_KDF-PKCS12KDF.7 \
+man/man7/EVP_KDF-PVKKDF.7 \
 man/man7/EVP_KDF-SCRYPT.7 \
 man/man7/EVP_KDF-SS.7 \
 man/man7/EVP_KDF-SSHKDF.7 \
diff --git a/doc/man7/EVP_KDF-PBKDF1.pod b/doc/man7/EVP_KDF-PBKDF1.pod
index ae13765211..0d24325cd9 100644
--- a/doc/man7/EVP_KDF-PBKDF1.pod
+++ b/doc/man7/EVP_KDF-PBKDF1.pod
@@ -53,6 +53,8 @@ of candidate passwords.
 No assumption is made regarding the given password; it is simply treated as a
 byte sequence.
 
+The legacy provider needs to be available in order to access this algorithm.
+
 =head1 CONFORMING TO
 
 RFC 8018
@@ -64,7 +66,8 @@ 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>
+L<EVP_KDF(3)/PARAMETERS>,
+L<OSSL_PROVIDER-legacy(7)>
 
 =head1 HISTORY
 
diff --git a/doc/man7/EVP_KDF-PBKDF1.pod b/doc/man7/EVP_KDF-PVKKDF.pod
similarity index 59%
copy from doc/man7/EVP_KDF-PBKDF1.pod
copy to doc/man7/EVP_KDF-PVKKDF.pod
index ae13765211..08aff0c9e7 100644
--- a/doc/man7/EVP_KDF-PBKDF1.pod
+++ b/doc/man7/EVP_KDF-PVKKDF.pod
@@ -2,20 +2,19 @@
 
 =head1 NAME
 
-EVP_KDF-PBKDF1 - The PBKDF1 EVP_KDF implementation
+EVP_KDF-PVKKDF - The PVK EVP_KDF implementation
 
 =head1 DESCRIPTION
 
-Support for computing the B<PBKDF1> password-based KDF through the B<EVP_KDF>
+Support for computing the B<PVK KDF> PIN-based KDF through the B<EVP_KDF>
 API.
 
-The EVP_KDF-PBKDF1 algorithm implements the PBKDF1 password-based key
-derivation function, as described in RFC 8018; it derives a key from a password
-using a salt and iteration count.
+The EVP_KDF-PVKKDF algorithm implements a PVK PIN-based key
+derivation function; it derives a key from a password using a salt.
 
 =head2 Identity
 
-"PBKDF1" is the name for this implementation; it
+"PVKKDF" is the name for this implementation; it
 can be used with the EVP_KDF_fetch() function.
 
 =head2 Supported parameters
@@ -28,10 +27,6 @@ The supported parameters are:
 
 =item "salt" (B<OSSL_KDF_PARAM_SALT>) <octet string>
 
-=item "iter" (B<OSSL_KDF_PARAM_ITER>) <unsigned integer>
-
-This parameter has a default value of 0 and should be set.
-
 =item "properties" (B<OSSL_KDF_PARAM_PROPERTIES>) <UTF8 string>
 
 =item "digest" (B<OSSL_KDF_PARAM_DIGEST>) <UTF8 string>
@@ -43,19 +38,12 @@ These parameters work as described in L<EVP_KDF(3)/PARAMETERS>.
 =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.
+encryption algorithm from a password in the "pass" and a salt in "salt".
 
 No assumption is made regarding the given password; it is simply treated as a
 byte sequence.
 
-=head1 CONFORMING TO
-
-RFC 8018
+The legacy provider needs to be available in order to access this algorithm.
 
 =head1 SEE ALSO
 
@@ -64,7 +52,8 @@ 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>
+L<EVP_KDF(3)/PARAMETERS>,
+L<OSSL_PROVIDER-legacy(7)>
 
 =head1 HISTORY
 
diff --git a/doc/man7/OSSL_PROVIDER-legacy.pod b/doc/man7/OSSL_PROVIDER-legacy.pod
index d2fdfe3676..5724996fdc 100644
--- a/doc/man7/OSSL_PROVIDER-legacy.pod
+++ b/doc/man7/OSSL_PROVIDER-legacy.pod
@@ -87,6 +87,8 @@ Disabled by default. Use I<enable-rc5> config option to enable.
 
 =item PBKDF1
 
+=item PVKKDF
+
 =back
 
 =begin comment
diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h
index e2573ebb4a..66817fa104 100644
--- a/providers/implementations/include/prov/implementations.h
+++ b/providers/implementations/include/prov/implementations.h
@@ -258,6 +258,7 @@ extern const OSSL_DISPATCH ossl_poly1305_functions[];
 /* KDFs / PRFs */
 extern const OSSL_DISPATCH ossl_kdf_pbkdf1_functions[];
 extern const OSSL_DISPATCH ossl_kdf_pbkdf2_functions[];
+extern const OSSL_DISPATCH ossl_kdf_pvk_functions[];
 extern const OSSL_DISPATCH ossl_kdf_pkcs12_functions[];
 #ifndef OPENSSL_NO_SCRYPT
 extern const OSSL_DISPATCH ossl_kdf_scrypt_functions[];
diff --git a/providers/implementations/include/prov/names.h b/providers/implementations/include/prov/names.h
index 1509598ffc..62aa7bd725 100644
--- a/providers/implementations/include/prov/names.h
+++ b/providers/implementations/include/prov/names.h
@@ -261,6 +261,7 @@
 #define PROV_NAMES_SSKDF "SSKDF"
 #define PROV_NAMES_PBKDF1 "PBKDF1"
 #define PROV_NAMES_PBKDF2 "PBKDF2:1.2.840.113549.1.5.12"
+#define PROV_NAMES_PVKKDF "PVKKDF"
 #define PROV_NAMES_SSHKDF "SSHKDF"
 #define PROV_NAMES_X963KDF "X963KDF:X942KDF-CONCAT"
 #define PROV_NAMES_X942KDF_ASN1 "X942KDF-ASN1:X942KDF"
diff --git a/providers/implementations/kdfs/build.info b/providers/implementations/kdfs/build.info
index f4620adce2..ddc3eabca2 100644
--- a/providers/implementations/kdfs/build.info
+++ b/providers/implementations/kdfs/build.info
@@ -7,6 +7,7 @@ $KBKDF_GOAL=../../libdefault.a ../../libfips.a
 $KRB5KDF_GOAL=../../libdefault.a
 $PBKDF1_GOAL=../../liblegacy.a
 $PBKDF2_GOAL=../../libdefault.a ../../libfips.a
+$PVKKDF_GOAL=../../liblegacy.a
 $PKCS12KDF_GOAL=../../libdefault.a
 $SSKDF_GOAL=../../libdefault.a ../../libfips.a
 $SCRYPT_GOAL=../../libdefault.a
@@ -28,6 +29,8 @@ SOURCE[$PBKDF2_GOAL]=pbkdf2.c
 # When the PBKDF2 moves to legacy, this can be removed.
 SOURCE[$PBKDF2_GOAL]=pbkdf2_fips.c
 
+SOURCE[$PBKDF1_GOAL]=pvkkdf.c
+
 SOURCE[$PKCS12KDF_GOAL]=pkcs12kdf.c
 
 SOURCE[$SSKDF_GOAL]=sskdf.c
diff --git a/providers/implementations/kdfs/pvkkdf.c b/providers/implementations/kdfs/pvkkdf.c
new file mode 100644
index 0000000000..2dad6309b9
--- /dev/null
+++ b/providers/implementations/kdfs/pvkkdf.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2018-2021 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/evp.h>
+#include <openssl/core_names.h>
+#include <openssl/proverr.h>
+#include <openssl/err.h>
+#include "prov/provider_ctx.h"
+#include "prov/providercommon.h"
+#include "prov/implementations.h"
+#include "prov/provider_util.h"
+
+static OSSL_FUNC_kdf_newctx_fn kdf_pvk_new;
+static OSSL_FUNC_kdf_freectx_fn kdf_pvk_free;
+static OSSL_FUNC_kdf_reset_fn kdf_pvk_reset;
+static OSSL_FUNC_kdf_derive_fn kdf_pvk_derive;
+static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_pvk_settable_ctx_params;
+static OSSL_FUNC_kdf_set_ctx_params_fn kdf_pvk_set_ctx_params;
+static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_pvk_gettable_ctx_params;
+static OSSL_FUNC_kdf_get_ctx_params_fn kdf_pvk_get_ctx_params;
+
+typedef struct {
+    void *provctx;
+    unsigned char *pass;
+    size_t pass_len;
+    unsigned char *salt;
+    size_t salt_len;
+    PROV_DIGEST digest;
+} KDF_PVK;
+
+static void kdf_pvk_init(KDF_PVK *ctx);
+
+static void *kdf_pvk_new(void *provctx)
+{
+    KDF_PVK *ctx;
+
+    if (!ossl_prov_is_running())
+        return NULL;
+
+    ctx = OPENSSL_zalloc(sizeof(*ctx));
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+    ctx->provctx = provctx;
+    kdf_pvk_init(ctx);
+    return ctx;
+}
+
+static void kdf_pvk_cleanup(KDF_PVK *ctx)
+{
+    ossl_prov_digest_reset(&ctx->digest);
+    OPENSSL_free(ctx->salt);
+    OPENSSL_clear_free(ctx->pass, ctx->pass_len);
+    OPENSSL_cleanse(ctx, sizeof(*ctx));
+}
+
+static void kdf_pvk_free(void *vctx)
+{
+    KDF_PVK *ctx = (KDF_PVK *)vctx;
+
+    if (ctx != NULL) {
+        kdf_pvk_cleanup(ctx);
+        OPENSSL_free(ctx);
+    }
+}
+
+static void kdf_pvk_reset(void *vctx)
+{
+    KDF_PVK *ctx = (KDF_PVK *)vctx;
+    void *provctx = ctx->provctx;
+
+    kdf_pvk_cleanup(ctx);
+    ctx->provctx = provctx;
+    kdf_pvk_init(ctx);
+}
+
+static void kdf_pvk_init(KDF_PVK *ctx)
+{
+    OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
+    OSSL_LIB_CTX *provctx = PROV_LIBCTX_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);
+}
+
+static int pvk_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_pvk_derive(void *vctx, unsigned char *key, size_t keylen,
+                             const OSSL_PARAM params[])
+{
+    KDF_PVK *ctx = (KDF_PVK *)vctx;
+    const EVP_MD *md;
+    EVP_MD_CTX *mctx;
+    int res;
+
+    if (!ossl_prov_is_running() || !kdf_pvk_set_ctx_params(ctx, params))
+        return 0;
+
+    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;
+    }
+
+    md = ossl_prov_digest_md(&ctx->digest);
+    if (md == NULL) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST);
+        return 0;
+    }
+    res = EVP_MD_get_size(md);
+    if (res <= 0) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH);
+        return 0;
+    }
+    if ((size_t)res > keylen) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE);
+        return 0;
+    }
+
+    mctx = EVP_MD_CTX_new();
+    res = mctx != NULL
+          && EVP_DigestInit_ex(mctx, md, NULL)
+          && EVP_DigestUpdate(mctx, ctx->salt, ctx->salt_len)
+          && EVP_DigestUpdate(mctx, ctx->pass, ctx->pass_len)
+          && EVP_DigestFinal_ex(mctx, key, NULL);
+    EVP_MD_CTX_free(mctx);
+    return res;
+}
+
+static int kdf_pvk_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+    const OSSL_PARAM *p;
+    KDF_PVK *ctx = vctx;
+    OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(ctx->provctx);
+
+    if (params == NULL)
+        return 1;
+
+    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 (!pvk_set_membuf(&ctx->pass, &ctx->pass_len, p))
+            return 0;
+
+    if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) {
+        if (!pvk_set_membuf(&ctx->salt, &ctx->salt_len,p))
+            return 0;
+    }
+
+    return 1;
+}
+
+static const OSSL_PARAM *kdf_pvk_settable_ctx_params(ossl_unused void *ctx,
+                                                        ossl_unused void *p_ctx)
+{
+    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_END
+    };
+    return known_settable_ctx_params;
+}
+
+static int kdf_pvk_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_pvk_gettable_ctx_params(ossl_unused void *ctx,
+                                                        ossl_unused void *p_ctx)
+{
+    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 ossl_kdf_pvk_functions[] = {
+    { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_pvk_new },
+    { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_pvk_free },
+    { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_pvk_reset },
+    { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_pvk_derive },
+    { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS,
+      (void(*)(void))kdf_pvk_settable_ctx_params },
+    { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_pvk_set_ctx_params },
+    { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
+      (void(*)(void))kdf_pvk_gettable_ctx_params },
+    { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_pvk_get_ctx_params },
+    { 0, NULL }
+};
diff --git a/providers/legacyprov.c b/providers/legacyprov.c
index a5999c5f8b..93c4223a15 100644
--- a/providers/legacyprov.c
+++ b/providers/legacyprov.c
@@ -145,6 +145,7 @@ static const OSSL_ALGORITHM legacy_ciphers[] = {
 
 static const OSSL_ALGORITHM legacy_kdfs[] = {
     ALG(PROV_NAMES_PBKDF1, ossl_kdf_pbkdf1_functions),
+    ALG(PROV_NAMES_PVKKDF, ossl_kdf_pvk_functions),
     { NULL, NULL, NULL }
 };
 
diff --git a/test/recipes/30-test_evp_data/evpkdf_pvkkdf.txt b/test/recipes/30-test_evp_data/evpkdf_pvkkdf.txt
new file mode 100644
index 0000000000..46ebec4ab2
--- /dev/null
+++ b/test/recipes/30-test_evp_data/evpkdf_pvkkdf.txt
@@ -0,0 +1,36 @@
+#
+# Copyright 2021 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
+
+# Tests start with one of these keywords
+#       Cipher Decrypt Derive Digest Encoding KDF MAC PBE
+#       PrivPubKeyPair Sign Verify VerifyRecover
+# and continue until a blank line. Lines starting with a pound sign are ignored.
+
+# Test cases created using OpenSSL
+Title = PVKKDF tests
+
+Availablein = legacy
+KDF = PVKKDF
+Ctrl.pass = pass:password
+Ctrl.salt = salt:saltsalt
+Ctrl.digest = digest:md5
+Output = AE7CF6D3A33A2117FA4F008D66F6D26F
+
+Availablein = legacy
+KDF = PVKKDF
+Ctrl.pass = pass:password
+Ctrl.salt = salt:salt
+Ctrl.digest = digest:md5
+Output = 67A1E09BB1F83F5007DC119C14D663AA
+
+Availablein = legacy
+KDF = PVKKDF
+Ctrl.pass = pass:password
+Ctrl.salt = salt:saltsalt
+Ctrl.digest = digest:md4
+Output = E85DE988BB00EF61067A0506DFB044EE


More information about the openssl-commits mailing list