summaryrefslogtreecommitdiffstats
path: root/crypto/cms
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2008-03-28 13:15:39 +0000
committerDr. Stephen Henson <steve@openssl.org>2008-03-28 13:15:39 +0000
commiteb9d8d8cd4ef3b1b6e1a14954c5b16438c27abf9 (patch)
treeb2abdf97a493a30fb6d9944222fd134d35166361 /crypto/cms
parentf7ccba3edf9f1f02d7bd3b019d7bc96f25a95718 (diff)
Support for verification of signed receipts.
Diffstat (limited to 'crypto/cms')
-rw-r--r--crypto/cms/cms.h18
-rw-r--r--crypto/cms/cms_asn1.c7
-rw-r--r--crypto/cms/cms_err.c16
-rw-r--r--crypto/cms/cms_ess.c157
-rw-r--r--crypto/cms/cms_lcl.h2
-rw-r--r--crypto/cms/cms_smime.c28
6 files changed, 219 insertions, 9 deletions
diff --git a/crypto/cms/cms.h b/crypto/cms/cms.h
index 4cc5d93bcf..22baa3e837 100644
--- a/crypto/cms/cms.h
+++ b/crypto/cms/cms.h
@@ -162,6 +162,10 @@ int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph,
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 @@ void ERR_load_CMS_strings(void);
#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 @@ void ERR_load_CMS_strings(void);
#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 @@ void ERR_load_CMS_strings(void);
#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 @@ void ERR_load_CMS_strings(void);
#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 2979993eb2..7f7132c3bb 100644
--- a/crypto/cms/cms_asn1.c
+++ b/crypto/cms/cms_asn1.c
@@ -371,3 +371,10 @@ ASN1_SEQUENCE(CMS_ReceiptRequest) = {
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 93e15e33fc..420a401770 100644
--- a/crypto/cms/cms_err.c
+++ b/crypto/cms/cms_err.c
@@ -107,10 +107,11 @@ static ERR_STRING_DATA CMS_str_functs[]=
{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 @@ static ERR_STRING_DATA CMS_str_reasons[]=
{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 @@ static ERR_STRING_DATA CMS_str_reasons[]=
{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 @@ static ERR_STRING_DATA CMS_str_reasons[]=
{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 9377217e33..ff9b2a86f2 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 @@ void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr,
*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 5111617fdd..ec644c36fb 100644
--- a/crypto/cms/cms_lcl.h
+++ b/crypto/cms/cms_lcl.h
@@ -449,6 +449,8 @@ int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
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 6388df89d1..b37d17c5af 100644
--- a/crypto/cms/cms_smime.c
+++ b/crypto/cms/cms_smime.c
@@ -65,18 +65,19 @@ static int cms_copy_content(BIO *out, BIO *in, unsigned int flags)
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 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
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)
{