Remove some unnecessary dependencies on EVP_PKEY_set_type

EVP_PKEY_set_type needs to pull in every supported EVP_PKEY type, but
most of our calls within the library already know what type they're
working with. Have them call evp_pkey_set_method directly.

Bug: 497
Change-Id: I17cb9a0dff0da55206686bce1d8e1df4773f6f4d
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/67127
Reviewed-by: Bob Beck <bbe@google.com>
Auto-Submit: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/evp/evp.c b/crypto/evp/evp.c
index f3f3d7e..babf709 100644
--- a/crypto/evp/evp.c
+++ b/crypto/evp/evp.c
@@ -149,9 +149,7 @@
 
 int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) {
   if (to->type == EVP_PKEY_NONE) {
-    if (!EVP_PKEY_set_type(to, from->type)) {
-      return 0;
-    }
+    evp_pkey_set_method(to, from->ameth);
   } else if (to->type != from->type) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES);
     return 0;
@@ -225,8 +223,7 @@
   }
 }
 
-static void evp_pkey_set_method(EVP_PKEY *pkey,
-                                const EVP_PKEY_ASN1_METHOD *method) {
+void evp_pkey_set_method(EVP_PKEY *pkey, const EVP_PKEY_ASN1_METHOD *method) {
   free_it(pkey);
   pkey->ameth = method;
   pkey->type = pkey->ameth->pkey_id;
diff --git a/crypto/evp/evp_asn1.c b/crypto/evp/evp_asn1.c
index f270c3e..8f341e9 100644
--- a/crypto/evp/evp_asn1.c
+++ b/crypto/evp/evp_asn1.c
@@ -77,28 +77,26 @@
     &x25519_asn1_meth,
 };
 
-static int parse_key_type(CBS *cbs, int *out_type) {
+static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs) {
   CBS oid;
   if (!CBS_get_asn1(cbs, &oid, CBS_ASN1_OBJECT)) {
-    return 0;
+    return NULL;
   }
 
   for (unsigned i = 0; i < OPENSSL_ARRAY_SIZE(kASN1Methods); i++) {
     const EVP_PKEY_ASN1_METHOD *method = kASN1Methods[i];
     if (CBS_len(&oid) == method->oid_len &&
         OPENSSL_memcmp(CBS_data(&oid), method->oid, method->oid_len) == 0) {
-      *out_type = method->pkey_id;
-      return 1;
+      return method;
     }
   }
 
-  return 0;
+  return NULL;
 }
 
 EVP_PKEY *EVP_parse_public_key(CBS *cbs) {
   // Parse the SubjectPublicKeyInfo.
   CBS spki, algorithm, key;
-  int type;
   uint8_t padding;
   if (!CBS_get_asn1(cbs, &spki, CBS_ASN1_SEQUENCE) ||
       !CBS_get_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
@@ -107,7 +105,8 @@
     OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
     return NULL;
   }
-  if (!parse_key_type(&algorithm, &type)) {
+  const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm);
+  if (method == NULL) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
     return NULL;
   }
@@ -121,10 +120,10 @@
 
   // Set up an |EVP_PKEY| of the appropriate type.
   EVP_PKEY *ret = EVP_PKEY_new();
-  if (ret == NULL ||
-      !EVP_PKEY_set_type(ret, type)) {
+  if (ret == NULL) {
     goto err;
   }
+  evp_pkey_set_method(ret, method);
 
   // Call into the type-specific SPKI decoding function.
   if (ret->ameth->pub_decode == NULL) {
@@ -155,7 +154,6 @@
   // Parse the PrivateKeyInfo.
   CBS pkcs8, algorithm, key;
   uint64_t version;
-  int type;
   if (!CBS_get_asn1(cbs, &pkcs8, CBS_ASN1_SEQUENCE) ||
       !CBS_get_asn1_uint64(&pkcs8, &version) ||
       version != 0 ||
@@ -164,7 +162,8 @@
     OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
     return NULL;
   }
-  if (!parse_key_type(&algorithm, &type)) {
+  const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm);
+  if (method == NULL) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
     return NULL;
   }
@@ -173,10 +172,10 @@
 
   // Set up an |EVP_PKEY| of the appropriate type.
   EVP_PKEY *ret = EVP_PKEY_new();
-  if (ret == NULL ||
-      !EVP_PKEY_set_type(ret, type)) {
+  if (ret == NULL) {
     goto err;
   }
+  evp_pkey_set_method(ret, method);
 
   // Call into the type-specific PrivateKeyInfo decoding function.
   if (ret->ameth->priv_decode == NULL) {
diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h
index 6678c41..cf287c8 100644
--- a/crypto/evp/internal.h
+++ b/crypto/evp/internal.h
@@ -295,6 +295,10 @@
 extern const EVP_PKEY_METHOD x25519_pkey_meth;
 extern const EVP_PKEY_METHOD hkdf_pkey_meth;
 
+// evp_pkey_set_method behaves like |EVP_PKEY_set_type|, but takes a pointer to
+// a method table. This avoids depending on every |EVP_PKEY_ASN1_METHOD|.
+void evp_pkey_set_method(EVP_PKEY *pkey, const EVP_PKEY_ASN1_METHOD *method);
+
 
 #if defined(__cplusplus)
 }  // extern C
diff --git a/crypto/evp/p_ed25519.c b/crypto/evp/p_ed25519.c
index 647ea05..66e7197 100644
--- a/crypto/evp/p_ed25519.c
+++ b/crypto/evp/p_ed25519.c
@@ -30,10 +30,7 @@
     return 0;
   }
 
-  if (!EVP_PKEY_set_type(pkey, EVP_PKEY_ED25519)) {
-    OPENSSL_free(key);
-    return 0;
-  }
+  evp_pkey_set_method(pkey, &ed25519_asn1_meth);
 
   uint8_t pubkey_unused[32];
   ED25519_keypair(pubkey_unused, key->key);
diff --git a/crypto/evp/p_x25519.c b/crypto/evp/p_x25519.c
index 6218943..a4c9136 100644
--- a/crypto/evp/p_x25519.c
+++ b/crypto/evp/p_x25519.c
@@ -30,10 +30,7 @@
     return 0;
   }
 
-  if (!EVP_PKEY_set_type(pkey, EVP_PKEY_X25519)) {
-    OPENSSL_free(key);
-    return 0;
-  }
+  evp_pkey_set_method(pkey, &x25519_asn1_meth);
 
   X25519_keypair(key->pub, key->priv);
   key->has_private = 1;