diff options
Diffstat (limited to 'providers/implementations/kdfs')
-rw-r--r-- | providers/implementations/kdfs/build.info | 3 | ||||
-rw-r--r-- | providers/implementations/kdfs/pbkdf1.c | 242 |
2 files changed, 245 insertions, 0 deletions
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 } +}; |