Signed receipt generation code.
authorDr. Stephen Henson <steve@openssl.org>
Fri, 28 Mar 2008 19:43:16 +0000 (19:43 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Fri, 28 Mar 2008 19:43:16 +0000 (19:43 +0000)
apps/cms.c
crypto/cms/cms.h
crypto/cms/cms_err.c
crypto/cms/cms_ess.c
crypto/cms/cms_lcl.h
crypto/cms/cms_smime.c

index ef873ee..30dd296 100644 (file)
@@ -91,7 +91,7 @@ static CMS_ReceiptRequest *make_receipt_request(STACK *rr_to, int rr_allorfirst,
 #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_SIGN_RECEIPT     (15 | SMIME_IP | SMIME_OP)
 #define SMIME_VERIFY_RECEIPT   (16 | SMIME_IP)
 
 int MAIN(int, char **);
@@ -159,6 +159,8 @@ int MAIN(int argc, char **argv)
                        operation = SMIME_DECRYPT;
                else if (!strcmp (*args, "-sign"))
                        operation = SMIME_SIGN;
+               else if (!strcmp (*args, "-sign_receipt"))
+                       operation = SMIME_SIGN_RECEIPT;
                else if (!strcmp (*args, "-resign"))
                        operation = SMIME_RESIGN;
                else if (!strcmp (*args, "-verify"))
@@ -541,6 +543,7 @@ int MAIN(int argc, char **argv)
                keyfile = NULL;
                need_rand = 1;
                }
+
        else if (operation == SMIME_DECRYPT)
                {
                if (!recipfile && !keyfile && !secret_key)
@@ -724,12 +727,22 @@ int MAIN(int argc, char **argv)
                        }
                }
 
+       if (operation == SMIME_SIGN_RECEIPT)
+               {
+               if (!(signer = load_cert(bio_err,signerfile,FORMAT_PEM,NULL,
+                       e, "receipt signer certificate file")))
+                       {
+                       ERR_print_errors(bio_err);
+                       goto end;
+                       }
+               }
+
        if (operation == SMIME_DECRYPT)
                {
                if (!keyfile)
                        keyfile = recipfile;
                }
-       else if (operation == SMIME_SIGN)
+       else if ((operation == SMIME_SIGN) || (operation == SMIME_SIGN_RECEIPT))
                {
                if (!keyfile)
                        keyfile = signerfile;
@@ -888,6 +901,21 @@ int MAIN(int argc, char **argv)
                                                secret_key, secret_keylen,
                                                flags);
 
+               }
+       else if (operation == SMIME_SIGN_RECEIPT)
+               {
+               CMS_ContentInfo *srcms = NULL;
+               STACK_OF(CMS_SignerInfo) *sis;
+               CMS_SignerInfo *si;
+               sis = CMS_get0_SignerInfos(cms);
+               if (!sis)
+                       goto end;
+               si = sk_CMS_SignerInfo_value(sis, 0);
+               srcms = CMS_sign_receipt(si, signer, key, other, flags);
+               if (!srcms)
+                       goto end;
+               CMS_ContentInfo_free(cms);
+               cms = srcms;
                }
        else if (operation & SMIME_SIGNERS)
                {
index 22baa3e..19fde29 100644 (file)
@@ -140,6 +140,11 @@ int CMS_final(CMS_ContentInfo *cms, BIO *data, int flags);
 CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
                                                BIO *data, unsigned int flags);
 
+CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
+                                       X509 *signcert, EVP_PKEY *pkey,
+                                       STACK_OF(X509) *certs,
+                                       unsigned int flags);
+
 int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags);
 CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags);
 
@@ -342,6 +347,7 @@ void ERR_load_CMS_strings(void);
 #define CMS_F_CMS_DIGESTALGORITHM_INIT_BIO              116
 #define CMS_F_CMS_DIGESTEDDATA_DO_FINAL                         117
 #define CMS_F_CMS_DIGEST_VERIFY                                 118
+#define CMS_F_CMS_ENCODE_RECEIPT                        161
 #define CMS_F_CMS_ENCRYPT                               119
 #define CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO             120
 #define CMS_F_CMS_ENCRYPTEDDATA_DECRYPT                         121
@@ -357,6 +363,7 @@ void ERR_load_CMS_strings(void);
 #define CMS_F_CMS_GET0_ENVELOPED                        131
 #define CMS_F_CMS_GET0_REVOCATION_CHOICES               132
 #define CMS_F_CMS_GET0_SIGNED                           133
+#define CMS_F_CMS_MSGSIGDIGEST_ADD1                     162
 #define CMS_F_CMS_RECEIPTREQUEST_CREATE0                159
 #define CMS_F_CMS_RECEIPT_VERIFY                        160
 #define CMS_F_CMS_RECIPIENTINFO_DECRYPT                         134
@@ -380,6 +387,7 @@ void ERR_load_CMS_strings(void);
 #define CMS_F_CMS_SIGNERINFO_VERIFY                     152
 #define CMS_F_CMS_SIGNERINFO_VERIFY_CERT                153
 #define CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT             154
+#define CMS_F_CMS_SIGN_RECEIPT                          163
 #define CMS_F_CMS_STREAM                                155
 #define CMS_F_CMS_UNCOMPRESS                            156
 #define CMS_F_CMS_VERIFY                                157
@@ -427,6 +435,7 @@ void ERR_load_CMS_strings(void);
 #define CMS_R_NO_DEFAULT_DIGEST                                 128
 #define CMS_R_NO_DIGEST_SET                             129
 #define CMS_R_NO_KEY                                    130
+#define CMS_R_NO_KEY_OR_CERT                            174
 #define CMS_R_NO_MATCHING_DIGEST                        131
 #define CMS_R_NO_MATCHING_RECIPIENT                     132
 #define CMS_R_NO_MATCHING_SIGNATURE                     166
index 420a401..9c813e5 100644 (file)
@@ -91,6 +91,7 @@ static ERR_STRING_DATA CMS_str_functs[]=
 {ERR_FUNC(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO), "CMS_DIGESTALGORITHM_INIT_BIO"},
 {ERR_FUNC(CMS_F_CMS_DIGESTEDDATA_DO_FINAL),    "CMS_DIGESTEDDATA_DO_FINAL"},
 {ERR_FUNC(CMS_F_CMS_DIGEST_VERIFY),    "CMS_digest_verify"},
+{ERR_FUNC(CMS_F_CMS_ENCODE_RECEIPT),   "CMS_ENCODE_RECEIPT"},
 {ERR_FUNC(CMS_F_CMS_ENCRYPT),  "CMS_encrypt"},
 {ERR_FUNC(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO),        "CMS_ENCRYPTEDCONTENT_INIT_BIO"},
 {ERR_FUNC(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT),    "CMS_EncryptedData_decrypt"},
@@ -106,6 +107,7 @@ static ERR_STRING_DATA CMS_str_functs[]=
 {ERR_FUNC(CMS_F_CMS_GET0_ENVELOPED),   "CMS_GET0_ENVELOPED"},
 {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_MSGSIGDIGEST_ADD1),        "CMS_MSGSIGDIGEST_ADD1"},
 {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"},
@@ -129,6 +131,7 @@ static ERR_STRING_DATA CMS_str_functs[]=
 {ERR_FUNC(CMS_F_CMS_SIGNERINFO_VERIFY),        "CMS_SignerInfo_verify"},
 {ERR_FUNC(CMS_F_CMS_SIGNERINFO_VERIFY_CERT),   "CMS_SIGNERINFO_VERIFY_CERT"},
 {ERR_FUNC(CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT),        "CMS_SignerInfo_verify_content"},
+{ERR_FUNC(CMS_F_CMS_SIGN_RECEIPT),     "CMS_SIGN_RECEIPT"},
 {ERR_FUNC(CMS_F_CMS_STREAM),   "CMS_stream"},
 {ERR_FUNC(CMS_F_CMS_UNCOMPRESS),       "CMS_uncompress"},
 {ERR_FUNC(CMS_F_CMS_VERIFY),   "CMS_verify"},
@@ -179,6 +182,7 @@ static ERR_STRING_DATA CMS_str_reasons[]=
 {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_KEY_OR_CERT)        ,"no key or cert"},
 {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"},
index ff9b2a8..b2ff4fc 100644 (file)
@@ -190,6 +190,8 @@ void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr,
                *prto = rr->receiptsTo;
        }
 
+/* Digest a SignerInfo structure for msgSigDigest attribute processing */
+
 static int cms_msgSigDigest(CMS_SignerInfo *si,
                                unsigned char *dig, unsigned int *diglen)
        {
@@ -203,6 +205,26 @@ static int cms_msgSigDigest(CMS_SignerInfo *si,
        return 1;
        }
 
+/* Add a msgSigDigest attribute to a SignerInfo */
+
+int cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src)
+       {
+       unsigned char dig[EVP_MAX_MD_SIZE];
+       unsigned int diglen;
+       if (!cms_msgSigDigest(src, dig, &diglen))
+               {
+               CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, CMS_R_MSGSIGDIGEST_ERROR);
+               return 0;
+               }
+       if (!CMS_signed_add1_attr_by_NID(dest, NID_id_smime_aa_msgSigDigest,
+                                       V_ASN1_OCTET_STRING, dig, diglen))
+               {
+               CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, ERR_R_MALLOC_FAILURE);
+               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)
@@ -348,3 +370,52 @@ int cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms)
        return r;
 
        }
+
+/* Encode a Receipt into an OCTET STRING read for including into content of
+ * a SignedData ContentInfo.
+ */
+
+ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si)
+       {
+       CMS_Receipt rct;
+       CMS_ReceiptRequest *rr = NULL;
+       ASN1_OBJECT *ctype;
+       ASN1_OCTET_STRING *os = NULL;
+
+       /* Get original receipt request */
+
+       /* Get original receipt request details */
+
+       if (!CMS_get1_ReceiptRequest(si, &rr))
+               {
+               CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_RECEIPT_REQUEST);
+               goto err;
+               }
+
+       /* Get original content type */
+
+       ctype = CMS_signed_get0_data_by_OBJ(si,
+                               OBJ_nid2obj(NID_pkcs9_contentType),
+                                       -3, V_ASN1_OBJECT);
+       if (!ctype)
+               {
+               CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_CONTENT_TYPE);
+               goto err;
+               }
+
+       rct.version = 1;
+       rct.contentType = ctype;
+       rct.signedContentIdentifier = rr->signedContentIdentifier;
+       rct.originatorSignatureValue = si->signature;
+
+       os = ASN1_item_pack(&rct, ASN1_ITEM_rptr(CMS_Receipt), NULL);
+
+       err:
+       if (rr)
+               CMS_ReceiptRequest_free(rr);
+
+       return os;
+
+       }
+
+
index ec644c3..c8ecfa7 100644 (file)
@@ -450,6 +450,8 @@ int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
                                const unsigned char *key, size_t keylen);
 
 int cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms);
+int cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src);
+ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si);
 
 BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms);
        
index b37d17c..48885ce 100644 (file)
@@ -471,6 +471,78 @@ CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
        return NULL;
        }
 
+CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
+                                       X509 *signcert, EVP_PKEY *pkey,
+                                       STACK_OF(X509) *certs,
+                                       unsigned int flags)
+       {
+       CMS_SignerInfo *rct_si;
+       CMS_ContentInfo *cms = NULL;
+       ASN1_OCTET_STRING **pos, *os;
+       BIO *rct_cont = NULL;
+       int r = 0;
+
+       flags &= ~CMS_STREAM;
+       /* Not really detached but avoids content being allocated */
+       flags |= CMS_PARTIAL|CMS_BINARY|CMS_DETACHED;
+       if (!pkey || !signcert)
+               {
+               CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_NO_KEY_OR_CERT);
+               return NULL;
+               }
+
+       /* Initialize signed data */
+
+       cms = CMS_sign(NULL, NULL, certs, NULL, flags);
+       if (!cms)
+               goto err;
+
+       /* Set inner content type to signed receipt */
+       if (!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_smime_ct_receipt)))
+               goto err;
+
+       rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags);
+       if (!rct_si)
+               {
+               CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_ADD_SIGNER_ERROR);
+               goto err;
+               }
+
+       os = cms_encode_Receipt(si);
+
+       if (!os)
+               goto err;
+
+       /* Set content to digest */
+       rct_cont = BIO_new_mem_buf(os->data, os->length);
+       if (!rct_cont)
+               goto err;
+
+       /* Add msgSigDigest attribute */
+
+       if (!cms_msgSigDigest_add1(rct_si, si))
+               goto err;
+
+       /* Finalize structure */
+       if (!CMS_final(cms, rct_cont, flags))
+               goto err;
+
+       /* Set embedded content */
+       pos = CMS_get0_content(cms);
+       *pos = os;
+
+       r = 1;
+
+       err:
+       if (rct_cont)
+               BIO_free(rct_cont);
+       if (r)
+               return cms;
+       CMS_ContentInfo_free(cms);
+       return NULL;
+
+       }
+
 CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data,
                                const EVP_CIPHER *cipher, unsigned int flags)
        {