PKCS#7: avoid NULL pointer dereferences with missing content
[openssl.git] / crypto / pkcs7 / pk7_doit.c
index dd6f6756b255aa0c567441205cad369d3eb05b11..31a1b983f1d9d175752af9c8ad7a52308c1a22d9 100644 (file)
@@ -261,6 +261,25 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
     PKCS7_RECIP_INFO *ri = NULL;
     ASN1_OCTET_STRING *os = NULL;
 
+    if (p7 == NULL) {
+        PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_INVALID_NULL_POINTER);
+        return NULL;
+    }
+    /*
+     * The content field in the PKCS7 ContentInfo is optional, but that really
+     * only applies to inner content (precisely, detached signatures).
+     *
+     * When reading content, missing outer content is therefore treated as an
+     * error.
+     *
+     * When creating content, PKCS7_content_new() must be called before
+     * calling this method, so a NULL p7->d is always an error.
+     */
+    if (p7->d.ptr == NULL) {
+        PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_NO_CONTENT);
+        return NULL;
+    }
+
     i = OBJ_obj2nid(p7->type);
     p7->state = PKCS7_S_HEADER;
 
@@ -411,6 +430,16 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
     unsigned char *ek = NULL, *tkey = NULL;
     int eklen = 0, tkeylen = 0;
 
+    if (p7 == NULL) {
+        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_INVALID_NULL_POINTER);
+        return NULL;
+    }
+
+    if (p7->d.ptr == NULL) {
+        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT);
+        return NULL;
+    }
+
     i = OBJ_obj2nid(p7->type);
     p7->state = PKCS7_S_HEADER;
 
@@ -707,6 +736,16 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
     STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL;
     ASN1_OCTET_STRING *os = NULL;
 
+    if (p7 == NULL) {
+        PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_INVALID_NULL_POINTER);
+        return 0;
+    }
+
+    if (p7->d.ptr == NULL) {
+        PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_NO_CONTENT);
+        return 0;
+    }
+
     EVP_MD_CTX_init(&ctx_tmp);
     i = OBJ_obj2nid(p7->type);
     p7->state = PKCS7_S_HEADER;
@@ -746,6 +785,7 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
         /* If detached data then the content is excluded */
         if (PKCS7_type_is_data(p7->d.sign->contents) && p7->detached) {
             M_ASN1_OCTET_STRING_free(os);
+            os = NULL;
             p7->d.sign->contents->d.data = NULL;
         }
         break;
@@ -755,6 +795,7 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
         /* If detached data then the content is excluded */
         if (PKCS7_type_is_data(p7->d.digest->contents) && p7->detached) {
             M_ASN1_OCTET_STRING_free(os);
+            os = NULL;
             p7->d.digest->contents->d.data = NULL;
         }
         break;
@@ -820,22 +861,30 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
         M_ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len);
     }
 
-    if (!PKCS7_is_detached(p7) && !(os->flags & ASN1_STRING_FLAG_NDEF)) {
-        char *cont;
-        long contlen;
-        btmp = BIO_find_type(bio, BIO_TYPE_MEM);
-        if (btmp == NULL) {
-            PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_UNABLE_TO_FIND_MEM_BIO);
-            goto err;
-        }
-        contlen = BIO_get_mem_data(btmp, &cont);
+    if (!PKCS7_is_detached(p7)) {
         /*
-         * Mark the BIO read only then we can use its copy of the data
-         * instead of making an extra copy.
+         * NOTE(emilia): I think we only reach os == NULL here because detached
+         * digested data support is broken.
          */
-        BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY);
-        BIO_set_mem_eof_return(btmp, 0);
-        ASN1_STRING_set0(os, (unsigned char *)cont, contlen);
+        if (os == NULL)
+            goto err;
+        if (!(os->flags & ASN1_STRING_FLAG_NDEF)) {
+            char *cont;
+            long contlen;
+            btmp = BIO_find_type(bio, BIO_TYPE_MEM);
+            if (btmp == NULL) {
+                PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_UNABLE_TO_FIND_MEM_BIO);
+                goto err;
+            }
+            contlen = BIO_get_mem_data(btmp, &cont);
+            /*
+             * Mark the BIO read only then we can use its copy of the data
+             * instead of making an extra copy.
+             */
+            BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY);
+            BIO_set_mem_eof_return(btmp, 0);
+            ASN1_STRING_set0(os, (unsigned char *)cont, contlen);
+        }
     }
     ret = 1;
  err:
@@ -910,6 +959,16 @@ int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio,
     STACK_OF(X509) *cert;
     X509 *x509;
 
+    if (p7 == NULL) {
+        PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_INVALID_NULL_POINTER);
+        return 0;
+    }
+
+    if (p7->d.ptr == NULL) {
+        PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_NO_CONTENT);
+        return 0;
+    }
+
     if (PKCS7_type_is_signed(p7)) {
         cert = p7->d.sign->cert;
     } else if (PKCS7_type_is_signedAndEnveloped(p7)) {