From 7707526b8dfa8063c4537c11199c15ad7a3cab1c Mon Sep 17 00:00:00 2001 From: Pauli Date: Wed, 21 Aug 2019 08:06:29 +1000 Subject: [PATCH] Fix users of KDFs to use params not ctls Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/9662) --- crypto/dh/dh_kdf.c | 32 ++++--- crypto/ec/ecdh_kdf.c | 28 +++++-- crypto/evp/p5_crpt2.c | 26 ++++-- crypto/evp/pbe_scrypt.c | 25 ++++-- crypto/evp/pkey_kdf.c | 180 +++++++++++++++++++++++++++------------- 5 files changed, 198 insertions(+), 93 deletions(-) diff --git a/crypto/dh/dh_kdf.c b/crypto/dh/dh_kdf.c index 03b1e4edd5..781d34a94f 100644 --- a/crypto/dh/dh_kdf.c +++ b/crypto/dh/dh_kdf.c @@ -11,10 +11,12 @@ #ifndef OPENSSL_NO_CMS # include +# include # include # include # include # include +# include int DH_KDF_X9_42(unsigned char *out, size_t outlen, const unsigned char *Z, size_t Zlen, @@ -23,8 +25,12 @@ int DH_KDF_X9_42(unsigned char *out, size_t outlen, { int ret = 0, nid; EVP_KDF_CTX *kctx = NULL; - const EVP_KDF *kdf = NULL; + EVP_KDF *kdf = NULL; const char *oid_sn; + OSSL_PARAM params[5], *p = params; + const char *mdname = EVP_MD_name(md); + const OSSL_PROVIDER *prov = EVP_MD_provider(md); + OPENSSL_CTX *provctx = ossl_provider_library_context(prov); nid = OBJ_obj2nid(key_oid); if (nid == NID_undef) @@ -33,20 +39,24 @@ int DH_KDF_X9_42(unsigned char *out, size_t outlen, if (oid_sn == NULL) return 0; - kdf = EVP_get_kdfbyname(SN_x942kdf); - if (kdf == NULL) + kdf = EVP_KDF_fetch(provctx, SN_x942kdf, NULL); + if ((kctx = EVP_KDF_CTX_new(kdf)) == NULL) goto err; - kctx = EVP_KDF_CTX_new(kdf); - ret = - kctx != NULL - && EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_MD, md) > 0 - && EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KEY, Z, Zlen) > 0 - && (ukm == NULL - || EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_UKM, ukm, ukmlen) > 0) - && EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_CEK_ALG, oid_sn) > 0 + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, + (char *)mdname, strlen(mdname) + 1); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, + (unsigned char *)Z, Zlen); + if (ukm != NULL) + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_UKM, + (unsigned char *)ukm, ukmlen); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_CEK_ALG, + (char *)oid_sn, strlen(oid_sn) + 1); + *p = OSSL_PARAM_construct_end(); + ret = EVP_KDF_CTX_set_params(kctx, params) > 0 && EVP_KDF_derive(kctx, out, outlen) > 0; err: EVP_KDF_CTX_free(kctx); + EVP_KDF_free(kdf); return ret; } #endif /* OPENSSL_NO_CMS */ diff --git a/crypto/ec/ecdh_kdf.c b/crypto/ec/ecdh_kdf.c index f556dc66a0..55e676d20a 100644 --- a/crypto/ec/ecdh_kdf.c +++ b/crypto/ec/ecdh_kdf.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -19,18 +20,27 @@ int ecdh_KDF_X9_63(unsigned char *out, size_t outlen, const unsigned char *sinfo, size_t sinfolen, const EVP_MD *md) { - int ret; + int ret = 0; EVP_KDF_CTX *kctx = NULL; + OSSL_PARAM params[4], *p = params; + const char *mdname = EVP_MD_name(md); + EVP_KDF *kdf = EVP_KDF_fetch(NULL, SN_x963kdf, NULL); - kctx = EVP_KDF_CTX_new(EVP_get_kdfbyname(SN_x963kdf)); - ret = - kctx != NULL - && EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_MD, md) > 0 - && EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KEY, Z, Zlen) > 0 - && EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SHARED_INFO, sinfo, sinfolen) > 0 - && EVP_KDF_derive(kctx, out, outlen) > 0; + if ((kctx = EVP_KDF_CTX_new(kdf)) != NULL) { + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, + (char *)mdname, + strlen(mdname) + 1); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, + (void *)Z, Zlen); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, + (void *)sinfo, sinfolen); + *p = OSSL_PARAM_construct_end(); - EVP_KDF_CTX_free(kctx); + ret = EVP_KDF_CTX_set_params(kctx, params) > 0 + && EVP_KDF_derive(kctx, out, outlen) > 0; + EVP_KDF_CTX_free(kctx); + } + EVP_KDF_free(kdf); return ret; } diff --git a/crypto/evp/p5_crpt2.c b/crypto/evp/p5_crpt2.c index a7d4cafaf9..c12d35c8ab 100644 --- a/crypto/evp/p5_crpt2.c +++ b/crypto/evp/p5_crpt2.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "internal/evp_int.h" #include "evp_locl.h" @@ -23,8 +24,11 @@ int PKCS5_PBKDF2_HMAC(const char *pass, int passlen, const EVP_MD *digest, int keylen, unsigned char *out) { const char *empty = ""; - int rv = 1; + int rv = 1, mode = 1; + EVP_KDF *kdf; EVP_KDF_CTX *kctx; + const char *mdname = EVP_MD_name(digest); + OSSL_PARAM params[6], *p = params; /* Keep documented behaviour. */ if (pass == NULL) { @@ -36,15 +40,21 @@ int PKCS5_PBKDF2_HMAC(const char *pass, int passlen, if (salt == NULL && saltlen == 0) salt = (unsigned char *)empty; - kctx = EVP_KDF_CTX_new_id(EVP_KDF_PBKDF2); + kdf = EVP_KDF_fetch(NULL, LN_id_pbkdf2, NULL); + kctx = EVP_KDF_CTX_new(kdf); + EVP_KDF_free(kdf); if (kctx == NULL) return 0; - if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_PASS, pass, (size_t)passlen) != 1 - || EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_PBKDF2_PKCS5_MODE, 1) != 1 - || EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SALT, - salt, (size_t)saltlen) != 1 - || EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_ITER, iter) != 1 - || EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_MD, digest) != 1 + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD, + (char *)pass, (size_t)passlen); + *p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_PKCS5, &mode); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, + (unsigned char *)salt, saltlen); + *p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_ITER, &iter); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, + (char *)mdname, strlen(mdname) + 1); + *p = OSSL_PARAM_construct_end(); + if (EVP_KDF_CTX_set_params(kctx, params) != 1 || EVP_KDF_derive(kctx, out, keylen) != 1) rv = 0; diff --git a/crypto/evp/pbe_scrypt.c b/crypto/evp/pbe_scrypt.c index c0ab238eb8..7a9f6f47a4 100644 --- a/crypto/evp/pbe_scrypt.c +++ b/crypto/evp/pbe_scrypt.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "internal/numbers.h" #ifndef OPENSSL_NO_SCRYPT @@ -40,7 +41,9 @@ int EVP_PBE_scrypt(const char *pass, size_t passlen, { const char *empty = ""; int rv = 1; + EVP_KDF *kdf; EVP_KDF_CTX *kctx; + OSSL_PARAM params[7], *z = params; if (r > UINT32_MAX || p > UINT32_MAX) { EVPerr(EVP_F_EVP_PBE_SCRYPT, EVP_R_PARAMETER_TOO_LARGE); @@ -59,17 +62,23 @@ int EVP_PBE_scrypt(const char *pass, size_t passlen, if (maxmem == 0) maxmem = SCRYPT_MAX_MEM; - kctx = EVP_KDF_CTX_new_id(EVP_KDF_SCRYPT); + kdf = EVP_KDF_fetch(NULL, SN_id_scrypt, NULL); + kctx = EVP_KDF_CTX_new(kdf); + EVP_KDF_free(kdf); if (kctx == NULL) return 0; - if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_PASS, pass, (size_t)passlen) != 1 - || EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SALT, - salt, (size_t)saltlen) != 1 - || EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SCRYPT_N, N) != 1 - || EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SCRYPT_R, (uint32_t)r) != 1 - || EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SCRYPT_P, (uint32_t)p) != 1 - || EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_MAXMEM_BYTES, maxmem) != 1 + *z++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD, + (unsigned char *)pass, + passlen); + *z++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, + (unsigned char *)salt, saltlen); + *z++ = OSSL_PARAM_construct_uint64(OSSL_KDF_PARAM_SCRYPT_N, &N); + *z++ = OSSL_PARAM_construct_uint64(OSSL_KDF_PARAM_SCRYPT_R, &r); + *z++ = OSSL_PARAM_construct_uint64(OSSL_KDF_PARAM_SCRYPT_P, &p); + *z++ = OSSL_PARAM_construct_uint64(OSSL_KDF_PARAM_SCRYPT_MAXMEM, &maxmem); + *z = OSSL_PARAM_construct_end(); + if (EVP_KDF_CTX_set_params(kctx, params) != 1 || EVP_KDF_derive(kctx, key, keylen) != 1) rv = 0; diff --git a/crypto/evp/pkey_kdf.c b/crypto/evp/pkey_kdf.c index f983ad2ff3..977440814e 100644 --- a/crypto/evp/pkey_kdf.c +++ b/crypto/evp/pkey_kdf.c @@ -12,130 +12,187 @@ #include #include #include +#include +#include +#include #include "internal/numbers.h" #include "internal/evp_int.h" +#define MAX_PARAM 20 + +typedef struct { + EVP_KDF_CTX *kctx; + /* TODO(3.0): come up with a better way to do this */ + OSSL_PARAM params[MAX_PARAM]; + int palloc[MAX_PARAM]; + uint64_t uint64s[MAX_PARAM]; + int ints[MAX_PARAM]; + int pidx; +} EVP_PKEY_KDF_CTX; + +static void pkey_kdf_free_param_data(EVP_PKEY_KDF_CTX *pkctx) +{ + int i; + + for (i = 0; i < pkctx->pidx; i++) + if (pkctx->palloc[i]) + OPENSSL_free(pkctx->params[i].data); + pkctx->pidx = 0; +} + static int pkey_kdf_init(EVP_PKEY_CTX *ctx) { + EVP_PKEY_KDF_CTX *pkctx; EVP_KDF_CTX *kctx; + const char *kdf_name = OBJ_nid2sn(ctx->pmeth->pkey_id); + EVP_KDF *kdf; - kctx = EVP_KDF_CTX_new_id(ctx->pmeth->pkey_id); - if (kctx == NULL) + pkctx = OPENSSL_zalloc(sizeof(*pkctx)); + if (pkctx == NULL) return 0; - ctx->data = kctx; + kdf = EVP_KDF_fetch(NULL, kdf_name, NULL); + kctx = EVP_KDF_CTX_new(kdf); + EVP_KDF_free(kdf); + if (kctx == NULL) { + OPENSSL_free(pkctx); + return 0; + } + + pkctx->kctx = kctx; + ctx->data = pkctx; return 1; } static void pkey_kdf_cleanup(EVP_PKEY_CTX *ctx) { - EVP_KDF_CTX *kctx = ctx->data; + EVP_PKEY_KDF_CTX *pkctx = ctx->data; - EVP_KDF_CTX_free(kctx); + EVP_KDF_CTX_free(pkctx->kctx); + pkey_kdf_free_param_data(pkctx); + OPENSSL_free(pkctx); } static int pkey_kdf_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) { - EVP_KDF_CTX *kctx = ctx->data; - uint64_t u64_value; - int cmd; - int ret; + EVP_PKEY_KDF_CTX *pkctx = ctx->data; + enum { T_OCTET_STRING, T_UINT64, T_DIGEST, T_INT } cmd; + const char *name, *mdname; + OSSL_PARAM *p = pkctx->params + pkctx->pidx; switch (type) { case EVP_PKEY_CTRL_PASS: - cmd = EVP_KDF_CTRL_SET_PASS; + cmd = T_OCTET_STRING; + name = OSSL_KDF_PARAM_PASSWORD; break; case EVP_PKEY_CTRL_HKDF_SALT: case EVP_PKEY_CTRL_SCRYPT_SALT: - cmd = EVP_KDF_CTRL_SET_SALT; + cmd = T_OCTET_STRING; + name = OSSL_KDF_PARAM_SALT; break; case EVP_PKEY_CTRL_TLS_MD: case EVP_PKEY_CTRL_HKDF_MD: - cmd = EVP_KDF_CTRL_SET_MD; + cmd = T_DIGEST; + name = OSSL_KDF_PARAM_DIGEST; break; case EVP_PKEY_CTRL_TLS_SECRET: - cmd = EVP_KDF_CTRL_SET_TLS_SECRET; - ret = EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_RESET_TLS_SEED); - if (ret < 1) - return ret; + cmd = T_OCTET_STRING; + name = OSSL_KDF_PARAM_SECRET; break; case EVP_PKEY_CTRL_TLS_SEED: - cmd = EVP_KDF_CTRL_ADD_TLS_SEED; + cmd = T_OCTET_STRING; + name = OSSL_KDF_PARAM_SEED; break; case EVP_PKEY_CTRL_HKDF_KEY: - cmd = EVP_KDF_CTRL_SET_KEY; + cmd = T_OCTET_STRING; + name = OSSL_KDF_PARAM_KEY; break; case EVP_PKEY_CTRL_HKDF_INFO: - cmd = EVP_KDF_CTRL_ADD_HKDF_INFO; + cmd = T_OCTET_STRING; + name = OSSL_KDF_PARAM_INFO; break; case EVP_PKEY_CTRL_HKDF_MODE: - cmd = EVP_KDF_CTRL_SET_HKDF_MODE; + cmd = T_INT; + name = OSSL_KDF_PARAM_MODE; break; case EVP_PKEY_CTRL_SCRYPT_N: - cmd = EVP_KDF_CTRL_SET_SCRYPT_N; + cmd = T_UINT64; + name = OSSL_KDF_PARAM_SCRYPT_N; break; case EVP_PKEY_CTRL_SCRYPT_R: - cmd = EVP_KDF_CTRL_SET_SCRYPT_R; + cmd = T_UINT64; /* Range checking occurs on the provider side */ + name = OSSL_KDF_PARAM_SCRYPT_R; break; case EVP_PKEY_CTRL_SCRYPT_P: - cmd = EVP_KDF_CTRL_SET_SCRYPT_P; + cmd = T_UINT64; /* Range checking occurs on the provider side */ + name = OSSL_KDF_PARAM_SCRYPT_P; break; case EVP_PKEY_CTRL_SCRYPT_MAXMEM_BYTES: - cmd = EVP_KDF_CTRL_SET_MAXMEM_BYTES; + cmd = T_UINT64; + name = OSSL_KDF_PARAM_SCRYPT_MAXMEM; break; default: return -2; } switch (cmd) { - case EVP_KDF_CTRL_SET_PASS: - case EVP_KDF_CTRL_SET_SALT: - case EVP_KDF_CTRL_SET_KEY: - case EVP_KDF_CTRL_SET_TLS_SECRET: - case EVP_KDF_CTRL_ADD_TLS_SEED: - case EVP_KDF_CTRL_ADD_HKDF_INFO: - return EVP_KDF_ctrl(kctx, cmd, (const unsigned char *)p2, (size_t)p1); - - case EVP_KDF_CTRL_SET_MD: - return EVP_KDF_ctrl(kctx, cmd, (const EVP_MD *)p2); - - case EVP_KDF_CTRL_SET_HKDF_MODE: - return EVP_KDF_ctrl(kctx, cmd, (int)p1); - - case EVP_KDF_CTRL_SET_SCRYPT_R: - case EVP_KDF_CTRL_SET_SCRYPT_P: - u64_value = *(uint64_t *)p2; - if (u64_value > UINT32_MAX) { - EVPerr(EVP_F_PKEY_KDF_CTRL, EVP_R_PARAMETER_TOO_LARGE); - return 0; - } + case T_OCTET_STRING: + *p = OSSL_PARAM_construct_octet_string(name, (unsigned char *)p2, + (size_t)p1); + break; - return EVP_KDF_ctrl(kctx, cmd, (uint32_t)u64_value); + case T_DIGEST: + mdname = EVP_MD_name((const EVP_MD *)p2); + *p = OSSL_PARAM_construct_utf8_string(name, (char *)mdname, + strlen(mdname) + 1); + break; - case EVP_KDF_CTRL_SET_SCRYPT_N: - case EVP_KDF_CTRL_SET_MAXMEM_BYTES: - return EVP_KDF_ctrl(kctx, cmd, *(uint64_t *)p2); + /* + * These are special because the helper macros pass a pointer to the + * stack, so a local copy is required. + */ + case T_INT: + pkctx->ints[pkctx->pidx] = *(int *)p2; + *p = OSSL_PARAM_construct_int(name, pkctx->ints + pkctx->pidx); + break; - default: - return 0; + case T_UINT64: + pkctx->uint64s[pkctx->pidx] = *(uint64_t *)p2; + *p = OSSL_PARAM_construct_uint64(name, pkctx->uint64s + pkctx->pidx); + break; } + pkctx->palloc[pkctx->pidx++] = 0; + return 1; } static int pkey_kdf_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, const char *value) { - EVP_KDF_CTX *kctx = ctx->data; + EVP_PKEY_KDF_CTX *pkctx = ctx->data; + EVP_KDF_CTX *kctx = pkctx->kctx; + const EVP_KDF *kdf = EVP_KDF_CTX_kdf(kctx); + const OSSL_PARAM *defs = EVP_KDF_CTX_settable_params(kdf); + OSSL_PARAM *p = pkctx->params + pkctx->pidx; + /* Deal with ctrl name aliasing */ if (strcmp(type, "md") == 0) - return EVP_KDF_ctrl_str(kctx, "digest", value); - return EVP_KDF_ctrl_str(kctx, type, value); + type = OSSL_KDF_PARAM_DIGEST; + /* scrypt uses 'N', params uses 'n' */ + if (strcmp(type, "N") == 0) + type = OSSL_KDF_PARAM_SCRYPT_N; + + if (!OSSL_PARAM_allocate_from_text(p, defs, type, value, strlen(value))) + return 0; + pkctx->palloc[pkctx->pidx++] = 1; + return 1; } static int pkey_kdf_derive_init(EVP_PKEY_CTX *ctx) { - EVP_KDF_CTX *kctx = ctx->data; + EVP_PKEY_KDF_CTX *pkctx = ctx->data; - EVP_KDF_reset(kctx); + pkey_kdf_free_param_data(pkctx); + EVP_KDF_reset(pkctx->kctx); return 1; } @@ -146,9 +203,18 @@ static int pkey_kdf_derive_init(EVP_PKEY_CTX *ctx) static int pkey_kdf_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen) { - EVP_KDF_CTX *kctx = ctx->data; + EVP_PKEY_KDF_CTX *pkctx = ctx->data; + EVP_KDF_CTX *kctx = pkctx->kctx; size_t outlen = EVP_KDF_size(kctx); + int r; + if (pkctx->pidx > 0) { + pkctx->params[pkctx->pidx] = OSSL_PARAM_construct_end(); + r = EVP_KDF_CTX_set_params(kctx, pkctx->params); + pkey_kdf_free_param_data(pkctx); + if (!r) + return 0; + } if (outlen == 0 || outlen == SIZE_MAX) { /* Variable-output algorithm */ if (key == NULL) -- 2.25.1