Enforce that d2i_PrivateKey returns a key of the specified type.

If d2i_PrivateKey hit the PKCS#8 codepath, it didn't enforce that the key was
of the specified type.

Note that this requires tweaking d2i_AutoPrivateKey slightly. A PKCS #8
PrivateKeyInfo may have 3 or 4 elements (optional attributes), so we were
relying on this bug for d2i_AutoPrivateKey to work.

Change-Id: If50b7a742f535d208e944ba37c3a585689d1da43
Reviewed-on: https://boringssl-review.googlesource.com/7253
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/evp/evp_asn1.c b/crypto/evp/evp_asn1.c
index f9bd51c..ecf304c 100644
--- a/crypto/evp/evp_asn1.c
+++ b/crypto/evp/evp_asn1.c
@@ -223,6 +223,11 @@
     if (ret == NULL) {
       return NULL;
     }
+    if (ret->type != type) {
+      OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES);
+      EVP_PKEY_free(ret);
+      return NULL;
+    }
   }
 
   if (out != NULL) {
@@ -261,24 +266,22 @@
     return NULL;
   }
 
-  /* Count the elements to determine the format. */
-  switch (num_elements(*inp, (size_t)len)) {
-    case 3: {
-      /* Parse the input as a PKCS#8 PrivateKeyInfo. */
-      CBS cbs;
-      CBS_init(&cbs, *inp, (size_t)len);
-      EVP_PKEY *ret = EVP_parse_private_key(&cbs);
-      if (ret == NULL) {
-        return NULL;
-      }
-      if (out != NULL) {
-        EVP_PKEY_free(*out);
-        *out = ret;
-      }
-      *inp = CBS_data(&cbs);
-      return ret;
+  /* Parse the input as a PKCS#8 PrivateKeyInfo. */
+  CBS cbs;
+  CBS_init(&cbs, *inp, (size_t)len);
+  EVP_PKEY *ret = EVP_parse_private_key(&cbs);
+  if (ret != NULL) {
+    if (out != NULL) {
+      EVP_PKEY_free(*out);
+      *out = ret;
     }
+    *inp = CBS_data(&cbs);
+    return ret;
+  }
+  ERR_clear_error();
 
+  /* Count the elements to determine the legacy key format. */
+  switch (num_elements(*inp, (size_t)len)) {
     case 4:
       return d2i_PrivateKey(EVP_PKEY_EC, out, inp, len);
 
diff --git a/crypto/evp/evp_extra_test.cc b/crypto/evp/evp_extra_test.cc
index 0d03527..3d08638 100644
--- a/crypto/evp/evp_extra_test.cc
+++ b/crypto/evp/evp_extra_test.cc
@@ -640,6 +640,15 @@
   }
   ERR_clear_error();
 
+  derp = kExampleRSAKeyPKCS8;
+  pkey.reset(d2i_PrivateKey(EVP_PKEY_EC, nullptr, &derp,
+             sizeof(kExampleRSAKeyPKCS8)));
+  if (pkey) {
+    fprintf(stderr, "Imported RSA key as EC key.\n");
+    return false;
+  }
+  ERR_clear_error();
+
   return true;
 }