diff --git a/CHANGES b/CHANGES
index 667b0f74a..7ba48fcb8 100644
--- 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.
diff --git a/crypto/pkcs7/pk7_asn1.c b/crypto/pkcs7/pk7_asn1.c
index 8d06c0b68..9c5eda2b3 100644
--- a/crypto/pkcs7/pk7_asn1.c
+++ b/crypto/pkcs7/pk7_asn1.c
@@ -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);
diff --git a/crypto/pkcs7/pk7_doit.c b/crypto/pkcs7/pk7_doit.c
index d294c5e28..022ce46c4 100644
--- a/crypto/pkcs7/pk7_doit.c
+++ b/crypto/pkcs7/pk7_doit.c
@@ -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;
diff --git a/crypto/pkcs7/pkcs7.h b/crypto/pkcs7/pkcs7.h
index 2835d58a5..4852c59da 100644
--- a/crypto/pkcs7/pkcs7.h
+++ b/crypto/pkcs7/pkcs7.h
@@ -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);