The branch master has been updated via 094287551a31ba74eb9bfdb4a808d19f4553371b (commit) via 8bb6fdfc9971557f3aaa4e5dfc4cab0e5e9220a6 (commit) via 0f183675b8ea2490ca5e0b4e66baa27a3e6478ba (commit) from d136db212ecaeb65e399de8d6b30e8b5ecc044d9 (commit)
- Log ----------------------------------------------------------------- commit 094287551a31ba74eb9bfdb4a808d19f4553371b Author: Jon Spillett <jon.spill...@oracle.com> Date: Wed May 19 14:52:16 2021 +1000 Add a test for PKCS5_PBE_keyivgen() Reviewed-by: Shane Lontis <shane.lon...@oracle.com> Reviewed-by: Paul Dale <pa...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/14326) commit 8bb6fdfc9971557f3aaa4e5dfc4cab0e5e9220a6 Author: Jon Spillett <jon.spill...@oracle.com> Date: Thu May 6 15:25:29 2021 +1000 Added PKCS5_PBE_keyivgen_ex() to allow PBKDF1 algorithms to be fetched for a specific library context Reviewed-by: Shane Lontis <shane.lon...@oracle.com> Reviewed-by: Paul Dale <pa...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/14326) commit 0f183675b8ea2490ca5e0b4e66baa27a3e6478ba Author: Jon Spillett <jon.spill...@oracle.com> Date: Fri Feb 26 15:21:47 2021 +1000 Add PBKDF1 to the legacy provider Reviewed-by: Shane Lontis <shane.lon...@oracle.com> Reviewed-by: Paul Dale <pa...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/14326) ----------------------------------------------------------------------- Summary of changes: CHANGES.md | 13 ++ crypto/evp/evp_pbe.c | 12 +- crypto/evp/p5_crpt.c | 73 ++++--- doc/man3/PKCS5_PBE_keyivgen.pod | 11 +- doc/man7/OSSL_PROVIDER-legacy.pod | 8 + include/openssl/core_names.h | 1 + include/openssl/evp.h | 4 + providers/common/build.info | 3 + .../implementations/include/prov/implementations.h | 1 + providers/implementations/kdfs/build.info | 3 + providers/implementations/kdfs/pbkdf1.c | 242 +++++++++++++++++++++ providers/legacyprov.c | 7 + test/build.info | 6 +- test/evp_kdf_test.c | 186 ++++++++++++---- test/pbetest.c | 139 ++++++++++++ .../{04-test_encoder_decoder.t => 05-test_pbe.t} | 13 +- test/recipes/30-test_evp.t | 1 + test/recipes/30-test_evp_data/evpkdf_pbkdf1.txt | 136 ++++++++++++ util/libcrypto.num | 1 + 19 files changed, 765 insertions(+), 95 deletions(-) create mode 100644 providers/implementations/kdfs/pbkdf1.c create mode 100644 test/pbetest.c copy test/recipes/{04-test_encoder_decoder.t => 05-test_pbe.t} (65%) create mode 100644 test/recipes/30-test_evp_data/evpkdf_pbkdf1.txt diff --git a/CHANGES.md b/CHANGES.md index b53216512f..82c027bc73 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -176,6 +176,19 @@ breaking changes, and mappings for the large list of deprecated functions. *Matt Caswell* + * PKCS#5 PBKDF1 key derivation has been moved from PKCS5_PBE_keyivgen() into + the legacy crypto provider as an EVP_KDF. Applications requiring this KDF + will need to load the legacy crypto provider. This includes these PBE + algorithms which use this KDF: + - NID_pbeWithMD2AndDES_CBC + - NID_pbeWithMD5AndDES_CBC + - NID_pbeWithSHA1AndRC2_CBC + - NID_pbeWithMD2AndRC2_CBC + - NID_pbeWithMD5AndRC2_CBC + - NID_pbeWithSHA1AndDES_CBC + + *Jon Spillett* + * Deprecated obsolete EVP_PKEY_CTX_get0_dh_kdf_ukm() and EVP_PKEY_CTX_get0_ecdh_kdf_ukm() functions. diff --git a/crypto/evp/evp_pbe.c b/crypto/evp/evp_pbe.c index 7c73cfc501..6347a0635f 100644 --- a/crypto/evp/evp_pbe.c +++ b/crypto/evp/evp_pbe.c @@ -34,11 +34,11 @@ static STACK_OF(EVP_PBE_CTL) *pbe_algs; static const EVP_PBE_CTL builtin_pbe[] = { {EVP_PBE_TYPE_OUTER, NID_pbeWithMD2AndDES_CBC, - NID_des_cbc, NID_md2, PKCS5_PBE_keyivgen, NULL}, + NID_des_cbc, NID_md2, PKCS5_PBE_keyivgen, PKCS5_PBE_keyivgen_ex}, {EVP_PBE_TYPE_OUTER, NID_pbeWithMD5AndDES_CBC, - NID_des_cbc, NID_md5, PKCS5_PBE_keyivgen, NULL}, + NID_des_cbc, NID_md5, PKCS5_PBE_keyivgen, PKCS5_PBE_keyivgen_ex}, {EVP_PBE_TYPE_OUTER, NID_pbeWithSHA1AndRC2_CBC, - NID_rc2_64_cbc, NID_sha1, PKCS5_PBE_keyivgen, NULL}, + NID_rc2_64_cbc, NID_sha1, PKCS5_PBE_keyivgen, PKCS5_PBE_keyivgen_ex}, {EVP_PBE_TYPE_OUTER, NID_id_pbkdf2, -1, -1, PKCS5_v2_PBKDF2_keyivgen}, @@ -58,11 +58,11 @@ static const EVP_PBE_CTL builtin_pbe[] = { {EVP_PBE_TYPE_OUTER, NID_pbes2, -1, -1, PKCS5_v2_PBE_keyivgen, &PKCS5_v2_PBE_keyivgen_ex}, {EVP_PBE_TYPE_OUTER, NID_pbeWithMD2AndRC2_CBC, - NID_rc2_64_cbc, NID_md2, PKCS5_PBE_keyivgen, NULL}, + NID_rc2_64_cbc, NID_md2, PKCS5_PBE_keyivgen, PKCS5_PBE_keyivgen_ex}, {EVP_PBE_TYPE_OUTER, NID_pbeWithMD5AndRC2_CBC, - NID_rc2_64_cbc, NID_md5, PKCS5_PBE_keyivgen, NULL}, + NID_rc2_64_cbc, NID_md5, PKCS5_PBE_keyivgen, PKCS5_PBE_keyivgen_ex}, {EVP_PBE_TYPE_OUTER, NID_pbeWithSHA1AndDES_CBC, - NID_des_cbc, NID_sha1, PKCS5_PBE_keyivgen, NULL}, + NID_des_cbc, NID_sha1, PKCS5_PBE_keyivgen, PKCS5_PBE_keyivgen_ex}, {EVP_PBE_TYPE_PRF, NID_hmacWithSHA1, -1, NID_sha1, 0}, {EVP_PBE_TYPE_PRF, NID_hmac_md5, -1, NID_md5, 0}, diff --git a/crypto/evp/p5_crpt.c b/crypto/evp/p5_crpt.c index 4d9e894f0f..abf153cb43 100644 --- a/crypto/evp/p5_crpt.c +++ b/crypto/evp/p5_crpt.c @@ -12,6 +12,8 @@ #include "internal/cryptlib.h" #include <openssl/x509.h> #include <openssl/evp.h> +#include <openssl/core_names.h> +#include <openssl/kdf.h> /* * Doesn't do anything now: Builtin PBE algorithms in static table. @@ -21,19 +23,23 @@ void PKCS5_PBE_add(void) { } -int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *cctx, const char *pass, int passlen, - ASN1_TYPE *param, const EVP_CIPHER *cipher, - const EVP_MD *md, int en_de) +int PKCS5_PBE_keyivgen_ex(EVP_CIPHER_CTX *cctx, const char *pass, int passlen, + ASN1_TYPE *param, const EVP_CIPHER *cipher, + const EVP_MD *md, int en_de, OSSL_LIB_CTX *libctx, + const char *propq) { - EVP_MD_CTX *ctx; unsigned char md_tmp[EVP_MAX_MD_SIZE]; unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH]; - int i, ivl, kl; - PBEPARAM *pbe; + int ivl, kl; + PBEPARAM *pbe = NULL; int saltlen, iter; unsigned char *salt; int mdsize; int rv = 0; + EVP_KDF *kdf; + EVP_KDF_CTX *kctx = NULL; + OSSL_PARAM params[5], *p = params; + const char *mdname = EVP_MD_name(md); /* Extract useful info from parameter */ if (param == NULL || param->type != V_ASN1_SEQUENCE || @@ -51,14 +57,12 @@ int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *cctx, const char *pass, int passlen, ivl = EVP_CIPHER_iv_length(cipher); if (ivl < 0 || ivl > 16) { ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH); - PBEPARAM_free(pbe); - return 0; + goto err; } kl = EVP_CIPHER_key_length(cipher); if (kl < 0 || kl > (int)sizeof(md_tmp)) { ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_KEY_LENGTH); - PBEPARAM_free(pbe); - return 0; + goto err; } if (pbe->iter == NULL) @@ -73,33 +77,25 @@ int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *cctx, const char *pass, int passlen, else if (passlen == -1) passlen = strlen(pass); - ctx = EVP_MD_CTX_new(); - if (ctx == NULL) { - ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); + mdsize = EVP_MD_size(md); + if (mdsize < 0) goto err; - } - if (!EVP_DigestInit_ex(ctx, md, NULL)) - goto err; - if (!EVP_DigestUpdate(ctx, pass, passlen)) - goto err; - if (!EVP_DigestUpdate(ctx, salt, saltlen)) + kdf = EVP_KDF_fetch(libctx, OSSL_KDF_NAME_PBKDF1, propq); + kctx = EVP_KDF_CTX_new(kdf); + EVP_KDF_free(kdf); + if (kctx == NULL) goto err; - PBEPARAM_free(pbe); - pbe = NULL; - if (!EVP_DigestFinal_ex(ctx, md_tmp, NULL)) - goto err; - mdsize = EVP_MD_size(md); - if (mdsize < 0) + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD, + (char *)pass, (size_t)passlen); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, + salt, saltlen); + *p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_ITER, &iter); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, + (char *)mdname, 0); + *p = OSSL_PARAM_construct_end(); + if (EVP_KDF_derive(kctx, md_tmp, mdsize, params) != 1) goto err; - for (i = 1; i < iter; i++) { - if (!EVP_DigestInit_ex(ctx, md, NULL)) - goto err; - if (!EVP_DigestUpdate(ctx, md_tmp, mdsize)) - goto err; - if (!EVP_DigestFinal_ex(ctx, md_tmp, NULL)) - goto err; - } memcpy(key, md_tmp, kl); memcpy(iv, md_tmp + (16 - ivl), ivl); if (!EVP_CipherInit_ex(cctx, cipher, NULL, key, iv, en_de)) @@ -109,7 +105,16 @@ int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *cctx, const char *pass, int passlen, OPENSSL_cleanse(iv, EVP_MAX_IV_LENGTH); rv = 1; err: + EVP_KDF_CTX_free(kctx); PBEPARAM_free(pbe); - EVP_MD_CTX_free(ctx); return rv; } + +int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *cctx, const char *pass, int passlen, + ASN1_TYPE *param, const EVP_CIPHER *cipher, + const EVP_MD *md, int en_de) +{ + return PKCS5_PBE_keyivgen_ex(cctx, pass, passlen, param, cipher, md, en_de, + NULL, NULL); +} + diff --git a/doc/man3/PKCS5_PBE_keyivgen.pod b/doc/man3/PKCS5_PBE_keyivgen.pod index 4515346407..72de3153b9 100644 --- a/doc/man3/PKCS5_PBE_keyivgen.pod +++ b/doc/man3/PKCS5_PBE_keyivgen.pod @@ -2,7 +2,7 @@ =head1 NAME -PKCS5_PBE_keyivgen, PKCS5_pbe2_set, PKCS5_pbe2_set_iv, +PKCS5_PBE_keyivgen, PKCS5_PBE_keyivgen_ex, PKCS5_pbe2_set, PKCS5_pbe2_set_iv, PKCS5_pbe2_set_iv_ex, PKCS5_pbe_set, PKCS5_pbe_set_ex, PKCS5_pbe2_set_scrypt, PKCS5_pbe_set0_algor, PKCS5_pbe_set0_algor_ex, PKCS5_v2_PBE_keyivgen, PKCS5_v2_PBE_keyivgen_ex, @@ -17,6 +17,10 @@ PKCS5_pbkdf2_set, PKCS5_pbkdf2_set_ex, EVP_PBE_scrypt, EVP_PBE_scrypt_ex int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, ASN1_TYPE *param, const EVP_CIPHER *cipher, const EVP_MD *md, int en_de); + int PKCS5_PBE_keyivgen_ex(EVP_CIPHER_CTX *cctx, const char *pass, int passlen, + ASN1_TYPE *param, const EVP_CIPHER *cipher, + const EVP_MD *md, int en_de, OSSL_LIB_CTX *libctx, + const char *propq); int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, ASN1_TYPE *param, const EVP_CIPHER *cipher, const EVP_MD *md, int en_de); @@ -79,7 +83,7 @@ PKCS5_pbkdf2_set, PKCS5_pbkdf2_set_ex, EVP_PBE_scrypt, EVP_PBE_scrypt_ex =head2 Key Derivation -PKCS5_PBE_keyivgen() takes a password I<pass> of +PKCS5_PBE_keyivgen() and PKCS5_PBE_keyivgen_ex() take a password I<pass> of length I<passlen>, parameters I<param> and a message digest function I<md_type> and performs a key derivation according to PKCS#5 PBES1. The resulting key is then used to initialise the cipher context I<ctx> with a cipher I<cipher> for @@ -158,6 +162,9 @@ PKCS5_v2_PBE_keyivgen_ex(), EVP_PBE_scrypt_ex(), PKCS5_v2_scrypt_keyivgen_ex(), PKCS5_pbe_set0_algor_ex(), PKCS5_pbe_set_ex(), PKCS5_pbe2_set_iv_ex() and PKCS5_pbkdf2_set_ex() were added in OpenSSL 3.0. +From OpenSSL 3.0 the PBKDF1 algorithm used in PKCS5_PBE_keyivgen() and +PKCS5_PBE_keyivgen_ex() has been moved to the legacy provider as an EVP_KDF. + =head1 COPYRIGHT Copyright 2021 The OpenSSL Project Authors. All Rights Reserved. diff --git a/doc/man7/OSSL_PROVIDER-legacy.pod b/doc/man7/OSSL_PROVIDER-legacy.pod index 1fa86ab2cd..0e2965d618 100644 --- a/doc/man7/OSSL_PROVIDER-legacy.pod +++ b/doc/man7/OSSL_PROVIDER-legacy.pod @@ -79,6 +79,14 @@ Disabled by default. Use I<enable-rc5> config option to enable. =back +=head2 Key Derivation Function (KDF) + +=over 4 + +=item PBKDF1 + +=back + =begin comment When algorithms for other operations start appearing, the diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index c01be930ab..36d9489e90 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -220,6 +220,7 @@ extern "C" { /* Known KDF names */ #define OSSL_KDF_NAME_HKDF "HKDF" +#define OSSL_KDF_NAME_PBKDF1 "PBKDF1" #define OSSL_KDF_NAME_PBKDF2 "PBKDF2" #define OSSL_KDF_NAME_SCRYPT "SCRYPT" #define OSSL_KDF_NAME_SSHKDF "SSHKDF" diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 27e14d07b6..a793db6e0e 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1438,6 +1438,10 @@ int EVP_CIPHER_get_asn1_iv(EVP_CIPHER_CTX *c, ASN1_TYPE *type); int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, ASN1_TYPE *param, const EVP_CIPHER *cipher, const EVP_MD *md, int en_de); +int PKCS5_PBE_keyivgen_ex(EVP_CIPHER_CTX *cctx, const char *pass, int passlen, + ASN1_TYPE *param, const EVP_CIPHER *cipher, + const EVP_MD *md, int en_de, OSSL_LIB_CTX *libctx, + const char *propq); int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen, const unsigned char *salt, int saltlen, int iter, int keylen, unsigned char *out); diff --git a/providers/common/build.info b/providers/common/build.info index e23ff58855..a14bf09037 100644 --- a/providers/common/build.info +++ b/providers/common/build.info @@ -4,4 +4,7 @@ SOURCE[../libcommon.a]=provider_err.c provider_ctx.c $FIPSCOMMON=provider_util.c capabilities.c bio_prov.c digest_to_nid.c\ securitycheck.c provider_seeding.c SOURCE[../libdefault.a]=$FIPSCOMMON securitycheck_default.c +IF[{- !$disabled{module} && !$disabled{shared} -}] + SOURCE[../liblegacy.a]=provider_util.c +ENDIF SOURCE[../libfips.a]=$FIPSCOMMON securitycheck_fips.c diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h index 6afea01df0..ae09ccd506 100644 --- a/providers/implementations/include/prov/implementations.h +++ b/providers/implementations/include/prov/implementations.h @@ -249,6 +249,7 @@ extern const OSSL_DISPATCH ossl_siphash_functions[]; 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_pkcs12_functions[]; #ifndef OPENSSL_NO_SCRYPT diff --git a/providers/implementations/kdfs/build.info b/providers/implementations/kdfs/build.info index 1711466e3f..f4620adce2 100644 --- a/providers/implementations/kdfs/build.info +++ b/providers/implementations/kdfs/build.info @@ -5,6 +5,7 @@ $TLS1_PRF_GOAL=../../libdefault.a ../../libfips.a $HKDF_GOAL=../../libdefault.a ../../libfips.a $KBKDF_GOAL=../../libdefault.a ../../libfips.a $KRB5KDF_GOAL=../../libdefault.a +$PBKDF1_GOAL=../../liblegacy.a $PBKDF2_GOAL=../../libdefault.a ../../libfips.a $PKCS12KDF_GOAL=../../libdefault.a $SSKDF_GOAL=../../libdefault.a ../../libfips.a @@ -20,6 +21,8 @@ SOURCE[$KBKDF_GOAL]=kbkdf.c SOURCE[$KRB5KDF_GOAL]=krb5kdf.c +SOURCE[$PBKDF1_GOAL]=pbkdf1.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. diff --git a/providers/implementations/kdfs/pbkdf1.c b/providers/implementations/kdfs/pbkdf1.c new file mode 100644 index 0000000000..af715efc91 --- /dev/null +++ b/providers/implementations/kdfs/pbkdf1.c @@ -0,0 +1,242 @@ +/* + * Copyright 1999-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/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 <openssl/proverr.h> +#include "internal/cryptlib.h" +#include "internal/numbers.h" +#include "crypto/evp.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_pbkdf1_new; +static OSSL_FUNC_kdf_freectx_fn kdf_pbkdf1_free; +static OSSL_FUNC_kdf_reset_fn kdf_pbkdf1_reset; +static OSSL_FUNC_kdf_derive_fn kdf_pbkdf1_derive; +static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_pbkdf1_settable_ctx_params; +static OSSL_FUNC_kdf_set_ctx_params_fn kdf_pbkdf1_set_ctx_params; +static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_pbkdf1_gettable_ctx_params; +static OSSL_FUNC_kdf_get_ctx_params_fn kdf_pbkdf1_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; +} KDF_PBKDF1; + +/* + * PKCS5 PBKDF1 compatible key/IV generation as specified in: + * https://tools.ietf.org/html/rfc8018#page-10 + */ + +static int kdf_pbkdf1_do_derive(const unsigned char *pass, size_t passlen, + const unsigned char *salt, size_t saltlen, + uint64_t iter, const EVP_MD *md_type, + unsigned char *out, size_t n) +{ + uint64_t i; + int mdsize, ret = 0; + unsigned char md_tmp[EVP_MAX_MD_SIZE]; + EVP_MD_CTX *ctx = NULL; + + ctx = EVP_MD_CTX_new(); + if (ctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EVP_DigestInit_ex(ctx, md_type, NULL) + || !EVP_DigestUpdate(ctx, pass, passlen) + || !EVP_DigestUpdate(ctx, salt, saltlen) + || !EVP_DigestFinal_ex(ctx, md_tmp, NULL)) + goto err; + mdsize = EVP_MD_size(md_type); + if (mdsize < 0) + goto err; + for (i = 1; i < iter; i++) { + if (!EVP_DigestInit_ex(ctx, md_type, NULL)) + goto err; + if (!EVP_DigestUpdate(ctx, md_tmp, mdsize)) + goto err; + if (!EVP_DigestFinal_ex(ctx, md_tmp, NULL)) + goto err; + } + + memcpy(out, md_tmp, n); + ret = 1; +err: + EVP_MD_CTX_free(ctx); + return ret; +} + +static void *kdf_pbkdf1_new(void *provctx) +{ + KDF_PBKDF1 *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; + return ctx; +} + +static void kdf_pbkdf1_cleanup(KDF_PBKDF1 *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_pbkdf1_free(void *vctx) +{ + KDF_PBKDF1 *ctx = (KDF_PBKDF1 *)vctx; + + if (ctx != NULL) { + kdf_pbkdf1_cleanup(ctx); + OPENSSL_free(ctx); + } +} + +static void kdf_pbkdf1_reset(void *vctx) +{ + KDF_PBKDF1 *ctx = (KDF_PBKDF1 *)vctx; + void *provctx = ctx->provctx; + + kdf_pbkdf1_cleanup(ctx); + ctx->provctx = provctx; +} + +static int kdf_pbkdf1_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_pbkdf1_derive(void *vctx, unsigned char *key, size_t keylen, + const OSSL_PARAM params[]) +{ + KDF_PBKDF1 *ctx = (KDF_PBKDF1 *)vctx; + const EVP_MD *md; + + if (!ossl_prov_is_running() || !kdf_pbkdf1_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); + return kdf_pbkdf1_do_derive(ctx->pass, ctx->pass_len, ctx->salt, ctx->salt_len, + ctx->iter, md, key, keylen); +} + +static int kdf_pbkdf1_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + KDF_PBKDF1 *ctx = vctx; + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, libctx)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PASSWORD)) != NULL) + if (!kdf_pbkdf1_set_membuf(&ctx->pass, &ctx->pass_len, p)) + return 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) + if (!kdf_pbkdf1_set_membuf(&ctx->salt, &ctx->salt_len,p)) + 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_pbkdf1_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_uint64(OSSL_KDF_PARAM_ITER, NULL), + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +static int kdf_pbkdf1_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_pbkdf1_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_pbkdf1_functions[] = { + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_pbkdf1_new }, + { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_pbkdf1_free }, + { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_pbkdf1_reset }, + { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_pbkdf1_derive }, + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, + (void(*)(void))kdf_pbkdf1_settable_ctx_params }, + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_pbkdf1_set_ctx_params }, + { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, + (void(*)(void))kdf_pbkdf1_gettable_ctx_params }, + { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_pbkdf1_get_ctx_params }, + { 0, NULL } +}; diff --git a/providers/legacyprov.c b/providers/legacyprov.c index 1f137a721f..b5fc5f523f 100644 --- a/providers/legacyprov.c +++ b/providers/legacyprov.c @@ -143,6 +143,11 @@ static const OSSL_ALGORITHM legacy_ciphers[] = { { NULL, NULL, NULL } }; +static const OSSL_ALGORITHM legacy_kdfs[] = { + ALG("PBKDF1", ossl_kdf_pbkdf1_functions), + { NULL, NULL, NULL } +}; + static const OSSL_ALGORITHM *legacy_query(void *provctx, int operation_id, int *no_cache) { @@ -152,6 +157,8 @@ static const OSSL_ALGORITHM *legacy_query(void *provctx, int operation_id, return legacy_digests; case OSSL_OP_CIPHER: return legacy_ciphers; + case OSSL_OP_KDF: + return legacy_kdfs; } return NULL; } diff --git a/test/build.info b/test/build.info index 183c972602..f91f7a49f5 100644 --- a/test/build.info +++ b/test/build.info @@ -32,7 +32,7 @@ IF[{- !$disabled{tests} -}] sanitytest rsa_complex exdatatest bntest \ ecstresstest gmdifftest pbelutest \ destest mdc2test \ - exptest \ + exptest pbetest \ evp_pkey_provided_test evp_test evp_extra_test evp_extra_test2 \ evp_fetch_prov_test evp_libctx_test ossl_store_test \ v3nametest v3ext \ @@ -121,6 +121,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[exptest]=../include ../apps/include DEPEND[exptest]=../libcrypto libtestutil.a + SOURCE[pbetest]=pbetest.c + INCLUDE[pbetest]=../include ../apps/include + DEPEND[pbetest]=../libcrypto libtestutil.a + SOURCE[fatalerrtest]=fatalerrtest.c helpers/ssltestlib.c INCLUDE[fatalerrtest]=../include ../apps/include DEPEND[fatalerrtest]=../libcrypto ../libssl libtestutil.a diff --git a/test/evp_kdf_test.c b/test/evp_kdf_test.c index 1bed159227..1dea980f00 100644 --- a/test/evp_kdf_test.c +++ b/test/evp_kdf_test.c @@ -34,6 +34,9 @@ static OSSL_PARAM *construct_tls1_prf_params(const char *digest, const char *sec OSSL_PARAM *params = OPENSSL_malloc(sizeof(OSSL_PARAM) * 4); OSSL_PARAM *p = params; + if (params == NULL) + return NULL; + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, (char *)digest, 0); *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SECRET, @@ -60,8 +63,8 @@ static int test_kdf_tls1_prf(void) params = construct_tls1_prf_params("sha256", "secret", "seed"); - ret = - TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_TLS1_PRF)) + ret = TEST_ptr(params) + && TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_TLS1_PRF)) && TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out), params), 0) && TEST_mem_eq(out, sizeof(out), expected, sizeof(expected)); @@ -78,8 +81,8 @@ static int test_kdf_tls1_prf_invalid_digest(void) params = construct_tls1_prf_params("blah", "secret", "seed"); - ret = - TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_TLS1_PRF)) + ret = TEST_ptr(params) + && TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_TLS1_PRF)) && TEST_false(EVP_KDF_CTX_set_params(kctx, params)); EVP_KDF_CTX_free(kctx); @@ -97,8 +100,8 @@ static int test_kdf_tls1_prf_zero_output_size(void) params = construct_tls1_prf_params("sha256", "secret", "seed"); /* Negative test - derive should fail */ - ret = - TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_TLS1_PRF)) + ret = TEST_ptr(params) + && TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_TLS1_PRF)) && TEST_true(EVP_KDF_CTX_set_params(kctx, params)) && TEST_int_eq(EVP_KDF_derive(kctx, out, 0, NULL), 0); @@ -116,8 +119,8 @@ static int test_kdf_tls1_prf_empty_secret(void) params = construct_tls1_prf_params("sha256", "", "seed"); - ret = - TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_TLS1_PRF)) + ret = TEST_ptr(params) + && TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_TLS1_PRF)) && TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out), params), 0); EVP_KDF_CTX_free(kctx); @@ -134,8 +137,8 @@ static int test_kdf_tls1_prf_1byte_secret(void) params = construct_tls1_prf_params("sha256", "1", "seed"); - ret = - TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_TLS1_PRF)) + ret = TEST_ptr(params) + && TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_TLS1_PRF)) && TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out), params), 0); EVP_KDF_CTX_free(kctx); @@ -153,8 +156,8 @@ static int test_kdf_tls1_prf_empty_seed(void) params = construct_tls1_prf_params("sha256", "secret", ""); /* Negative test - derive should fail */ - ret = - TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_TLS1_PRF)) + ret = TEST_ptr(params) + && TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_TLS1_PRF)) && TEST_true(EVP_KDF_CTX_set_params(kctx, params)) && TEST_int_eq(EVP_KDF_derive(kctx, out, sizeof(out), NULL), 0); @@ -172,8 +175,8 @@ static int test_kdf_tls1_prf_1byte_seed(void) params = construct_tls1_prf_params("sha256", "secret", "1"); - ret = - TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_TLS1_PRF)) + ret = TEST_ptr(params) + && TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_TLS1_PRF)) && TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out), params), 0); EVP_KDF_CTX_free(kctx); @@ -187,6 +190,9 @@ static OSSL_PARAM *construct_hkdf_params(char *digest, char *key, OSSL_PARAM *params = OPENSSL_malloc(sizeof(OSSL_PARAM) * 5); OSSL_PARAM *p = params; + if (params == NULL) + return NULL; + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, digest, 0); *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, @@ -203,7 +209,7 @@ static OSSL_PARAM *construct_hkdf_params(char *digest, char *key, static int test_kdf_hkdf(void) { int ret; - EVP_KDF_CTX *kctx; + EVP_KDF_CTX *kctx = NULL; unsigned char out[10]; OSSL_PARAM *params; static const unsigned char expected[sizeof(out)] = { @@ -212,8 +218,8 @@ static int test_kdf_hkdf(void) params = construct_hkdf_params("sha256", "secret", 6, "salt", "label"); - ret = - TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)) + ret = TEST_ptr(params) + && TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)) && TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out), params), 0) && TEST_mem_eq(out, sizeof(out), expected, sizeof(expected)); @@ -225,13 +231,13 @@ static int test_kdf_hkdf(void) static int test_kdf_hkdf_invalid_digest(void) { int ret; - EVP_KDF_CTX *kctx; + EVP_KDF_CTX *kctx = NULL; OSSL_PARAM *params; params = construct_hkdf_params("blah", "secret", 6, "salt", "label"); - ret = - TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)) + ret = TEST_ptr(params) + && TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)) && TEST_false(EVP_KDF_CTX_set_params(kctx, params)); EVP_KDF_CTX_free(kctx); @@ -242,15 +248,15 @@ static int test_kdf_hkdf_invalid_digest(void) static int test_kdf_hkdf_zero_output_size(void) { int ret; - EVP_KDF_CTX *kctx; + EVP_KDF_CTX *kctx = NULL; unsigned char out[10]; OSSL_PARAM *params; params = construct_hkdf_params("sha256", "secret", 6, "salt", "label"); /* Negative test - derive should fail */ - ret = - TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)) + ret = TEST_ptr(params) + && TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)) && TEST_true(EVP_KDF_CTX_set_params(kctx, params)) && TEST_int_eq(EVP_KDF_derive(kctx, out, 0, NULL), 0); @@ -262,14 +268,14 @@ static int test_kdf_hkdf_zero_output_size(void) static int test_kdf_hkdf_empty_key(void) { int ret; - EVP_KDF_CTX *kctx; + EVP_KDF_CTX *kctx = NULL; unsigned char out[10]; OSSL_PARAM *params; params = construct_hkdf_params("sha256", "", 0, "salt", "label"); - ret = - TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)) + ret = TEST_ptr(params) + && TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)) && TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out), params), 0); EVP_KDF_CTX_free(kctx); @@ -280,14 +286,14 @@ static int test_kdf_hkdf_empty_key(void) static int test_kdf_hkdf_1byte_key(void) { int ret; - EVP_KDF_CTX *kctx; + EVP_KDF_CTX *kctx = NULL; unsigned char out[10]; OSSL_PARAM *params; params = construct_hkdf_params("sha256", "1", 1, "salt", "label"); - ret = - TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)) + ret = TEST_ptr(params) + && TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)) && TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out), params), 0); EVP_KDF_CTX_free(kctx); @@ -298,14 +304,14 @@ static int test_kdf_hkdf_1byte_key(void) static int test_kdf_hkdf_empty_salt(void) { int ret; - EVP_KDF_CTX *kctx; + EVP_KDF_CTX *kctx = NULL; unsigned char out[10]; OSSL_PARAM *params; params = construct_hkdf_params("sha256", "secret", 6, "", "label"); - ret = - TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)) + ret = TEST_ptr(params) + && TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)) && TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out), params), 0); EVP_KDF_CTX_free(kctx); @@ -313,12 +319,74 @@ static int test_kdf_hkdf_empty_salt(void) return ret; } +static OSSL_PARAM *construct_pbkdf1_params(char *pass, char *digest, char *salt, + unsigned int *iter) +{ + OSSL_PARAM *params = OPENSSL_malloc(sizeof(OSSL_PARAM) * 5); + OSSL_PARAM *p = params; + + if (params == NULL) + return NULL; + + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD, + (unsigned char *)pass, strlen(pass)); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, + (unsigned char *)salt, strlen(salt)); + *p++ = OSSL_PARAM_construct_uint(OSSL_KDF_PARAM_ITER, iter); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, + digest, 0); + *p = OSSL_PARAM_construct_end(); + + return params; +} + +static int test_kdf_pbkdf1(void) +{ + int ret = 0; + EVP_KDF_CTX *kctx = NULL; + unsigned char out[25]; + unsigned int iterations = 4096; + OSSL_PARAM *params; + OSSL_PROVIDER *prov = NULL; + const unsigned char expected[sizeof(out)] = { + 0xfb, 0x83, 0x4d, 0x36, 0x6d, 0xbc, 0x53, 0x87, 0x35, 0x1b, 0x34, 0x75, + 0x95, 0x88, 0x32, 0x4f, 0x3e, 0x82, 0x81, 0x01, 0x21, 0x93, 0x64, 0x00, + 0xcc + }; + + /* PBKDF1 only available in the legacy provider */ + prov = OSSL_PROVIDER_load(NULL, "legacy"); + if (prov == NULL) + return TEST_skip("PBKDF1 only available in legacy provider"); + + params = construct_pbkdf1_params("passwordPASSWORDpassword", "sha256", + "saltSALTsaltSALTsaltSALTsaltSALTsalt", + &iterations); + + if (!TEST_ptr(params) + || !TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF1)) + || !TEST_true(EVP_KDF_CTX_set_params(kctx, params)) + || !TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out), NULL), 0) + || !TEST_mem_eq(out, sizeof(out), expected, sizeof(expected))) + goto err; + + ret = 1; +err: + EVP_KDF_CTX_free(kctx); + OPENSSL_free(params); + OSSL_PROVIDER_unload(prov); + return ret; +} + static OSSL_PARAM *construct_pbkdf2_params(char *pass, char *digest, char *salt, unsigned int *iter, int *mode) { OSSL_PARAM *params = OPENSSL_malloc(sizeof(OSSL_PARAM) * 6); OSSL_PARAM *p = params; + if (params == NULL) + return NULL; + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD, (unsigned char *)pass, strlen(pass)); *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, @@ -335,7 +403,7 @@ static OSSL_PARAM *construct_pbkdf2_params(char *pass, char *digest, char *salt, static int test_kdf_pbkdf2(void) { int ret = 0; - EVP_KDF_CTX *kctx; + EVP_KDF_CTX *kctx = NULL; unsigned char out[25]; unsigned int iterations = 4096; int mode = 0; @@ -351,7 +419,8 @@ static int test_kdf_pbkdf2(void) "saltSALTsaltSALTsaltSALTsaltSALTsalt", &iterations, &mode); - if (!TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF2)) + if (!TEST_ptr(params) + || !TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF2)) || !TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out), params), 0) || !TEST_mem_eq(out, sizeof(out), expected, sizeof(expected))) goto err; @@ -366,7 +435,7 @@ err: static int test_kdf_pbkdf2_small_output(void) { int ret = 0; - EVP_KDF_CTX *kctx; + EVP_KDF_CTX *kctx = NULL; unsigned char out[25]; unsigned int iterations = 4096; int mode = 0; @@ -376,7 +445,8 @@ static int test_kdf_pbkdf2_small_output(void) "saltSALTsaltSALTsaltSALTsaltSALTsalt", &iterations, &mode); - if (!TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF2)) + if (!TEST_ptr(params) + || !TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF2)) || !TEST_true(EVP_KDF_CTX_set_params(kctx, params)) /* A key length that is too small should fail */ || !TEST_int_eq(EVP_KDF_derive(kctx, out, 112 / 8 - 1, NULL), 0)) @@ -392,7 +462,7 @@ err: static int test_kdf_pbkdf2_large_output(void) { int ret = 0; - EVP_KDF_CTX *kctx; + EVP_KDF_CTX *kctx = NULL; unsigned char out[25]; size_t len = 0; unsigned int iterations = 4096; @@ -406,7 +476,8 @@ static int test_kdf_pbkdf2_large_output(void) "saltSALTsaltSALTsaltSALTsaltSALTsalt", &iterations, &mode); - if (!TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF2)) + if (!TEST_ptr(params) + || !TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF2)) /* A key length that is too large should fail */ || !TEST_true(EVP_KDF_CTX_set_params(kctx, params)) || (len != 0 && !TEST_int_eq(EVP_KDF_derive(kctx, out, len, NULL), 0))) @@ -422,7 +493,7 @@ err: static int test_kdf_pbkdf2_small_salt(void) { int ret = 0; - EVP_KDF_CTX *kctx; + EVP_KDF_CTX *kctx = NULL; unsigned int iterations = 4096; int mode = 0; OSSL_PARAM *params; @@ -431,7 +502,8 @@ static int test_kdf_pbkdf2_small_salt(void) "saltSALT", &iterations, &mode); - if (!TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF2)) + if (!TEST_ptr(params) + || !TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF2)) /* A salt that is too small should fail */ || !TEST_false(EVP_KDF_CTX_set_params(kctx, params))) goto err; @@ -446,7 +518,7 @@ err: static int test_kdf_pbkdf2_small_iterations(void) { int ret = 0; - EVP_KDF_CTX *kctx; + EVP_KDF_CTX *kctx = NULL; unsigned int iterations = 1; int mode = 0; OSSL_PARAM *params; @@ -455,7 +527,8 @@ static int test_kdf_pbkdf2_small_iterations(void) "saltSALTsaltSALTsaltSALTsaltSALTsalt", &iterations, &mode); - if (!TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF2)) + if (!TEST_ptr(params) + || !TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF2)) /* An iteration count that is too small should fail */ || !TEST_false(EVP_KDF_CTX_set_params(kctx, params))) goto err; @@ -470,7 +543,7 @@ err: static int test_kdf_pbkdf2_small_salt_pkcs5(void) { int ret = 0; - EVP_KDF_CTX *kctx; + EVP_KDF_CTX *kctx = NULL; unsigned char out[25]; unsigned int iterations = 4096; int mode = 1; @@ -481,7 +554,8 @@ static int test_kdf_pbkdf2_small_salt_pkcs5(void) "saltSALT", &iterations, &mode); - if (!TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF2)) + if (!TEST_ptr(params) + || !TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF2)) /* A salt that is too small should pass in pkcs5 mode */ || !TEST_true(EVP_KDF_CTX_set_params(kctx, params)) || !TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out), NULL), 0)) @@ -506,7 +580,7 @@ err: static int test_kdf_pbkdf2_small_iterations_pkcs5(void) { int ret = 0; - EVP_KDF_CTX *kctx; + EVP_KDF_CTX *kctx = NULL; unsigned char out[25]; unsigned int iterations = 1; int mode = 1; @@ -517,7 +591,8 @@ static int test_kdf_pbkdf2_small_iterations_pkcs5(void) "saltSALTsaltSALTsaltSALTsaltSALTsalt", &iterations, &mode); - if (!TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF2)) + if (!TEST_ptr(params) + || !TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF2)) /* An iteration count that is too small will pass in pkcs5 mode */ || !TEST_true(EVP_KDF_CTX_set_params(kctx, params)) || !TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out), NULL), 0)) @@ -542,7 +617,7 @@ err: static int test_kdf_pbkdf2_invalid_digest(void) { int ret = 0; - EVP_KDF_CTX *kctx; + EVP_KDF_CTX *kctx = NULL; unsigned int iterations = 4096; int mode = 0; OSSL_PARAM *params; @@ -551,7 +626,8 @@ static int test_kdf_pbkdf2_invalid_digest(void) "saltSALTsaltSALTsaltSALTsaltSALTsalt", &iterations, &mode); - if (!TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF2)) + if (!TEST_ptr(params) + || !TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_PBKDF2)) /* Unknown digest should fail */ || !TEST_false(EVP_KDF_CTX_set_params(kctx, params))) goto err; @@ -831,6 +907,9 @@ static OSSL_PARAM *construct_kbkdf_params(char *digest, char *mac, unsigned char OSSL_PARAM *params = OPENSSL_malloc(sizeof(OSSL_PARAM) * 7); OSSL_PARAM *p = params; + if (params == NULL) + return NULL; + *p++ = OSSL_PARAM_construct_utf8_string( OSSL_KDF_PARAM_DIGEST, digest, 0); *p++ = OSSL_PARAM_construct_utf8_string( @@ -857,6 +936,8 @@ static int test_kdf_kbkdf_invalid_digest(void) static unsigned char key[] = {0x01}; params = construct_kbkdf_params("blah", "HMAC", key, 1, "prf", "test"); + if (!TEST_ptr(params)) + return 0; /* Negative test case - set_params should fail */ kctx = get_kdfbyname("KBKDF"); @@ -877,6 +958,8 @@ static int test_kdf_kbkdf_invalid_mac(void) static unsigned char key[] = {0x01}; params = construct_kbkdf_params("sha256", "blah", key, 1, "prf", "test"); + if (!TEST_ptr(params)) + return 0; /* Negative test case - set_params should fail */ kctx = get_kdfbyname("KBKDF"); @@ -898,6 +981,8 @@ static int test_kdf_kbkdf_empty_key(void) unsigned char result[32] = { 0 }; params = construct_kbkdf_params("sha256", "HMAC", key, 0, "prf", "test"); + if (!TEST_ptr(params)) + return 0; /* Negative test case - derive should fail */ kctx = get_kdfbyname("KBKDF"); @@ -920,6 +1005,8 @@ static int test_kdf_kbkdf_1byte_key(void) unsigned char result[32] = { 0 }; params = construct_kbkdf_params("sha256", "HMAC", key, 1, "prf", "test"); + if (!TEST_ptr(params)) + return 0; kctx = get_kdfbyname("KBKDF"); ret = TEST_ptr(kctx) @@ -940,6 +1027,8 @@ static int test_kdf_kbkdf_zero_output_size(void) unsigned char result[32] = { 0 }; params = construct_kbkdf_params("sha256", "HMAC", key, 1, "prf", "test"); + if (!TEST_ptr(params)) + return 0; /* Negative test case - derive should fail */ kctx = get_kdfbyname("KBKDF"); @@ -1394,6 +1483,7 @@ int setup_tests(void) ADD_TEST(test_kdf_hkdf_empty_key); ADD_TEST(test_kdf_hkdf_1byte_key); ADD_TEST(test_kdf_hkdf_empty_salt); + ADD_TEST(test_kdf_pbkdf1); ADD_TEST(test_kdf_pbkdf2); ADD_TEST(test_kdf_pbkdf2_small_output); ADD_TEST(test_kdf_pbkdf2_large_output); diff --git a/test/pbetest.c b/test/pbetest.c new file mode 100644 index 0000000000..81dbfc1388 --- /dev/null +++ b/test/pbetest.c @@ -0,0 +1,139 @@ +/* + * Copyright 2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (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 <string.h> + +#include "testutil.h" + +#include <openssl/evp.h> +#include <openssl/x509.h> +#include <openssl/rc4.h> +#include <openssl/md5.h> + +#if !defined OPENSSL_NO_RC4 && !defined OPENSSL_NO_MD5 +# if !defined OPENSSL_NO_DES && !defined OPENSSL_NO_SHA1 + +static const char pbe_password[] = "MyVoiceIsMyPassport"; + +static unsigned char pbe_salt[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, +}; + +static const int pbe_iter = 1000; + +static unsigned char pbe_plaintext[] = { + 0x57, 0x65, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, + 0x6c, 0x6c, 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, + 0x6f, 0x66, 0x20, 0x73, 0x74, 0x61, 0x72, 0x73, +}; +# endif +#endif + +/* Expected output generated using OpenSSL 1.1.1 */ + +#if !defined OPENSSL_NO_RC4 && !defined OPENSSL_NO_MD5 +static const unsigned char pbe_ciphertext_rc4_md5[] = { + 0x21, 0x90, 0xfa, 0xee, 0x95, 0x66, 0x59, 0x45, + 0xfa, 0x1e, 0x9f, 0xe2, 0x25, 0xd2, 0xf9, 0x71, + 0x94, 0xe4, 0x3d, 0xc9, 0x7c, 0xb0, 0x07, 0x23, +}; +#endif + +#if !defined OPENSSL_NO_DES && !defined OPENSSL_NO_SHA1 +static const unsigned char pbe_ciphertext_des_sha1[] = { + 0xce, 0x4b, 0xb0, 0x0a, 0x7b, 0x48, 0xd7, 0xe3, + 0x9a, 0x9f, 0x46, 0xd6, 0x41, 0x42, 0x4b, 0x44, + 0x36, 0x45, 0x5f, 0x60, 0x8f, 0x3c, 0xd0, 0x55, + 0xd0, 0x8d, 0xa9, 0xab, 0x78, 0x5b, 0x63, 0xaf, +}; +#endif + +#if !defined OPENSSL_NO_RC4 && !defined OPENSSL_NO_MD5 +# if !defined OPENSSL_NO_DES && !defined OPENSSL_NO_SHA1 +static int test_pkcs5_pbe(const EVP_CIPHER *cipher, const EVP_MD *md, + const unsigned char *exp, const int exp_len) +{ + int ret = 0; + EVP_CIPHER_CTX *ctx; + X509_ALGOR *algor = NULL; + int i, outlen; + unsigned char out[32]; + + ctx = EVP_CIPHER_CTX_new(); + if (!TEST_ptr(ctx)) + goto err; + + algor = X509_ALGOR_new(); + if (!TEST_ptr(algor)) + goto err; + + if (!TEST_true(PKCS5_pbe_set0_algor(algor, EVP_CIPHER_nid(cipher), pbe_iter, + pbe_salt, sizeof(pbe_salt))) + || !TEST_true(PKCS5_PBE_keyivgen(ctx, pbe_password, strlen(pbe_password), + algor->parameter, cipher, md, 1)) + || !TEST_true(EVP_CipherUpdate(ctx, out, &i, pbe_plaintext, + sizeof(pbe_plaintext)))) + goto err; + outlen = i; + + if (!TEST_true(EVP_CipherFinal_ex(ctx, out + i, &i))) + goto err; + outlen += i; + + if (!TEST_mem_eq(out, outlen, exp, exp_len)) + goto err; + + /* Decrypt */ + + if (!TEST_true(PKCS5_PBE_keyivgen(ctx, pbe_password, strlen(pbe_password), + algor->parameter, cipher, md, 0)) + || !TEST_true(EVP_CipherUpdate(ctx, out, &i, exp, exp_len))) + goto err; + + outlen = i; + if (!TEST_true(EVP_CipherFinal_ex(ctx, out + i, &i))) + goto err; + + if (!TEST_mem_eq(out, outlen, pbe_plaintext, sizeof(pbe_plaintext))) + goto err; + + ret = 1; +err: + EVP_CIPHER_CTX_free(ctx); + X509_ALGOR_free(algor); + return ret; +} +# endif +#endif + +#if !defined OPENSSL_NO_RC4 && !defined OPENSSL_NO_MD5 +static int test_pkcs5_pbe_rc4_md5(void) +{ + return test_pkcs5_pbe(EVP_rc4(), EVP_md5(), pbe_ciphertext_rc4_md5, sizeof(pbe_ciphertext_rc4_md5)); +} +#endif + +#if !defined OPENSSL_NO_DES && !defined OPENSSL_NO_SHA1 +static int test_pkcs5_pbe_des_sha1(void) +{ + return test_pkcs5_pbe(EVP_des_cbc(), EVP_sha1(), pbe_ciphertext_des_sha1, sizeof(pbe_ciphertext_des_sha1)); +} +#endif + +int setup_tests(void) +{ +#if !defined OPENSSL_NO_RC4 && !defined OPENSSL_NO_MD5 + ADD_TEST(test_pkcs5_pbe_rc4_md5); +#endif +#if !defined OPENSSL_NO_DES && !defined OPENSSL_NO_SHA1 + ADD_TEST(test_pkcs5_pbe_des_sha1); +#endif + + return 1; +} diff --git a/test/recipes/04-test_encoder_decoder.t b/test/recipes/05-test_pbe.t similarity index 65% copy from test/recipes/04-test_encoder_decoder.t copy to test/recipes/05-test_pbe.t index 2041eb1fb9..76319f1151 100644 --- a/test/recipes/04-test_encoder_decoder.t +++ b/test/recipes/05-test_pbe.t @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2020 The OpenSSL Project Authors. All Rights Reserved. +# 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 @@ -10,14 +10,19 @@ use strict; use warnings; use OpenSSL::Test::Simple; +use OpenSSL::Test; +use OpenSSL::Test::Utils; use OpenSSL::Test qw/:DEFAULT srctop_file bldtop_dir/; use Cwd qw(abs_path); -setup("test_encoder_decoder"); +setup("test_pbe"); + +plan skip_all => "PKCS5 PBE only available in legacy provider" + if disabled("legacy"); plan tests => 1; -$ENV{OPENSSL_MODULES} = abs_path(bldtop_dir("providers")); $ENV{OPENSSL_CONF} = abs_path(srctop_file("test", "default-and-legacy.cnf")); -ok(run(test(["endecode_test"]))); +ok(run(test((["pbetest"])), "Running PBE test")); + diff --git a/test/recipes/30-test_evp.t b/test/recipes/30-test_evp.t index 8a5c26629c..73077142cd 100644 --- a/test/recipes/30-test_evp.t +++ b/test/recipes/30-test_evp.t @@ -44,6 +44,7 @@ my @files = qw( evpciph_aes_wrap.txt evpciph_des3_common.txt evpkdf_hkdf.txt + evpkdf_pbkdf1.txt evpkdf_pbkdf2.txt evpkdf_ss.txt evpkdf_ssh.txt diff --git a/test/recipes/30-test_evp_data/evpkdf_pbkdf1.txt b/test/recipes/30-test_evp_data/evpkdf_pbkdf1.txt new file mode 100644 index 0000000000..1e362fdeb9 --- /dev/null +++ b/test/recipes/30-test_evp_data/evpkdf_pbkdf1.txt @@ -0,0 +1,136 @@ +# +# 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. + +Title = PBKDF1 tests + +Availablein = legacy +KDF = PBKDF1 +Ctrl.pass = pass:password +Ctrl.salt = salt:saltsalt +Ctrl.iter = iter:1 +Ctrl.digest = digest:md2 +Output = 2C5DAEBD49984F34642ACC09BAD696D7 + +Availablein = legacy +KDF = PBKDF1 +Ctrl.pass = pass:password +Ctrl.salt = salt:saltsalt +Ctrl.iter = iter:1 +Ctrl.digest = digest:md5 +Output = FDBDF3419FFF98BDB0241390F62A9DB3 + +Availablein = legacy +KDF = PBKDF1 +Ctrl.pass = pass:password +Ctrl.salt = salt:saltsalt +Ctrl.iter = iter:1 +Ctrl.digest = digest:sha1 +Output = CAB86DD6261710891E8CB56EE3625691 + +Availablein = legacy +KDF = PBKDF1 +Ctrl.pass = pass:password +Ctrl.salt = salt:saltsalt +Ctrl.iter = iter:2 +Ctrl.digest = digest:md2 +Output = FD7999A1AB54B01B4FC39389A5FE820D + +Availablein = legacy +KDF = PBKDF1 +Ctrl.pass = pass:password +Ctrl.salt = salt:saltsalt +Ctrl.iter = iter:2 +Ctrl.digest = digest:md5 +Output = 3D4A8D4FB4C6E8686B21D36142902966 + +Availablein = legacy +KDF = PBKDF1 +Ctrl.pass = pass:password +Ctrl.salt = salt:saltsalt +Ctrl.iter = iter:2 +Ctrl.digest = digest:sha1 +Output = E3A8DFCF2EEA6DC81D2AD154274FAAE9 + +Availablein = legacy +KDF = PBKDF1 +Ctrl.pass = pass:password +Ctrl.salt = salt:saltsalt +Ctrl.iter = iter:4096 +Ctrl.digest = digest:md2 +Output = 94E4671F438BD6C441C5B120C6CC79CA + +Availablein = legacy +KDF = PBKDF1 +Ctrl.pass = pass:password +Ctrl.salt = salt:saltsalt +Ctrl.iter = iter:4096 +Ctrl.digest = digest:md5 +Output = 3283ED8F8D037045157DA055BFF84A02 + +Availablein = legacy +KDF = PBKDF1 +Ctrl.pass = pass:password +Ctrl.salt = salt:saltsalt +Ctrl.iter = iter:4096 +Ctrl.digest = digest:sha1 +Output = 3CB0C21E81127F5BFF2EEA2B5DC3F31D + +Availablein = legacy +KDF = PBKDF1 +Ctrl.pass = pass:passwordPASSWORDpassword +Ctrl.salt = salt:saltSALT +Ctrl.iter = iter:65537 +Ctrl.digest = digest:md2 +Output = 36DAA8DEB8B471B26AA8CE064A81E54F + +Availablein = legacy +KDF = PBKDF1 +Ctrl.pass = pass:passwordPASSWORDpassword +Ctrl.salt = salt:saltSALT +Ctrl.iter = iter:65537 +Ctrl.digest = digest:md5 +Output = 763F3BA457E3F9ED088B04B5361D7CCA + +Availablein = legacy +KDF = PBKDF1 +Ctrl.pass = pass:passwordPASSWORDpassword +Ctrl.salt = salt:saltSALT +Ctrl.iter = iter:65537 +Ctrl.digest = digest:sha1 +Output = B2B4635718AAAD9FEF23FE328EB83ECF + +Title = PBKDF1 tests for empty inputs + +Availablein = legacy +KDF = PBKDF1 +Ctrl.pass = pass: +Ctrl.salt = salt:saltsalt +Ctrl.iter = iter:1 +Ctrl.digest = digest:md2 +Output = 8ECD1C4C1D57C415295784CCD4686905 + +Availablein = legacy +KDF = PBKDF1 +Ctrl.pass = pass: +Ctrl.salt = salt:saltsalt +Ctrl.iter = iter:1 +Ctrl.digest = digest:md5 +Output = F3D07DE5EFB5E2C3EAFC16B0CF7E07FA + +Availablein = legacy +KDF = PBKDF1 +Ctrl.pass = pass: +Ctrl.salt = salt:saltsalt +Ctrl.iter = iter:1 +Ctrl.digest = digest:sha1 +Output = 2C2ABACE4BD8BB19F67113DA146DBB8C diff --git a/util/libcrypto.num b/util/libcrypto.num index c0c9ee7024..0ac771216c 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5413,3 +5413,4 @@ BIO_get_line 5540 3_0_0 EXIST::FUNCTION: OSSL_LIB_CTX_new_from_dispatch 5541 3_0_0 EXIST::FUNCTION: OSSL_LIB_CTX_new_child 5542 3_0_0 EXIST::FUNCTION: OSSL_PROVIDER_get0_dispatch 5543 3_0_0 EXIST::FUNCTION: +PKCS5_PBE_keyivgen_ex 5544 3_0_0 EXIST::FUNCTION: