/*
- * Copyright 2017-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2017-2023 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
#include <openssl/kdf.h>
#include <openssl/err.h>
#include <openssl/core_names.h>
+#include <openssl/proverr.h>
#include "crypto/evp.h"
#include "internal/numbers.h"
#include "prov/implementations.h"
#include "prov/provider_ctx.h"
#include "prov/providercommon.h"
-#include "prov/providercommonerr.h"
-#include "prov/implementations.h"
+#include "prov/provider_util.h"
#ifndef OPENSSL_NO_SCRYPT
static OSSL_FUNC_kdf_newctx_fn kdf_scrypt_new;
+static OSSL_FUNC_kdf_dupctx_fn kdf_scrypt_dup;
static OSSL_FUNC_kdf_freectx_fn kdf_scrypt_free;
static OSSL_FUNC_kdf_reset_fn kdf_scrypt_reset;
static OSSL_FUNC_kdf_derive_fn kdf_scrypt_derive;
const unsigned char *salt, size_t saltlen,
uint64_t N, uint64_t r, uint64_t p, uint64_t maxmem,
unsigned char *key, size_t keylen, EVP_MD *sha256,
- OPENSSL_CTX *libctx, const char *propq);
+ OSSL_LIB_CTX *libctx, const char *propq);
typedef struct {
- void *provctx;
+ OSSL_LIB_CTX *libctx;
+ char *propq;
unsigned char *pass;
size_t pass_len;
unsigned char *salt;
static void kdf_scrypt_init(KDF_SCRYPT *ctx);
-static void *kdf_scrypt_new(void *provctx)
+static void *kdf_scrypt_new_inner(OSSL_LIB_CTX *libctx)
{
KDF_SCRYPT *ctx;
return NULL;
ctx = OPENSSL_zalloc(sizeof(*ctx));
- if (ctx == NULL) {
- ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
- return NULL;
- }
- ctx->provctx = provctx;
- ctx->sha256 = EVP_MD_fetch(PROV_LIBRARY_CONTEXT_OF(provctx),
- "sha256", NULL);
- if (ctx->sha256 == NULL) {
- OPENSSL_free(ctx);
- ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOAD_SHA256);
+ if (ctx == NULL)
return NULL;
- }
+ ctx->libctx = libctx;
kdf_scrypt_init(ctx);
return ctx;
}
+static void *kdf_scrypt_new(void *provctx)
+{
+ return kdf_scrypt_new_inner(PROV_LIBCTX_OF(provctx));
+}
+
static void kdf_scrypt_free(void *vctx)
{
KDF_SCRYPT *ctx = (KDF_SCRYPT *)vctx;
if (ctx != NULL) {
+ OPENSSL_free(ctx->propq);
EVP_MD_free(ctx->sha256);
kdf_scrypt_reset(ctx);
OPENSSL_free(ctx);
kdf_scrypt_init(ctx);
}
+static void *kdf_scrypt_dup(void *vctx)
+{
+ const KDF_SCRYPT *src = (const KDF_SCRYPT *)vctx;
+ KDF_SCRYPT *dest;
+
+ dest = kdf_scrypt_new_inner(src->libctx);
+ if (dest != NULL) {
+ if (src->sha256 != NULL && !EVP_MD_up_ref(src->sha256))
+ goto err;
+ if (src->propq != NULL) {
+ dest->propq = OPENSSL_strdup(src->propq);
+ if (dest->propq == NULL)
+ goto err;
+ }
+ if (!ossl_prov_memdup(src->salt, src->salt_len,
+ &dest->salt, &dest->salt_len)
+ || !ossl_prov_memdup(src->pass, src->pass_len,
+ &dest->pass , &dest->pass_len))
+ goto err;
+ dest->N = src->N;
+ dest->r = src->r;
+ dest->p = src->p;
+ dest->maxmem_bytes = src->maxmem_bytes;
+ dest->sha256 = src->sha256;
+ }
+ return dest;
+
+ err:
+ kdf_scrypt_free(dest);
+ return NULL;
+}
+
static void kdf_scrypt_init(KDF_SCRYPT *ctx)
{
/* Default values are the most conservative recommendation given in the
const OSSL_PARAM *p)
{
OPENSSL_clear_free(*buffer, *buflen);
+ *buffer = NULL;
+ *buflen = 0;
+
if (p->data_size == 0) {
- if ((*buffer = OPENSSL_malloc(1)) == NULL) {
- ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ if ((*buffer = OPENSSL_malloc(1)) == NULL)
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_scrypt_derive(void *vctx, unsigned char *key,
- size_t keylen)
+static int set_digest(KDF_SCRYPT *ctx)
+{
+ EVP_MD_free(ctx->sha256);
+ ctx->sha256 = EVP_MD_fetch(ctx->libctx, "sha256", ctx->propq);
+ if (ctx->sha256 == NULL) {
+ OPENSSL_free(ctx);
+ ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOAD_SHA256);
+ return 0;
+ }
+ return 1;
+}
+
+static int set_property_query(KDF_SCRYPT *ctx, const char *propq)
+{
+ OPENSSL_free(ctx->propq);
+ ctx->propq = NULL;
+ if (propq != NULL) {
+ ctx->propq = OPENSSL_strdup(propq);
+ if (ctx->propq == NULL)
+ return 0;
+ }
+ return 1;
+}
+
+static int kdf_scrypt_derive(void *vctx, unsigned char *key, size_t keylen,
+ const OSSL_PARAM params[])
{
KDF_SCRYPT *ctx = (KDF_SCRYPT *)vctx;
- if (!ossl_prov_is_running())
+ if (!ossl_prov_is_running() || !kdf_scrypt_set_ctx_params(ctx, params))
return 0;
if (ctx->pass == NULL) {
return 0;
}
+ if (ctx->sha256 == NULL && !set_digest(ctx))
+ return 0;
+
return scrypt_alg((char *)ctx->pass, ctx->pass_len, ctx->salt,
ctx->salt_len, ctx->N, ctx->r, ctx->p,
ctx->maxmem_bytes, key, keylen, ctx->sha256,
- PROV_LIBRARY_CONTEXT_OF(ctx->provctx), NULL);
+ ctx->libctx, ctx->propq);
}
static int is_power_of_two(uint64_t value)
KDF_SCRYPT *ctx = vctx;
uint64_t u64_value;
+ if (params == NULL)
+ return 1;
+
if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PASSWORD)) != NULL)
if (!scrypt_set_membuf(&ctx->pass, &ctx->pass_len, p))
return 0;
return 0;
ctx->maxmem_bytes = u64_value;
}
+
+ p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PROPERTIES);
+ if (p != NULL) {
+ if (p->data_type != OSSL_PARAM_UTF8_STRING
+ || !set_property_query(ctx, p->data)
+ || !set_digest(ctx))
+ return 0;
+ }
return 1;
}
-static const OSSL_PARAM *kdf_scrypt_settable_ctx_params(ossl_unused void *p_ctx)
+static const OSSL_PARAM *kdf_scrypt_settable_ctx_params(ossl_unused void *ctx,
+ ossl_unused void *p_ctx)
{
static const OSSL_PARAM known_settable_ctx_params[] = {
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PASSWORD, NULL, 0),
OSSL_PARAM_uint32(OSSL_KDF_PARAM_SCRYPT_R, NULL),
OSSL_PARAM_uint32(OSSL_KDF_PARAM_SCRYPT_P, NULL),
OSSL_PARAM_uint64(OSSL_KDF_PARAM_SCRYPT_MAXMEM, NULL),
+ OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
OSSL_PARAM_END
};
return known_settable_ctx_params;
return -2;
}
-static const OSSL_PARAM *kdf_scrypt_gettable_ctx_params(ossl_unused void *p_ctx)
+static const OSSL_PARAM *kdf_scrypt_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),
return known_gettable_ctx_params;
}
-const OSSL_DISPATCH kdf_scrypt_functions[] = {
+const OSSL_DISPATCH ossl_kdf_scrypt_functions[] = {
{ OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_scrypt_new },
+ { OSSL_FUNC_KDF_DUPCTX, (void(*)(void))kdf_scrypt_dup },
{ OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_scrypt_free },
{ OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_scrypt_reset },
{ OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_scrypt_derive },
{ OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
(void(*)(void))kdf_scrypt_gettable_ctx_params },
{ OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_scrypt_get_ctx_params },
- { 0, NULL }
+ OSSL_DISPATCH_END
};
#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
const unsigned char *salt, size_t saltlen,
uint64_t N, uint64_t r, uint64_t p, uint64_t maxmem,
unsigned char *key, size_t keylen, EVP_MD *sha256,
- OPENSSL_CTX *libctx, const char *propq)
+ OSSL_LIB_CTX *libctx, const char *propq)
{
int rv = 0;
unsigned char *B;
return 0;
/* Check p * r < SCRYPT_PR_MAX avoiding overflow */
if (p > SCRYPT_PR_MAX / r) {
- EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED);
+ ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED);
return 0;
}
if (16 * r <= LOG2_UINT64_MAX) {
if (N >= (((uint64_t)1) << (16 * r))) {
- EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED);
+ ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED);
return 0;
}
}
* have to be revised when/if PKCS5_PBKDF2_HMAC accepts size_t.]
*/
if (Blen > INT_MAX) {
- EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED);
+ ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED);
return 0;
}
*/
i = UINT64_MAX / (32 * sizeof(uint32_t));
if (N + 2 > i / r) {
- EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED);
+ ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED);
return 0;
}
Vlen = 32 * r * (N + 2) * sizeof(uint32_t);
/* check total allocated size fits in uint64_t */
if (Blen > UINT64_MAX - Vlen) {
- EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED);
+ ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED);
return 0;
}
maxmem = SIZE_MAX;
if (Blen + Vlen > maxmem) {
- EVPerr(EVP_F_SCRYPT_ALG, EVP_R_MEMORY_LIMIT_EXCEEDED);
+ ERR_raise(ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED);
return 0;
}
return 1;
B = OPENSSL_malloc((size_t)(Blen + Vlen));
- if (B == NULL) {
- EVPerr(EVP_F_SCRYPT_ALG, ERR_R_MALLOC_FAILURE);
+ if (B == NULL)
return 0;
- }
X = (uint32_t *)(B + Blen);
T = X + 32 * r;
V = T + 32 * r;
- if (pkcs5_pbkdf2_hmac_with_libctx(pass, passlen, salt, saltlen, 1, sha256,
- (int)Blen, B, libctx, propq) == 0)
+ if (ossl_pkcs5_pbkdf2_hmac_ex(pass, passlen, salt, saltlen, 1, sha256,
+ (int)Blen, B, libctx, propq) == 0)
goto err;
for (i = 0; i < p; i++)
scryptROMix(B + 128 * r * i, r, N, X, T, V);
- if (pkcs5_pbkdf2_hmac_with_libctx(pass, passlen, B, (int)Blen, 1, sha256,
- keylen, key, libctx, propq) == 0)
+ if (ossl_pkcs5_pbkdf2_hmac_ex(pass, passlen, B, (int)Blen, 1, sha256,
+ keylen, key, libctx, propq) == 0)
goto err;
rv = 1;
err:
if (rv == 0)
- EVPerr(EVP_F_SCRYPT_ALG, EVP_R_PBKDF2_ERROR);
+ ERR_raise(ERR_LIB_EVP, EVP_R_PBKDF2_ERROR);
OPENSSL_clear_free(B, (size_t)(Blen + Vlen));
return rv;