From 6a9bd9298bd706e3a4a40ecfa1d89f65f8592c65 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Wed, 20 May 2020 16:20:27 +0100 Subject: [PATCH] Make EVP_PKEY_[get1|set1]_tls_encodedpoint work with provided keys EVP_PKEY_[get1|set1]_tls_encodedpoint() only worked if an ameth was present which isn't the case for provided keys. Support has been added to dh, ec and ecx keys. Reviewed-by: Shane Lontis (Merged from https://github.com/openssl/openssl/pull/11898) --- crypto/dh/dh_ameth.c | 2 +- crypto/dh/dh_key.c | 40 ++++--- crypto/dh/dh_local.h | 3 - crypto/evp/p_lib.c | 39 +++++++ doc/man7/EVP_PKEY-DH.pod | 5 + doc/man7/EVP_PKEY-EC.pod | 5 + doc/man7/EVP_PKEY-X25519.pod | 5 + include/crypto/dh.h | 3 + include/openssl/core_names.h | 1 + providers/implementations/keymgmt/dh_kmgmt.c | 38 +++++++ providers/implementations/keymgmt/ec_kmgmt.c | 31 ++++++ providers/implementations/keymgmt/ecx_kmgmt.c | 100 ++++++++++++++++-- 12 files changed, 247 insertions(+), 25 deletions(-) diff --git a/crypto/dh/dh_ameth.c b/crypto/dh/dh_ameth.c index d93d519444..d5e5f72517 100644 --- a/crypto/dh/dh_ameth.c +++ b/crypto/dh/dh_ameth.c @@ -438,7 +438,7 @@ static int dh_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) case ASN1_PKEY_CTRL_SET1_TLS_ENCPT: return dh_buf2key(EVP_PKEY_get0_DH(pkey), arg2, arg1); case ASN1_PKEY_CTRL_GET1_TLS_ENCPT: - return dh_key2buf(EVP_PKEY_get0_DH(pkey), arg2); + return dh_key2buf(EVP_PKEY_get0_DH(pkey), arg2, 0, 1); default: return -2; } diff --git a/crypto/dh/dh_key.c b/crypto/dh/dh_key.c index 1893b487ca..5d2acca25c 100644 --- a/crypto/dh/dh_key.c +++ b/crypto/dh/dh_key.c @@ -351,10 +351,10 @@ err: return 0; } -size_t dh_key2buf(const DH *dh, unsigned char **pbuf_out) +size_t dh_key2buf(const DH *dh, unsigned char **pbuf_out, size_t size, int alloc) { const BIGNUM *pubkey; - unsigned char *pbuf; + unsigned char *pbuf = NULL; const BIGNUM *p; int p_size; @@ -366,19 +366,29 @@ size_t dh_key2buf(const DH *dh, unsigned char **pbuf_out) DHerr(DH_F_DH_KEY2BUF, DH_R_INVALID_PUBKEY); return 0; } - if ((pbuf = OPENSSL_malloc(p_size)) == NULL) { - DHerr(DH_F_DH_KEY2BUF, ERR_R_MALLOC_FAILURE); - return 0; - } - /* - * As per Section 4.2.8.1 of RFC 8446 left pad public - * key with zeros to the size of p - */ - if (BN_bn2binpad(pubkey, pbuf, p_size) < 0) { - OPENSSL_free(pbuf); - DHerr(DH_F_DH_KEY2BUF, DH_R_BN_ERROR); - return 0; + if (pbuf_out != NULL && (alloc || *pbuf_out != NULL)) { + if (!alloc) { + if (size >= (size_t)p_size) + pbuf = *pbuf_out; + } else { + pbuf = OPENSSL_malloc(p_size); + } + + if (pbuf == NULL) { + DHerr(DH_F_DH_KEY2BUF, ERR_R_MALLOC_FAILURE); + return 0; + } + /* + * As per Section 4.2.8.1 of RFC 8446 left pad public + * key with zeros to the size of p + */ + if (BN_bn2binpad(pubkey, pbuf, p_size) < 0) { + if (alloc) + OPENSSL_free(pbuf); + DHerr(DH_F_DH_KEY2BUF, DH_R_BN_ERROR); + return 0; + } + *pbuf_out = pbuf; } - *pbuf_out = pbuf; return p_size; } diff --git a/crypto/dh/dh_local.h b/crypto/dh/dh_local.h index a54d25f487..51c3f974e1 100644 --- a/crypto/dh/dh_local.h +++ b/crypto/dh/dh_local.h @@ -58,6 +58,3 @@ struct dh_method { int (*generate_params) (DH *dh, int prime_len, int generator, BN_GENCB *cb); }; - -int dh_buf2key(DH *key, const unsigned char *buf, size_t len); -size_t dh_key2buf(const DH *dh, unsigned char **pbuf); diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c index 4670912588..1d57a22aee 100644 --- a/crypto/evp/p_lib.c +++ b/crypto/evp/p_lib.c @@ -1215,6 +1215,18 @@ int EVP_PKEY_supports_digest_nid(EVP_PKEY *pkey, int nid) int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *pkey, const unsigned char *pt, size_t ptlen) { + if (pkey->ameth == NULL) { + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + + if (pkey->keymgmt == NULL || pkey->keydata == NULL) + return 0; + + params[0] = + OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT, + (unsigned char *)pt, ptlen); + return evp_keymgmt_set_params(pkey->keymgmt, pkey->keydata, params); + } + if (ptlen > INT_MAX) return 0; if (evp_pkey_asn1_ctrl(pkey, ASN1_PKEY_CTRL_SET1_TLS_ENCPT, ptlen, @@ -1226,6 +1238,33 @@ int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *pkey, size_t EVP_PKEY_get1_tls_encodedpoint(EVP_PKEY *pkey, unsigned char **ppt) { int rv; + + if (pkey->ameth == NULL) { + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + + if (pkey->keymgmt == NULL || pkey->keydata == NULL) + return 0; + + params[0] = + OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT, + NULL, 0); + if (!evp_keymgmt_get_params(pkey->keymgmt, pkey->keydata, params)) + return 0; + + *ppt = OPENSSL_malloc(params[0].return_size); + if (*ppt == NULL) + return 0; + + params[0] = + OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT, + *ppt, params[0].return_size); + if (!evp_keymgmt_get_params(pkey->keymgmt, pkey->keydata, params)) + return 0; + + return params[0].return_size; + } + + rv = evp_pkey_asn1_ctrl(pkey, ASN1_PKEY_CTRL_GET1_TLS_ENCPT, 0, ppt); if (rv <= 0) return 0; diff --git a/doc/man7/EVP_PKEY-DH.pod b/doc/man7/EVP_PKEY-DH.pod index 33b19a74f9..d2a49b7bfa 100644 --- a/doc/man7/EVP_PKEY-DH.pod +++ b/doc/man7/EVP_PKEY-DH.pod @@ -54,6 +54,11 @@ validation is required. The default value is 2. These are not named safe prime groups so setting this value for the OpenSSL FIPS provider will instead choose a named safe prime group based on the size of I

. +=item "tls-encoded-pt" (B) + +Used for getting and setting the encoding of the DH public key used in a key +exchange message for the TLS protocol. + =back =head2 DH domain parameter / key generation parameters diff --git a/doc/man7/EVP_PKEY-EC.pod b/doc/man7/EVP_PKEY-EC.pod index 1995cf7676..85e633ceed 100644 --- a/doc/man7/EVP_PKEY-EC.pod +++ b/doc/man7/EVP_PKEY-EC.pod @@ -39,6 +39,11 @@ The public key value in EC point format. The private key value. +=item "tls-encoded-pt" (B) + +Used for getting and setting the encoding of the EC public key used in key +exchange message for the TLS protocol. + =back =head1 EXAMPLES diff --git a/doc/man7/EVP_PKEY-X25519.pod b/doc/man7/EVP_PKEY-X25519.pod index fa8c86844a..ebeda8d814 100644 --- a/doc/man7/EVP_PKEY-X25519.pod +++ b/doc/man7/EVP_PKEY-X25519.pod @@ -34,6 +34,11 @@ The public key value. The private key value. +=item "tls-encoded-pt" (B) + +Used for getting and setting the encoding of the public key used in a key exchange +message for the TLS protocol. + =back =head2 ED25519 and ED448 parameters diff --git a/include/crypto/dh.h b/include/crypto/dh.h index 1ae2c2f0a3..f67b4e01cd 100644 --- a/include/crypto/dh.h +++ b/include/crypto/dh.h @@ -32,3 +32,6 @@ int dh_check_priv_key(const DH *dh, const BIGNUM *priv_key, int *ret); int dh_check_pairwise(DH *dh); const DH_METHOD *dh_get_method(const DH *dh); + +int dh_buf2key(DH *key, const unsigned char *buf, size_t len); +size_t dh_key2buf(const DH *dh, unsigned char **pbuf, size_t size, int alloc); diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index 8bafc1ba5e..f04168e819 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -194,6 +194,7 @@ extern "C" { #define OSSL_PKEY_PARAM_MASKGENFUNC "mgf" #define OSSL_PKEY_PARAM_MGF1_DIGEST "mgf1-digest" #define OSSL_PKEY_PARAM_MGF1_PROPERTIES "mgf1-properties" +#define OSSL_PKEY_PARAM_TLS_ENCODED_PT "tls-encoded-pt" /* Diffie-Hellman/DSA public/private key */ #define OSSL_PKEY_PARAM_PUB_KEY "pub" diff --git a/providers/implementations/keymgmt/dh_kmgmt.c b/providers/implementations/keymgmt/dh_kmgmt.c index 1e344bdc20..0dd1796dc0 100644 --- a/providers/implementations/keymgmt/dh_kmgmt.c +++ b/providers/implementations/keymgmt/dh_kmgmt.c @@ -36,6 +36,8 @@ static OSSL_OP_keymgmt_gen_fn dh_gen; static OSSL_OP_keymgmt_gen_cleanup_fn dh_gen_cleanup; static OSSL_OP_keymgmt_get_params_fn dh_get_params; static OSSL_OP_keymgmt_gettable_params_fn dh_gettable_params; +static OSSL_OP_keymgmt_set_params_fn dh_set_params; +static OSSL_OP_keymgmt_settable_params_fn dh_settable_params; static OSSL_OP_keymgmt_has_fn dh_has; static OSSL_OP_keymgmt_match_fn dh_match; static OSSL_OP_keymgmt_validate_fn dh_validate; @@ -298,6 +300,15 @@ static ossl_inline int dh_get_params(void *key, OSSL_PARAM params[]) if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL && !OSSL_PARAM_set_int(p, DH_size(dh))) return 0; + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_TLS_ENCODED_PT)) != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) + return 0; + p->return_size = dh_key2buf(dh, (unsigned char **)&p->data, + p->data_size, 0); + if (p->return_size == 0) + return 0; + } + return ffc_params_todata(dh_get0_params(dh), NULL, params) && dh_key_todata(dh, NULL, params); } @@ -306,6 +317,7 @@ static const OSSL_PARAM dh_params[] = { OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT, NULL, 0), DH_IMEXPORTABLE_PARAMETERS, DH_IMEXPORTABLE_PUBLIC_KEY, DH_IMEXPORTABLE_PRIVATE_KEY, @@ -317,6 +329,30 @@ static const OSSL_PARAM *dh_gettable_params(void) return dh_params; } +static const OSSL_PARAM dh_known_settable_params[] = { + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *dh_settable_params(void) +{ + return dh_known_settable_params; +} + +static int dh_set_params(void *key, const OSSL_PARAM params[]) +{ + DH *dh = key; + const OSSL_PARAM *p; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_TLS_ENCODED_PT); + if (p != NULL + && (p->data_type != OSSL_PARAM_OCTET_STRING + || !dh_buf2key(dh, p->data, p->data_size))) + return 0; + + return 1; +} + static int dh_validate_public(DH *dh) { const BIGNUM *pub_key = NULL; @@ -621,6 +657,8 @@ const OSSL_DISPATCH dh_keymgmt_functions[] = { { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))dh_freedata }, { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))dh_get_params }, { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))dh_gettable_params }, + { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))dh_set_params }, + { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))dh_settable_params }, { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))dh_has }, { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))dh_match }, { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))dh_validate }, diff --git a/providers/implementations/keymgmt/ec_kmgmt.c b/providers/implementations/keymgmt/ec_kmgmt.c index 8e7b9f3014..7e3220739f 100644 --- a/providers/implementations/keymgmt/ec_kmgmt.c +++ b/providers/implementations/keymgmt/ec_kmgmt.c @@ -504,6 +504,20 @@ int ec_get_params(void *key, OSSL_PARAM params[]) if (!OSSL_PARAM_set_int(p, ecdh_cofactor_mode)) return 0; } + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_TLS_ENCODED_PT)) != NULL) { + BN_CTX *ctx = BN_CTX_new_ex(ec_key_get_libctx(key)); + + if (ctx == NULL) + return 0; + p->return_size = EC_POINT_point2oct(EC_KEY_get0_group(key), + EC_KEY_get0_public_key(key), + POINT_CONVERSION_UNCOMPRESSED, + p->data, p->return_size, ctx); + BN_CTX_free(ctx); + if (p->return_size == 0) + return 0; + } + ret = domparams_to_params(eck, NULL, params) && key_to_params(eck, NULL, params, 1, &pub_key) && otherparams_to_params(eck, NULL, params); @@ -515,6 +529,7 @@ static const OSSL_PARAM ec_known_gettable_params[] = { OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT, NULL, 0), EC_IMEXPORTABLE_DOM_PARAMETERS, EC_IMEXPORTABLE_PUBLIC_KEY, EC_IMEXPORTABLE_PRIVATE_KEY, @@ -530,6 +545,7 @@ const OSSL_PARAM *ec_gettable_params(void) static const OSSL_PARAM ec_known_settable_params[] = { OSSL_PARAM_int(OSSL_PKEY_PARAM_USE_COFACTOR_ECDH, NULL), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT, NULL, 0), OSSL_PARAM_END }; @@ -543,6 +559,21 @@ static int ec_set_params(void *key, const OSSL_PARAM params[]) { EC_KEY *eck = key; + const OSSL_PARAM *p; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_TLS_ENCODED_PT); + if (p != NULL) { + BN_CTX *ctx = BN_CTX_new_ex(ec_key_get_libctx(key)); + int ret = 1; + + if (ctx == NULL + || p->data_type != OSSL_PARAM_OCTET_STRING + || !EC_KEY_oct2key(key, p->data, p->data_size, ctx)) + ret = 0; + BN_CTX_free(ctx); + if (!ret) + return 0; + } return ec_key_otherparams_fromdata(eck, params); } diff --git a/providers/implementations/keymgmt/ecx_kmgmt.c b/providers/implementations/keymgmt/ecx_kmgmt.c index e2b613e5e0..c7a90543f9 100644 --- a/providers/implementations/keymgmt/ecx_kmgmt.c +++ b/providers/implementations/keymgmt/ecx_kmgmt.c @@ -46,6 +46,14 @@ static OSSL_OP_keymgmt_gettable_params_fn x25519_gettable_params; static OSSL_OP_keymgmt_gettable_params_fn x448_gettable_params; static OSSL_OP_keymgmt_gettable_params_fn ed25519_gettable_params; static OSSL_OP_keymgmt_gettable_params_fn ed448_gettable_params; +static OSSL_OP_keymgmt_set_params_fn x25519_set_params; +static OSSL_OP_keymgmt_set_params_fn x448_set_params; +static OSSL_OP_keymgmt_set_params_fn ed25519_set_params; +static OSSL_OP_keymgmt_set_params_fn ed448_set_params; +static OSSL_OP_keymgmt_settable_params_fn x25519_settable_params; +static OSSL_OP_keymgmt_settable_params_fn x448_settable_params; +static OSSL_OP_keymgmt_settable_params_fn ed25519_settable_params; +static OSSL_OP_keymgmt_settable_params_fn ed448_settable_params; static OSSL_OP_keymgmt_has_fn ecx_has; static OSSL_OP_keymgmt_match_fn ecx_match; static OSSL_OP_keymgmt_import_fn ecx_import; @@ -233,6 +241,13 @@ static int ecx_get_params(void *key, OSSL_PARAM params[], int bits, int secbits, if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL && !OSSL_PARAM_set_int(p, size)) return 0; + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_TLS_ENCODED_PT)) != NULL + && (ecx->type == ECX_KEY_TYPE_X25519 + || ecx->type == ECX_KEY_TYPE_X448)) { + if (!OSSL_PARAM_set_octet_string(p, ecx->pubkey, ecx->keylen)) + return 0; + } + return key_to_params(ecx, NULL, params); } @@ -273,16 +288,17 @@ static int ed448_get_params(void *key, OSSL_PARAM params[]) && ed_get_params(key, params); } -static const OSSL_PARAM ecx_params[] = { +static const OSSL_PARAM ecx_gettable_params[] = { OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_MANDATORY_DIGEST, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT, NULL, 0), ECX_KEY_TYPES(), OSSL_PARAM_END }; -static const OSSL_PARAM ed_params[] = { +static const OSSL_PARAM ed_gettable_params[] = { OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), @@ -292,22 +308,92 @@ static const OSSL_PARAM ed_params[] = { static const OSSL_PARAM *x25519_gettable_params(void) { - return ecx_params; + return ecx_gettable_params; } static const OSSL_PARAM *x448_gettable_params(void) { - return ecx_params; + return ecx_gettable_params; } static const OSSL_PARAM *ed25519_gettable_params(void) { - return ed_params; + return ed_gettable_params; } static const OSSL_PARAM *ed448_gettable_params(void) { - return ed_params; + return ed_gettable_params; +} + +static int ecx_set_params(void *key, const OSSL_PARAM params[]) +{ + ECX_KEY *ecxkey = key; + const OSSL_PARAM *p; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_TLS_ENCODED_PT); + if (p != NULL) { + void *buf = ecxkey->pubkey; + + if (p->data_size != ecxkey->keylen + || !OSSL_PARAM_get_octet_string(p, &buf, sizeof(ecxkey->pubkey), + NULL)) + return 0; + OPENSSL_clear_free(ecxkey->privkey, ecxkey->keylen); + ecxkey->privkey = NULL; + ecxkey->haspubkey = 1; + } + + return 1; +} + +static int x25519_set_params(void *key, const OSSL_PARAM params[]) +{ + return ecx_set_params(key, params); +} + +static int x448_set_params(void *key, const OSSL_PARAM params[]) +{ + return ecx_set_params(key, params); +} + +static int ed25519_set_params(void *key, const OSSL_PARAM params[]) +{ + return 1; +} + +static int ed448_set_params(void *key, const OSSL_PARAM params[]) +{ + return 1; +} + +static const OSSL_PARAM ecx_settable_params[] = { + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM ed_settable_params[] = { + OSSL_PARAM_END +}; + +static const OSSL_PARAM *x25519_settable_params(void) +{ + return ecx_settable_params; +} + +static const OSSL_PARAM *x448_settable_params(void) +{ + return ecx_settable_params; +} + +static const OSSL_PARAM *ed25519_settable_params(void) +{ + return ed_settable_params; +} + +static const OSSL_PARAM *ed448_settable_params(void) +{ + return ed_settable_params; } static void *ecx_gen_init(void *provctx, int selection, ECX_KEY_TYPE type) @@ -450,6 +536,8 @@ static void ecx_gen_cleanup(void *genctx) { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ecx_key_free }, \ { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))alg##_get_params }, \ { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))alg##_gettable_params }, \ + { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))alg##_set_params }, \ + { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))alg##_settable_params }, \ { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ecx_has }, \ { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))ecx_match }, \ { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ecx_import }, \ -- 2.25.1