Support for verification of signed receipts.
diff --git a/CHANGES b/CHANGES
index 40c163b..2e1ab47 100644
--- a/CHANGES
+++ b/CHANGES
@@ -59,8 +59,9 @@
   *) Initial support for Cryptographic Message Syntax (aka CMS) based
      on RFC3850, RFC3851 and RFC3852. New cms directory and cms utility,
      support for data, signedData, compressedData, digestedData and
-     encryptedData types currently included, more to come. Scripts to
-     check against RFC4134 examples draft.
+     encryptedData, envelopedData types included. Scripts to check against
+     RFC4134 examples draft and interop and consistency checks of many
+     content types and variants.
      [Steve Henson]
 
   *) Zlib compression BIO. This is a filter BIO which compressed and
diff --git a/apps/cms.c b/apps/cms.c
index 7a63778..ef873ee 100644
--- a/apps/cms.c
+++ b/apps/cms.c
@@ -91,6 +91,8 @@
 #define SMIME_COMPRESS		(12 | SMIME_OP)
 #define SMIME_ENCRYPTED_DECRYPT	(13 | SMIME_IP)
 #define SMIME_ENCRYPTED_ENCRYPT	(14 | SMIME_OP)
+#define SMIME_SIGN_RECEIPT	(15 | SMIME_OP | SMIME_IP)
+#define SMIME_VERIFY_RECEIPT	(16 | SMIME_IP)
 
 int MAIN(int, char **);
 
@@ -101,17 +103,17 @@
 	int ret = 0;
 	char **args;
 	const char *inmode = "r", *outmode = "w";
-	char *infile = NULL, *outfile = NULL;
+	char *infile = NULL, *outfile = NULL, *rctfile = NULL;
 	char *signerfile = NULL, *recipfile = NULL;
 	STACK *sksigners = NULL, *skkeys = NULL;
 	char *certfile = NULL, *keyfile = NULL, *contfile=NULL;
 	const EVP_CIPHER *cipher = NULL;
-	CMS_ContentInfo *cms = NULL;
+	CMS_ContentInfo *cms = NULL, *rcms = NULL;
 	X509_STORE *store = NULL;
 	X509 *cert = NULL, *recip = NULL, *signer = NULL;
 	EVP_PKEY *key = NULL;
 	STACK_OF(X509) *encerts = NULL, *other = NULL;
-	BIO *in = NULL, *out = NULL, *indata = NULL;
+	BIO *in = NULL, *out = NULL, *indata = NULL, *rctin = NULL;
 	int badarg = 0;
 	int flags = CMS_DETACHED, noout = 0, print = 0;
 	int rr_print = 0, rr_allorfirst = -1;
@@ -124,7 +126,7 @@
 	int need_rand = 0;
 	const EVP_MD *sign_md = NULL;
 	int informat = FORMAT_SMIME, outformat = FORMAT_SMIME;
-        int keyform = FORMAT_PEM;
+        int rctformat = FORMAT_SMIME, keyform = FORMAT_PEM;
 #ifndef OPENSSL_NO_ENGINE
 	char *engine=NULL;
 #endif
@@ -161,6 +163,14 @@
 			operation = SMIME_RESIGN;
 		else if (!strcmp (*args, "-verify"))
 			operation = SMIME_VERIFY;
+		else if (!strcmp(*args,"-verify_receipt"))
+			{
+			operation = SMIME_VERIFY_RECEIPT;
+			if (!args[1])
+				goto argerr;
+			args++;
+			rctfile = *args;
+			}
 		else if (!strcmp (*args, "-cmsout"))
 			operation = SMIME_CMSOUT;
 		else if (!strcmp (*args, "-data_out"))
@@ -425,6 +435,12 @@
 				goto argerr;
 			keyform = str2fmt(*++args);
 			}
+		else if (!strcmp (*args, "-rctform"))
+			{
+			if (!args[1])
+				goto argerr;
+			rctformat = str2fmt(*++args);
+			}
 		else if (!strcmp (*args, "-certfile"))
 			{
 			if (!args[1])
@@ -770,6 +786,35 @@
 			}
 		}
 
+	if (rctfile)
+		{
+		char *rctmode = (rctformat == FORMAT_ASN1) ? "rb" : "r";
+		if (!(rctin = BIO_new_file(rctfile, rctmode)))
+			{
+			BIO_printf (bio_err,
+				 "Can't open receipt file %s\n", rctfile);
+			goto end;
+			}
+		
+		if (rctformat == FORMAT_SMIME) 
+			rcms = SMIME_read_CMS(rctin, NULL);
+		else if (rctformat == FORMAT_PEM) 
+			rcms = PEM_read_bio_CMS(rctin, NULL, NULL, NULL);
+		else if (rctformat == FORMAT_ASN1) 
+			rcms = d2i_CMS_bio(rctin, NULL);
+		else
+			{
+			BIO_printf(bio_err, "Bad input format for receipt\n");
+			goto end;
+			}
+
+		if (!rcms)
+			{
+			BIO_printf(bio_err, "Error reading receipt\n");
+			goto end;
+			}
+		}
+
 	if (outfile)
 		{
 		if (!(out = BIO_new_file(outfile, outmode)))
@@ -790,7 +835,7 @@
 #endif
 		}
 
-	if (operation == SMIME_VERIFY)
+	if ((operation == SMIME_VERIFY) || (operation == SMIME_VERIFY_RECEIPT))
 		{
 		if (!(store = setup_verify(bio_err, CAfile, CApath)))
 			goto end;
@@ -1001,6 +1046,16 @@
 			receipt_request_print(bio_err, cms);
 					
 		}
+	else if (operation == SMIME_VERIFY_RECEIPT)
+		{
+		if (CMS_verify_receipt(rcms, cms, other, store, flags) > 0)
+			BIO_printf(bio_err, "Verification successful\n");
+		else
+			{
+			BIO_printf(bio_err, "Verification failure\n");
+			goto end;
+			}
+		}
 	else
 		{
 		if (noout)
@@ -1068,6 +1123,8 @@
 	X509_free(signer);
 	EVP_PKEY_free(key);
 	CMS_ContentInfo_free(cms);
+	CMS_ContentInfo_free(rcms);
+	BIO_free(rctin);
 	BIO_free(in);
 	BIO_free(indata);
 	BIO_free_all(out);
diff --git a/crypto/cms/cms.h b/crypto/cms/cms.h
index 4cc5d93..22baa3e 100644
--- a/crypto/cms/cms.h
+++ b/crypto/cms/cms.h
@@ -162,6 +162,10 @@
 int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
 		 X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags);
 
+int CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms,
+			STACK_OF(X509) *certs,
+			X509_STORE *store, unsigned int flags);
+
 STACK_OF(X509) *CMS_get0_signers(CMS_ContentInfo *cms);
 
 CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *in,
@@ -354,6 +358,7 @@
 #define CMS_F_CMS_GET0_REVOCATION_CHOICES		 132
 #define CMS_F_CMS_GET0_SIGNED				 133
 #define CMS_F_CMS_RECEIPTREQUEST_CREATE0		 159
+#define CMS_F_CMS_RECEIPT_VERIFY			 160
 #define CMS_F_CMS_RECIPIENTINFO_DECRYPT			 134
 #define CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT		 135
 #define CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT		 136
@@ -387,7 +392,9 @@
 #define CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR	 102
 #define CMS_R_CMS_DATAFINAL_ERROR			 103
 #define CMS_R_CMS_LIB					 104
+#define CMS_R_CONTENTIDENTIFIER_MISMATCH		 170
 #define CMS_R_CONTENT_NOT_FOUND				 105
+#define CMS_R_CONTENT_TYPE_MISMATCH			 171
 #define CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA		 106
 #define CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA		 107
 #define CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA		 108
@@ -395,6 +402,7 @@
 #define CMS_R_CTRL_ERROR				 110
 #define CMS_R_CTRL_FAILURE				 111
 #define CMS_R_DECRYPT_ERROR				 112
+#define CMS_R_DIGEST_ERROR				 161
 #define CMS_R_ERROR_GETTING_PUBLIC_KEY			 113
 #define CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE	 114
 #define CMS_R_ERROR_SETTING_KEY				 115
@@ -404,21 +412,31 @@
 #define CMS_R_MD_BIO_INIT_ERROR				 119
 #define CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH	 120
 #define CMS_R_MESSAGEDIGEST_WRONG_LENGTH		 121
+#define CMS_R_MSGSIGDIGEST_ERROR			 172
+#define CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE		 162
+#define CMS_R_MSGSIGDIGEST_WRONG_LENGTH			 163
+#define CMS_R_NEED_ONE_SIGNER				 164
+#define CMS_R_NOT_A_SIGNED_RECEIPT			 165
 #define CMS_R_NOT_ENCRYPTED_DATA			 122
 #define CMS_R_NOT_KEK					 123
 #define CMS_R_NOT_KEY_TRANSPORT				 124
 #define CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE		 125
 #define CMS_R_NO_CIPHER					 126
 #define CMS_R_NO_CONTENT				 127
+#define CMS_R_NO_CONTENT_TYPE				 173
 #define CMS_R_NO_DEFAULT_DIGEST				 128
 #define CMS_R_NO_DIGEST_SET				 129
 #define CMS_R_NO_KEY					 130
 #define CMS_R_NO_MATCHING_DIGEST			 131
 #define CMS_R_NO_MATCHING_RECIPIENT			 132
+#define CMS_R_NO_MATCHING_SIGNATURE			 166
+#define CMS_R_NO_MSGSIGDIGEST				 167
 #define CMS_R_NO_PRIVATE_KEY				 133
 #define CMS_R_NO_PUBLIC_KEY				 134
+#define CMS_R_NO_RECEIPT_REQUEST			 168
 #define CMS_R_NO_SIGNERS				 135
 #define CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE	 136
+#define CMS_R_RECEIPT_DECODE_ERROR			 169
 #define CMS_R_RECIPIENT_ERROR				 137
 #define CMS_R_SIGNER_CERTIFICATE_NOT_FOUND		 138
 #define CMS_R_SIGNFINAL_ERROR				 139
diff --git a/crypto/cms/cms_asn1.c b/crypto/cms/cms_asn1.c
index 2979993..7f7132c 100644
--- a/crypto/cms/cms_asn1.c
+++ b/crypto/cms/cms_asn1.c
@@ -371,3 +371,10 @@
   ASN1_SEQUENCE_OF(CMS_ReceiptRequest, receiptsTo, GENERAL_NAMES)
 } ASN1_SEQUENCE_END(CMS_ReceiptRequest)
 
+ASN1_SEQUENCE(CMS_Receipt) = {
+  ASN1_SIMPLE(CMS_Receipt, version, LONG),
+  ASN1_SIMPLE(CMS_Receipt, contentType, ASN1_OBJECT),
+  ASN1_SIMPLE(CMS_Receipt, signedContentIdentifier, ASN1_OCTET_STRING),
+  ASN1_SIMPLE(CMS_Receipt, originatorSignatureValue, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(CMS_Receipt)
+
diff --git a/crypto/cms/cms_err.c b/crypto/cms/cms_err.c
index 93e15e3..420a401 100644
--- a/crypto/cms/cms_err.c
+++ b/crypto/cms/cms_err.c
@@ -107,10 +107,11 @@
 {ERR_FUNC(CMS_F_CMS_GET0_REVOCATION_CHOICES),	"CMS_GET0_REVOCATION_CHOICES"},
 {ERR_FUNC(CMS_F_CMS_GET0_SIGNED),	"CMS_GET0_SIGNED"},
 {ERR_FUNC(CMS_F_CMS_RECEIPTREQUEST_CREATE0),	"CMS_ReceiptRequest_create0"},
+{ERR_FUNC(CMS_F_CMS_RECEIPT_VERIFY),	"CMS_RECEIPT_VERIFY"},
 {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_DECRYPT),	"CMS_RecipientInfo_decrypt"},
 {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT),	"CMS_RECIPIENTINFO_KEKRI_DECRYPT"},
 {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT),	"CMS_RECIPIENTINFO_KEKRI_ENCRYPT"},
-{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID),	"CMS_RECIPIENTINFO_KEKRI_GET0_ID"},
+{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID),	"CMS_RecipientInfo_kekri_get0_id"},
 {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_ID_CMP),	"CMS_RecipientInfo_kekri_id_cmp"},
 {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP),	"CMS_RecipientInfo_ktri_cert_cmp"},
 {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT),	"CMS_RECIPIENTINFO_KTRI_DECRYPT"},
@@ -143,7 +144,9 @@
 {ERR_REASON(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR),"cipher parameter initialisation error"},
 {ERR_REASON(CMS_R_CMS_DATAFINAL_ERROR)   ,"cms datafinal error"},
 {ERR_REASON(CMS_R_CMS_LIB)               ,"cms lib"},
+{ERR_REASON(CMS_R_CONTENTIDENTIFIER_MISMATCH),"contentidentifier mismatch"},
 {ERR_REASON(CMS_R_CONTENT_NOT_FOUND)     ,"content not found"},
+{ERR_REASON(CMS_R_CONTENT_TYPE_MISMATCH) ,"content type mismatch"},
 {ERR_REASON(CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA),"content type not compressed data"},
 {ERR_REASON(CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA),"content type not enveloped data"},
 {ERR_REASON(CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA),"content type not signed data"},
@@ -151,6 +154,7 @@
 {ERR_REASON(CMS_R_CTRL_ERROR)            ,"ctrl error"},
 {ERR_REASON(CMS_R_CTRL_FAILURE)          ,"ctrl failure"},
 {ERR_REASON(CMS_R_DECRYPT_ERROR)         ,"decrypt error"},
+{ERR_REASON(CMS_R_DIGEST_ERROR)          ,"digest error"},
 {ERR_REASON(CMS_R_ERROR_GETTING_PUBLIC_KEY),"error getting public key"},
 {ERR_REASON(CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE),"error reading messagedigest attribute"},
 {ERR_REASON(CMS_R_ERROR_SETTING_KEY)     ,"error setting key"},
@@ -160,21 +164,31 @@
 {ERR_REASON(CMS_R_MD_BIO_INIT_ERROR)     ,"md bio init error"},
 {ERR_REASON(CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH),"messagedigest attribute wrong length"},
 {ERR_REASON(CMS_R_MESSAGEDIGEST_WRONG_LENGTH),"messagedigest wrong length"},
+{ERR_REASON(CMS_R_MSGSIGDIGEST_ERROR)    ,"msgsigdigest error"},
+{ERR_REASON(CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE),"msgsigdigest verification failure"},
+{ERR_REASON(CMS_R_MSGSIGDIGEST_WRONG_LENGTH),"msgsigdigest wrong length"},
+{ERR_REASON(CMS_R_NEED_ONE_SIGNER)       ,"need one signer"},
+{ERR_REASON(CMS_R_NOT_A_SIGNED_RECEIPT)  ,"not a signed receipt"},
 {ERR_REASON(CMS_R_NOT_ENCRYPTED_DATA)    ,"not encrypted data"},
 {ERR_REASON(CMS_R_NOT_KEK)               ,"not kek"},
 {ERR_REASON(CMS_R_NOT_KEY_TRANSPORT)     ,"not key transport"},
 {ERR_REASON(CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE),"not supported for this key type"},
 {ERR_REASON(CMS_R_NO_CIPHER)             ,"no cipher"},
 {ERR_REASON(CMS_R_NO_CONTENT)            ,"no content"},
+{ERR_REASON(CMS_R_NO_CONTENT_TYPE)       ,"no content type"},
 {ERR_REASON(CMS_R_NO_DEFAULT_DIGEST)     ,"no default digest"},
 {ERR_REASON(CMS_R_NO_DIGEST_SET)         ,"no digest set"},
 {ERR_REASON(CMS_R_NO_KEY)                ,"no key"},
 {ERR_REASON(CMS_R_NO_MATCHING_DIGEST)    ,"no matching digest"},
 {ERR_REASON(CMS_R_NO_MATCHING_RECIPIENT) ,"no matching recipient"},
+{ERR_REASON(CMS_R_NO_MATCHING_SIGNATURE) ,"no matching signature"},
+{ERR_REASON(CMS_R_NO_MSGSIGDIGEST)       ,"no msgsigdigest"},
 {ERR_REASON(CMS_R_NO_PRIVATE_KEY)        ,"no private key"},
 {ERR_REASON(CMS_R_NO_PUBLIC_KEY)         ,"no public key"},
+{ERR_REASON(CMS_R_NO_RECEIPT_REQUEST)    ,"no receipt request"},
 {ERR_REASON(CMS_R_NO_SIGNERS)            ,"no signers"},
 {ERR_REASON(CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE),"private key does not match certificate"},
+{ERR_REASON(CMS_R_RECEIPT_DECODE_ERROR)  ,"receipt decode error"},
 {ERR_REASON(CMS_R_RECIPIENT_ERROR)       ,"recipient error"},
 {ERR_REASON(CMS_R_SIGNER_CERTIFICATE_NOT_FOUND),"signer certificate not found"},
 {ERR_REASON(CMS_R_SIGNFINAL_ERROR)       ,"signfinal error"},
diff --git a/crypto/cms/cms_ess.c b/crypto/cms/cms_ess.c
index 9377217..ff9b2a8 100644
--- a/crypto/cms/cms_ess.c
+++ b/crypto/cms/cms_ess.c
@@ -62,6 +62,7 @@
 #include "asn1_locl.h"
 
 DECLARE_ASN1_ITEM(CMS_ReceiptRequest)
+DECLARE_ASN1_ITEM(CMS_Receipt)
 
 IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest)
 
@@ -189,5 +190,161 @@
 		*prto = rr->receiptsTo;
 	}
 
+static int cms_msgSigDigest(CMS_SignerInfo *si,
+				unsigned char *dig, unsigned int *diglen)
+	{
+	const EVP_MD *md;
+	md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
+	if (md == NULL)
+		return 0;
+	if (!ASN1_item_digest(ASN1_ITEM_rptr(CMS_Attributes_Verify), md,
+						si->signedAttrs, dig, diglen))
+		return 0;
+	return 1;
+	}
 
+/* Verify signed receipt after it has already passed normal CMS verify */
 
+int cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms)
+	{
+	int r = 0, i;
+	CMS_ReceiptRequest *rr = NULL;
+	CMS_Receipt *rct = NULL;
+	STACK_OF(CMS_SignerInfo) *sis, *osis;
+	CMS_SignerInfo *si, *osi;
+	ASN1_OCTET_STRING *msig, **pcont;
+	ASN1_OBJECT *octype;
+	unsigned char dig[EVP_MAX_MD_SIZE];
+	unsigned int diglen;
+
+	/* Get SignerInfos, also checks SignedData content type */
+	osis = CMS_get0_SignerInfos(req_cms);
+	sis = CMS_get0_SignerInfos(cms);
+	if (!osis || !sis)
+		goto err;
+
+	if (sk_CMS_SignerInfo_num(sis) != 1)
+		{
+		CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NEED_ONE_SIGNER);
+		goto err;
+		}
+
+	/* Check receipt content type */
+	if (OBJ_obj2nid(CMS_get0_eContentType(cms)) != NID_id_smime_ct_receipt)
+		{
+		CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NOT_A_SIGNED_RECEIPT);
+		goto err;
+		}
+
+	/* Extract and decode receipt content */
+	pcont = CMS_get0_content(cms);
+	if (!pcont || !*pcont)
+		{
+		CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT);
+		goto err;
+		}
+
+	rct = ASN1_item_unpack(*pcont, ASN1_ITEM_rptr(CMS_Receipt));
+
+	if (!rct)	
+		{
+		CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_RECEIPT_DECODE_ERROR);
+		goto err;
+		}
+
+	/* Locate original request */
+
+	for (i = 0; i < sk_CMS_SignerInfo_num(osis); i++)
+		{
+		osi = sk_CMS_SignerInfo_value(osis, i);
+		if (!ASN1_STRING_cmp(osi->signature,
+					rct->originatorSignatureValue))
+			break;
+		}
+
+	if (i == sk_CMS_SignerInfo_num(osis))
+		{
+		CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MATCHING_SIGNATURE);
+		goto err;
+		}
+
+	si = sk_CMS_SignerInfo_value(sis, 0);
+
+	/* Get msgSigDigest value and compare */
+
+	msig = CMS_signed_get0_data_by_OBJ(si,
+				OBJ_nid2obj(NID_id_smime_aa_msgSigDigest),
+					-3, V_ASN1_OCTET_STRING);
+
+	if (!msig)
+		{
+		CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MSGSIGDIGEST);
+		goto err;
+		}
+
+	if (!cms_msgSigDigest(osi, dig, &diglen))
+		{
+		CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_ERROR);
+		goto err;
+		}
+
+	if (diglen != (unsigned int)msig->length)
+			{
+			CMSerr(CMS_F_CMS_RECEIPT_VERIFY,
+				CMS_R_MSGSIGDIGEST_WRONG_LENGTH);
+			goto err;
+			}
+
+	if (memcmp(dig, msig->data, diglen))
+			{
+			CMSerr(CMS_F_CMS_RECEIPT_VERIFY,
+				CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE);
+			goto err;
+			}
+
+	/* Compare content types */
+
+	octype = CMS_signed_get0_data_by_OBJ(osi,
+				OBJ_nid2obj(NID_pkcs9_contentType),
+					-3, V_ASN1_OBJECT);
+	if (!octype)
+		{
+		CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT_TYPE);
+		goto err;
+		}
+
+	/* Compare details in receipt request */
+
+	if (OBJ_cmp(octype, rct->contentType))
+		{
+		CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENT_TYPE_MISMATCH);
+		goto err;
+		}
+
+	/* Get original receipt request details */
+
+	if (!CMS_get1_ReceiptRequest(osi, &rr))
+		{
+		CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_RECEIPT_REQUEST);
+		goto err;
+		}
+
+	if (ASN1_STRING_cmp(rr->signedContentIdentifier,
+					rct->signedContentIdentifier))
+		{
+		CMSerr(CMS_F_CMS_RECEIPT_VERIFY,
+					CMS_R_CONTENTIDENTIFIER_MISMATCH);
+		goto err;
+		}
+
+	r = 1;
+
+	err:
+	if (rr)
+		CMS_ReceiptRequest_free(rr);
+	if (rct)
+		M_ASN1_free_of(rct, CMS_Receipt);
+
+	return r;
+
+	}
diff --git a/crypto/cms/cms_lcl.h b/crypto/cms/cms_lcl.h
index 5111617..ec644c3 100644
--- a/crypto/cms/cms_lcl.h
+++ b/crypto/cms/cms_lcl.h
@@ -449,6 +449,8 @@
 				const EVP_CIPHER *cipher,
 				const unsigned char *key, size_t keylen);
 
+int cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms);
+
 BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms);
 	
 #ifdef  __cplusplus
diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c
index 6388df8..b37d17c 100644
--- a/crypto/cms/cms_smime.c
+++ b/crypto/cms/cms_smime.c
@@ -65,18 +65,19 @@
 	int r = 0, i;
 	BIO *tmpout = NULL;
 
-	if(flags & CMS_TEXT)
-		{
+	if (out == NULL)
+		tmpout = BIO_new(BIO_s_null());
+	else if (flags & CMS_TEXT)
 		tmpout = BIO_new(BIO_s_mem());
-		if(!tmpout)
-			{
-			CMSerr(CMS_F_CMS_COPY_CONTENT,ERR_R_MALLOC_FAILURE);
-			goto err;
-			}
-		}
 	else
 		tmpout = out;
 
+	if(!tmpout)
+		{
+		CMSerr(CMS_F_CMS_COPY_CONTENT,ERR_R_MALLOC_FAILURE);
+		goto err;
+		}
+
 	/* Read all content through chain to process digest, decrypt etc */
 	for (;;)
 	{
@@ -419,6 +420,17 @@
 	return ret;
 	}
 
+int CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms,
+			STACK_OF(X509) *certs,
+			X509_STORE *store, unsigned int flags)
+	{
+	int r;
+	r = CMS_verify(rcms, certs, store, NULL, NULL, flags);
+	if (r <= 0)
+		return r;
+	return cms_Receipt_verify(rcms, ocms);
+	}
+
 CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
 						BIO *data, unsigned int flags)
 	{