Fix a padding oracle in PKCS7_dataDecode and CMS_decrypt_set1_pkey
[openssl.git] / crypto / pkcs7 / pk7_doit.c
index dd6f675..63bc882 100644 (file)
@@ -191,7 +191,8 @@ static int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri,
 }
 
 static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen,
 }
 
 static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen,
-                               PKCS7_RECIP_INFO *ri, EVP_PKEY *pkey)
+                               PKCS7_RECIP_INFO *ri, EVP_PKEY *pkey,
+                               size_t fixlen)
 {
     EVP_PKEY_CTX *pctx = NULL;
     unsigned char *ek = NULL;
 {
     EVP_PKEY_CTX *pctx = NULL;
     unsigned char *ek = NULL;
@@ -224,7 +225,9 @@ static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen,
     }
 
     if (EVP_PKEY_decrypt(pctx, ek, &eklen,
     }
 
     if (EVP_PKEY_decrypt(pctx, ek, &eklen,
-                         ri->enc_key->data, ri->enc_key->length) <= 0) {
+                         ri->enc_key->data, ri->enc_key->length) <= 0
+            || eklen == 0
+            || (fixlen != 0 && eklen != fixlen)) {
         ret = 0;
         PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_EVP_LIB);
         goto err;
         ret = 0;
         PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_EVP_LIB);
         goto err;
@@ -261,6 +264,25 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
     PKCS7_RECIP_INFO *ri = NULL;
     ASN1_OCTET_STRING *os = NULL;
 
     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;
 
     i = OBJ_obj2nid(p7->type);
     p7->state = PKCS7_S_HEADER;
 
@@ -321,7 +343,7 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
         ivlen = EVP_CIPHER_iv_length(evp_cipher);
         xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher));
         if (ivlen > 0)
         ivlen = EVP_CIPHER_iv_length(evp_cipher);
         xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher));
         if (ivlen > 0)
-            if (RAND_pseudo_bytes(iv, ivlen) <= 0)
+            if (RAND_bytes(iv, ivlen) <= 0)
                 goto err;
         if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, NULL, NULL, 1) <= 0)
             goto err;
                 goto err;
         if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, NULL, NULL, 1) <= 0)
             goto err;
@@ -356,16 +378,18 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
     }
 
     if (bio == NULL) {
     }
 
     if (bio == NULL) {
-        if (PKCS7_is_detached(p7))
+        if (PKCS7_is_detached(p7)) {
             bio = BIO_new(BIO_s_null());
             bio = BIO_new(BIO_s_null());
-        else if (os && os->length > 0)
+        } else if (os && os->length > 0) {
             bio = BIO_new_mem_buf(os->data, os->length);
             bio = BIO_new_mem_buf(os->data, os->length);
-        if (bio == NULL) {
+        } else {
             bio = BIO_new(BIO_s_mem());
             if (bio == NULL)
                 goto err;
             BIO_set_mem_eof_return(bio, 0);
         }
             bio = BIO_new(BIO_s_mem());
             if (bio == NULL)
                 goto err;
             BIO_set_mem_eof_return(bio, 0);
         }
+        if (bio == NULL)
+            goto err;
     }
     if (out)
         BIO_push(out, bio);
     }
     if (out)
         BIO_push(out, bio);
@@ -411,11 +435,27 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
     unsigned char *ek = NULL, *tkey = NULL;
     int eklen = 0, tkeylen = 0;
 
     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;
 
     switch (i) {
     case NID_pkcs7_signed:
     i = OBJ_obj2nid(p7->type);
     p7->state = PKCS7_S_HEADER;
 
     switch (i) {
     case NID_pkcs7_signed:
+        /*
+         * p7->d.sign->contents is a PKCS7 structure consisting of a contentType
+         * field and optional content.
+         * data_body is NULL if that structure has no (=detached) content
+         * or if the contentType is wrong (i.e., not "data").
+         */
         data_body = PKCS7_get_octet_string(p7->d.sign->contents);
         if (!PKCS7_is_detached(p7) && data_body == NULL) {
             PKCS7err(PKCS7_F_PKCS7_DATADECODE,
         data_body = PKCS7_get_octet_string(p7->d.sign->contents);
         if (!PKCS7_is_detached(p7) && data_body == NULL) {
             PKCS7err(PKCS7_F_PKCS7_DATADECODE,
@@ -427,6 +467,7 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
     case NID_pkcs7_signedAndEnveloped:
         rsk = p7->d.signed_and_enveloped->recipientinfo;
         md_sk = p7->d.signed_and_enveloped->md_algs;
     case NID_pkcs7_signedAndEnveloped:
         rsk = p7->d.signed_and_enveloped->recipientinfo;
         md_sk = p7->d.signed_and_enveloped->md_algs;
+        /* data_body is NULL if the optional EncryptedContent is missing. */
         data_body = p7->d.signed_and_enveloped->enc_data->enc_data;
         enc_alg = p7->d.signed_and_enveloped->enc_data->algorithm;
         evp_cipher = EVP_get_cipherbyobj(enc_alg->algorithm);
         data_body = p7->d.signed_and_enveloped->enc_data->enc_data;
         enc_alg = p7->d.signed_and_enveloped->enc_data->algorithm;
         evp_cipher = EVP_get_cipherbyobj(enc_alg->algorithm);
@@ -439,6 +480,7 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
     case NID_pkcs7_enveloped:
         rsk = p7->d.enveloped->recipientinfo;
         enc_alg = p7->d.enveloped->enc_data->algorithm;
     case NID_pkcs7_enveloped:
         rsk = p7->d.enveloped->recipientinfo;
         enc_alg = p7->d.enveloped->enc_data->algorithm;
+        /* data_body is NULL if the optional EncryptedContent is missing. */
         data_body = p7->d.enveloped->enc_data->enc_data;
         evp_cipher = EVP_get_cipherbyobj(enc_alg->algorithm);
         if (evp_cipher == NULL) {
         data_body = p7->d.enveloped->enc_data->enc_data;
         evp_cipher = EVP_get_cipherbyobj(enc_alg->algorithm);
         if (evp_cipher == NULL) {
@@ -452,6 +494,12 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
         goto err;
     }
 
         goto err;
     }
 
+    /* Detached content must be supplied via in_bio instead. */
+    if (data_body == NULL && in_bio == NULL) {
+        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT);
+        goto err;
+    }
+
     /* We will be checking the signature */
     if (md_sk != NULL) {
         for (i = 0; i < sk_X509_ALGOR_num(md_sk); i++) {
     /* We will be checking the signature */
     if (md_sk != NULL) {
         for (i = 0; i < sk_X509_ALGOR_num(md_sk); i++) {
@@ -526,13 +574,14 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
             for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
                 ri = sk_PKCS7_RECIP_INFO_value(rsk, i);
 
             for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
                 ri = sk_PKCS7_RECIP_INFO_value(rsk, i);
 
-                if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) < 0)
+                if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey,
+                        EVP_CIPHER_key_length(evp_cipher)) < 0)
                     goto err;
                 ERR_clear_error();
             }
         } else {
             /* Only exit on fatal errors, not decrypt failure */
                     goto err;
                 ERR_clear_error();
             }
         } else {
             /* Only exit on fatal errors, not decrypt failure */
-            if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) < 0)
+            if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey, 0) < 0)
                 goto err;
             ERR_clear_error();
         }
                 goto err;
             ERR_clear_error();
         }
@@ -594,11 +643,13 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
         etmp = NULL;
     }
 #if 1
         etmp = NULL;
     }
 #if 1
-    if (PKCS7_is_detached(p7) || (in_bio != NULL)) {
+    if (in_bio != NULL) {
         bio = in_bio;
     } else {
 # if 0
         bio = BIO_new(BIO_s_mem());
         bio = in_bio;
     } else {
 # if 0
         bio = BIO_new(BIO_s_mem());
+        if (bio == NULL)
+            goto err;
         /*
          * We need to set this so that when we have read all the data, the
          * encrypt BIO, if present, will read EOF and encode the last few
         /*
          * We need to set this so that when we have read all the data, the
          * encrypt BIO, if present, will read EOF and encode the last few
@@ -613,6 +664,8 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
             bio = BIO_new_mem_buf(data_body->data, data_body->length);
         else {
             bio = BIO_new(BIO_s_mem());
             bio = BIO_new_mem_buf(data_body->data, data_body->length);
         else {
             bio = BIO_new(BIO_s_mem());
+            if (bio == NULL)
+                goto err;
             BIO_set_mem_eof_return(bio, 0);
         }
         if (bio == NULL)
             BIO_set_mem_eof_return(bio, 0);
         }
         if (bio == NULL)
@@ -707,6 +760,16 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
     STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL;
     ASN1_OCTET_STRING *os = NULL;
 
     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;
     EVP_MD_CTX_init(&ctx_tmp);
     i = OBJ_obj2nid(p7->type);
     p7->state = PKCS7_S_HEADER;
@@ -746,6 +809,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);
         /* 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;
             p7->d.sign->contents->d.data = NULL;
         }
         break;
@@ -755,6 +819,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);
         /* 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;
             p7->d.digest->contents->d.data = NULL;
         }
         break;
@@ -820,22 +885,30 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
         M_ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len);
     }
 
         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:
     }
     ret = 1;
  err:
@@ -910,6 +983,16 @@ int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio,
     STACK_OF(X509) *cert;
     X509 *x509;
 
     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)) {
     if (PKCS7_type_is_signed(p7)) {
         cert = p7->d.sign->cert;
     } else if (PKCS7_type_is_signedAndEnveloped(p7)) {
@@ -1083,7 +1166,6 @@ PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx)
     rsk = p7->d.signed_and_enveloped->recipientinfo;
     if (rsk == NULL)
         return NULL;
     rsk = p7->d.signed_and_enveloped->recipientinfo;
     if (rsk == NULL)
         return NULL;
-    ri = sk_PKCS7_RECIP_INFO_value(rsk, 0);
     if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx)
         return (NULL);
     ri = sk_PKCS7_RECIP_INFO_value(rsk, idx);
     if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx)
         return (NULL);
     ri = sk_PKCS7_RECIP_INFO_value(rsk, idx);