diff options
-rw-r--r-- | crypto/dh/build.info | 5 | ||||
-rw-r--r-- | crypto/dh/dh_ctrl.c | 566 | ||||
-rw-r--r-- | crypto/dh/dh_kdf.c | 74 | ||||
-rw-r--r-- | crypto/dh/dh_lib.c | 192 | ||||
-rw-r--r-- | crypto/evp/pmeth_lib.c | 23 | ||||
-rw-r--r-- | doc/man3/EVP_PKEY_CTX_ctrl.pod | 27 | ||||
-rw-r--r-- | include/crypto/dh.h | 6 | ||||
-rw-r--r-- | include/openssl/dh.h | 49 | ||||
-rw-r--r-- | providers/implementations/exchange/dh_exch.c | 302 | ||||
-rw-r--r-- | test/evp_libctx_test.c | 88 |
10 files changed, 1044 insertions, 288 deletions
diff --git a/crypto/dh/build.info b/crypto/dh/build.info index 656e6ea828..887ef78b0b 100644 --- a/crypto/dh/build.info +++ b/crypto/dh/build.info @@ -1,10 +1,11 @@ LIBS=../../libcrypto -$COMMON=dh_lib.c dh_key.c dh_group_params.c dh_check.c dh_backend.c dh_gen.c +$COMMON=dh_lib.c dh_key.c dh_group_params.c dh_check.c dh_backend.c dh_gen.c \ + dh_kdf.c SOURCE[../../libcrypto]=$COMMON\ dh_asn1.c dh_err.c \ - dh_ameth.c dh_pmeth.c dh_prn.c dh_rfc5114.c dh_kdf.c dh_meth.c + dh_ameth.c dh_pmeth.c dh_prn.c dh_rfc5114.c dh_meth.c dh_ctrl.c IF[{- !$disabled{'deprecated-0.9.8'} -}] SOURCE[../../libcrypto]=dh_depr.c ENDIF diff --git a/crypto/dh/dh_ctrl.c b/crypto/dh/dh_ctrl.c new file mode 100644 index 0000000000..6fddd271a8 --- /dev/null +++ b/crypto/dh/dh_ctrl.c @@ -0,0 +1,566 @@ +/* + * Copyright 1995-2020 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 + */ + +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <stdio.h> +#include "crypto/evp.h" +#include <openssl/bn.h> +#include <openssl/engine.h> +#include <openssl/obj_mac.h> +#include <openssl/core_names.h> +#include "internal/cryptlib.h" +#include "internal/refcount.h" +#include "crypto/dh.h" +#include "dh_local.h" + +static int dh_paramgen_check(EVP_PKEY_CTX *ctx) +{ + if (ctx == NULL || !EVP_PKEY_CTX_IS_GEN_OP(ctx)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + /* If key type not DH return error */ + if (ctx->pmeth != NULL + && ctx->pmeth->pkey_id != EVP_PKEY_DH + && ctx->pmeth->pkey_id != EVP_PKEY_DHX) + return -1; + return 1; +} + +static int dh_param_derive_check(EVP_PKEY_CTX *ctx) +{ + if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + /* If key type not DH return error */ + if (ctx->pmeth != NULL + && ctx->pmeth->pkey_id != EVP_PKEY_DH + && ctx->pmeth->pkey_id != EVP_PKEY_DHX) + return -1; + return 1; +} + +int EVP_PKEY_CTX_set_dh_paramgen_gindex(EVP_PKEY_CTX *ctx, int gindex) +{ + int ret; + OSSL_PARAM params[2], *p = params; + + if ((ret = dh_paramgen_check(ctx)) <= 0) + return ret; + + *p++ = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_FFC_GINDEX, &gindex); + *p = OSSL_PARAM_construct_end(); + + return EVP_PKEY_CTX_set_params(ctx, params); +} + +int EVP_PKEY_CTX_set_dh_paramgen_seed(EVP_PKEY_CTX *ctx, + const unsigned char *seed, + size_t seedlen) +{ + int ret; + OSSL_PARAM params[2], *p = params; + + if ((ret = dh_paramgen_check(ctx)) <= 0) + return ret; + + *p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_FFC_SEED, + (void *)seed, seedlen); + *p = OSSL_PARAM_construct_end(); + + return EVP_PKEY_CTX_set_params(ctx, params); +} + +int EVP_PKEY_CTX_set_dh_paramgen_type(EVP_PKEY_CTX *ctx, int typ) +{ + int ret; + OSSL_PARAM params[2], *p = params; + const char *name; + + if ((ret = dh_paramgen_check(ctx)) <= 0) + return ret; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.keymgmt.genctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, + EVP_PKEY_CTRL_DH_PARAMGEN_TYPE, typ, NULL); + + name = dh_gen_type_id2name(typ); + if (name == NULL) + return 0; + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_FFC_TYPE, + (char *) name, 0); + *p = OSSL_PARAM_construct_end(); + + return EVP_PKEY_CTX_set_params(ctx, params); +} + +int EVP_PKEY_CTX_set_dh_paramgen_prime_len(EVP_PKEY_CTX *ctx, int pbits) +{ + int ret; + OSSL_PARAM params[2], *p = params; + size_t bits = pbits; + + if ((ret = dh_paramgen_check(ctx)) <= 0) + return ret; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.keymgmt.genctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, + EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN, pbits, + NULL); + *p++ = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_FFC_PBITS, &bits); + *p = OSSL_PARAM_construct_end(); + return EVP_PKEY_CTX_set_params(ctx, params); +} + +int EVP_PKEY_CTX_set_dh_paramgen_subprime_len(EVP_PKEY_CTX *ctx, int qbits) +{ + int ret; + OSSL_PARAM params[2], *p = params; + size_t bits2 = qbits; + + if ((ret = dh_paramgen_check(ctx)) <= 0) + return ret; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.keymgmt.genctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, + EVP_PKEY_CTRL_DH_PARAMGEN_SUBPRIME_LEN, qbits, + NULL); + *p++ = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_FFC_QBITS, &bits2); + *p = OSSL_PARAM_construct_end(); + + return EVP_PKEY_CTX_set_params(ctx, params); +} + +int EVP_PKEY_CTX_set_dh_paramgen_generator(EVP_PKEY_CTX *ctx, int gen) +{ + int ret; + OSSL_PARAM params[2], *p = params; + + if ((ret = dh_paramgen_check(ctx)) <= 0) + return ret; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.keymgmt.genctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, + EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR, gen, NULL); + *p++ = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_DH_GENERATOR, &gen); + *p = OSSL_PARAM_construct_end(); + + return EVP_PKEY_CTX_set_params(ctx, params); +} + +int EVP_PKEY_CTX_set_dh_rfc5114(EVP_PKEY_CTX *ctx, int gen) +{ + int ret; + OSSL_PARAM params[2], *p = params; + const char *name; + + if ((ret = dh_paramgen_check(ctx)) <= 0) + return ret; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.keymgmt.genctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_PARAMGEN, + EVP_PKEY_CTRL_DH_RFC5114, gen, NULL); + name = ffc_named_group_from_uid(gen); + if (name == NULL) + return 0; + + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + (void *)name, 0); + *p = OSSL_PARAM_construct_end(); + return EVP_PKEY_CTX_set_params(ctx, params); +} + +int EVP_PKEY_CTX_set_dhx_rfc5114(EVP_PKEY_CTX *ctx, int gen) +{ + return EVP_PKEY_CTX_set_dh_rfc5114(ctx, gen); +} + +int EVP_PKEY_CTX_set_dh_nid(EVP_PKEY_CTX *ctx, int nid) +{ + int ret; + OSSL_PARAM params[2], *p = params; + const char *name; + + if ((ret = dh_paramgen_check(ctx)) <= 0) + return ret; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.keymgmt.genctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, + EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN, + EVP_PKEY_CTRL_DH_NID, nid, NULL); + name = ffc_named_group_from_uid(nid); + if (name == NULL) + return 0; + + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + (void *)name, 0); + *p = OSSL_PARAM_construct_end(); + return EVP_PKEY_CTX_set_params(ctx, params); +} + +int EVP_PKEY_CTX_set_dh_kdf_type(EVP_PKEY_CTX *ctx, int kdf) +{ + int ret; + const char *kdf_type; + OSSL_PARAM params[2], *p = params; + + ret = dh_param_derive_check(ctx); + if (ret != 1) + return ret; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.kex.exchprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_DH_KDF_TYPE, kdf, NULL); + switch (kdf) { + case EVP_PKEY_DH_KDF_NONE: + kdf_type = ""; + break; + case EVP_PKEY_DH_KDF_X9_42: + kdf_type = OSSL_KDF_NAME_X942KDF; + break; + default: + return -2; + } + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, + /* + * Cast away the const. This is read + * only so should be safe + */ + (char *)kdf_type, 0); + *p = OSSL_PARAM_construct_end(); + + ret = evp_pkey_ctx_set_params_strict(ctx, params); + if (ret == -2) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + return ret; +} + +int EVP_PKEY_CTX_get_dh_kdf_type(EVP_PKEY_CTX *ctx) +{ + int ret; + char kdf_type[80]; /* 80 should be big enough */ + OSSL_PARAM params[2], *p = params; + + ret = dh_param_derive_check(ctx); + if (ret != 1) + return ret; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.kex.exchprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_DH_KDF_TYPE, -2, NULL); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, + kdf_type, sizeof(kdf_type)); + *p = OSSL_PARAM_construct_end(); + + ret = evp_pkey_ctx_get_params_strict(ctx, params); + if (ret == -2) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } else if (ret != 1) { + return -1; + } + + if (kdf_type[0] == '\0') + return EVP_PKEY_DH_KDF_NONE; + else if (strcmp(kdf_type, OSSL_KDF_NAME_X942KDF) == 0) + return EVP_PKEY_DH_KDF_X9_42; + + return -1; +} + +int EVP_PKEY_CTX_set0_dh_kdf_oid(EVP_PKEY_CTX *ctx, ASN1_OBJECT *oid) +{ + int ret; + OSSL_PARAM params[2], *p = params; + const char *oid_name; + + ret = dh_param_derive_check(ctx); + if (ret != 1) + return ret; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.kex.exchprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_DH_KDF_OID, 0, (void *)(oid)); + oid_name = OBJ_nid2sn(OBJ_obj2nid(oid)); + + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_CEK_ALG, + (char *)oid_name, 0); + *p = OSSL_PARAM_construct_end(); + ret = evp_pkey_ctx_set_params_strict(ctx, params); + if (ret == -2) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + + return ret; +} + +int EVP_PKEY_CTX_get0_dh_kdf_oid(EVP_PKEY_CTX *ctx, ASN1_OBJECT **oid) +{ + int ret, nid; + OSSL_PARAM params[2], *p = params; + char oid_name[80]; /* 80 should be big enough */ + + ret = dh_param_derive_check(ctx); + if (ret != 1) + return ret; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.kex.exchprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_GET_DH_KDF_OID, 0, (void *)(oid)); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_CEK_ALG, + oid_name, sizeof(oid_name)); + *p = OSSL_PARAM_construct_end(); + + ret = evp_pkey_ctx_get_params_strict(ctx, params); + if (ret == -2) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } else if (ret != 1) { + return -1; + } + nid = OBJ_sn2nid(oid_name); + if (nid == NID_undef) + nid = OBJ_ln2nid(oid_name); + *oid = (nid == NID_undef ? NULL : OBJ_nid2obj(nid)); + return *oid != NULL; +} + +int EVP_PKEY_CTX_set_dh_kdf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) +{ + int ret; + OSSL_PARAM params[2], *p = params; + const char *md_name = NULL; + + ret = dh_param_derive_check(ctx); + if (ret != 1) + return ret; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.kex.exchprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_DH_KDF_MD, 0, (void *)(md)); + md_name = (md == NULL) ? "" : EVP_MD_name(md); + + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, + /* + * Cast away the const. This is read + * only so should be safe + */ + (char *)md_name, 0); + *p = OSSL_PARAM_construct_end(); + + ret = evp_pkey_ctx_set_params_strict(ctx, params); + if (ret == -2) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + return ret; +} + +int EVP_PKEY_CTX_get_dh_kdf_md(EVP_PKEY_CTX *ctx, const EVP_MD **pmd) +{ + int ret; + char name[80] = ""; /* 80 should be big enough */ + OSSL_PARAM params[2], *p = params; + + ret = dh_param_derive_check(ctx); + if (ret != 1) + return ret; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.kex.exchprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_GET_DH_KDF_MD, 0, (void *)(pmd)); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, + name, sizeof(name)); + *p = OSSL_PARAM_construct_end(); + + ret = evp_pkey_ctx_get_params_strict(ctx, params); + if (ret == -2) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } else if (ret != 1) { + return -1; + } + + /* May be NULL meaning "unknown" */ + *pmd = EVP_get_digestbyname(name); + + return 1; +} + +int EVP_PKEY_CTX_set_dh_kdf_outlen(EVP_PKEY_CTX *ctx, int inlen) +{ + int ret; + size_t len = inlen; + OSSL_PARAM params[2], *p = params; + + ret = dh_param_derive_check(ctx); + if (ret != 1) + return ret; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.kex.exchprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_DH_KDF_OUTLEN, inlen, NULL); + if (inlen <= 0) { + /* + * This would ideally be -1 or 0, but we have to retain compatibility + * with legacy behaviour of EVP_PKEY_CTX_ctrl() which returned -2 if + * in <= 0 + */ + return -2; + } + + *p++ = OSSL_PARAM_construct_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, + &len); + *p = OSSL_PARAM_construct_end(); + + ret = evp_pkey_ctx_set_params_strict(ctx, params); + if (ret == -2) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + return ret; +} + +int EVP_PKEY_CTX_get_dh_kdf_outlen(EVP_PKEY_CTX *ctx, int *plen) +{ + int ret; + size_t len = UINT_MAX; + OSSL_PARAM params[2], *p = params; + + ret = dh_param_derive_check(ctx); + if (ret != 1) + return ret; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.kex.exchprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_GET_DH_KDF_OUTLEN, 0, + (void *)(plen)); + *p++ = OSSL_PARAM_construct_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, + &len); + *p = OSSL_PARAM_construct_end(); + + ret = evp_pkey_ctx_get_params_strict(ctx, params); + if (ret == -2) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } else if (ret != 1) { + return -1; + } + + if (len > INT_MAX) + return -1; + + *plen = (int)len; + + return 1; +} + +int EVP_PKEY_CTX_set0_dh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char *ukm, int len) +{ + int ret; + OSSL_PARAM params[2], *p = params; + + ret = dh_param_derive_check(ctx); + if (ret != 1) + return ret; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.kex.exchprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_DH_KDF_UKM, len, (void *)(ukm)); + + *p++ = OSSL_PARAM_construct_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, + /* + * Cast away the const. This is read + * only so should be safe + */ + (void *)ukm, + (size_t)len); + *p = OSSL_PARAM_construct_end(); + + ret = evp_pkey_ctx_set_params_strict(ctx, params); + if (ret == -2) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } + if (ret == 1) + OPENSSL_free(ukm); + return ret; +} + +int EVP_PKEY_CTX_get0_dh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char **pukm) +{ + int ret; + size_t ukmlen; + OSSL_PARAM params[3], *p = params; + + ret = dh_param_derive_check(ctx); + if (ret != 1) + return ret; + + /* TODO(3.0): Remove this eventually when no more legacy */ + if (ctx->op.kex.exchprovctx == NULL) + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE, + EVP_PKEY_CTRL_GET_DH_KDF_UKM, 0, (void *)(pukm)); + + *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_EXCHANGE_PARAM_KDF_UKM, + (void **)pukm, 0); + *p++ = OSSL_PARAM_construct_size_t(OSSL_EXCHANGE_PARAM_KDF_UKM_LEN, + &ukmlen); + *p = OSSL_PARAM_construct_end(); + + ret = evp_pkey_ctx_get_params_strict(ctx, params); + if (ret == -2) { + ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); + /* Uses the same return values as EVP_PKEY_CTX_ctrl */ + return -2; + } else if (ret != 1) { + return -1; + } + + if (ukmlen > INT_MAX) + return -1; + + return (int)ukmlen; +} diff --git a/crypto/dh/dh_kdf.c b/crypto/dh/dh_kdf.c index 1b8a320db1..0b1e5881c3 100644 --- a/crypto/dh/dh_kdf.c +++ b/crypto/dh/dh_kdf.c @@ -14,40 +14,34 @@ #include "internal/deprecated.h" #include "e_os.h" +#include "e_os.h" +#include <string.h> +#include <openssl/core_names.h> +#include <openssl/dh.h> +#include <openssl/evp.h> +#include <openssl/asn1.h> +#include <openssl/kdf.h> +#include <internal/provider.h> +#include <crypto/dh.h> -#ifndef OPENSSL_NO_CMS -# include <string.h> -# include <openssl/core_names.h> -# include <openssl/dh.h> -# include <openssl/evp.h> -# include <openssl/asn1.h> -# include <openssl/kdf.h> -# include <internal/provider.h> - -int DH_KDF_X9_42(unsigned char *out, size_t outlen, - const unsigned char *Z, size_t Zlen, - ASN1_OBJECT *key_oid, - const unsigned char *ukm, size_t ukmlen, const EVP_MD *md) +/* Key derivation function from X9.63/SECG */ +int dh_KDF_X9_42_asn1(unsigned char *out, size_t outlen, + const unsigned char *Z, size_t Zlen, + const char *cek_alg, + const unsigned char *ukm, size_t ukmlen, const EVP_MD *md, + OPENSSL_CTX *libctx, const char *propq) { - int ret = 0, nid; + int ret = 0; EVP_KDF_CTX *kctx = 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) - return 0; - oid_sn = OBJ_nid2sn(nid); - if (oid_sn == NULL) - return 0; - - kdf = EVP_KDF_fetch(provctx, OSSL_KDF_NAME_X942KDF, NULL); - if ((kctx = EVP_KDF_CTX_new(kdf)) == NULL) + kdf = EVP_KDF_fetch(libctx, OSSL_KDF_NAME_X942KDF, propq); + kctx = EVP_KDF_CTX_new(kdf); + if (kctx == NULL) goto err; + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, (char *)mdname, 0); *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, @@ -56,13 +50,35 @@ int DH_KDF_X9_42(unsigned char *out, size_t outlen, *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, 0); + (char *)cek_alg, 0); *p = OSSL_PARAM_construct_end(); ret = EVP_KDF_CTX_set_params(kctx, params) > 0 - && EVP_KDF_derive(kctx, out, outlen) > 0; + && EVP_KDF_derive(kctx, out, outlen) > 0; err: EVP_KDF_CTX_free(kctx); EVP_KDF_free(kdf); return ret; } -#endif /* OPENSSL_NO_CMS */ + +#if !defined(FIPS_MODULE) && !defined(OPENSSL_NO_CMS) +int DH_KDF_X9_42(unsigned char *out, size_t outlen, + const unsigned char *Z, size_t Zlen, + ASN1_OBJECT *key_oid, + const unsigned char *ukm, size_t ukmlen, const EVP_MD *md) +{ + int nid; + const char *key_alg = NULL; + const OSSL_PROVIDER *prov = EVP_MD_provider(md); + OPENSSL_CTX *libctx = ossl_provider_library_context(prov); + + nid = OBJ_obj2nid(key_oid); + if (nid == NID_undef) + return 0; + key_alg = OBJ_nid2sn(nid); + if (key_alg == NULL) + return 0; + + return dh_KDF_X9_42_asn1(out, outlen, Z, Zlen, key_alg, + ukm, ukmlen, md, libctx, NULL); +} +#endif /* !defined(FIPS_MODULE) && !defined(OPENSSL_NO_CMS) */ diff --git a/crypto/dh/dh_lib.c b/crypto/dh/dh_lib.c index 2a3921a137..a6f4e64137 100644 --- a/crypto/dh/dh_lib.c +++ b/crypto/dh/dh_lib.c @@ -344,195 +344,3 @@ int dh_ffc_params_fromdata(DH *dh, const OSSL_PARAM params[]) } return ret; } - -static int dh_paramgen_check(EVP_PKEY_CTX *ctx) -{ - if (ctx == NULL || !EVP_PKEY_CTX_IS_GEN_OP(ctx)) { - ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED); - /* Uses the same return values as EVP_PKEY_CTX_ctrl */ - return -2; - } - /* If key type not DH return error */ - if (ctx->pmeth != NULL - && ctx->pmeth->pkey_id != EVP_PKEY_DH - && ctx->pmeth->pkey_id != EVP_PKEY_DHX) - return -1; - return 1; -} - -int EVP_PKEY_CTX_set_dh_paramgen_gindex(EVP_PKEY_CTX *ctx, int gindex) -{ - int ret; - OSSL_PARAM params[2], *p = params; - - if ((ret = dh_paramgen_check(ctx)) <= 0) - return ret; - - *p++ = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_FFC_GINDEX, &gindex); - *p++ = OSSL_PARAM_construct_end(); - - return EVP_PKEY_CTX_set_params(ctx, params); -} - -int EVP_PKEY_CTX_set_dh_paramgen_seed(EVP_PKEY_CTX *ctx, - const unsigned char *seed, - size_t seedlen) -{ - int ret; - OSSL_PARAM params[2], *p = params; - - if ((ret = dh_paramgen_check(ctx)) <= 0) - return ret; - - *p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_FFC_SEED, - (void *)seed, seedlen); - *p++ = OSSL_PARAM_construct_end(); - - return EVP_PKEY_CTX_set_params(ctx, params); -} - -int EVP_PKEY_CTX_set_dh_paramgen_type(EVP_PKEY_CTX *ctx, int typ) -{ - int ret; - OSSL_PARAM params[2], *p = params; - const char *name; - - if ((ret = dh_paramgen_check(ctx)) <= 0) - return ret; - -#if !defined(FIPS_MODULE) - /* TODO(3.0): Remove this eventually when no more legacy */ - if (ctx->op.keymgmt.genctx == NULL) - return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, - EVP_PKEY_CTRL_DH_PARAMGEN_TYPE, typ, NULL); -#endif - - name = dh_gen_type_id2name(typ); - if (name == NULL) - return 0; - *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_FFC_TYPE, - (char *) name, 0); - *p++ = OSSL_PARAM_construct_end(); - - return EVP_PKEY_CTX_set_params(ctx, params); -} - -int EVP_PKEY_CTX_set_dh_paramgen_prime_len(EVP_PKEY_CTX *ctx, int pbits) -{ - int ret; - OSSL_PARAM params[2], *p = params; - size_t bits = pbits; - - if ((ret = dh_paramgen_check(ctx)) <= 0) - return ret; - -#if !defined(FIPS_MODULE) - /* TODO(3.0): Remove this eventually when no more legacy */ - if (ctx->op.keymgmt.genctx == NULL) - return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, - EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN, pbits, - NULL); -#endif - *p++ = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_FFC_PBITS, &bits); - *p++ = OSSL_PARAM_construct_end(); - return EVP_PKEY_CTX_set_params(ctx, params); -} - -int EVP_PKEY_CTX_set_dh_paramgen_subprime_len(EVP_PKEY_CTX *ctx, int qbits) -{ - int ret; - OSSL_PARAM params[2], *p = params; - size_t bits2 = qbits; - - if ((ret = dh_paramgen_check(ctx)) <= 0) - return ret; - -#if !defined(FIPS_MODULE) - /* TODO(3.0): Remove this eventually when no more legacy */ - if (ctx->op.keymgmt.genctx == NULL) - return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, - EVP_PKEY_CTRL_DH_PARAMGEN_SUBPRIME_LEN, qbits, - NULL); -#endif - *p++ = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_FFC_QBITS, &bits2); - *p++ = OSSL_PARAM_construct_end(); - - return EVP_PKEY_CTX_set_params(ctx, params); -} - -int EVP_PKEY_CTX_set_dh_paramgen_generator(EVP_PKEY_CTX *ctx, int gen) -{ - int ret; - OSSL_PARAM params[2], *p = params; - - if ((ret = dh_paramgen_check(ctx)) <= 0) - return ret; - -#if !defined(FIPS_MODULE) - /* TODO(3.0): Remove this eventually when no more legacy */ - if (ctx->op.keymgmt.genctx == NULL) - return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, - EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR, gen, NULL); -#endif - - *p++ = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_DH_GENERATOR, &gen); - *p++ = OSSL_PARAM_construct_end(); - - return EVP_PKEY_CTX_set_params(ctx, params); -} - -int EVP_PKEY_CTX_set_dh_rfc5114(EVP_PKEY_CTX *ctx, int gen) -{ - int ret; - OSSL_PARAM params[2], *p = params; - const char *name; - - if ((ret = dh_paramgen_check(ctx)) <= 0) - return ret; - -#if !defined(FIPS_MODULE) - /* TODO(3.0): Remove this eventually when no more legacy */ - if (ctx->op.keymgmt.genctx == NULL) - return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_PARAMGEN, - EVP_PKEY_CTRL_DH_RFC5114, gen, NULL); -#endif - name = ffc_named_group_from_uid(gen); - if (name == NULL) - return 0; - - *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, - (void *)name, 0); - *p++ = OSSL_PARAM_construct_end(); - return EVP_PKEY_CTX_set_params(ctx, params); -} - -int EVP_PKEY_CTX_set_dhx_rfc5114(EVP_PKEY_CTX *ctx, int gen) -{ - return EVP_PKEY_CTX_set_dh_rfc5114(ctx, gen); -} - -int EVP_PKEY_CTX_set_dh_nid(EVP_PKEY_CTX *ctx, int nid) -{ - int ret; - OSSL_PARAM params[2], *p = params; - const char *name; - - if ((ret = dh_paramgen_check(ctx)) <= 0) - return ret; - -#if !defined(FIPS_MODULE) - /* TODO(3.0): Remove this eventually when no more legacy */ - if (ctx->op.keymgmt.genctx == NULL) - return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, - EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN, - EVP_PKEY_CTRL_DH_NID, nid, NULL); -#endif - name = ffc_named_group_from_uid(nid); - if (name == NULL) - return 0; - - *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, - (void *)name, 0); - *p++ = OSSL_PARAM_construct_end(); - return EVP_PKEY_CTX_set_params(ctx, params); -} diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index 6f2f52912b..ba85a8c143 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -150,7 +150,6 @@ static int is_legacy_alg(int id, const char *keytype) * support */ case EVP_PKEY_SM2: - case EVP_PKEY_DHX: case EVP_PKEY_CMAC: case EVP_PKEY_HMAC: case EVP_PKEY_SIPHASH: @@ -1040,6 +1039,28 @@ static int legacy_ctrl_to_param(EVP_PKEY_CTX *ctx, int keytype, int optype, return -2; # ifndef OPENSSL_NO_DH + if (keytype == EVP_PKEY_DHX) { + switch (cmd) { + case EVP_PKEY_CTRL_DH_KDF_TYPE: + return EVP_PKEY_CTX_set_dh_kdf_type(ctx, p1); + case EVP_PKEY_CTRL_DH_KDF_MD: + return EVP_PKEY_CTX_set_dh_kdf_md(ctx, p2); + case EVP_PKEY_CTRL_DH_KDF_OUTLEN: + return EVP_PKEY_CTX_set_dh_kdf_outlen(ctx, p1); + case EVP_PKEY_CTRL_DH_KDF_UKM: + return EVP_PKEY_CTX_set0_dh_kdf_ukm(ctx, p2, p1); + case EVP_PKEY_CTRL_DH_KDF_OID: + return EVP_PKEY_CTX_set0_dh_kdf_oid(ctx, p2); + case EVP_PKEY_CTRL_GET_DH_KDF_MD: + return EVP_PKEY_CTX_get_dh_kdf_md(ctx, p2); + case EVP_PKEY_CTRL_GET_DH_KDF_OUTLEN: + return EVP_PKEY_CTX_get_dh_kdf_outlen(ctx, p2); + case EVP_PKEY_CTRL_GET_DH_KDF_UKM: + return EVP_PKEY_CTX_get0_dh_kdf_ukm(ctx, p2); + case EVP_PKEY_CTRL_GET_DH_KDF_OID: + return EVP_PKEY_CTX_get0_dh_kdf_oid(ctx, p2); + } + } if (keytype == EVP_PKEY_DH) { switch (cmd) { case EVP_PKEY_CTRL_DH_PAD: diff --git a/doc/man3/EVP_PKEY_CTX_ctrl.pod b/doc/man3/EVP_PKEY_CTX_ctrl.pod index bd98a2f1d7..85f2b64cc5 100644 --- a/doc/man3/EVP_PKEY_CTX_ctrl.pod +++ b/doc/man3/EVP_PKEY_CTX_ctrl.pod @@ -486,47 +486,47 @@ EVP_PKEY_derive() is the output of the KDF instead of the DH shared secret. The KDF output is typically used as a Key Encryption Key (KEK) that in turn encrypts a Content Encryption Key (CEK). -The EVP_PKEY_CTX_set_dh_kdf_type() macro sets the key derivation function type +The EVP_PKEY_CTX_set_dh_kdf_type() method sets the key derivation function type to I<kdf> for DH key derivation. Possible values are B<EVP_PKEY_DH_KDF_NONE> and B<EVP_PKEY_DH_KDF_X9_42> which uses the key derivation specified in RFC2631 (based on the keying algorithm described in X9.42). When using key derivation, the I<kdf_oid>, I<kdf_md> and I<kdf_outlen> parameters must also be specified. -The EVP_PKEY_CTX_get_dh_kdf_type() macro gets the key derivation function type +The EVP_PKEY_CTX_get_dh_kdf_type() method gets the key derivation function type for I<ctx> used for DH key derivation. Possible values are B<EVP_PKEY_DH_KDF_NONE> and B<EVP_PKEY_DH_KDF_X9_42>. -The EVP_PKEY_CTX_set0_dh_kdf_oid() macro sets the key derivation function +The EVP_PKEY_CTX_set0_dh_kdf_oid() method sets the key derivation function object identifier to I<oid> for DH key derivation. This OID should identify the algorithm to be used with the Content Encryption Key. The library takes ownership of the object identifier so the caller should not free the original memory pointed to by I<oid>. -The EVP_PKEY_CTX_get0_dh_kdf_oid() macro gets the key derivation function oid +The EVP_PKEY_CTX_get0_dh_kdf_oid() method gets the key deri |