From: Dr. Stephen Henson Date: Fri, 28 Mar 2008 19:43:16 +0000 (+0000) Subject: Signed receipt generation code. X-Git-Tag: OpenSSL_0_9_8k^2~486 X-Git-Url: https://git.openssl.org/?p=openssl.git;a=commitdiff_plain;h=36309aa2be6c80fcb6500d3c189d1d6bc52e11f3 Signed receipt generation code. --- diff --git a/apps/cms.c b/apps/cms.c index ef873eef59..30dd296bc0 100644 --- a/apps/cms.c +++ b/apps/cms.c @@ -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) { diff --git a/crypto/cms/cms.h b/crypto/cms/cms.h index 22baa3e837..19fde29e93 100644 --- a/crypto/cms/cms.h +++ b/crypto/cms/cms.h @@ -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 diff --git a/crypto/cms/cms_err.c b/crypto/cms/cms_err.c index 420a401770..9c813e5db6 100644 --- a/crypto/cms/cms_err.c +++ b/crypto/cms/cms_err.c @@ -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"}, diff --git a/crypto/cms/cms_ess.c b/crypto/cms/cms_ess.c index ff9b2a86f2..b2ff4fc595 100644 --- a/crypto/cms/cms_ess.c +++ b/crypto/cms/cms_ess.c @@ -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; + + } + + diff --git a/crypto/cms/cms_lcl.h b/crypto/cms/cms_lcl.h index ec644c36fb..c8ecfa724a 100644 --- a/crypto/cms/cms_lcl.h +++ b/crypto/cms/cms_lcl.h @@ -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); diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c index b37d17c5af..48885ce675 100644 --- a/crypto/cms/cms_smime.c +++ b/crypto/cms/cms_smime.c @@ -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) {