From c2041da8c15027ddde5afcf9809d8d3a975eb25b Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Wed, 18 Mar 2020 15:54:47 +0100 Subject: [PATCH] EVP & TLS: Add necessary EC_KEY data extraction functions, and use them libssl code uses EVP_PKEY_get0_EC_KEY() to extract certain basic data from the EC_KEY. We replace that with internal EVP_PKEY functions. This may or may not be refactored later on. Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/11358) --- Configurations/unix-Makefile.tmpl | 1 + crypto/evp/p_lib.c | 43 ++++++++++++++++++++++ include/internal/evp.h | 23 ++++++++++++ include/openssl/evp.h | 1 + ssl/ssl_rsa.c | 2 +- ssl/statem/statem_lib.c | 8 ++-- ssl/t1_lib.c | 61 ++++++++++++++++--------------- util/libcrypto.num | 1 + util/missingcrypto.txt | 2 + 9 files changed, 107 insertions(+), 35 deletions(-) create mode 100644 include/internal/evp.h diff --git a/Configurations/unix-Makefile.tmpl b/Configurations/unix-Makefile.tmpl index a019779993..a35ce10caf 100644 --- a/Configurations/unix-Makefile.tmpl +++ b/Configurations/unix-Makefile.tmpl @@ -1025,6 +1025,7 @@ errors: qw( include/internal/dso.h include/internal/o_dir.h include/internal/err.h + include/internal/evp.h include/internal/sslconf.h ); our @cryptoskipheaders = ( @sslheaders, qw( include/openssl/conf_api.h diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c index c3a7fbe692..8e7af17c31 100644 --- a/crypto/evp/p_lib.c +++ b/crypto/evp/p_lib.c @@ -33,6 +33,7 @@ #include "crypto/asn1.h" #include "crypto/evp.h" +#include "internal/evp.h" #include "internal/provider.h" #include "evp_local.h" @@ -810,6 +811,48 @@ int EVP_PKEY_can_sign(const EVP_PKEY *pkey) return 0; } +#ifndef OPENSSL_NO_EC +/* + * TODO rewrite when we have proper data extraction functions + * Note: an octet pointer would be desirable! + */ +static OSSL_CALLBACK get_ec_curve_name_cb; +static int get_ec_curve_name_cb(const OSSL_PARAM params[], void *arg) +{ + const OSSL_PARAM *p = NULL; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_NAME)) != NULL) + return OSSL_PARAM_get_utf8_string(p, arg, 0); + + /* If there is no curve name, this is not an EC key */ + return 0; +} + +int evp_pkey_get_EC_KEY_curve_nid(const EVP_PKEY *pkey) +{ + int ret = NID_undef; + + if (pkey->keymgmt == NULL) { + if (EVP_PKEY_base_id(pkey) == EVP_PKEY_EC) { + EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey); + + ret = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)); + } + } else if (EVP_PKEY_is_a(pkey, "EC") || EVP_PKEY_is_a(pkey, "SM2")) { + char *curve_name = NULL; + + ret = evp_keymgmt_export(pkey->keymgmt, pkey->keydata, + OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + get_ec_curve_name_cb, &curve_name); + if (ret) + ret = ec_curve_name2nid(curve_name); + OPENSSL_free(curve_name); + } + + return ret; +} +#endif + static int print_reset_indent(BIO **out, int pop_f_prefix, long saved_indent) { BIO_set_indent(*out, saved_indent); diff --git a/include/internal/evp.h b/include/internal/evp.h new file mode 100644 index 0000000000..404e48322c --- /dev/null +++ b/include/internal/evp.h @@ -0,0 +1,23 @@ +/* + * Copyright 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 + */ + +#ifndef OSSL_INTERNAL_EVP_H +# define OSSL_INTERNAL_EVP_H + +# include + +# ifndef OPENSSL_NO_EC +/* + * TODO(3.0) While waiting for more generic getters, we have these functions + * as an interim solution. This should be removed when the generic getters + * appear. + */ +int evp_pkey_get_EC_KEY_curve_nid(const EVP_PKEY *pkey); +# endif +#endif diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 4545bf7170..a14e899202 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1111,6 +1111,7 @@ int EVP_PKEY_base_id(const EVP_PKEY *pkey); int EVP_PKEY_bits(const EVP_PKEY *pkey); int EVP_PKEY_security_bits(const EVP_PKEY *pkey); int EVP_PKEY_size(const EVP_PKEY *pkey); +int EVP_PKEY_can_sign(const EVP_PKEY *pkey); int EVP_PKEY_set_type(EVP_PKEY *pkey, int type); int EVP_PKEY_set_type_str(EVP_PKEY *pkey, const char *str, int len); int EVP_PKEY_set_type_by_keymgmt(EVP_PKEY *pkey, EVP_KEYMGMT *keymgmt); diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c index 3a222e5571..ac9d01a766 100644 --- a/ssl/ssl_rsa.c +++ b/ssl/ssl_rsa.c @@ -338,7 +338,7 @@ static int ssl_set_cert(CERT *c, X509 *x) return 0; } #ifndef OPENSSL_NO_EC - if (i == SSL_PKEY_ECC && !EC_KEY_can_sign(EVP_PKEY_get0_EC_KEY(pkey))) { + if (i == SSL_PKEY_ECC && !EVP_PKEY_can_sign(pkey)) { SSLerr(SSL_F_SSL_SET_CERT, SSL_R_ECC_CERT_NOT_FOR_SIGNING); return 0; } diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index e9cfee027e..71a259e8f0 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -14,6 +14,7 @@ #include "../ssl_local.h" #include "statem_local.h" #include "internal/cryptlib.h" +#include "internal/evp.h" #include #include #include @@ -1531,7 +1532,6 @@ static int is_tls13_capable(const SSL *s) int i; #ifndef OPENSSL_NO_EC int curve; - EC_KEY *eckey; #endif #ifndef OPENSSL_NO_PSK @@ -1563,10 +1563,8 @@ static int is_tls13_capable(const SSL *s) * more restrictive so check that our sig algs are consistent with this * EC cert. See section 4.2.3 of RFC8446. */ - eckey = EVP_PKEY_get0_EC_KEY(s->cert->pkeys[SSL_PKEY_ECC].privatekey); - if (eckey == NULL) - continue; - curve = EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey)); + curve = evp_pkey_get_EC_KEY_curve_nid(s->cert->pkeys[SSL_PKEY_ECC] + .privatekey); if (tls_check_sigalg_curve(s, curve)) return 1; #else diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 624add64a8..beadf28f11 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -22,6 +22,7 @@ #include #include #include "internal/nelem.h" +#include "internal/evp.h" #include "ssl_local.h" #include @@ -583,7 +584,7 @@ static int tls1_check_pkey_comp(SSL *s, EVP_PKEY *pkey) size_t i; /* If not an EC key nothing to check */ - if (EVP_PKEY_id(pkey) != EVP_PKEY_EC) + if (!EVP_PKEY_is_a(pkey, "EC")) return 1; ec = EVP_PKEY_get0_EC_KEY(pkey); grp = EC_KEY_get0_group(ec); @@ -624,13 +625,11 @@ static int tls1_check_pkey_comp(SSL *s, EVP_PKEY *pkey) /* Return group id of a key */ static uint16_t tls1_get_group_id(EVP_PKEY *pkey) { - EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey); - const EC_GROUP *grp; + int curve_nid = evp_pkey_get_EC_KEY_curve_nid(pkey); - if (ec == NULL) + if (curve_nid == NID_undef) return 0; - grp = EC_KEY_get0_group(ec); - return tls1_nid2group_id(EC_GROUP_get_curve_name(grp)); + return tls1_nid2group_id(curve_nid); } /* @@ -645,7 +644,7 @@ static int tls1_check_cert_param(SSL *s, X509 *x, int check_ee_md) if (pkey == NULL) return 0; /* If not EC nothing to do */ - if (EVP_PKEY_id(pkey) != EVP_PKEY_EC) + if (!EVP_PKEY_is_a(pkey, "EC")) return 1; /* Check compression */ if (!tls1_check_pkey_comp(s, pkey)) @@ -1111,10 +1110,22 @@ int tls12_check_peer_sigalg(SSL *s, uint16_t sig, EVP_PKEY *pkey) const EVP_MD *md = NULL; char sigalgstr[2]; size_t sent_sigslen, i, cidx; - int pkeyid = EVP_PKEY_id(pkey); + int pkeyid = -1; const SIGALG_LOOKUP *lu; int secbits = 0; + /* + * TODO(3.0) Remove this when we adapted this function for provider + * side keys. We know that EVP_PKEY_get0() downgrades an EVP_PKEY + * to contain a legacy key. + * + * THIS IS TEMPORARY + */ + EVP_PKEY_get0(pkey); + if (EVP_PKEY_id(pkey) == EVP_PKEY_NONE) + return 0; + + pkeyid = EVP_PKEY_id(pkey); /* Should never happen */ if (pkeyid == -1) return -1; @@ -1163,8 +1174,7 @@ int tls12_check_peer_sigalg(SSL *s, uint16_t sig, EVP_PKEY *pkey) /* For TLS 1.3 or Suite B check curve matches signature algorithm */ if (SSL_IS_TLS13(s) || tls1_suiteb(s)) { - EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey); - int curve = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)); + int curve = evp_pkey_get_EC_KEY_curve_nid(pkey); if (lu->curve != NID_undef && curve != lu->curve) { SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, @@ -2449,17 +2459,14 @@ int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain, if (!s->server && strict_mode) { STACK_OF(X509_NAME) *ca_dn; int check_type = 0; - switch (EVP_PKEY_id(pk)) { - case EVP_PKEY_RSA: + + if (EVP_PKEY_is_a(pk, "RSA")) check_type = TLS_CT_RSA_SIGN; - break; - case EVP_PKEY_DSA: + else if (EVP_PKEY_is_a(pk, "DSA")) check_type = TLS_CT_DSS_SIGN; - break; - case EVP_PKEY_EC: + else if (EVP_PKEY_is_a(pk, "EC")) check_type = TLS_CT_ECDSA_SIGN; - break; - } + if (check_type) { const uint8_t *ctypes = s->s3.tmp.ctype; size_t j; @@ -2820,10 +2827,8 @@ static const SIGALG_LOOKUP *find_sig_alg(SSL *s, X509 *x, EVP_PKEY *pkey) if (lu->sig == EVP_PKEY_EC) { #ifndef OPENSSL_NO_EC - if (curve == -1) { - EC_KEY *ec = EVP_PKEY_get0_EC_KEY(tmppkey); - curve = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)); - } + if (curve == -1) + curve = evp_pkey_get_EC_KEY_curve_nid(tmppkey); if (lu->curve != NID_undef && curve != lu->curve) continue; #else @@ -2882,15 +2887,13 @@ int tls_choose_sigalg(SSL *s, int fatalerrs) size_t i; if (s->s3.tmp.peer_sigalgs != NULL) { #ifndef OPENSSL_NO_EC - int curve; + int curve = -1; /* For Suite B need to match signature algorithm to curve */ - if (tls1_suiteb(s)) { - EC_KEY *ec = EVP_PKEY_get0_EC_KEY(s->cert->pkeys[SSL_PKEY_ECC].privatekey); - curve = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)); - } else { - curve = -1; - } + if (tls1_suiteb(s)) + curve = + evp_pkey_get_EC_KEY_curve_nid(s->cert->pkeys[SSL_PKEY_ECC] + .privatekey); #endif /* diff --git a/util/libcrypto.num b/util/libcrypto.num index e29234aaf9..73d70efe99 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5039,3 +5039,4 @@ EVP_PKEY_get_utf8_string_param ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_get_octet_string_param ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_is_a ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_can_sign ? 3_0_0 EXIST::FUNCTION: +evp_pkey_get_EC_KEY_curve_nid ? 3_0_0 EXIST::FUNCTION:EC diff --git a/util/missingcrypto.txt b/util/missingcrypto.txt index d6d30912f3..a53909f4d2 100644 --- a/util/missingcrypto.txt +++ b/util/missingcrypto.txt @@ -1558,6 +1558,8 @@ conf_ssl_name_find(3) d2i_X509_bio(3) d2i_X509_fp(3) err_free_strings_int(3) +# The following is internal but exported by libcrypto +evp_pkey_get_EC_KEY_curve_nid(3) i2a_ACCESS_DESCRIPTION(3) i2a_ASN1_ENUMERATED(3) i2a_ASN1_INTEGER(3) -- 2.25.1