Various tidies/fixes:
[openssl.git] / crypto / cms / cms_smime.c
index da0fac0..c9be5a0 100644 (file)
@@ -77,12 +77,20 @@ static int cms_copy_content(BIO *out, BIO *in, unsigned int flags)
        else
                tmpout = out;
 
-       /* Read all content through chain to determine content digests */
+       /* Read all content through chain to process digest, decrypt etc */
        for (;;)
        {
                i=BIO_read(in,buf,sizeof(buf));
                if (i <= 0)
+                       {
+                       if (BIO_method_type(in) == BIO_TYPE_CIPHER)
+                               {
+                               if (!BIO_get_cipher_status(in))
+                                       goto err;
+                               }
                        break;
+                       }
+                               
                if (tmpout)
                        BIO_write(tmpout, buf, i);
        }
@@ -105,6 +113,17 @@ static int cms_copy_content(BIO *out, BIO *in, unsigned int flags)
 
        }
 
+static int check_content(CMS_ContentInfo *cms)
+       {
+       ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
+       if (!pos || !*pos)
+               {
+               CMSerr(CMS_F_CHECK_CONTENT, CMS_R_NO_CONTENT);
+               return 0;
+               }
+       return 1;
+       }
+
 int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags)
        {
        BIO *cont;
@@ -148,15 +167,8 @@ int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
                return 0;
                }
 
-       if (!dcont)
-               {
-               ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
-               if (!pos || !*pos)
-                       {
-                       CMSerr(CMS_F_CMS_DIGEST_VERIFY, CMS_R_NO_CONTENT);
-                       return 0;
-                       }
-               }
+       if (!dcont && !check_content(cms))
+               return 0;
 
        cont = CMS_dataInit(cms, dcont);
        if (!cont)
@@ -201,16 +213,8 @@ int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms,
                return 0;
                }
 
-       if (!dcont)
-               {
-               ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
-               if (!pos || !*pos)
-                       {
-                       CMSerr(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT,
-                                       CMS_R_NO_CONTENT);
-                       return 0;
-                       }
-               }
+       if (!dcont && !check_content(cms))
+               return 0;
 
        if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0)
                return 0;
@@ -296,15 +300,8 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
        int i, scount = 0, ret = 0;
        BIO *cmsbio = NULL, *tmpin = NULL;
 
-       if (!dcont)
-               {
-               ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
-               if (!pos || !*pos)
-                       {
-                       CMSerr(CMS_F_CMS_VERIFY, CMS_R_NO_CONTENT);
-                       return 0;
-                       }
-               }
+       if (!dcont && !check_content(cms))
+               return 0;
 
        /* Attempt to find all signer certificates */
 
@@ -450,8 +447,8 @@ CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
 
        if ((flags & (CMS_STREAM|CMS_PARTIAL)) || CMS_final(cms, data, flags))
                return cms;
-
-       return cms;
+       else
+               goto err;
 
        merr:
        CMSerr(CMS_F_CMS_SIGN, ERR_R_MALLOC_FAILURE);
@@ -462,18 +459,93 @@ CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
        return NULL;
        }
 
-/* Placeholders for now... */
-
-CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *in,
+CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data,
                                const EVP_CIPHER *cipher, unsigned int flags)
        {
+       CMS_ContentInfo *cms;
+       int i;
+       X509 *recip;
+       cms = CMS_EnvelopedData_create(cipher);
+       if (!cms)
+               goto merr;
+       for (i = 0; i < sk_X509_num(certs); i++)
+               {
+               recip = sk_X509_value(certs, i);
+               if (!CMS_add1_recipient_cert(cms, recip, flags))
+                       {
+                       CMSerr(CMS_F_CMS_ENCRYPT, CMS_R_RECIPIENT_ERROR);
+                       goto err;
+                       }
+               }
+
+       if(!(flags & CMS_DETACHED))
+               CMS_set_detached(cms, 0);
+
+       if ((flags & (CMS_STREAM|CMS_PARTIAL)) || CMS_final(cms, data, flags))
+               return cms;
+       else
+               goto err;
+
+       merr:
+       CMSerr(CMS_F_CMS_ENCRYPT, ERR_R_MALLOC_FAILURE);
+       err:
+       if (cms)
+               CMS_ContentInfo_free(cms);
        return NULL;
        }
        
-int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pkey, X509 *cert, BIO *data,
+int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert,
+                               BIO *dcont, BIO *out,
                                unsigned int flags)
        {
-       return 0;
+       int i, r;
+       BIO *cont;
+       if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped)
+               {
+               CMSerr(CMS_F_CMS_DECRYPT, CMS_R_TYPE_NOT_ENVELOPED_DATA);
+               return 0;
+               }
+       if (!dcont && !check_content(cms))
+               return 0;
+       if (pk)
+               {
+               STACK_OF(CMS_RecipientInfo) *ris;
+               CMS_RecipientInfo *ri;
+               ris = CMS_get0_RecipientInfos(cms);
+               for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
+                       {
+                       ri = sk_CMS_RecipientInfo_value(ris, i);
+                       if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS)
+                               continue;
+                       /* If we have a cert try matching RecipientInfo
+                        * otherwise try them all.
+                        */
+                       if (!cert ||
+                       (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0))
+                               {
+                               CMS_RecipientInfo_set0_pkey(ri, pk);
+                               r = CMS_RecipientInfo_decrypt(cms, ri);
+                               CMS_RecipientInfo_set0_pkey(ri, NULL);
+                               if (r > 0)
+                                       break;
+                               if (cert)
+                                       return 0;
+                               ERR_clear_error();
+                               }
+                       }
+
+               if (i == sk_CMS_RecipientInfo_num(ris))
+                       {
+                       CMSerr(CMS_F_CMS_DECRYPT, CMS_R_NO_MATCHING_RECIPIENT);
+                       return 0;
+                       }
+               }
+       cont = CMS_dataInit(cms, dcont);
+       if (!cont)
+               return 0;
+       r = cms_copy_content(out, cont, flags);
+       BIO_free_all(cont);
+       return r;
        }
 
 int CMS_final(CMS_ContentInfo *cms, BIO *data, int flags)
@@ -520,15 +592,8 @@ int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
                return 0;
                }
 
-       if (!dcont)
-               {
-               ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
-               if (!pos || !*pos)
-                       {
-                       CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_NO_CONTENT);
-                       return 0;
-                       }
-               }
+       if (!dcont && !check_content(cms))
+               return 0;
 
        cont = CMS_dataInit(cms, dcont);
        if (!cont)