Use the right class/tag when decoding an embedded key
authorMatt Caswell <matt@openssl.org>
Thu, 27 May 2021 15:24:00 +0000 (16:24 +0100)
committerMatt Caswell <matt@openssl.org>
Tue, 8 Jun 2021 17:53:28 +0000 (18:53 +0100)
When a key (SubjectPublicKeyInfo) is embedded in some other structure
it may use an implicit tag. However the decoders can only handle the
universal class and don't know how to interpret the implicit tag.
Therefore we modify the data into a form the decoders can handle.

Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/15504)

crypto/x509/x_pubkey.c

index 2fe5724743b6a3a5fc2d2dd71195e831c171c0a2..9ba63788bcb35f6bb81af8294b7f08b6fdbac1f8 100644 (file)
@@ -111,9 +111,11 @@ static int x509_pubkey_ex_d2i_ex(ASN1_VALUE **pval,
                                  const char *propq)
 {
     const unsigned char *in_saved = *in;
+    size_t publen;
     X509_PUBKEY *pubkey;
     int ret;
     OSSL_DECODER_CTX *dctx = NULL;
+    unsigned char *tmpbuf = NULL;
 
     if (*pval == NULL && !x509_pubkey_ex_new_ex(pval, it, libctx, propq))
         return 0;
@@ -128,6 +130,12 @@ static int x509_pubkey_ex_d2i_ex(ASN1_VALUE **pval,
                                 tag, aclass, opt, ctx)) <= 0)
         return ret;
 
+    publen = *in - in_saved;
+    if (!ossl_assert(publen > 0)) {
+        ERR_raise(ERR_LIB_ASN1, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
     pubkey = (X509_PUBKEY *)*pval;
     EVP_PKEY_free(pubkey->pkey);
     pubkey->pkey = NULL;
@@ -151,9 +159,24 @@ static int x509_pubkey_ex_d2i_ex(ASN1_VALUE **pval,
 
     /* Try to decode it into an EVP_PKEY with OSSL_DECODER */
     if (ret <= 0 && !pubkey->flag_force_legacy) {
-        const unsigned char *p = in_saved;
+        const unsigned char *p;
         char txtoidname[OSSL_MAX_NAME_SIZE];
 
+        /*
+        * The decoders don't know how to handle anything other than Universal
+        * class so we modify the data accordingly.
+        */
+        if (aclass != V_ASN1_UNIVERSAL) {
+            tmpbuf = OPENSSL_memdup(in_saved, publen);
+            if (tmpbuf == NULL) {
+                ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
+                return 0;
+            }
+            in_saved = tmpbuf;
+            *tmpbuf = V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE;
+        }
+        p = in_saved;
+
         if (OBJ_obj2txt(txtoidname, sizeof(txtoidname),
                         pubkey->algor->algorithm, 0) <= 0) {
             ERR_clear_last_mark();
@@ -176,6 +199,7 @@ static int x509_pubkey_ex_d2i_ex(ASN1_VALUE **pval,
     ret = 1;
  end:
     OSSL_DECODER_CTX_free(dctx);
+    OPENSSL_free(tmpbuf);
     return ret;
 }