Add KDFs to providers

Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9662)
master
Pauli 4 years ago
parent 7707526b8d
commit e3405a4a9a

@ -1,4 +1,4 @@
SUBDIRS=digests ciphers macs exchange keymgmt
SUBDIRS=digests ciphers macs kdfs exchange keymgmt
SOURCE[../../libcrypto]=\
provider_err.c provlib.c

@ -115,17 +115,6 @@ extern const OSSL_DISPATCH camellia192ctr_functions[];
extern const OSSL_DISPATCH camellia128ctr_functions[];
#endif /* OPENSSL_NO_CAMELLIA */
/* MACs */
extern const OSSL_DISPATCH blake2bmac_functions[];
extern const OSSL_DISPATCH blake2smac_functions[];
extern const OSSL_DISPATCH cmac_functions[];
extern const OSSL_DISPATCH gmac_functions[];
extern const OSSL_DISPATCH hmac_functions[];
extern const OSSL_DISPATCH kmac128_functions[];
extern const OSSL_DISPATCH kmac256_functions[];
extern const OSSL_DISPATCH siphash_functions[];
extern const OSSL_DISPATCH poly1305_functions[];
extern const OSSL_DISPATCH tdes_ede3_ecb_functions[];
extern const OSSL_DISPATCH tdes_ede3_cbc_functions[];
@ -144,6 +133,32 @@ extern const OSSL_DISPATCH tdes_desx_cbc_functions[];
extern const OSSL_DISPATCH tdes_wrap_cbc_functions[];
#endif /* FIPS_MODE */
/* MACs */
extern const OSSL_DISPATCH blake2bmac_functions[];
extern const OSSL_DISPATCH blake2smac_functions[];
extern const OSSL_DISPATCH cmac_functions[];
extern const OSSL_DISPATCH gmac_functions[];
extern const OSSL_DISPATCH hmac_functions[];
extern const OSSL_DISPATCH kmac128_functions[];
extern const OSSL_DISPATCH kmac256_functions[];
extern const OSSL_DISPATCH siphash_functions[];
extern const OSSL_DISPATCH poly1305_functions[];
/* KDFs / PRFs */
extern const OSSL_DISPATCH kdf_pbkdf2_functions[];
#ifndef OPENSSL_NO_SCRYPT
extern const OSSL_DISPATCH kdf_scrypt_functions[];
#endif
extern const OSSL_DISPATCH kdf_tls1_prf_functions[];
extern const OSSL_DISPATCH kdf_hkdf_functions[];
extern const OSSL_DISPATCH kdf_sshkdf_functions[];
extern const OSSL_DISPATCH kdf_sskdf_functions[];
extern const OSSL_DISPATCH kdf_x963_kdf_functions[];
#ifndef OPENSSL_NO_CMS
extern const OSSL_DISPATCH kdf_x942_kdf_functions[];
#endif
/* Key management */
extern const OSSL_DISPATCH dh_keymgmt_functions[];

@ -1,7 +1,7 @@
$COMMON=tls1_prf.c hkdf.c scrypt.c pbkdf2.c sskdf.c
$COMMON=tls1_prf.c hkdf.c pbkdf2.c sskdf.c
LIBS=../../../libcrypto
SOURCE[../../../libcrypto]=$COMMON sshkdf.c x942kdf.c
SOURCE[../../../libcrypto]=$COMMON
INCLUDE[../../../libcrypto]=. ../../../crypto
IF[{- !$disabled{fips} -}]

@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 2016-2019 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
@ -13,14 +13,26 @@
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>
#include <openssl/core_names.h>
#include "internal/cryptlib.h"
#include "internal/numbers.h"
#include "internal/evp_int.h"
#include "kdf_local.h"
#include "internal/provider_ctx.h"
#include "internal/providercommonerr.h"
#include "internal/provider_algs.h"
#include "e_os.h"
#define HKDF_MAXBUF 1024
static void kdf_hkdf_reset(EVP_KDF_IMPL *impl);
static OSSL_OP_kdf_newctx_fn kdf_hkdf_new;
static OSSL_OP_kdf_freectx_fn kdf_hkdf_free;
static OSSL_OP_kdf_reset_fn kdf_hkdf_reset;
static OSSL_OP_kdf_derive_fn kdf_hkdf_derive;
static OSSL_OP_kdf_settable_ctx_params_fn kdf_hkdf_settable_ctx_params;
static OSSL_OP_kdf_set_ctx_params_fn kdf_hkdf_set_ctx_params;
static OSSL_OP_kdf_gettable_ctx_params_fn kdf_hkdf_gettable_ctx_params;
static OSSL_OP_kdf_get_ctx_params_fn kdf_hkdf_get_ctx_params;
static int HKDF(const EVP_MD *evp_md,
const unsigned char *salt, size_t salt_len,
const unsigned char *key, size_t key_len,
@ -35,209 +47,236 @@ static int HKDF_Expand(const EVP_MD *evp_md,
const unsigned char *info, size_t info_len,
unsigned char *okm, size_t okm_len);
struct evp_kdf_impl_st {
typedef struct {
void *provctx;
int mode;
const EVP_MD *md;
EVP_MD *md;
unsigned char *salt;
size_t salt_len;
unsigned char *key;
size_t key_len;
unsigned char info[HKDF_MAXBUF];
size_t info_len;
};
} KDF_HKDF;
static EVP_KDF_IMPL *kdf_hkdf_new(void)
static void *kdf_hkdf_new(void *provctx)
{
EVP_KDF_IMPL *impl;
KDF_HKDF *ctx;
if ((impl = OPENSSL_zalloc(sizeof(*impl))) == NULL)
KDFerr(KDF_F_KDF_HKDF_NEW, ERR_R_MALLOC_FAILURE);
return impl;
if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
else
ctx->provctx = provctx;
return ctx;
}
static void kdf_hkdf_free(EVP_KDF_IMPL *impl)
static void kdf_hkdf_free(void *vctx)
{
kdf_hkdf_reset(impl);
OPENSSL_free(impl);
}
KDF_HKDF *ctx = (KDF_HKDF *)vctx;
static void kdf_hkdf_reset(EVP_KDF_IMPL *impl)
{
OPENSSL_free(impl->salt);
OPENSSL_clear_free(impl->key, impl->key_len);
OPENSSL_cleanse(impl->info, impl->info_len);
memset(impl, 0, sizeof(*impl));
kdf_hkdf_reset(ctx);
EVP_MD_meth_free(ctx->md);
OPENSSL_free(ctx);
}
static int kdf_hkdf_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args)
static void kdf_hkdf_reset(void *vctx)
{
const unsigned char *p;
size_t len;
const EVP_MD *md;
switch (cmd) {
case EVP_KDF_CTRL_SET_MD:
md = va_arg(args, const EVP_MD *);
if (md == NULL)
return 0;
impl->md = md;
return 1;
case EVP_KDF_CTRL_SET_HKDF_MODE:
impl->mode = va_arg(args, int);
return 1;
case EVP_KDF_CTRL_SET_SALT:
p = va_arg(args, const unsigned char *);
len = va_arg(args, size_t);
if (len == 0 || p == NULL)
return 1;
OPENSSL_free(impl->salt);
impl->salt = OPENSSL_memdup(p, len);
if (impl->salt == NULL)
return 0;
impl->salt_len = len;
return 1;
case EVP_KDF_CTRL_SET_KEY:
p = va_arg(args, const unsigned char *);
len = va_arg(args, size_t);
OPENSSL_clear_free(impl->key, impl->key_len);
impl->key = OPENSSL_memdup(p, len);
if (impl->key == NULL)
return 0;
impl->key_len = len;
return 1;
case EVP_KDF_CTRL_RESET_HKDF_INFO:
OPENSSL_cleanse(impl->info, impl->info_len);
impl->info_len = 0;
return 1;
case EVP_KDF_CTRL_ADD_HKDF_INFO:
p = va_arg(args, const unsigned char *);
len = va_arg(args, size_t);
if (len == 0 || p == NULL)
return 1;
if (len > (HKDF_MAXBUF - impl->info_len))
return 0;
KDF_HKDF *ctx = (KDF_HKDF *)vctx;
memcpy(impl->info + impl->info_len, p, len);
impl->info_len += len;
return 1;
default:
return -2;
}
OPENSSL_free(ctx->salt);
OPENSSL_clear_free(ctx->key, ctx->key_len);
OPENSSL_cleanse(ctx->info, ctx->info_len);
memset(ctx, 0, sizeof(*ctx));
}
static int kdf_hkdf_ctrl_str(EVP_KDF_IMPL *impl, const char *type,
const char *value)
{
if (strcmp(type, "mode") == 0) {
int mode;
if (strcmp(value, "EXTRACT_AND_EXPAND") == 0)
mode = EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND;
else if (strcmp(value, "EXTRACT_ONLY") == 0)
mode = EVP_KDF_HKDF_MODE_EXTRACT_ONLY;
else if (strcmp(value, "EXPAND_ONLY") == 0)
mode = EVP_KDF_HKDF_MODE_EXPAND_ONLY;
else
return 0;
return call_ctrl(kdf_hkdf_ctrl, impl, EVP_KDF_CTRL_SET_HKDF_MODE, mode);
}
if (strcmp(type, "digest") == 0)
return kdf_md2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_SET_MD, value);
if (strcmp(type, "salt") == 0)
return kdf_str2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_SET_SALT, value);
if (strcmp(type, "hexsalt") == 0)
return kdf_hex2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_SET_SALT, value);
if (strcmp(type, "key") == 0)
return kdf_str2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_SET_KEY, value);
if (strcmp(type, "hexkey") == 0)
return kdf_hex2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_SET_KEY, value);
if (strcmp(type, "info") == 0)
return kdf_str2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_ADD_HKDF_INFO,
value);
if (strcmp(type, "hexinfo") == 0)
return kdf_hex2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_ADD_HKDF_INFO,
value);
return -2;
}
static size_t kdf_hkdf_size(EVP_KDF_IMPL *impl)
static size_t kdf_hkdf_size(KDF_HKDF *ctx)
{
int sz;
if (impl->mode != EVP_KDF_HKDF_MODE_EXTRACT_ONLY)
if (ctx->mode != EVP_KDF_HKDF_MODE_EXTRACT_ONLY)
return SIZE_MAX;
if (impl->md == NULL) {
KDFerr(KDF_F_KDF_HKDF_SIZE, KDF_R_MISSING_MESSAGE_DIGEST);
if (ctx->md == NULL) {
ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST);
return 0;
}
sz = EVP_MD_size(impl->md);
sz = EVP_MD_size(ctx->md);
if (sz < 0)
return 0;
return sz;
}
static int kdf_hkdf_derive(EVP_KDF_IMPL *impl, unsigned char *key,
size_t keylen)
static int kdf_hkdf_derive(void *vctx, unsigned char *key, size_t keylen)
{
if (impl->md == NULL) {
KDFerr(KDF_F_KDF_HKDF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST);
KDF_HKDF *ctx = (KDF_HKDF *)vctx;
if (ctx->md == NULL) {
ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST);
return 0;
}
if (impl->key == NULL) {
KDFerr(KDF_F_KDF_HKDF_DERIVE, KDF_R_MISSING_KEY);
if (ctx->key == NULL) {
ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
return 0;
}
switch (impl->mode) {
switch (ctx->mode) {
case EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND:
return HKDF(impl->md, impl->salt, impl->salt_len, impl->key,
impl->key_len, impl->info, impl->info_len, key,
return HKDF(ctx->md, ctx->salt, ctx->salt_len, ctx->key,
ctx->key_len, ctx->info, ctx->info_len, key,
keylen);
case EVP_KDF_HKDF_MODE_EXTRACT_ONLY:
return HKDF_Extract(impl->md, impl->salt, impl->salt_len, impl->key,
impl->key_len, key, keylen);
return HKDF_Extract(ctx->md, ctx->salt, ctx->salt_len, ctx->key,
ctx->key_len, key, keylen);
case EVP_KDF_HKDF_MODE_EXPAND_ONLY:
return HKDF_Expand(impl->md, impl->key, impl->key_len, impl->info,
impl->info_len, key, keylen);
return HKDF_Expand(ctx->md, ctx->key, ctx->key_len, ctx->info,
ctx->info_len, key, keylen);
default:
return 0;
}
}
const EVP_KDF hkdf_kdf_meth = {
EVP_KDF_HKDF,
kdf_hkdf_new,
kdf_hkdf_free,
kdf_hkdf_reset,
kdf_hkdf_ctrl,
kdf_hkdf_ctrl_str,
kdf_hkdf_size,
kdf_hkdf_derive
static int kdf_hkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
const OSSL_PARAM *p;
KDF_HKDF *ctx = vctx;
EVP_MD *md;
int n;
const char *properties = NULL;
/* Grab search properties, this should be before the digest lookup */
if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PROPERTIES))
!= NULL) {
if (p->data_type != OSSL_PARAM_UTF8_STRING)
return 0;
properties = p->data;
}
/* Handle aliasing of digest parameter names */
if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DIGEST)) != NULL) {
if (p->data_type != OSSL_PARAM_UTF8_STRING)
return 0;
md = EVP_MD_fetch(PROV_LIBRARY_CONTEXT_OF(ctx->provctx), p->data,
properties);
if (md == NULL) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST);
return 0;
}
EVP_MD_meth_free(ctx->md);
ctx->md = md;
}
if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MODE)) != NULL) {
if (p->data_type == OSSL_PARAM_UTF8_STRING) {
if (strcasecmp(p->data, "EXTRACT_AND_EXPAND") == 0) {
ctx->mode = EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND;
} else if (strcasecmp(p->data, "EXTRACT_ONLY") == 0) {
ctx->mode = EVP_KDF_HKDF_MODE_EXTRACT_ONLY;
} else if (strcasecmp(p->data, "EXPAND_ONLY") == 0) {
ctx->mode = EVP_KDF_HKDF_MODE_EXPAND_ONLY;
} else {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
return 0;
}
} else if (OSSL_PARAM_get_int(p, &n)) {
if (n != EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND
&& n != EVP_KDF_HKDF_MODE_EXTRACT_ONLY
&& n != EVP_KDF_HKDF_MODE_EXPAND_ONLY) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
return 0;
}
ctx->mode = n;
} else {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
return 0;
}
}
if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL) {
OPENSSL_clear_free(ctx->key, ctx->key_len);
ctx->key = NULL;
if (!OSSL_PARAM_get_octet_string(p, (void **)&ctx->key, 0,
&ctx->key_len))
return 0;
}
if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) {
if (p->data_size != 0 && p->data != NULL) {
OPENSSL_free(ctx->salt);
ctx->salt = NULL;
if (!OSSL_PARAM_get_octet_string(p, (void **)&ctx->salt, 0,
&ctx->salt_len))
return 0;
}
}
/* The info fields concatenate, so process them all */
if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO)) != NULL) {
ctx->info_len = 0;
for (; p != NULL; p = OSSL_PARAM_locate_const(p + 1,
OSSL_KDF_PARAM_INFO)) {
const void *q = ctx->info + ctx->info_len;
size_t sz = 0;
if (p->data_size != 0
&& p->data != NULL
&& !OSSL_PARAM_get_octet_string(p, (void **)&q,
HKDF_MAXBUF - ctx->info_len,
&sz))
return 0;
ctx->info_len += sz;
}
}
return 1;
}
static const OSSL_PARAM *kdf_hkdf_settable_ctx_params(void)
{
static const OSSL_PARAM known_settable_ctx_params[] = {
OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MODE, NULL, 0),
OSSL_PARAM_int(OSSL_KDF_PARAM_MODE, NULL),
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_SALT, NULL, 0),
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0),
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0),
OSSL_PARAM_END
};
return known_settable_ctx_params;
}
static int kdf_hkdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
KDF_HKDF *ctx = (KDF_HKDF *)vctx;
OSSL_PARAM *p;
if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL)
return OSSL_PARAM_set_size_t(p, kdf_hkdf_size(ctx));
return -2;
}
static const OSSL_PARAM *kdf_hkdf_gettable_ctx_params(void)
{
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 kdf_hkdf_functions[] = {
{ OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_hkdf_new },
{ OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_hkdf_free },
{ OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_hkdf_reset },
{ OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_hkdf_derive },
{ OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS,
(void(*)(void))kdf_hkdf_settable_ctx_params },
{ OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_hkdf_set_ctx_params },
{ OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
(void(*)(void))kdf_hkdf_gettable_ctx_params },
{ OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_hkdf_get_ctx_params },
{ 0, NULL }
};
/*
@ -325,7 +364,7 @@ static int HKDF_Extract(const EVP_MD *evp_md,
if (sz < 0)
return 0;
if (prk_len != (size_t)sz) {
KDFerr(KDF_F_HKDF_EXTRACT, KDF_R_WRONG_OUTPUT_BUFFER_SIZE);
ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_OUTPUT_BUFFER_SIZE);
return 0;
}
/* calc: PRK = HMAC-Hash(salt, IKM) */

@ -13,9 +13,13 @@
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>
#include <openssl/core_names.h>
#include "internal/cryptlib.h"
#include "internal/numbers.h"
#include "internal/evp_int.h"
#include "kdf_local.h"
#include "internal/provider_ctx.h"
#include "internal/providercommonerr.h"
#include "internal/provider_algs.h"
/* Constants specified in SP800-132 */
#define KDF_PBKDF2_MIN_KEY_LEN_BITS 112
@ -32,195 +36,216 @@
# define KDF_PBKDF2_DEFAULT_CHECKS 0
#endif /* FIPS_MODE */
static void kdf_pbkdf2_reset(EVP_KDF_IMPL *impl);
static void kdf_pbkdf2_init(EVP_KDF_IMPL *impl);
static OSSL_OP_kdf_newctx_fn kdf_pbkdf2_new;
static OSSL_OP_kdf_freectx_fn kdf_pbkdf2_free;
static OSSL_OP_kdf_reset_fn kdf_pbkdf2_reset;
static OSSL_OP_kdf_derive_fn kdf_pbkdf2_derive;
static OSSL_OP_kdf_settable_ctx_params_fn kdf_pbkdf2_settable_ctx_params;
static OSSL_OP_kdf_set_ctx_params_fn kdf_pbkdf2_set_ctx_params;
static int pbkdf2_derive(const char *pass, size_t passlen,
const unsigned char *salt, int saltlen, int iter,
const unsigned char *salt, int saltlen, uint64_t iter,
const EVP_MD *digest, unsigned char *key,
size_t keylen, int extra_checks);
struct evp_kdf_impl_st {
typedef struct {
void *provctx;
unsigned char *pass;
size_t pass_len;
unsigned char *salt;
size_t salt_len;
int iter;
const EVP_MD *md;
uint64_t iter;
EVP_MD *md;
int lower_bound_checks;
};
} KDF_PBKDF2;
static EVP_KDF_IMPL *kdf_pbkdf2_new(void)
static void kdf_pbkdf2_init(KDF_PBKDF2 *ctx);
static void *kdf_pbkdf2_new(void *provctx)
{
EVP_KDF_IMPL *impl;
KDF_PBKDF2 *ctx;
impl = OPENSSL_zalloc(sizeof(*impl));
if (impl == NULL) {
KDFerr(KDF_F_KDF_PBKDF2_NEW, ERR_R_MALLOC_FAILURE);
ctx = OPENSSL_zalloc(sizeof(*ctx));
if (ctx == NULL) {
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
return NULL;
}
kdf_pbkdf2_init(impl);
return impl;
ctx->provctx = provctx;
kdf_pbkdf2_init(ctx);
return ctx;
}
static void kdf_pbkdf2_free(EVP_KDF_IMPL *impl)
static void kdf_pbkdf2_free(void *vctx)
{
kdf_pbkdf2_reset(impl);
OPENSSL_free(impl);
KDF_PBKDF2 *ctx = (KDF_PBKDF2 *)vctx;
kdf_pbkdf2_reset(ctx);
EVP_MD_meth_free(ctx->md);
OPENSSL_free(ctx);
}
static void kdf_pbkdf2_reset(EVP_KDF_IMPL *impl)
static void kdf_pbkdf2_reset(void *vctx)
{
OPENSSL_free(impl->salt);
OPENSSL_clear_free(impl->pass, impl->pass_len);
memset(impl, 0, sizeof(*impl));
kdf_pbkdf2_init(impl);
KDF_PBKDF2 *ctx = (KDF_PBKDF2 *)vctx;
OPENSSL_free(ctx->salt);
OPENSSL_clear_free(ctx->pass, ctx->pass_len);
memset(ctx, 0, sizeof(*ctx));
kdf_pbkdf2_init(ctx);
}
static void kdf_pbkdf2_init(EVP_KDF_IMPL *impl)
static void kdf_pbkdf2_init(KDF_PBKDF2 *ctx)
{
impl->iter = PKCS5_DEFAULT_ITER;
impl->md = EVP_sha1();
impl->lower_bound_checks = KDF_PBKDF2_DEFAULT_CHECKS;
ctx->iter = PKCS5_DEFAULT_ITER;
ctx->md = EVP_MD_fetch(PROV_LIBRARY_CONTEXT_OF(ctx->provctx), SN_sha1,
NULL);
ctx->lower_bound_checks = KDF_PBKDF2_DEFAULT_CHECKS;
}
static int pbkdf2_set_membuf(unsigned char **buffer, size_t *buflen,
const unsigned char *new_buffer,
size_t new_buflen)
const OSSL_PARAM *p)
{
if (new_buffer == NULL)
return 1;
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_pbkdf2_derive(void *vctx, unsigned char *key,
size_t keylen)
{
KDF_PBKDF2 *ctx = (KDF_PBKDF2 *)vctx;
if (new_buflen > 0) {
*buffer = OPENSSL_memdup(new_buffer, new_buflen);
} else {
*buffer = OPENSSL_malloc(1);
if (ctx->pass == NULL) {
ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_PASS);
return 0;
}
if (*buffer == NULL) {
KDFerr(KDF_F_PBKDF2_SET_MEMBUF, ERR_R_MALLOC_FAILURE);
if (ctx->salt == NULL) {
ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SALT);
return 0;
}
*buflen = new_buflen;
return 1;
return pbkdf2_derive((char *)ctx->pass, ctx->pass_len,
ctx->salt, ctx->salt_len, ctx->iter,
ctx->md, key, keylen, ctx->lower_bound_checks);
}
static int kdf_pbkdf2_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args)
static int kdf_pbkdf2_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
int iter, pkcs5, min_iter;
const unsigned char *p;
size_t len;
const EVP_MD *md;
switch (cmd) {
case EVP_KDF_CTRL_SET_PBKDF2_PKCS5_MODE:
pkcs5 = va_arg(args, int);
impl->lower_bound_checks = (pkcs5 == 0) ? 1 : 0;
return 1;
case EVP_KDF_CTRL_SET_PASS:
p = va_arg(args, const unsigned char *);
len = va_arg(args, size_t);
return pbkdf2_set_membuf(&impl->pass, &impl->pass_len, p, len);
case EVP_KDF_CTRL_SET_SALT:
p = va_arg(args, const unsigned char *);
len = va_arg(args, size_t);
if (impl->lower_bound_checks != 0 && len < KDF_PBKDF2_MIN_SALT_LEN) {
KDFerr(KDF_F_KDF_PBKDF2_CTRL, KDF_R_INVALID_SALT_LEN);
const OSSL_PARAM *p;
KDF_PBKDF2 *ctx = vctx;
EVP_MD *md;
int pkcs5;
uint64_t iter, min_iter;
const char *properties = NULL;
/* Grab search properties, this should be before the digest lookup */
if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PROPERTIES))
!= NULL) {
if (p->data_type != OSSL_PARAM_UTF8_STRING)
return 0;
}
return pbkdf2_set_membuf(&impl->salt, &impl->salt_len, p, len);
case EVP_KDF_CTRL_SET_ITER:
iter = va_arg(args, int);
min_iter = impl->lower_bound_checks != 0 ? KDF_PBKDF2_MIN_ITERATIONS : 1;
if (iter < min_iter) {
KDFerr(KDF_F_KDF_PBKDF2_CTRL, KDF_R_INVALID_ITERATION_COUNT);
properties = p->data;
}
/* Handle aliasing of digest parameter names */
if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DIGEST)) != NULL) {
if (p->data_type != OSSL_PARAM_UTF8_STRING)
return 0;
}
impl->iter = iter;
return 1;
case EVP_KDF_CTRL_SET_MD:
md = va_arg(args, const EVP_MD *);
md = EVP_MD_fetch(PROV_LIBRARY_CONTEXT_OF(ctx->provctx), p->data,
properties);
if (md == NULL) {
KDFerr(KDF_F_KDF_PBKDF2_CTRL, KDF_R_VALUE_MISSING);
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST);
return 0;
}
impl->md = md;
return 1;
default:
return -2;
EVP_MD_meth_free(ctx->md);
ctx->md = md;
}
}
static int kdf_pbkdf2_ctrl_str(EVP_KDF_IMPL *impl, const char *type,
const char *value)
{
if (value == NULL) {
KDFerr(KDF_F_KDF_PBKDF2_CTRL_STR, KDF_R_VALUE_MISSING);
return 0;
if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PKCS5)) != NULL) {
if (!OSSL_PARAM_get_int(p, &pkcs5))
return 0;
ctx->lower_bound_checks = pkcs5 == 0;
}
if (strcmp(type, "pass") == 0)
return kdf_str2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_PASS,
value);
if (strcmp(type, "hexpass") == 0)
return kdf_hex2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_PASS,
value);
if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PASSWORD)) != NULL)
if (!pbkdf2_set_membuf(&ctx->pass, &ctx->pass_len, p))
return 0;
if (strcmp(type, "salt") == 0)
return kdf_str2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_SALT,
value);
if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT)) != NULL) {
if (ctx->lower_bound_checks != 0
&& p->data_size < KDF_PBKDF2_MIN_SALT_LEN) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH);
return 0;
}
if (!pbkdf2_set_membuf(&ctx->salt, &ctx->salt_len,p))
return 0;
}
if (strcmp(type, "hexsalt") == 0)
return kdf_hex2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_SALT,
value);
if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_ITER)) != NULL) {
if (!OSSL_PARAM_get_uint64(p, &iter))
return 0;
min_iter = ctx->lower_bound_checks != 0 ? KDF_PBKDF2_MIN_ITERATIONS : 1;
if (iter < min_iter) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_ITERATION_COUNT);
return 0;
}
ctx->iter = iter;
}
return 1;
}
if (strcmp(type, "iter") == 0)
return call_ctrl(kdf_pbkdf2_ctrl, impl, EVP_KDF_CTRL_SET_ITER,
atoi(value));
static const OSSL_PARAM *kdf_pbkdf2_settable_ctx_params(void)
{
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_int(OSSL_KDF_PARAM_PKCS5, NULL),
OSSL_PARAM_END
};
return known_settable_ctx_params;
}
if (strcmp(type, "digest") == 0)
return kdf_md2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_MD, value);
static int kdf_pbkdf2_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
OSSL_PARAM *p;
if (strcmp(type, "pkcs5") == 0)
return kdf_str2ctrl(impl, kdf_pbkdf2_ctrl,
EVP_KDF_CTRL_SET_PBKDF2_PKCS5_MODE, value);
if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL)
return OSSL_PARAM_set_size_t(p, SIZE_MAX);
return -2;
}
static int kdf_pbkdf2_derive(EVP_KDF_IMPL *impl, unsigned char *key,
size_t keylen)
static const OSSL_PARAM *kdf_pbkdf2_gettable_ctx_params(void)
{
if (impl->pass == NULL) {
KDFerr(KDF_F_KDF_PBKDF2_DERIVE, KDF_R_MISSING_PASS);
return 0;
}
if (impl->salt == NULL) {
KDFerr(KDF_F_KDF_PBKDF2_DERIVE, KDF_R_MISSING_SALT);
return 0;
}
return pbkdf2_derive((char *)impl->pass, impl->pass_len,
impl->salt, impl->salt_len, impl->iter,
impl->md, key, keylen, impl->lower_bound_checks);
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 EVP_KDF pbkdf2_kdf_meth = {
EVP_KDF_PBKDF2,
kdf_pbkdf2_new,
kdf_pbkdf2_free,
kdf_pbkdf2_reset,
kdf_pbkdf2_ctrl,
kdf_pbkdf2_ctrl_str,
NULL,
kdf_pbkdf2_derive
const OSSL_DISPATCH kdf_pbkdf2_functions[] = {
{ OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_pbkdf2_new },
{ OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_pbkdf2_free },
{ OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_pbkdf2_reset },
{ OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_pbkdf2_derive },
{ OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS,
(void(*)(void))kdf_pbkdf2_settable_ctx_params },
{ OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_pbkdf2_set_ctx_params },
{ OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
(void(*)(void))kdf_pbkdf2_gettable_ctx_params },
{ OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_pbkdf2_get_ctx_params },
{ 0, NULL }
};
/*
@ -234,13 +259,14 @@ const EVP_KDF pbkdf2_kdf_meth = {
* - Randomly-generated portion of the salt shall be at least 128 bits.
*/
static int pbkdf2_derive(const char *pass, size_t passlen,
const unsigned char *salt, int saltlen, int iter,
const unsigned char *salt, int saltlen, uint64_t iter,
const EVP_MD *digest, unsigned char *key,
size_t keylen, int lower_bound_checks)
{
int ret = 0;
unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4];
int cplen, j, k, tkeylen, mdlen;
int cplen, k, tkeylen, mdlen;
uint64_t j;
unsigned long i = 1;
HMAC_CTX *hctx_tpl = NULL, *hctx = NULL;
@ -253,23 +279,23 @@ static int pbkdf2_derive(const char *pass, size_t passlen,
* results in an overflow of the loop counter 'i'.
*/
if ((keylen / mdlen) >= KDF_PBKDF2_MAX_KEY_LEN_DIGEST_RATIO) {
KDFerr(KDF_F_PBKDF2_DERIVE, KDF_R_INVALID_KEY_LEN);
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LEN);
return 0;
}
if (lower_bound_checks) {
if ((keylen * 8) < KDF_PBKDF2_MIN_KEY_LEN_BITS) {
KDFerr(KDF_F_PBKDF2_DERIVE, KDF_R_INVALID_KEY_LEN);
return 0;
}
if (saltlen < KDF_PBKDF2_MIN_SALT_LEN) {
KDFerr(KDF_F_PBKDF2_DERIVE, KDF_R_INVALID_SALT_LEN);
if ((keylen * 8) < KDF_PBKDF2_MIN_KEY_LEN_BITS) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LEN);
return 0;
}
if (saltlen < KDF_PBKDF2_MIN_SALT_LEN) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH);
return 0;
}
if (iter < KDF_PBKDF2_MIN_ITERATIONS) {
KDFerr(KDF_F_PBKDF2_DERIVE, KDF_R_INVALID_ITERATION_COUNT);
return 0;
}
}
if (iter < KDF_PBKDF2_MIN_ITERATIONS) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_ITERATION_COUNT);
return 0;
}
}
hctx_tpl = HMAC_CTX_new();

@ -1,292 +0,0 @@
/*
* Copyright 2018-2018 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 <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>
#include "internal/cryptlib.h"
#include "internal/numbers.h"
#include "internal/evp_int.h"
#include "kdf_local.h"
/* See RFC 4253, Section 7.2 */
static void kdf_sshkdf_reset(EVP_KDF_IMPL *impl);
static int SSHKDF(const EVP_MD *evp_md,
const unsigned char *key, size_t key_len,
const unsigned char *xcghash, size_t xcghash_len,
const unsigned char *session_id, size_t session_id_len,
char type, unsigned char *okey, size_t okey_len);
struct evp_kdf_impl_st {
const EVP_MD *md;
unsigned char *key; /* K */
size_t key_len;
unsigned char *xcghash; /* H */
size_t xcghash_len;
char type; /* X */
unsigned char *session_id;
size_t session_id_len;
};
static EVP_KDF_IMPL *kdf_sshkdf_new(void)
{
EVP_KDF_IMPL *impl;
if ((impl = OPENSSL_zalloc(sizeof(*impl))) == NULL)
KDFerr(KDF_F_KDF_SSHKDF_NEW, ERR_R_MALLOC_FAILURE);
return impl;
}
static void kdf_sshkdf_free(EVP_KDF_IMPL *impl)
{
kdf_sshkdf_reset(impl);
OPENSSL_free(impl);
}
static void kdf_sshkdf_reset(EVP_KDF_IMPL *impl)
{
OPENSSL_clear_free(impl->key, impl->key_len);
OPENSSL_clear_free(impl->xcghash, impl->xcghash_len);
OPENSSL_clear_free(impl->session_id, impl->session_id_len);
memset(impl, 0, sizeof(*impl));
}
static int kdf_sshkdf_parse_buffer_arg(unsigned char **dst, size_t *dst_len,
va_list args)
{
const unsigned char *p;
size_t len;
p = va_arg(args, const unsigned char *);
len = va_arg(args, size_t);
OPENSSL_clear_free(*dst, *dst_len);
*dst = OPENSSL_memdup(p, len);
if (*dst == NULL)
return 0;
*dst_len = len;
return 1;
}
static int kdf_sshkdf_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args)
{
int t;
switch (cmd) {
case EVP_KDF_CTRL_SET_MD:
impl->md = va_arg(args, const EVP_MD *);
if (impl->md == NULL)
return 0;
return 1;
case EVP_KDF_CTRL_SET_KEY:
return kdf_sshkdf_parse_buffer_arg(&impl->key,
&impl->key_len, args);
case EVP_KDF_CTRL_SET_SSHKDF_XCGHASH:
return kdf_sshkdf_parse_buffer_arg(&impl->xcghash,
&impl->xcghash_len, args);
case EVP_KDF_CTRL_SET_SSHKDF_SESSION_ID:
return kdf_sshkdf_parse_buffer_arg(&impl->session_id,
&impl->session_id_len, args);
case EVP_KDF_CTRL_SET_SSHKDF_TYPE:
t = va_arg(args, int);
if (t < 65 || t > 70) {
KDFerr(KDF_F_KDF_SSHKDF_CTRL, KDF_R_VALUE_ERROR);
return 0;
}
impl->type = (char)t;
return 1;
default:
return -2;
}
}
static int kdf_sshkdf_ctrl_str(EVP_KDF_IMPL *impl, const char *type,
const char *value)
{
if (value == NULL) {
KDFerr(KDF_F_KDF_SSHKDF_CTRL_STR, KDF_R_VALUE_MISSING);
return 0;
}
if (strcmp(type, "digest") == 0)
return kdf_md2ctrl(impl, kdf_sshkdf_ctrl, EVP_KDF_CTRL_SET_MD, value);
/* alias, for historical reasons */
if (strcmp(type, "md") == 0)
return kdf_md2ctrl(impl, kdf_sshkdf_ctrl, EVP_KDF_CTRL_SET_MD, value);
if (strcmp(type, "key") == 0)
return kdf_str2ctrl(impl, kdf_sshkdf_ctrl,
EVP_KDF_CTRL_SET_KEY, value);
if (strcmp(type, "hexkey") == 0)
return kdf_hex2ctrl(impl, kdf_sshkdf_ctrl,
EVP_KDF_CTRL_SET_KEY, value);
if (strcmp(type, "xcghash") == 0)
return kdf_str2ctrl(impl, kdf_sshkdf_ctrl,
EVP_KDF_CTRL_SET_SSHKDF_XCGHASH, value);
if (strcmp(type, "hexxcghash") == 0)
return kdf_hex2ctrl(impl, kdf_sshkdf_ctrl,
EVP_KDF_CTRL_SET_SSHKDF_XCGHASH, value);
if (strcmp(type, "session_id") == 0)
return kdf_str2ctrl(impl, kdf_sshkdf_ctrl,
EVP_KDF_CTRL_SET_SSHKDF_SESSION_ID, value);
if (strcmp(type, "hexsession_id") == 0)
return kdf_hex2ctrl(impl, kdf_sshkdf_ctrl,
EVP_KDF_CTRL_SET_SSHKDF_SESSION_ID, value);
if (strcmp(type, "type") == 0) {
if (strlen(value) != 1) {
KDFerr(KDF_F_KDF_SSHKDF_CTRL_STR, KDF_R_VALUE_ERROR);
return 0;
}
return call_ctrl(kdf_sshkdf_ctrl, impl, EVP_KDF_CTRL_SET_SSHKDF_TYPE,
(int)value[0]);
}
KDFerr(KDF_F_KDF_SSHKDF_CTRL_STR, KDF_R_UNKNOWN_PARAMETER_TYPE);
return -2;
}
static size_t kdf_sshkdf_size(EVP_KDF_IMPL *impl)
{
return SIZE_MAX;
}
static int kdf_sshkdf_derive(EVP_KDF_IMPL *impl, unsigned char *key,
size_t keylen)
{
if (impl->md == NULL) {
KDFerr(KDF_F_KDF_SSHKDF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST);
return 0;
}
if (impl->key == NULL) {
KDFerr(KDF_F_KDF_SSHKDF_DERIVE, KDF_R_MISSING_KEY);
return 0;
}
if (impl->xcghash == NULL) {
KDFerr(KDF_F_KDF_SSHKDF_DERIVE, KDF_R_MISSING_XCGHASH);
return 0;
}
if (impl->session_id == NULL) {
KDFerr(KDF_F_KDF_SSHKDF_DERIVE, KDF_R_MISSING_SESSION_ID);
return 0;
}
if (impl->type == 0) {
KDFerr(KDF_F_KDF_SSHKDF_DERIVE, KDF_R_MISSING_TYPE);
return 0;
}
return SSHKDF(impl->md, impl->key, impl->key_len,
impl->xcghash, impl->xcghash_len,
impl->session_id, impl->session_id_len,
impl->type, key, keylen);
}
const EVP_KDF sshkdf_kdf_meth = {
EVP_KDF_SSHKDF,
kdf_sshkdf_new,
kdf_sshkdf_free,
kdf_sshkdf_reset,
kdf_sshkdf_ctrl,
kdf_sshkdf_ctrl_str,
kdf_sshkdf_size,
kdf_sshkdf_derive,
};
static int SSHKDF(const EVP_MD *evp_md,
const unsigned char *key, size_t key_len,
const unsigned char *xcghash, size_t xcghash_len,
const unsigned char *session_id, size_t session_id_len,
char type, unsigned char *okey, size_t okey_len)
{
EVP_MD_CTX *md = NULL;
unsigned char digest[EVP_MAX_MD_SIZE];
unsigned int dsize = 0;
size_t cursize = 0;
int ret = 0;
md = EVP_MD_CTX_new();
if (md == NULL)
return 0;
if (!EVP_DigestInit_ex(md, evp_md, NULL))
goto out;
if (!EVP_DigestUpdate(md, key, key_len))
goto out;
if (!EVP_DigestUpdate(md, xcghash, xcghash_len))
goto out;
if (!EVP_DigestUpdate(md, &type, 1))
goto out;
if (!EVP_DigestUpdate(md, session_id, session_id_len))
goto out;
if (!EVP_DigestFinal_ex(md, digest, &dsize))
goto out;
if (okey_len < dsize) {
memcpy(okey, digest, okey_len);
ret = 1;
goto out;
}
memcpy(okey, digest, dsize);
for (cursize = dsize; cursize < okey_len; cursize += dsize) {
if (!EVP_DigestInit_ex(md, evp_md, NULL))
goto out;
if (!EVP_DigestUpdate(md, key, key_len))
goto out;
if (!EVP_DigestUpdate(md, xcghash, xcghash_len))
goto out;
if (!EVP_DigestUpdate(md, okey, cursize))
goto out;
if (!EVP_DigestFinal_ex(md, digest, &dsize))
goto out;
if (okey_len < cursize + dsize) {
memcpy(okey + cursize, digest, okey_len - cursize);
ret = 1;
goto out;
}
memcpy(okey + cursize, digest, dsize);
}
ret = 1;
out:
EVP_MD_CTX_free(md);
OPENSSL_cleanse(digest, EVP_MAX_MD_SIZE);
return ret;
}

@ -43,12 +43,16 @@
#include <openssl/core_names.h>
#include <openssl/params.h>
#include "internal/cryptlib.h"
#include "internal/numbers.h"
#include "internal/evp_int.h"
#include "kdf_local.h"
#include "internal/provider_ctx.h"
#include "internal/providercommonerr.h"
#include "internal/provider_algs.h"
struct evp_kdf_impl_st {
typedef struct {
void *provctx;
EVP_MAC *mac; /* H(x) = HMAC_hash OR H(x) = KMAC */
const EVP_MD *md; /* H(x) = hash OR when H(x) = HMAC_hash */
EVP_MD *md; /* H(x) = hash OR when H(x) = HMAC_hash */
unsigned char *secret;
size_t secret_len;
unsigned char *info;
@ -56,7 +60,7 @@ struct evp_kdf_impl_st {
unsigned char *salt;
size_t salt_len;
size_t out_len; /* optional KMAC parameter */
};
} KDF_SSKDF;
#define SSKDF_MAX_INLEN (1<<30)
#define SSKDF_KMAC128_DEFAULT_SALT_SIZE (168 - 4)
@ -65,6 +69,16 @@ struct evp_kdf_impl_st {
/* KMAC uses a Customisation string of 'KDF' */
static const unsigned char kmac_custom_str[] = { 0x4B, 0x44, 0x46 };
static OSSL_OP_kdf_newctx_fn sskdf_new;
static OSSL_OP_kdf_freectx_fn sskdf_free;
static OSSL_OP_kdf_reset_fn sskdf_reset;
static OSSL_OP_kdf_derive_fn sskdf_derive;
static OSSL_OP_kdf_derive_fn x963kdf_derive;
static OSSL_OP_kdf_settable_ctx_params_fn sskdf_settable_ctx_params;
static OSSL_OP_kdf_set_ctx_params_fn sskdf_set_ctx_params;
static OSSL_OP_kdf_gettable_ctx_params_fn sskdf_gettable_ctx_params;
static OSSL_OP_kdf_get_ctx_params_fn sskdf_get_ctx_params;
/*
* Refer to https://csrc.nist.gov/publications/detail/sp/800-56c/rev-1/final
* Section 4. One-Step Key Derivation using H(x) = hash(x)
@ -287,172 +301,69 @@ end:
return ret;
}
static EVP_KDF_IMPL *sskdf_new(void)
static void *sskdf_new(void *provctx)
{
EVP_KDF_IMPL *impl;
KDF_SSKDF *ctx;
if ((impl = OPENSSL_zalloc(sizeof(*impl))) == NULL)
KDFerr(KDF_F_SSKDF_NEW, ERR_R_MALLOC_FAILURE);
return impl;
if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
ctx->provctx = provctx;
return ctx;
}
static void sskdf_reset(EVP_KDF_IMPL *impl)
static void sskdf_reset(void *vctx)
{
OPENSSL_clear_free(impl->secret, impl->secret_len);
OPENSSL_clear_free(impl->info, impl->info_len);
OPENSSL_clear_free(impl->salt, impl->salt_len);
EVP_MAC_free(impl->mac);
#if 0 /* TODO(3.0) When we switch to fetched MDs */
EVP_MD_meth_free(impl->md);
#endif
memset(impl, 0, sizeof(*impl));
}
KDF_SSKDF *ctx = (KDF_SSKDF *)vctx;
static void sskdf_free(EVP_KDF_IMPL *impl)
{
sskdf_reset(impl);
OPENSSL_free(impl);
OPENSSL_clear_free(ctx->secret, ctx->secret_len);
OPENSSL_clear_free(ctx->info, ctx->info_len);
OPENSSL_clear_free(ctx->salt, ctx->salt_len);
EVP_MAC_free(ctx->mac);
memset(ctx, 0, sizeof(*ctx));
}
static int sskdf_set_buffer(va_list args, unsigned char **out, size_t *out_len)
static void sskdf_free(void *vctx)
{
const unsigned char *p;
size_t len;
p = va_arg(args, const unsigned char *);
len = va_arg(args, size_t);
if (len == 0 || p == NULL)
return 1;
KDF_SSKDF *ctx = (KDF_SSKDF *)vctx;
OPENSSL_free(*out);
*out = OPENSSL_memdup(p, len);
if (*out == NULL)
return 0;
*out_len = len;
return 1;
sskdf_reset(ctx);
EVP_MD_meth_free(ctx->md);
EVP_MAC_free(ctx->mac);
OPENSSL_free(ctx);
}
static int sskdf_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args)
static int sskdf_set_buffer(unsigned char **out, size_t *out_len,
const OSSL_PARAM *p)
{
const EVP_MD *md;
switch (cmd) {
case EVP_KDF_CTRL_SET_KEY:
return sskdf_set_buffer(args, &impl->secret, &impl->secret_len);
case EVP_KDF_CTRL_SET_SSKDF_INFO:
return sskdf_set_buffer(args, &impl->info, &impl->info_len);
case EVP_KDF_CTRL_SET_MD:
md = va_arg(args, const EVP_MD *);
if (md == NULL)
return 0;
#if 0 /* TODO(3.0) When we switch to fetched MDs */
EVP_MD_meth_free(impl->md);
#endif
impl->md = md;
return 1;
case EVP_KDF_CTRL_SET_MAC:
{
const char *name;
EVP_MAC *mac;
name = va_arg(args, const char *);
if (name == NULL)
return 0;
EVP_MAC_free(impl->mac);
impl->mac = NULL;
/*
* TODO(3.0) add support for OPENSSL_CTX and properties in KDFs
*/
mac = EVP_MAC_fetch(NULL, name, NULL);
if (mac == NULL)
return 0;
impl->mac = mac;
return 1;
}
case EVP_KDF_CTRL_SET_SALT:
return sskdf_set_buffer(args, &impl->salt, &impl->salt_len);
case EVP_KDF_CTRL_SET_MAC_SIZE:
impl->out_len = va_arg(args, size_t);
if (p->data == NULL || p->data_size == 0)
return 1;
default:
return -2;
}
}
static int sskdf_ctrl_str(EVP_KDF_IMPL *impl, const char *type,
const char *value)
{
if (strcmp(type, "secret") == 0 || strcmp(type, "key") == 0)
return kdf_str2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_KEY,
value);
if (strcmp(type, "hexsecret") == 0 || strcmp(type, "hexkey") == 0)
return kdf_hex2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_KEY,
value);
if (strcmp(type, "info") == 0)
return kdf_str2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_SSKDF_INFO,
value);
if (strcmp(type, "hexinfo") == 0)
return kdf_hex2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_SSKDF_INFO,
value);
if (strcmp(type, "digest") == 0)
return kdf_md2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_MD, value);
if (strcmp(type, "mac") == 0)
return kdf_str2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_MAC, value);
if (strcmp(type, "salt") == 0)
return kdf_str2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_SALT, value);
if (strcmp(type, "hexsalt") == 0)
return kdf_hex2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_SALT, value);
if (strcmp(type, "maclen") == 0) {
int val = atoi(value);
if (val < 0) {
KDFerr(KDF_F_SSKDF_CTRL_STR, KDF_R_VALUE_ERROR);
return 0;
}
return call_ctrl(sskdf_ctrl, impl, EVP_KDF_CTRL_SET_MAC_SIZE,
(size_t)val);
}
return -2;
OPENSSL_free(*out);
*out = NULL;
return OSSL_PARAM_get_octet_string(p, (void **)out, 0, out_len);
}
static size_t sskdf_size(EVP_KDF_IMPL *impl)
static size_t sskdf_size(KDF_SSKDF *ctx)
{
int len;
if (impl->md == NULL) {
KDFerr(KDF_F_SSKDF_SIZE, KDF_R_MISSING_MESSAGE_DIGEST);
if (ctx->md == NULL) {
ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST);
return 0;
}
len = EVP_MD_size(impl->md);
len = EVP_MD_size(ctx->md);
return (len <= 0) ? 0 : (size_t)len;
}