1183234Ssimon/* crypto/cms/cms_ess.c */
2280304Sjkim/*
3280304Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4183234Ssimon * project.
5183234Ssimon */
6183234Ssimon/* ====================================================================
7183234Ssimon * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
8183234Ssimon *
9183234Ssimon * Redistribution and use in source and binary forms, with or without
10183234Ssimon * modification, are permitted provided that the following conditions
11183234Ssimon * are met:
12183234Ssimon *
13183234Ssimon * 1. Redistributions of source code must retain the above copyright
14280304Sjkim *    notice, this list of conditions and the following disclaimer.
15183234Ssimon *
16183234Ssimon * 2. Redistributions in binary form must reproduce the above copyright
17183234Ssimon *    notice, this list of conditions and the following disclaimer in
18183234Ssimon *    the documentation and/or other materials provided with the
19183234Ssimon *    distribution.
20183234Ssimon *
21183234Ssimon * 3. All advertising materials mentioning features or use of this
22183234Ssimon *    software must display the following acknowledgment:
23183234Ssimon *    "This product includes software developed by the OpenSSL Project
24183234Ssimon *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25183234Ssimon *
26183234Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27183234Ssimon *    endorse or promote products derived from this software without
28183234Ssimon *    prior written permission. For written permission, please contact
29183234Ssimon *    licensing@OpenSSL.org.
30183234Ssimon *
31183234Ssimon * 5. Products derived from this software may not be called "OpenSSL"
32183234Ssimon *    nor may "OpenSSL" appear in their names without prior written
33183234Ssimon *    permission of the OpenSSL Project.
34183234Ssimon *
35183234Ssimon * 6. Redistributions of any form whatsoever must retain the following
36183234Ssimon *    acknowledgment:
37183234Ssimon *    "This product includes software developed by the OpenSSL Project
38183234Ssimon *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39183234Ssimon *
40183234Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41183234Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42183234Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43183234Ssimon * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44183234Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45183234Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46183234Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47183234Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48183234Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49183234Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50183234Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51183234Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE.
52183234Ssimon * ====================================================================
53183234Ssimon */
54183234Ssimon
55183234Ssimon#include "cryptlib.h"
56183234Ssimon#include <openssl/asn1t.h>
57183234Ssimon#include <openssl/pem.h>
58183234Ssimon#include <openssl/rand.h>
59183234Ssimon#include <openssl/x509v3.h>
60183234Ssimon#include <openssl/err.h>
61183234Ssimon#include <openssl/cms.h>
62183234Ssimon#include "cms_lcl.h"
63183234Ssimon
64183234SsimonDECLARE_ASN1_ITEM(CMS_ReceiptRequest)
65183234SsimonDECLARE_ASN1_ITEM(CMS_Receipt)
66183234Ssimon
67238405SjkimIMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest)
68183234Ssimon
69183234Ssimon/* ESS services: for now just Signed Receipt related */
70183234Ssimon
71183234Ssimonint CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr)
72280304Sjkim{
73280304Sjkim    ASN1_STRING *str;
74280304Sjkim    CMS_ReceiptRequest *rr = NULL;
75280304Sjkim    if (prr)
76280304Sjkim        *prr = NULL;
77280304Sjkim    str = CMS_signed_get0_data_by_OBJ(si,
78280304Sjkim                                      OBJ_nid2obj
79280304Sjkim                                      (NID_id_smime_aa_receiptRequest), -3,
80280304Sjkim                                      V_ASN1_SEQUENCE);
81280304Sjkim    if (!str)
82280304Sjkim        return 0;
83183234Ssimon
84280304Sjkim    rr = ASN1_item_unpack(str, ASN1_ITEM_rptr(CMS_ReceiptRequest));
85280304Sjkim    if (!rr)
86280304Sjkim        return -1;
87280304Sjkim    if (prr)
88280304Sjkim        *prr = rr;
89280304Sjkim    else
90280304Sjkim        CMS_ReceiptRequest_free(rr);
91280304Sjkim    return 1;
92280304Sjkim}
93183234Ssimon
94183234SsimonCMS_ReceiptRequest *CMS_ReceiptRequest_create0(unsigned char *id, int idlen,
95280304Sjkim                                               int allorfirst,
96280304Sjkim                                               STACK_OF(GENERAL_NAMES)
97280304Sjkim                                               *receiptList, STACK_OF(GENERAL_NAMES)
98280304Sjkim                                               *receiptsTo)
99280304Sjkim{
100280304Sjkim    CMS_ReceiptRequest *rr = NULL;
101183234Ssimon
102280304Sjkim    rr = CMS_ReceiptRequest_new();
103280304Sjkim    if (!rr)
104280304Sjkim        goto merr;
105280304Sjkim    if (id)
106280304Sjkim        ASN1_STRING_set0(rr->signedContentIdentifier, id, idlen);
107280304Sjkim    else {
108280304Sjkim        if (!ASN1_STRING_set(rr->signedContentIdentifier, NULL, 32))
109280304Sjkim            goto merr;
110306196Sjkim        if (RAND_bytes(rr->signedContentIdentifier->data, 32) <= 0)
111280304Sjkim            goto err;
112280304Sjkim    }
113183234Ssimon
114280304Sjkim    sk_GENERAL_NAMES_pop_free(rr->receiptsTo, GENERAL_NAMES_free);
115280304Sjkim    rr->receiptsTo = receiptsTo;
116183234Ssimon
117280304Sjkim    if (receiptList) {
118280304Sjkim        rr->receiptsFrom->type = 1;
119280304Sjkim        rr->receiptsFrom->d.receiptList = receiptList;
120280304Sjkim    } else {
121280304Sjkim        rr->receiptsFrom->type = 0;
122280304Sjkim        rr->receiptsFrom->d.allOrFirstTier = allorfirst;
123280304Sjkim    }
124183234Ssimon
125280304Sjkim    return rr;
126183234Ssimon
127280304Sjkim merr:
128280304Sjkim    CMSerr(CMS_F_CMS_RECEIPTREQUEST_CREATE0, ERR_R_MALLOC_FAILURE);
129183234Ssimon
130280304Sjkim err:
131280304Sjkim    if (rr)
132280304Sjkim        CMS_ReceiptRequest_free(rr);
133183234Ssimon
134280304Sjkim    return NULL;
135183234Ssimon
136280304Sjkim}
137280304Sjkim
138183234Ssimonint CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr)
139280304Sjkim{
140280304Sjkim    unsigned char *rrder = NULL;
141280304Sjkim    int rrderlen, r = 0;
142183234Ssimon
143280304Sjkim    rrderlen = i2d_CMS_ReceiptRequest(rr, &rrder);
144280304Sjkim    if (rrderlen < 0)
145280304Sjkim        goto merr;
146183234Ssimon
147280304Sjkim    if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_receiptRequest,
148280304Sjkim                                     V_ASN1_SEQUENCE, rrder, rrderlen))
149280304Sjkim        goto merr;
150183234Ssimon
151280304Sjkim    r = 1;
152183234Ssimon
153280304Sjkim merr:
154280304Sjkim    if (!r)
155280304Sjkim        CMSerr(CMS_F_CMS_ADD1_RECEIPTREQUEST, ERR_R_MALLOC_FAILURE);
156183234Ssimon
157280304Sjkim    if (rrder)
158280304Sjkim        OPENSSL_free(rrder);
159183234Ssimon
160280304Sjkim    return r;
161183234Ssimon
162280304Sjkim}
163280304Sjkim
164183234Ssimonvoid CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr,
165280304Sjkim                                    ASN1_STRING **pcid,
166280304Sjkim                                    int *pallorfirst,
167280304Sjkim                                    STACK_OF(GENERAL_NAMES) **plist,
168280304Sjkim                                    STACK_OF(GENERAL_NAMES) **prto)
169280304Sjkim{
170280304Sjkim    if (pcid)
171280304Sjkim        *pcid = rr->signedContentIdentifier;
172280304Sjkim    if (rr->receiptsFrom->type == 0) {
173280304Sjkim        if (pallorfirst)
174280304Sjkim            *pallorfirst = (int)rr->receiptsFrom->d.allOrFirstTier;
175280304Sjkim        if (plist)
176280304Sjkim            *plist = NULL;
177280304Sjkim    } else {
178280304Sjkim        if (pallorfirst)
179280304Sjkim            *pallorfirst = -1;
180280304Sjkim        if (plist)
181280304Sjkim            *plist = rr->receiptsFrom->d.receiptList;
182280304Sjkim    }
183280304Sjkim    if (prto)
184280304Sjkim        *prto = rr->receiptsTo;
185280304Sjkim}
186183234Ssimon
187183234Ssimon/* Digest a SignerInfo structure for msgSigDigest attribute processing */
188183234Ssimon
189183234Ssimonstatic int cms_msgSigDigest(CMS_SignerInfo *si,
190280304Sjkim                            unsigned char *dig, unsigned int *diglen)
191280304Sjkim{
192280304Sjkim    const EVP_MD *md;
193280304Sjkim    md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
194280304Sjkim    if (md == NULL)
195280304Sjkim        return 0;
196280304Sjkim    if (!ASN1_item_digest(ASN1_ITEM_rptr(CMS_Attributes_Verify), md,
197280304Sjkim                          si->signedAttrs, dig, diglen))
198280304Sjkim        return 0;
199280304Sjkim    return 1;
200280304Sjkim}
201183234Ssimon
202183234Ssimon/* Add a msgSigDigest attribute to a SignerInfo */
203183234Ssimon
204183234Ssimonint cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src)
205280304Sjkim{
206280304Sjkim    unsigned char dig[EVP_MAX_MD_SIZE];
207280304Sjkim    unsigned int diglen;
208280304Sjkim    if (!cms_msgSigDigest(src, dig, &diglen)) {
209280304Sjkim        CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, CMS_R_MSGSIGDIGEST_ERROR);
210280304Sjkim        return 0;
211280304Sjkim    }
212280304Sjkim    if (!CMS_signed_add1_attr_by_NID(dest, NID_id_smime_aa_msgSigDigest,
213280304Sjkim                                     V_ASN1_OCTET_STRING, dig, diglen)) {
214280304Sjkim        CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, ERR_R_MALLOC_FAILURE);
215280304Sjkim        return 0;
216280304Sjkim    }
217280304Sjkim    return 1;
218280304Sjkim}
219183234Ssimon
220183234Ssimon/* Verify signed receipt after it has already passed normal CMS verify */
221183234Ssimon
222183234Ssimonint cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms)
223280304Sjkim{
224280304Sjkim    int r = 0, i;
225280304Sjkim    CMS_ReceiptRequest *rr = NULL;
226280304Sjkim    CMS_Receipt *rct = NULL;
227280304Sjkim    STACK_OF(CMS_SignerInfo) *sis, *osis;
228280304Sjkim    CMS_SignerInfo *si, *osi = NULL;
229280304Sjkim    ASN1_OCTET_STRING *msig, **pcont;
230280304Sjkim    ASN1_OBJECT *octype;
231280304Sjkim    unsigned char dig[EVP_MAX_MD_SIZE];
232280304Sjkim    unsigned int diglen;
233183234Ssimon
234280304Sjkim    /* Get SignerInfos, also checks SignedData content type */
235280304Sjkim    osis = CMS_get0_SignerInfos(req_cms);
236280304Sjkim    sis = CMS_get0_SignerInfos(cms);
237280304Sjkim    if (!osis || !sis)
238280304Sjkim        goto err;
239183234Ssimon
240280304Sjkim    if (sk_CMS_SignerInfo_num(sis) != 1) {
241280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NEED_ONE_SIGNER);
242280304Sjkim        goto err;
243280304Sjkim    }
244183234Ssimon
245280304Sjkim    /* Check receipt content type */
246280304Sjkim    if (OBJ_obj2nid(CMS_get0_eContentType(cms)) != NID_id_smime_ct_receipt) {
247280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NOT_A_SIGNED_RECEIPT);
248280304Sjkim        goto err;
249280304Sjkim    }
250183234Ssimon
251280304Sjkim    /* Extract and decode receipt content */
252280304Sjkim    pcont = CMS_get0_content(cms);
253280304Sjkim    if (!pcont || !*pcont) {
254280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT);
255280304Sjkim        goto err;
256280304Sjkim    }
257183234Ssimon
258280304Sjkim    rct = ASN1_item_unpack(*pcont, ASN1_ITEM_rptr(CMS_Receipt));
259183234Ssimon
260280304Sjkim    if (!rct) {
261280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_RECEIPT_DECODE_ERROR);
262280304Sjkim        goto err;
263280304Sjkim    }
264183234Ssimon
265280304Sjkim    /* Locate original request */
266183234Ssimon
267280304Sjkim    for (i = 0; i < sk_CMS_SignerInfo_num(osis); i++) {
268280304Sjkim        osi = sk_CMS_SignerInfo_value(osis, i);
269280304Sjkim        if (!ASN1_STRING_cmp(osi->signature, rct->originatorSignatureValue))
270280304Sjkim            break;
271280304Sjkim    }
272183234Ssimon
273280304Sjkim    if (i == sk_CMS_SignerInfo_num(osis)) {
274280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MATCHING_SIGNATURE);
275280304Sjkim        goto err;
276280304Sjkim    }
277183234Ssimon
278280304Sjkim    si = sk_CMS_SignerInfo_value(sis, 0);
279183234Ssimon
280280304Sjkim    /* Get msgSigDigest value and compare */
281183234Ssimon
282280304Sjkim    msig = CMS_signed_get0_data_by_OBJ(si,
283280304Sjkim                                       OBJ_nid2obj
284280304Sjkim                                       (NID_id_smime_aa_msgSigDigest), -3,
285280304Sjkim                                       V_ASN1_OCTET_STRING);
286183234Ssimon
287280304Sjkim    if (!msig) {
288280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MSGSIGDIGEST);
289280304Sjkim        goto err;
290280304Sjkim    }
291183234Ssimon
292280304Sjkim    if (!cms_msgSigDigest(osi, dig, &diglen)) {
293280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_ERROR);
294280304Sjkim        goto err;
295280304Sjkim    }
296183234Ssimon
297280304Sjkim    if (diglen != (unsigned int)msig->length) {
298280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_WRONG_LENGTH);
299280304Sjkim        goto err;
300280304Sjkim    }
301183234Ssimon
302280304Sjkim    if (memcmp(dig, msig->data, diglen)) {
303280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY,
304280304Sjkim               CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE);
305280304Sjkim        goto err;
306280304Sjkim    }
307183234Ssimon
308280304Sjkim    /* Compare content types */
309183234Ssimon
310280304Sjkim    octype = CMS_signed_get0_data_by_OBJ(osi,
311280304Sjkim                                         OBJ_nid2obj(NID_pkcs9_contentType),
312280304Sjkim                                         -3, V_ASN1_OBJECT);
313280304Sjkim    if (!octype) {
314280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT_TYPE);
315280304Sjkim        goto err;
316280304Sjkim    }
317183234Ssimon
318280304Sjkim    /* Compare details in receipt request */
319183234Ssimon
320280304Sjkim    if (OBJ_cmp(octype, rct->contentType)) {
321280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENT_TYPE_MISMATCH);
322280304Sjkim        goto err;
323280304Sjkim    }
324183234Ssimon
325280304Sjkim    /* Get original receipt request details */
326183234Ssimon
327280304Sjkim    if (CMS_get1_ReceiptRequest(osi, &rr) <= 0) {
328280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_RECEIPT_REQUEST);
329280304Sjkim        goto err;
330280304Sjkim    }
331183234Ssimon
332280304Sjkim    if (ASN1_STRING_cmp(rr->signedContentIdentifier,
333280304Sjkim                        rct->signedContentIdentifier)) {
334280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENTIDENTIFIER_MISMATCH);
335280304Sjkim        goto err;
336280304Sjkim    }
337183234Ssimon
338280304Sjkim    r = 1;
339183234Ssimon
340280304Sjkim err:
341280304Sjkim    if (rr)
342280304Sjkim        CMS_ReceiptRequest_free(rr);
343280304Sjkim    if (rct)
344280304Sjkim        M_ASN1_free_of(rct, CMS_Receipt);
345183234Ssimon
346280304Sjkim    return r;
347183234Ssimon
348280304Sjkim}
349183234Ssimon
350280304Sjkim/*
351280304Sjkim * Encode a Receipt into an OCTET STRING read for including into content of a
352280304Sjkim * SignedData ContentInfo.
353183234Ssimon */
354183234Ssimon
355183234SsimonASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si)
356280304Sjkim{
357280304Sjkim    CMS_Receipt rct;
358280304Sjkim    CMS_ReceiptRequest *rr = NULL;
359280304Sjkim    ASN1_OBJECT *ctype;
360280304Sjkim    ASN1_OCTET_STRING *os = NULL;
361183234Ssimon
362280304Sjkim    /* Get original receipt request */
363183234Ssimon
364280304Sjkim    /* Get original receipt request details */
365183234Ssimon
366280304Sjkim    if (CMS_get1_ReceiptRequest(si, &rr) <= 0) {
367280304Sjkim        CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_RECEIPT_REQUEST);
368280304Sjkim        goto err;
369280304Sjkim    }
370183234Ssimon
371280304Sjkim    /* Get original content type */
372183234Ssimon
373280304Sjkim    ctype = CMS_signed_get0_data_by_OBJ(si,
374280304Sjkim                                        OBJ_nid2obj(NID_pkcs9_contentType),
375280304Sjkim                                        -3, V_ASN1_OBJECT);
376280304Sjkim    if (!ctype) {
377280304Sjkim        CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_CONTENT_TYPE);
378280304Sjkim        goto err;
379280304Sjkim    }
380183234Ssimon
381280304Sjkim    rct.version = 1;
382280304Sjkim    rct.contentType = ctype;
383280304Sjkim    rct.signedContentIdentifier = rr->signedContentIdentifier;
384280304Sjkim    rct.originatorSignatureValue = si->signature;
385183234Ssimon
386280304Sjkim    os = ASN1_item_pack(&rct, ASN1_ITEM_rptr(CMS_Receipt), NULL);
387183234Ssimon
388280304Sjkim err:
389280304Sjkim    if (rr)
390280304Sjkim        CMS_ReceiptRequest_free(rr);
391183234Ssimon
392280304Sjkim    return os;
393183234Ssimon
394280304Sjkim}
395