Fix the S/MIME code so it now works again and
authorDr. Stephen Henson <steve@openssl.org>
Sun, 31 Dec 2000 17:31:57 +0000 (17:31 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Sun, 31 Dec 2000 17:31:57 +0000 (17:31 +0000)
uses the new ASN1 code.

CHANGES
crypto/pkcs7/pk7_asn1.c
crypto/pkcs7/pk7_doit.c
crypto/pkcs7/pkcs7.h

diff --git a/CHANGES b/CHANGES
index 667b0f7..7ba48fc 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -3,6 +3,19 @@
 
  Changes between 0.9.6 and 0.9.7  [xx XXX 2000]
 
+  *) Fix the PKCS#7 (S/MIME) code to work with new ASN1. Two new
+     ASN1_ITEM structures help with sign and verify. PKCS7_ATTR_SIGN
+     uses the special reorder version of SET OF to sort the attributes
+     and reorder them to match the encoded order. This resolves a long
+     standing problem: a verify on a PKCS7 structure just after signing
+     it used to fail because the attribute order did not match the
+     encoded order. PKCS7_ATTR_VERIFY does not reorder the attributes:
+     it uses the received order. This is necessary to tolerate some broken
+     software that does not order SET OF. This is handled by encoding
+     as a SEQUENCE OF but using implicit tagging (with UNIVERSAL class)
+     to produce the required SET OF.
+     [Steve Henson]
+
   *) Have mk1mf.pl generate the macros OPENSSL_BUILD_SHLIBCRYPTO and
      OPENSSL_BUILD_SHLIBSSL and use them appropriately in the header
      files to get correct declarations of the ASN.1 item variables.
index 8d06c0b..9c5eda2 100644 (file)
@@ -108,8 +108,10 @@ ASN1_SEQUENCE_cb(PKCS7_SIGNER_INFO, si_cb) = {
        ASN1_SIMPLE(PKCS7_SIGNER_INFO, version, ASN1_INTEGER),
        ASN1_SIMPLE(PKCS7_SIGNER_INFO, issuer_and_serial, PKCS7_ISSUER_AND_SERIAL),
        ASN1_SIMPLE(PKCS7_SIGNER_INFO, digest_alg, X509_ALGOR),
-       /* NB this should be a SET OF but we use a SEQUENCE OF so the original order
-        * is retained when the structure is reencoded.
+       /* NB this should be a SET OF but we use a SEQUENCE OF so the
+        * original order * is retained when the structure is reencoded.
+        * Since the attributes are implicitly tagged this will not affect
+        * the encoding.
         */
        ASN1_IMP_SEQUENCE_OF_OPT(PKCS7_SIGNER_INFO, auth_attr, X509_ATTRIBUTE, 0),
        ASN1_SIMPLE(PKCS7_SIGNER_INFO, digest_enc_alg, X509_ALGOR),
@@ -178,3 +180,22 @@ ASN1_SEQUENCE(PKCS7_DIGEST) = {
 } ASN1_SEQUENCE_END(PKCS7_DIGEST);
 
 IMPLEMENT_ASN1_FUNCTIONS(PKCS7_DIGEST)
+
+/* Specials for authenticated attributes */
+
+/* When signing attributes we want to reorder them to match the sorted
+ * encoding.
+ */
+
+ASN1_ITEM_TEMPLATE(PKCS7_ATTR_SIGN) = 
+       ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_ORDER, 0, PKCS7_ATTRIBUTES, X509_ATTRIBUTE)
+ASN1_ITEM_TEMPLATE_END(PKCS7_ATTR_SIGN);
+
+/* When verifying attributes we need to use the received order. So 
+ * we use SEQUENCE OF and tag it to SET OF
+ */
+
+ASN1_ITEM_TEMPLATE(PKCS7_ATTR_VERIFY) = 
+       ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF | ASN1_TFLG_IMPTAG | ASN1_TFLG_UNIVERSAL,
+                               V_ASN1_SET, PKCS7_ATTRIBUTES, X509_ATTRIBUTE)
+ASN1_ITEM_TEMPLATE_END(PKCS7_ATTR_VERIFY);
index d294c5e..022ce46 100644 (file)
@@ -471,8 +471,6 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
        EVP_MD_CTX *mdc,ctx_tmp;
        STACK_OF(X509_ATTRIBUTE) *sk;
        STACK_OF(PKCS7_SIGNER_INFO) *si_sk=NULL;
-       unsigned char *p,*pp=NULL;
-       int x;
        ASN1_OCTET_STRING *os=NULL;
 
        i=OBJ_obj2nid(p7->type);
@@ -552,8 +550,8 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
                         * attribute and only sign the attributes */
                        if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0))
                                {
-                               unsigned char md_data[EVP_MAX_MD_SIZE];
-                               unsigned int md_len;
+                               unsigned char md_data[EVP_MAX_MD_SIZE], *abuf=NULL;
+                               unsigned int md_len, alen;
                                ASN1_OCTET_STRING *digest;
                                ASN1_UTCTIME *sign_time;
                                const EVP_MD *md_tmp;
@@ -573,19 +571,13 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
                                        NID_pkcs9_messageDigest,
                                        V_ASN1_OCTET_STRING,digest);
 
-                               /* Now sign the mess */
+                               /* Now sign the attributes */
                                EVP_SignInit(&ctx_tmp,md_tmp);
-                               x=i2d_ASN1_SET_OF_X509_ATTRIBUTE(sk,NULL,
-                                          i2d_X509_ATTRIBUTE,
-                                          V_ASN1_SET,V_ASN1_UNIVERSAL,IS_SET);
-                               pp=(unsigned char *)OPENSSL_malloc(x);
-                               p=pp;
-                               i2d_ASN1_SET_OF_X509_ATTRIBUTE(sk,&p,
-                                          i2d_X509_ATTRIBUTE,
-                                          V_ASN1_SET,V_ASN1_UNIVERSAL,IS_SET);
-                               EVP_SignUpdate(&ctx_tmp,pp,x);
-                               OPENSSL_free(pp);
-                               pp=NULL;
+                               alen = ASN1_item_i2d((ASN1_VALUE *)sk,&abuf,
+                                                       &PKCS7_ATTR_SIGN_it);
+                               if(!abuf) goto err;
+                               EVP_SignUpdate(&ctx_tmp,abuf,alen);
+                               OPENSSL_free(abuf);
                                }
 
                        if (si->pkey->type == EVP_PKEY_DSA)
@@ -627,9 +619,6 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
                        (unsigned char *)buf_mem->data,buf_mem->length);
 #endif
                }
-       if (pp != NULL) OPENSSL_free(pp);
-       pp=NULL;
-
        ret=1;
 err:
        if (buf != NULL) BUF_MEM_free(buf);
@@ -691,7 +680,6 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
        {
        ASN1_OCTET_STRING *os;
        EVP_MD_CTX mdc_tmp,*mdc;
-       unsigned char *pp,*p;
        int ret=0,i;
        int md_type;
        STACK_OF(X509_ATTRIBUTE) *sk;
@@ -736,8 +724,8 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
        sk=si->auth_attr;
        if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0))
                {
-               unsigned char md_dat[EVP_MAX_MD_SIZE];
-                unsigned int md_len;
+               unsigned char md_dat[EVP_MAX_MD_SIZE], *abuf = NULL;
+                unsigned int md_len, alen;
                ASN1_OCTET_STRING *message_digest;
 
                EVP_DigestFinal(&mdc_tmp,md_dat,&md_len);
@@ -766,19 +754,12 @@ for (ii=0; ii<md_len; ii++) printf("%02X",md_dat[ii]); printf(" calc\n");
                        }
 
                EVP_VerifyInit(&mdc_tmp,EVP_get_digestbynid(md_type));
-               /* Note: when forming the encoding of the attributes we
-                * shouldn't reorder them or this will break the signature.
-                * This is done by using the IS_SEQUENCE flag.
-                */
-               i=i2d_ASN1_SET_OF_X509_ATTRIBUTE(sk,NULL,i2d_X509_ATTRIBUTE,
-                       V_ASN1_SET,V_ASN1_UNIVERSAL, IS_SEQUENCE);
-               pp=OPENSSL_malloc(i);
-               p=pp;
-               i2d_ASN1_SET_OF_X509_ATTRIBUTE(sk,&p,i2d_X509_ATTRIBUTE,
-                       V_ASN1_SET,V_ASN1_UNIVERSAL, IS_SEQUENCE);
-               EVP_VerifyUpdate(&mdc_tmp,pp,i);
-
-               OPENSSL_free(pp);
+
+               alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf,
+                                               &PKCS7_ATTR_VERIFY_it);
+               EVP_VerifyUpdate(&mdc_tmp, abuf, alen);
+
+               OPENSSL_free(abuf);
                }
 
        os=si->enc_digest;
index 2835d58..4852c59 100644 (file)
@@ -295,6 +295,9 @@ DECLARE_ASN1_FUNCTIONS(PKCS7_DIGEST)
 DECLARE_ASN1_FUNCTIONS(PKCS7_ENCRYPT)
 DECLARE_ASN1_FUNCTIONS(PKCS7)
 
+DECLARE_ASN1_ITEM(PKCS7_ATTR_SIGN)
+DECLARE_ASN1_ITEM(PKCS7_ATTR_VERIFY)
+
 void ERR_load_PKCS7_strings(void);