Various S/MIME bug and compatibility fixes.
[openssl.git] / crypto / pkcs7 / pk7_doit.c
index 921195f9344e576796b2d6c51a4d6d82647f1d42..9382f47767b0d141fc8d76b69147c2eee7188bd4 100644 (file)
@@ -67,6 +67,38 @@ static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype,
                         void *value);
 static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid);
 
+static int PKCS7_type_is_other(PKCS7* p7)
+       {
+       int isOther=1;
+       
+       int nid=OBJ_obj2nid(p7->type);
+
+       switch( nid )
+               {
+       case NID_pkcs7_data:
+       case NID_pkcs7_signed:
+       case NID_pkcs7_enveloped:
+       case NID_pkcs7_signedAndEnveloped:
+       case NID_pkcs7_digest:
+       case NID_pkcs7_encrypted:
+               isOther=0;
+               break;
+       default:
+               isOther=1;
+               }
+
+       return isOther;
+
+       }
+
+static int PKCS7_type_is_octet_string(PKCS7* p7)
+       {
+       if ( 0==PKCS7_type_is_other(p7) )
+               return 0;
+
+       return (V_ASN1_OCTET_STRING==p7->d.other->type) ? 1 : 0;
+       }
+
 BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
        {
        int i,j;
@@ -165,7 +197,7 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
                        goto err;
                xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher));
                if (ivlen > 0) RAND_pseudo_bytes(iv,ivlen);
-               EVP_CipherInit(ctx, evp_cipher, key, iv, 1);
+               EVP_CipherInit_ex(ctx, evp_cipher, NULL, key, iv, 1);
 
                if (ivlen > 0) {
                        if (xalg->parameter == NULL) 
@@ -209,7 +241,7 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
                        M_ASN1_OCTET_STRING_set(ri->enc_key,tmp,jj);
                        }
                OPENSSL_free(tmp);
-               memset(key, 0, keylen);
+               OPENSSL_cleanse(key, keylen);
 
                if (out == NULL)
                        out=btmp;
@@ -222,13 +254,20 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
                if (PKCS7_is_detached(p7))
                        bio=BIO_new(BIO_s_null());
                else {
-                       if (PKCS7_type_is_signed(p7) &&
-                               PKCS7_type_is_data(p7->d.sign->contents)) {
-                               ASN1_OCTET_STRING *os;
-                               os=p7->d.sign->contents->d.data;
-                               if (os->length > 0) bio = 
-                                       BIO_new_mem_buf(os->data, os->length);
-                       } 
+                       if (PKCS7_type_is_signed(p7) ) { 
+                               if ( PKCS7_type_is_data(p7->d.sign->contents)) {
+                                       ASN1_OCTET_STRING *os;
+                                       os=p7->d.sign->contents->d.data;
+                                       if (os->length > 0)
+                                               bio = BIO_new_mem_buf(os->data, os->length);
+                               }
+                               else if ( PKCS7_type_is_octet_string(p7->d.sign->contents) ) {
+                                       ASN1_OCTET_STRING *os;
+                                       os=p7->d.sign->contents->d.other->value.octet_string;
+                                       if (os->length > 0)
+                                               bio = BIO_new_mem_buf(os->data, os->length);
+                               }
+                       }
                        if(bio == NULL) {
                                bio=BIO_new(BIO_s_mem());
                                BIO_set_mem_eof_return(bio,0);
@@ -391,7 +430,7 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
 
                evp_ctx=NULL;
                BIO_get_cipher_ctx(etmp,&evp_ctx);
-               EVP_CipherInit(evp_ctx,evp_cipher,NULL,NULL,0);
+               EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0);
                if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
                        goto err;
 
@@ -407,9 +446,9 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
                                goto err;
                                }
                } 
-               EVP_CipherInit(evp_ctx,NULL,tmp,NULL,0);
+               EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0);
 
-               memset(tmp,0,jj);
+               OPENSSL_cleanse(tmp,jj);
 
                if (out == NULL)
                        out=etmp;
@@ -473,6 +512,7 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
        STACK_OF(PKCS7_SIGNER_INFO) *si_sk=NULL;
        ASN1_OCTET_STRING *os=NULL;
 
+       EVP_MD_CTX_init(&ctx_tmp);
        i=OBJ_obj2nid(p7->type);
        p7->state=PKCS7_S_HEADER;
 
@@ -537,8 +577,8 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
                        
                        /* We now have the EVP_MD_CTX, lets do the
                         * signing. */
-                       memcpy(&ctx_tmp,mdc,sizeof(ctx_tmp));
-                       if (!BUF_MEM_grow(buf,EVP_PKEY_size(si->pkey)))
+                       EVP_MD_CTX_copy_ex(&ctx_tmp,mdc);
+                       if (!BUF_MEM_grow_clean(buf,EVP_PKEY_size(si->pkey)))
                                {
                                PKCS7err(PKCS7_F_PKCS7_DATASIGN,ERR_R_BIO_LIB);
                                goto err;
@@ -556,15 +596,19 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
                                ASN1_UTCTIME *sign_time;
                                const EVP_MD *md_tmp;
 
-                               /* Add signing time */
-                               sign_time=X509_gmtime_adj(NULL,0);
-                               PKCS7_add_signed_attribute(si,
-                                       NID_pkcs9_signingTime,
-                                       V_ASN1_UTCTIME,sign_time);
+                               /* Add signing time if not already present */
+                               if (!PKCS7_get_signed_attribute(si,
+                                                       NID_pkcs9_signingTime))
+                                       {
+                                       sign_time=X509_gmtime_adj(NULL,0);
+                                       PKCS7_add_signed_attribute(si,
+                                               NID_pkcs9_signingTime,
+                                               V_ASN1_UTCTIME,sign_time);
+                                       }
 
                                /* Add digest */
                                md_tmp=EVP_MD_CTX_md(&ctx_tmp);
-                               EVP_DigestFinal(&ctx_tmp,md_data,&md_len);
+                               EVP_DigestFinal_ex(&ctx_tmp,md_data,&md_len);
                                digest=M_ASN1_OCTET_STRING_new();
                                M_ASN1_OCTET_STRING_set(digest,md_data,md_len);
                                PKCS7_add_signed_attribute(si,
@@ -572,7 +616,7 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
                                        V_ASN1_OCTET_STRING,digest);
 
                                /* Now sign the attributes */
-                               EVP_SignInit(&ctx_tmp,md_tmp);
+                               EVP_SignInit_ex(&ctx_tmp,md_tmp,NULL);
                                alen = ASN1_item_i2d((ASN1_VALUE *)sk,&abuf,
                                                        ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
                                if(!abuf) goto err;
@@ -584,6 +628,10 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
                        if (si->pkey->type == EVP_PKEY_DSA)
                                ctx_tmp.digest=EVP_dss1();
 #endif
+#ifndef OPENSSL_NO_ECDSA
+                       if (si->pkey->type == EVP_PKEY_EC)
+                               ctx_tmp.digest=EVP_ecdsa();
+#endif
 
                        if (!EVP_SignFinal(&ctx_tmp,(unsigned char *)buf->data,
                                (unsigned int *)&buf->length,si->pkey))
@@ -623,6 +671,7 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
                }
        ret=1;
 err:
+       EVP_MD_CTX_cleanup(&ctx_tmp);
        if (buf != NULL) BUF_MEM_free(buf);
        return(ret);
        }
@@ -661,7 +710,11 @@ int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio,
                }
 
        /* Lets verify */
-       X509_STORE_CTX_init(ctx,cert_store,x509,cert);
+       if(!X509_STORE_CTX_init(ctx,cert_store,x509,cert))
+               {
+               PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,ERR_R_X509_LIB);
+               goto err;
+               }
        X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_SMIME_SIGN);
        i=X509_verify_cert(ctx);
        if (i <= 0) 
@@ -688,6 +741,8 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
        BIO *btmp;
        EVP_PKEY *pkey;
 
+       EVP_MD_CTX_init(&mdc_tmp);
+
        if (!PKCS7_type_is_signed(p7) && 
                                !PKCS7_type_is_signedAndEnveloped(p7)) {
                PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
@@ -716,12 +771,17 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
                        }
                if (EVP_MD_CTX_type(mdc) == md_type)
                        break;
+               /* Workaround for some broken clients that put the signature
+                * OID instead of the digest OID in digest_alg->algorithm
+                */
+               if (EVP_MD_pkey_type(EVP_MD_CTX_md(mdc)) == md_type)
+                       break;
                btmp=BIO_next(btmp);
                }
 
        /* mdc is the digest ctx that we want, unless there are attributes,
         * in which case the digest is the signed attributes */
-       memcpy(&mdc_tmp,mdc,sizeof(mdc_tmp));
+       EVP_MD_CTX_copy_ex(&mdc_tmp,mdc);
 
        sk=si->auth_attr;
        if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0))
@@ -730,7 +790,7 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
                 unsigned int md_len, alen;
                ASN1_OCTET_STRING *message_digest;
 
-               EVP_DigestFinal(&mdc_tmp,md_dat,&md_len);
+               EVP_DigestFinal_ex(&mdc_tmp,md_dat,&md_len);
                message_digest=PKCS7_digest_from_attributes(sk);
                if (!message_digest)
                        {
@@ -755,7 +815,7 @@ for (ii=0; ii<md_len; ii++) printf("%02X",md_dat[ii]); printf(" calc\n");
                        goto err;
                        }
 
-               EVP_VerifyInit(&mdc_tmp,EVP_get_digestbynid(md_type));
+               EVP_VerifyInit_ex(&mdc_tmp,EVP_get_digestbynid(md_type), NULL);
 
                alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf,
                                                ASN1_ITEM_rptr(PKCS7_ATTR_VERIFY));
@@ -774,6 +834,9 @@ for (ii=0; ii<md_len; ii++) printf("%02X",md_dat[ii]); printf(" calc\n");
 #ifndef OPENSSL_NO_DSA
        if(pkey->type == EVP_PKEY_DSA) mdc_tmp.digest=EVP_dss1();
 #endif
+#ifndef OPENSSL_NO_ECDSA
+       if (pkey->type == EVP_PKEY_EC) mdc_tmp.digest=EVP_ecdsa();
+#endif
 
        i=EVP_VerifyFinal(&mdc_tmp,os->data,os->length, pkey);
        EVP_PKEY_free(pkey);
@@ -787,6 +850,7 @@ for (ii=0; ii<md_len; ii++) printf("%02X",md_dat[ii]); printf(" calc\n");
        else
                ret=1;
 err:
+       EVP_MD_CTX_cleanup(&mdc_tmp);
        return(ret);
        }