diff options
-rw-r--r-- | CHANGES.md | 13 | ||||
-rw-r--r-- | crypto/evp/p5_crpt.c | 78 | ||||
-rw-r--r-- | doc/man3/PKCS5_PBE_keyivgen.pod | 3 | ||||
-rw-r--r-- | doc/man7/OSSL_PROVIDER-legacy.pod | 8 | ||||
-rw-r--r-- | include/openssl/core_names.h | 1 | ||||
-rw-r--r-- | providers/common/build.info | 3 | ||||
-rw-r--r-- | providers/implementations/include/prov/implementations.h | 1 | ||||
-rw-r--r-- | providers/implementations/kdfs/build.info | 3 | ||||
-rw-r--r-- | providers/implementations/kdfs/pbkdf1.c | 242 | ||||
-rw-r--r-- | providers/legacyprov.c | 7 | ||||
-rw-r--r-- | test/evp_kdf_test.c | 186 | ||||
-rw-r--r-- | test/helpers/pkcs12.c | 2 | ||||
-rw-r--r-- | test/recipes/30-test_evp.t | 1 | ||||
-rw-r--r-- | test/recipes/30-test_evp_data/evpkdf_pbkdf1.txt | 136 |
14 files changed, 591 insertions, 93 deletions
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/p5_crpt.c b/crypto/evp/p5_crpt.c index 4d9e894f0f..59d1a23ad6 100644 --- a/crypto/evp/p5_crpt.c +++ b/crypto/evp/p5_crpt.c @@ -12,6 +12,11 @@ #include "internal/cryptlib.h" #include <openssl/x509.h> #include <openssl/evp.h> +#include <openssl/core_names.h> +#include <openssl/kdf.h> + +#define PKCS5_PBES1_OUTPUT_LENGTH 16 +#define PKCS5_PBES1_KEY_IV_LENGTH 8 /* * Doesn't do anything now: Builtin PBE algorithms in static table. @@ -25,15 +30,16 @@ 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) { - 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; + unsigned char out[PKCS5_PBES1_OUTPUT_LENGTH]; + 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 || @@ -49,16 +55,14 @@ int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *cctx, const char *pass, int passlen, } ivl = EVP_CIPHER_iv_length(cipher); - if (ivl < 0 || ivl > 16) { + if (ivl != PKCS5_PBES1_KEY_IV_LENGTH) { 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)) { + if (kl != PKCS5_PBES1_KEY_IV_LENGTH) { ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_KEY_LENGTH); - PBEPARAM_free(pbe); - return 0; + goto err; } if (pbe->iter == NULL) @@ -73,43 +77,29 @@ 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); - goto err; - } - - if (!EVP_DigestInit_ex(ctx, md, NULL)) - goto err; - if (!EVP_DigestUpdate(ctx, pass, passlen)) + kdf = EVP_KDF_fetch(NULL, OSSL_KDF_NAME_PBKDF1, NULL); + kctx = EVP_KDF_CTX_new(kdf); + EVP_KDF_free(kdf); + if (kctx == NULL) goto err; - if (!EVP_DigestUpdate(ctx, salt, saltlen)) - goto err; - PBEPARAM_free(pbe); - pbe = NULL; - if (!EVP_DigestFinal_ex(ctx, md_tmp, NULL)) + *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, out, PKCS5_PBES1_OUTPUT_LENGTH, params) != 1) goto err; - mdsize = EVP_MD_size(md); - if (mdsize < 0) - 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)) + + if (!EVP_CipherInit_ex(cctx, cipher, NULL, out, + out + PKCS5_PBES1_KEY_IV_LENGTH, en_de)) goto err; - OPENSSL_cleanse(md_tmp, EVP_MAX_MD_SIZE); - OPENSSL_cleanse(key, EVP_MAX_KEY_LENGTH); - OPENSSL_cleanse(iv, EVP_MAX_IV_LENGTH); + OPENSSL_cleanse(out, PKCS5_PBES1_OUTPUT_LENGTH); rv = 1; err: + EVP_KDF_CTX_free(kctx); PBEPARAM_free(pbe); - EVP_MD_CTX_free(ctx); return rv; } diff --git a/doc/man3/PKCS5_PBE_keyivgen.pod b/doc/man3/PKCS5_PBE_keyivgen.pod index 4515346407..67a7957987 100644 --- a/doc/man3/PKCS5_PBE_keyivgen.pod +++ b/doc/man3/PKCS5_PBE_keyivgen.pod @@ -158,6 +158,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/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..1a803774d6 --- /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 *provctx = PROV_LIBCTX_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 (!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/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_NAM |