]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
PKCS#7: avoid NULL pointer dereferences with missing content
authorEmilia Kasper <emilia@openssl.org>
Fri, 27 Feb 2015 15:52:23 +0000 (16:52 +0100)
committerMatt Caswell <matt@openssl.org>
Thu, 19 Mar 2015 13:00:45 +0000 (13:00 +0000)
In PKCS#7, the ASN.1 content component is optional.
This typically applies to inner content (detached signatures),
however we must also handle unexpected missing outer content
correctly.

This patch only addresses functions reachable from parsing,
decryption and verification, and functions otherwise associated
with reading potentially untrusted data.

Correcting all low-level API calls requires further work.

CVE-2015-0289

Thanks to Michal Zalewski (Google) for reporting this issue.

Reviewed-by: Steve Henson <steve@openssl.org>
Conflicts:
crypto/pkcs7/pk7_doit.c

crypto/pkcs7/pk7_doit.c
crypto/pkcs7/pk7_lib.c

index ba5b82401abd857c38d878d0f404d5cc2e02c742..db134ddcc3a5ace21dec60ea46e52a66ceea45b4 100644 (file)
@@ -147,6 +147,25 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
     EVP_PKEY *pkey;
     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;
 
@@ -325,6 +344,16 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
     STACK_OF(PKCS7_RECIP_INFO) *rsk = NULL;
     PKCS7_RECIP_INFO *ri = NULL;
 
+    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;
 
@@ -607,6 +636,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;
@@ -635,6 +674,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;
@@ -644,6 +684,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;
@@ -767,6 +808,12 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
     }
 
     if (!PKCS7_is_detached(p7)) {
+        /*
+         * NOTE(emilia): I think we only reach os == NULL here because detached
+         * digested data support is broken.
+         */
+        if (os == NULL)
+            goto err;
         btmp = BIO_find_type(bio, BIO_TYPE_MEM);
         if (btmp == NULL) {
             PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_UNABLE_TO_FIND_MEM_BIO);
@@ -803,6 +850,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)) {
index 7d19126da5e03bd48bb3dff3e2bd07fd4ea49169..c2ad3ec1ac62f5b9f1220d44e9bf540997f1f598 100644 (file)
@@ -69,6 +69,7 @@ long PKCS7_ctrl(PKCS7 *p7, int cmd, long larg, char *parg)
     nid = OBJ_obj2nid(p7->type);
 
     switch (cmd) {
+    /* NOTE(emilia): does not support detached digested data. */
     case PKCS7_OP_SET_DETACHED_SIGNATURE:
         if (nid == NID_pkcs7_signed) {
             ret = p7->detached = (int)larg;
@@ -464,6 +465,8 @@ int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md)
 
 STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7)
 {
+    if (p7 == NULL || p7->d.ptr == NULL)
+        return NULL;
     if (PKCS7_type_is_signed(p7)) {
         return (p7->d.sign->signer_info);
     } else if (PKCS7_type_is_signedAndEnveloped(p7)) {