Correctly handle errors in CMS I/O code.
[openssl.git] / crypto / cms / cms_smime.c
index b18c789f643fc4cf181169d8c8ae8cea4c8529bd..dec8ef32f87d76df48866807bf01a9150fc4c6d7 100644 (file)
@@ -89,11 +89,13 @@ static int cms_copy_content(BIO *out, BIO *in, unsigned int flags)
                                if (!BIO_get_cipher_status(in))
                                        goto err;
                                }
+                       if (i < 0)
+                               goto err;
                        break;
                        }
                                
-               if (tmpout)
-                       BIO_write(tmpout, buf, i);
+               if (tmpout && (BIO_write(tmpout, buf, i) != i))
+                       goto err;
        }
 
        if(flags & CMS_TEXT)
@@ -125,6 +127,23 @@ static int check_content(CMS_ContentInfo *cms)
        return 1;
        }
 
+static void do_free_upto(BIO *f, BIO *upto)
+       {
+       if (upto)
+               {
+               BIO *tbio;
+               do 
+                       {
+                       tbio = BIO_pop(f);
+                       BIO_free(f);
+                       f = tbio;
+                       }
+               while (f != upto);
+               }
+       else
+               BIO_free_all(f);
+       }
+
 int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags)
        {
        BIO *cont;
@@ -149,7 +168,7 @@ CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags)
        if (!cms)
                return NULL;
 
-       if ((flags & CMS_STREAM) || CMS_final(cms, in, flags))
+       if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
                return cms;
 
        CMS_ContentInfo_free(cms);
@@ -177,7 +196,7 @@ int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
        r = cms_copy_content(out, cont, flags);
        if (r)
                r = cms_DigestedData_do_final(cms, cont, 1);
-       BIO_free_all(cont);
+       do_free_upto(cont, dcont);
        return r;
        }
 
@@ -194,7 +213,7 @@ CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md,
        if(!(flags & CMS_DETACHED))
                CMS_set_detached(cms, 0);
 
-       if ((flags & CMS_STREAM) || CMS_final(cms, in, flags))
+       if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
                return cms;
 
        CMS_ContentInfo_free(cms);
@@ -223,7 +242,7 @@ int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms,
        if (!cont)
                return 0;
        r = cms_copy_content(out, cont, flags);
-       BIO_free_all(cont);
+       do_free_upto(cont, dcont);
        return r;
        }
 
@@ -246,7 +265,8 @@ CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
        if(!(flags & CMS_DETACHED))
                CMS_set_detached(cms, 0);
 
-       if ((flags & (CMS_STREAM|CMS_PARTIAL)) || CMS_final(cms, in, flags))
+       if ((flags & (CMS_STREAM|CMS_PARTIAL))
+               || CMS_final(cms, in, NULL, flags))
                return cms;
 
        CMS_ContentInfo_free(cms);
@@ -410,8 +430,9 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
        err:
        
        if (dcont && (tmpin == dcont))
-               BIO_pop(cmsbio);
-       BIO_free_all(cmsbio);
+               do_free_upto(cmsbio, dcont);
+       else
+               BIO_free_all(cmsbio);
 
        if (cms_certs)
                sk_X509_pop_free(cms_certs, X509_free);
@@ -438,28 +459,29 @@ CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
        {
        CMS_ContentInfo *cms;
        int i;
+
        cms = CMS_ContentInfo_new();
-       if (!cms)
+       if (!cms || !CMS_SignedData_init(cms))
                goto merr;
+
        if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags))
                {
                CMSerr(CMS_F_CMS_SIGN, CMS_R_ADD_SIGNER_ERROR);
                goto err;
                }
+
        for (i = 0; i < sk_X509_num(certs); i++)
                {
                X509 *x = sk_X509_value(certs, i);
                if (!CMS_add1_cert(cms, x))
                        goto merr;
                }
-       /* If no signer or certs initialize signedData */
-       if (!pkey && !i && !CMS_SignedData_init(cms))
-               goto merr;
 
        if(!(flags & CMS_DETACHED))
                CMS_set_detached(cms, 0);
 
-       if ((flags & (CMS_STREAM|CMS_PARTIAL)) || CMS_final(cms, data, flags))
+       if ((flags & (CMS_STREAM|CMS_PARTIAL))
+               || CMS_final(cms, data, NULL, flags))
                return cms;
        else
                goto err;
@@ -526,7 +548,7 @@ CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
                goto err;
 
        /* Finalize structure */
-       if (!CMS_final(cms, rct_cont, flags))
+       if (!CMS_final(cms, rct_cont, NULL, flags))
                goto err;
 
        /* Set embedded content */
@@ -567,7 +589,8 @@ CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data,
        if(!(flags & CMS_DETACHED))
                CMS_set_detached(cms, 0);
 
-       if ((flags & (CMS_STREAM|CMS_PARTIAL)) || CMS_final(cms, data, flags))
+       if ((flags & (CMS_STREAM|CMS_PARTIAL))
+               || CMS_final(cms, data, NULL, flags))
                return cms;
        else
                goto err;
@@ -675,15 +698,15 @@ int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert,
        if (!cont)
                return 0;
        r = cms_copy_content(out, cont, flags);
-       BIO_free_all(cont);
+       do_free_upto(cont, dcont);
        return r;
        }
 
-int CMS_final(CMS_ContentInfo *cms, BIO *data, int flags)
+int CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags)
        {
        BIO *cmsbio;
        int ret = 0;
-       if (!(cmsbio = CMS_dataInit(cms, NULL)))
+       if (!(cmsbio = CMS_dataInit(cms, dcont)))
                {
                CMSerr(CMS_F_CMS_FINAL,ERR_R_MALLOC_FAILURE);
                return 0;
@@ -703,7 +726,7 @@ int CMS_final(CMS_ContentInfo *cms, BIO *data, int flags)
        ret = 1;
 
        err:
-       BIO_free_all(cmsbio);
+       do_free_upto(cmsbio, dcont);
 
        return ret;
 
@@ -730,7 +753,7 @@ int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
        if (!cont)
                return 0;
        r = cms_copy_content(out, cont, flags);
-       BIO_free_all(cont);
+       do_free_upto(cont, dcont);
        return r;
        }
 
@@ -746,7 +769,7 @@ CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags)
        if(!(flags & CMS_DETACHED))
                CMS_set_detached(cms, 0);
 
-       if ((flags & CMS_STREAM) || CMS_final(cms, in, flags))
+       if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
                return cms;
 
        CMS_ContentInfo_free(cms);