[openssl] master update

Richard Levitte levitte at openssl.org
Wed Apr 8 13:33:07 UTC 2020


The branch master has been updated
       via  afce590b74159f7df1452fb2c4aa990a52536c38 (commit)
       via  e3be0f4389fe1680e1fd547a8575ea71b4518b57 (commit)
       via  c2041da8c15027ddde5afcf9809d8d3a975eb25b (commit)
       via  4f76d62f2384d3335bd1d043706995ae64b37348 (commit)
      from  82e1fc1bc06a87278b2dada07e40a4296e6898c7 (commit)


- Log -----------------------------------------------------------------
commit afce590b74159f7df1452fb2c4aa990a52536c38
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Mar 23 13:21:21 2020 +0100

    TLS: Temporarly downgrade newly generated EVP_PKEYs to legacy
    
    The transfer of TLS encodedpoint to backends isn't yet fully supported
    in provider implementations.  This is a temporary measure so as not to
    get stuck in other development.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/11358)

commit e3be0f4389fe1680e1fd547a8575ea71b4518b57
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Mar 23 13:19:40 2020 +0100

    Fix export of provided EC keys
    
    The exporter freed a buffer too soon, and there were attempts to use
    its data later, which was overwritten by something else at that
    point.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/11358)

commit c2041da8c15027ddde5afcf9809d8d3a975eb25b
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Mar 18 15:54:47 2020 +0100

    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 <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/11358)

commit 4f76d62f2384d3335bd1d043706995ae64b37348
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Mar 16 18:55:32 2020 +0100

    EVP: add EVP_PKEY_is_a() and EVP_PKEY_can_sign()
    
    EVP_PKEY_is_a() is the provider side key checking function corresponding
    to checking EVP_PKEY_id() or an EVP_PKEY against macros like EVP_PKEY_EC.
    It also works with legacy internal keys.
    
    We also add a warning indoc/man3/EVP_PKEY_set1_RSA.pod regarding the
    reliability of certain functions that only understand legacy keys.
    
    Finally, we take the opportunity to clean up doc/man3/EVP_PKEY_set1_RSA.pod
    to better conform with man-page layout norms, see man-pages(7) on Linux.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/11358)

-----------------------------------------------------------------------

Summary of changes:
 Configurations/unix-Makefile.tmpl            |   1 +
 crypto/evp/p_lib.c                           | 120 +++++++++++++++++++++++++++
 doc/man3/EVP_PKEY_is_a.pod                   |  72 ++++++++++++++++
 doc/man3/EVP_PKEY_set1_RSA.pod               |  41 +++++----
 include/internal/evp.h                       |  23 +++++
 include/openssl/evp.h                        |   2 +
 providers/implementations/keymgmt/ec_kmgmt.c |   7 +-
 ssl/ssl_rsa.c                                |   2 +-
 ssl/statem/extensions_clnt.c                 |  32 +++++++
 ssl/statem/extensions_srvr.c                 |  30 +++++++
 ssl/statem/statem_clnt.c                     |  30 +++++++
 ssl/statem/statem_lib.c                      |   8 +-
 ssl/statem/statem_srvr.c                     |  28 +++++++
 ssl/t1_lib.c                                 |  61 +++++++-------
 util/libcrypto.num                           |   3 +
 util/missingcrypto.txt                       |   2 +
 16 files changed, 406 insertions(+), 56 deletions(-)
 create mode 100644 doc/man3/EVP_PKEY_is_a.pod
 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 b176f100e8..8e7af17c31 100644
--- a/crypto/evp/p_lib.c
+++ b/crypto/evp/p_lib.c
@@ -24,6 +24,7 @@
 #include <openssl/rsa.h>
 #include <openssl/dsa.h>
 #include <openssl/dh.h>
+#include <openssl/ec.h>
 #include <openssl/cmac.h>
 #include <openssl/engine.h>
 #include <openssl/params.h>
@@ -32,9 +33,15 @@
 
 #include "crypto/asn1.h"
 #include "crypto/evp.h"
+#include "internal/evp.h"
 #include "internal/provider.h"
 #include "evp_local.h"
 
+#include "crypto/ec.h"
+
+/* TODO remove this when the EVP_PKEY_is_a() #legacy support hack is removed */
+#include "e_os.h"                /* strcasecmp on Windows */
+
 static int pkey_set_type(EVP_PKEY *pkey, ENGINE *e, int type, const char *str,
                          int len, EVP_KEYMGMT *keymgmt);
 static void evp_pkey_free_it(EVP_PKEY *key);
@@ -732,6 +739,119 @@ int EVP_PKEY_base_id(const EVP_PKEY *pkey)
     return EVP_PKEY_type(pkey->type);
 }
 
+int EVP_PKEY_is_a(const EVP_PKEY *pkey, const char *name)
+{
+#ifndef FIPS_MODE
+    if (pkey->keymgmt == NULL) {
+        /*
+         * These hard coded cases are pure hackery to get around the fact
+         * that names in crypto/objects/objects.txt are a mess.  There is
+         * no "EC", and "RSA" leads to the NID for 2.5.8.1.1, an OID that's
+         * fallen out in favor of { pkcs-1 1 }, i.e. 1.2.840.113549.1.1.1,
+         * the NID of which is used for EVP_PKEY_RSA.  Strangely enough,
+         * "DSA" is accurate...  but still, better be safe and hard-code
+         * names that we know.
+         * TODO Clean this away along with all other #legacy support.
+         */
+        int type;
+
+        if (strcasecmp(name, "RSA") == 0)
+            type = EVP_PKEY_RSA;
+#ifndef OPENSSL_NO_EC
+        else if (strcasecmp(name, "EC") == 0)
+            type = EVP_PKEY_EC;
+#endif
+#ifndef OPENSSL_NO_DSA
+        else if (strcasecmp(name, "DSA") == 0)
+            type = EVP_PKEY_DSA;
+#endif
+        else
+            type = EVP_PKEY_type(OBJ_sn2nid(name));
+        return EVP_PKEY_type(pkey->type) == type;
+    }
+#endif
+    return EVP_KEYMGMT_is_a(pkey->keymgmt, name);
+}
+
+int EVP_PKEY_can_sign(const EVP_PKEY *pkey)
+{
+    if (pkey->keymgmt == NULL) {
+        switch (EVP_PKEY_base_id(pkey)) {
+        case EVP_PKEY_RSA:
+            return 1;
+#ifndef OPENSSL_NO_DSA
+        case EVP_PKEY_DSA:
+            return 1;
+#endif
+#ifndef OPENSSL_NO_EC
+        case EVP_PKEY_ED25519:
+        case EVP_PKEY_ED448:
+            return 1;
+        case EVP_PKEY_EC:        /* Including SM2 */
+            return EC_KEY_can_sign(pkey->pkey.ec);
+#endif
+        default:
+            break;
+        }
+    } else {
+        const OSSL_PROVIDER *prov = EVP_KEYMGMT_provider(pkey->keymgmt);
+        OPENSSL_CTX *libctx = ossl_provider_library_context(prov);
+        const char *supported_sig =
+            pkey->keymgmt->query_operation_name != NULL
+            ? pkey->keymgmt->query_operation_name(OSSL_OP_SIGNATURE)
+            : evp_first_name(prov, pkey->keymgmt->name_id);
+        EVP_SIGNATURE *signature = NULL;
+
+        signature = EVP_SIGNATURE_fetch(libctx, supported_sig, NULL);
+        if (signature != NULL) {
+            EVP_SIGNATURE_free(signature);
+            return 1;
+        }
+    }
+    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)
 {
diff --git a/doc/man3/EVP_PKEY_is_a.pod b/doc/man3/EVP_PKEY_is_a.pod
new file mode 100644
index 0000000000..cfce3de5da
--- /dev/null
+++ b/doc/man3/EVP_PKEY_is_a.pod
@@ -0,0 +1,72 @@
+=pod
+
+=head1 NAME
+
+EVP_PKEY_is_a, EVP_PKEY_can_sign
+- key type and capabilities functions
+
+=head1 SYNOPSIS
+
+ #include <openssl/evp.h>
+
+ int EVP_PKEY_is_a(const EVP_PKEY *pkey, const char *name);
+ int EVP_PKEY_can_sign(const EVP_PKEY *pkey);
+
+=head1 DESCRIPTION
+
+EVP_PKEY_is_a() checks if the key type of I<pkey> is I<name>.
+
+EVP_PKEY_can_sign() checks if the functionality for the key type of
+I<pkey> supports signing.  No other check is done, such as whether
+I<pkey> contains a private key.
+
+=head1 RETURN VALUES
+
+EVP_PKEY_is_a() returns 1 if I<pkey> has the key type I<name>,
+otherwise 0.
+
+EVP_PKEY_can_sign() returns 1 if the I<pkey> key type functionality
+supports signing, otherwise 0.
+
+=head1 EXAMPLES
+
+=head2 EVP_PKEY_is_a()
+
+The loaded providers and what key types they support will ultimately
+determine what I<name> is possible to use with EVP_PKEY_is_a().  We do know
+that the default provider supports RSA, DH, DSA and EC keys, so we can use
+this as an crude example:
+
+ #include <openssl/evp.h>
+
+ ...
+     /* |pkey| is an EVP_PKEY* */
+     if (EVP_PKEY_is_a(pkey, "RSA")) {
+         BIGNUM *modulus = NULL;
+         if (EVP_PKEY_get_bn_param(pkey, "n", &modulus))
+             /* do whatever with the modulus */
+         BN_free(modulus);
+     }
+
+=head2 EVP_PKEY_can_sign()
+
+ #include <openssl/evp.h>
+
+ ...
+     /* |pkey| is an EVP_PKEY* */
+     if (!EVP_PKEY_can_sign(pkey)) {
+         fprintf(stderr, "Not a signing key!");
+         exit(1);
+     }
+     /* Sign something... */
+
+=head1 COPYRIGHT
+
+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
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man3/EVP_PKEY_set1_RSA.pod b/doc/man3/EVP_PKEY_set1_RSA.pod
index 8423a0a3b8..598cda4221 100644
--- a/doc/man3/EVP_PKEY_set1_RSA.pod
+++ b/doc/man3/EVP_PKEY_set1_RSA.pod
@@ -51,52 +51,61 @@ EVP_PKEY_set1_engine, EVP_PKEY_get0_engine - EVP_PKEY assignment functions
 =head1 DESCRIPTION
 
 EVP_PKEY_set1_RSA(), EVP_PKEY_set1_DSA(), EVP_PKEY_set1_DH() and
-EVP_PKEY_set1_EC_KEY() set the key referenced by B<pkey> to B<key>.
+EVP_PKEY_set1_EC_KEY() set the key referenced by I<pkey> to I<key>.
 
 EVP_PKEY_get1_RSA(), EVP_PKEY_get1_DSA(), EVP_PKEY_get1_DH() and
-EVP_PKEY_get1_EC_KEY() return the referenced key in B<pkey> or
-B<NULL> if the key is not of the correct type.
+EVP_PKEY_get1_EC_KEY() return the referenced key in I<pkey> or
+NULL if the key is not of the correct type.
 
 EVP_PKEY_get0_hmac(), EVP_PKEY_get0_poly1305(), EVP_PKEY_get0_siphash(),
 EVP_PKEY_get0_RSA(), EVP_PKEY_get0_DSA(), EVP_PKEY_get0_DH()
-and EVP_PKEY_get0_EC_KEY() also return the referenced key in B<pkey> or B<NULL>
+and EVP_PKEY_get0_EC_KEY() also return the referenced key in I<pkey> or NULL
 if the key is not of the correct type but the reference count of the
 returned key is B<not> incremented and so must not be freed up after use.
 
 EVP_PKEY_assign_RSA(), EVP_PKEY_assign_DSA(), EVP_PKEY_assign_DH(),
 EVP_PKEY_assign_EC_KEY(), EVP_PKEY_assign_POLY1305() and
-EVP_PKEY_assign_SIPHASH() also set the referenced key to B<key>
-however these use the supplied B<key> internally and so B<key>
-will be freed when the parent B<pkey> is freed.
+EVP_PKEY_assign_SIPHASH() also set the referenced key to I<key>
+however these use the supplied I<key> internally and so I<key>
+will be freed when the parent I<pkey> is freed.
 
-EVP_PKEY_base_id() returns the type of B<pkey>. For example
+EVP_PKEY_base_id() returns the type of I<pkey>. For example
 an RSA key will return B<EVP_PKEY_RSA>.
 
-EVP_PKEY_id() returns the actual OID associated with B<pkey>. Historically keys
+EVP_PKEY_id() returns the actual OID associated with I<pkey>. Historically keys
 using the same algorithm could use different OIDs. For example an RSA key could
 use the OIDs corresponding to the NIDs B<NID_rsaEncryption> (equivalent to
 B<EVP_PKEY_RSA>) or B<NID_rsa> (equivalent to B<EVP_PKEY_RSA2>). The use of
 alternative non-standard OIDs is now rare so B<EVP_PKEY_RSA2> et al are not
 often seen in practice.
 
-EVP_PKEY_type() returns the underlying type of the NID B<type>. For example
+EVP_PKEY_type() returns the underlying type of the NID I<type>. For example
 EVP_PKEY_type(EVP_PKEY_RSA2) will return B<EVP_PKEY_RSA>.
 
-EVP_PKEY_get0_engine() returns a reference to the ENGINE handling B<pkey>.
+EVP_PKEY_get0_engine() returns a reference to the ENGINE handling I<pkey>.
 
-EVP_PKEY_set1_engine() sets the ENGINE handling B<pkey> to B<engine>. It
+EVP_PKEY_set1_engine() sets the ENGINE handling I<pkey> to I<engine>. It
 must be called after the key algorithm and components are set up.
-If B<engine> does not include an B<EVP_PKEY_METHOD> for B<pkey> an
+If I<engine> does not include an B<EVP_PKEY_METHOD> for I<pkey> an
 error occurs.
 
 EVP_PKEY_set_alias_type() allows modifying a EVP_PKEY to use a
 different set of algorithms than the default.
 
+=head1 WARNINGS
+
+The following functions are only reliable with B<EVP_PKEY>s that have
+been assigned an internal key with EVP_PKEY_assign_*():
+
+EVP_PKEY_id(), EVP_PKEY_base_id(), EVP_PKEY_type(), EVP_PKEY_set_alias_type()
+
+For EVP_PKEY key type checking purposes, L<EVP_PKEY_is_a(3)> is more generic.
+
 =head1 NOTES
 
 In accordance with the OpenSSL naming convention the key obtained
-from or assigned to the B<pkey> using the B<1> functions must be
-freed as well as B<pkey>.
+from or assigned to the I<pkey> using the B<1> functions must be
+freed as well as I<pkey>.
 
 EVP_PKEY_assign_RSA(), EVP_PKEY_assign_DSA(), EVP_PKEY_assign_DH(),
 EVP_PKEY_assign_EC_KEY(), EVP_PKEY_assign_POLY1305()
@@ -129,7 +138,7 @@ EVP_PKEY_set1_RSA(), EVP_PKEY_set1_DSA(), EVP_PKEY_set1_DH() and
 EVP_PKEY_set1_EC_KEY() return 1 for success or 0 for failure.
 
 EVP_PKEY_get1_RSA(), EVP_PKEY_get1_DSA(), EVP_PKEY_get1_DH() and
-EVP_PKEY_get1_EC_KEY() return the referenced key or B<NULL> if
+EVP_PKEY_get1_EC_KEY() return the referenced key or NULL if
 an error occurred.
 
 EVP_PKEY_assign_RSA(), EVP_PKEY_assign_DSA(), EVP_PKEY_assign_DH(),
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 <openssl/evp.h>
+
+# 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 4903fc5f42..a14e899202 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -1104,12 +1104,14 @@ DEPRECATEDIN_3_0(int EVP_PKEY_decrypt_old(unsigned char *dec_key,
 DEPRECATEDIN_3_0(int EVP_PKEY_encrypt_old(unsigned char *enc_key,
                                           const unsigned char *key,
                                           int key_len, EVP_PKEY *pub_key))
+int EVP_PKEY_is_a(const EVP_PKEY *pkey, const char *name);
 int EVP_PKEY_type(int type);
 int EVP_PKEY_id(const EVP_PKEY *pkey);
 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/providers/implementations/keymgmt/ec_kmgmt.c b/providers/implementations/keymgmt/ec_kmgmt.c
index 77d4753723..661aa2de9f 100644
--- a/providers/implementations/keymgmt/ec_kmgmt.c
+++ b/providers/implementations/keymgmt/ec_kmgmt.c
@@ -352,13 +352,10 @@ int ec_export(void *keydata, int selection, OSSL_CALLBACK *param_cb,
     if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0)
         ok = ok && otherparams_to_params(ec, tmpl, NULL);
 
-    if (!ok
-        || (params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL)
-        goto err;
+    if (ok && (params = OSSL_PARAM_BLD_to_param(tmpl)) != NULL)
+        ok = param_cb(params, cbarg);
 
-    ok = param_cb(params, cbarg);
     OSSL_PARAM_BLD_free_params(params);
-err:
     OSSL_PARAM_BLD_free(tmpl);
     OPENSSL_free(pub_key);
     return ok;
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/extensions_clnt.c b/ssl/statem/extensions_clnt.c
index 776473e659..82e333628f 100644
--- a/ssl/statem/extensions_clnt.c
+++ b/ssl/statem/extensions_clnt.c
@@ -644,6 +644,21 @@ static int add_key_share(SSL *s, WPACKET *pkt, unsigned int curve_id)
             /* SSLfatal() already called */
             return 0;
         }
+
+        /*
+         * TODO(3.0) Remove this when EVP_PKEY_get1_tls_encodedpoint()
+         * knows how to get a key from an encoded point with the help of
+         * a OSSL_SERIALIZER deserializer.  We know that EVP_PKEY_get0()
+         * downgrades an EVP_PKEY to contain a legacy key.
+         *
+         * THIS IS TEMPORARY
+         */
+        EVP_PKEY_get0(key_share_key);
+        if (EVP_PKEY_id(key_share_key) == EVP_PKEY_NONE) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_ADD_KEY_SHARE,
+                     ERR_R_EC_LIB);
+            goto err;
+        }
     }
 
     /* Encode the public key. */
@@ -1906,6 +1921,23 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
                  ERR_R_MALLOC_FAILURE);
         return 0;
     }
+
+    /*
+     * TODO(3.0) Remove this when EVP_PKEY_get1_tls_encodedpoint()
+     * knows how to get a key from an encoded point with the help of
+     * a OSSL_SERIALIZER deserializer.  We know that EVP_PKEY_get0()
+     * downgrades an EVP_PKEY to contain a legacy key.
+     *
+     * THIS IS TEMPORARY
+     */
+    EVP_PKEY_get0(skey);
+    if (EVP_PKEY_id(skey) == EVP_PKEY_NONE) {
+        EVP_PKEY_free(skey);
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_KEY_SHARE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
     if (!EVP_PKEY_set1_tls_encodedpoint(skey, PACKET_data(&encoded_pt),
                                         PACKET_remaining(&encoded_pt))) {
         SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_KEY_SHARE,
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
index 549a207430..bafd62a0db 100644
--- a/ssl/statem/extensions_srvr.c
+++ b/ssl/statem/extensions_srvr.c
@@ -711,6 +711,21 @@ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
             return 0;
         }
 
+        /*
+         * TODO(3.0) Remove this when EVP_PKEY_get1_tls_encodedpoint()
+         * knows how to get a key from an encoded point with the help of
+         * a OSSL_SERIALIZER deserializer.  We know that EVP_PKEY_get0()
+         * downgrades an EVP_PKEY to contain a legacy key.
+         *
+         * THIS IS TEMPORARY
+         */
+        EVP_PKEY_get0(s->s3.peer_tmp);
+        if (EVP_PKEY_id(s->s3.peer_tmp) == EVP_PKEY_NONE) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_KEY_SHARE,
+                     ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+
         s->s3.group_id = group_id;
 
         if (!EVP_PKEY_set1_tls_encodedpoint(s->s3.peer_tmp,
@@ -1736,6 +1751,21 @@ EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt,
         return EXT_RETURN_FAIL;
     }
 
+    /*
+     * TODO(3.0) Remove this when EVP_PKEY_get1_tls_encodedpoint()
+     * knows how to get a key from an encoded point with the help of
+     * a OSSL_SERIALIZER deserializer.  We know that EVP_PKEY_get0()
+     * downgrades an EVP_PKEY to contain a legacy key.
+     *
+     * THIS IS TEMPORARY
+     */
+    EVP_PKEY_get0(skey);
+    if (EVP_PKEY_id(skey) == EVP_PKEY_NONE) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+                 ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+
     /* Generate encoding of server key */
     encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(skey, &encodedPoint);
     if (encoded_pt_len == 0) {
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index cdd413d1ef..7878d7b499 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -2227,6 +2227,21 @@ static int tls_process_ske_ecdhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey)
         return 0;
     }
 
+    /*
+     * TODO(3.0) Remove this when EVP_PKEY_get1_tls_encodedpoint()
+     * knows how to get a key from an encoded point with the help of
+     * a OSSL_SERIALIZER deserializer.  We know that EVP_PKEY_get0()
+     * downgrades an EVP_PKEY to contain a legacy key.
+     *
+     * THIS IS TEMPORARY
+     */
+    EVP_PKEY_get0(s->s3.peer_tmp);
+    if (EVP_PKEY_id(s->s3.peer_tmp) == EVP_PKEY_NONE) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SKE_ECDHE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
     if (!EVP_PKEY_set1_tls_encodedpoint(s->s3.peer_tmp,
                                         PACKET_data(&encoded_pt),
                                         PACKET_remaining(&encoded_pt))) {
@@ -3129,6 +3144,21 @@ static int tls_construct_cke_ecdhe(SSL *s, WPACKET *pkt)
         goto err;
     }
 
+    /*
+     * TODO(3.0) Remove this when EVP_PKEY_get1_tls_encodedpoint()
+     * knows how to get a key from an encoded point with the help of
+     * a OSSL_SERIALIZER deserializer.  We know that EVP_PKEY_get0()
+     * downgrades an EVP_PKEY to contain a legacy key.
+     *
+     * THIS IS TEMPORARY
+     */
+    EVP_PKEY_get0(ckey);
+    if (EVP_PKEY_id(skey) == EVP_PKEY_NONE) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_ECDHE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
     if (ssl_derive(s, ckey, skey, 0) == 0) {
         /* SSLfatal() already called */
         goto err;
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 <openssl/buffer.h>
 #include <openssl/objects.h>
 #include <openssl/evp.h>
@@ -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/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 43f9811163..1bab800ced 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -2624,6 +2624,18 @@ int tls_construct_server_key_exchange(SSL *s, WPACKET *pkt)
             goto err;
         }
 
+        /*
+         * TODO(3.0) Remove this when EVP_PKEY_get1_tls_encodedpoint()
+         * knows how to get a key from an encoded point with the help of
+         * a OSSL_SERIALIZER deserializer.  We know that EVP_PKEY_get0()
+         * downgrades an EVP_PKEY to contain a legacy key.
+         *
+         * THIS IS TEMPORARY
+         */
+        EVP_PKEY_get0(s->s3.tmp.pkey);
+        if (EVP_PKEY_id(s->s3.tmp.pkey) == EVP_PKEY_NONE)
+            goto err;
+
         /* Encode the public key. */
         encodedlen = EVP_PKEY_get1_tls_encodedpoint(s->s3.tmp.pkey,
                                                     &encodedPoint);
@@ -3207,6 +3219,22 @@ static int tls_process_cke_ecdhe(SSL *s, PACKET *pkt)
                      ERR_R_EVP_LIB);
             goto err;
         }
+
+        /*
+         * TODO(3.0) Remove this when EVP_PKEY_get1_tls_encodedpoint()
+         * knows how to get a key from an encoded point with the help of
+         * a OSSL_SERIALIZER deserializer.  We know that EVP_PKEY_get0()
+         * downgrades an EVP_PKEY to contain a legacy key.
+         *
+         * THIS IS TEMPORARY
+         */
+        EVP_PKEY_get0(ckey);
+        if (EVP_PKEY_id(ckey) == EVP_PKEY_NONE) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_ECDHE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
         if (EVP_PKEY_set1_tls_encodedpoint(ckey, data, i) == 0) {
             SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_ECDHE,
                      ERR_R_EC_LIB);
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 <openssl/dh.h>
 #include <openssl/bn.h>
 #include "internal/nelem.h"
+#include "internal/evp.h"
 #include "ssl_local.h"
 #include <openssl/ct.h>
 
@@ -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 12761e4adc..73d70efe99 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -5037,3 +5037,6 @@ EVP_PKEY_get_size_t_param               ?	3_0_0	EXIST::FUNCTION:
 EVP_PKEY_get_bn_param                   ?	3_0_0	EXIST::FUNCTION:
 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)


More information about the openssl-commits mailing list