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;
110280304Sjkim        if (RAND_pseudo_bytes(rr->signedContentIdentifier->data, 32)
111280304Sjkim            <= 0)
112280304Sjkim            goto err;
113280304Sjkim    }
114183234Ssimon
115280304Sjkim    sk_GENERAL_NAMES_pop_free(rr->receiptsTo, GENERAL_NAMES_free);
116280304Sjkim    rr->receiptsTo = receiptsTo;
117183234Ssimon
118280304Sjkim    if (receiptList) {
119280304Sjkim        rr->receiptsFrom->type = 1;
120280304Sjkim        rr->receiptsFrom->d.receiptList = receiptList;
121280304Sjkim    } else {
122280304Sjkim        rr->receiptsFrom->type = 0;
123280304Sjkim        rr->receiptsFrom->d.allOrFirstTier = allorfirst;
124280304Sjkim    }
125183234Ssimon
126280304Sjkim    return rr;
127183234Ssimon
128280304Sjkim merr:
129280304Sjkim    CMSerr(CMS_F_CMS_RECEIPTREQUEST_CREATE0, ERR_R_MALLOC_FAILURE);
130183234Ssimon
131280304Sjkim err:
132280304Sjkim    if (rr)
133280304Sjkim        CMS_ReceiptRequest_free(rr);
134183234Ssimon
135280304Sjkim    return NULL;
136183234Ssimon
137280304Sjkim}
138280304Sjkim
139183234Ssimonint CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr)
140280304Sjkim{
141280304Sjkim    unsigned char *rrder = NULL;
142280304Sjkim    int rrderlen, r = 0;
143183234Ssimon
144280304Sjkim    rrderlen = i2d_CMS_ReceiptRequest(rr, &rrder);
145280304Sjkim    if (rrderlen < 0)
146280304Sjkim        goto merr;
147183234Ssimon
148280304Sjkim    if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_receiptRequest,
149280304Sjkim                                     V_ASN1_SEQUENCE, rrder, rrderlen))
150280304Sjkim        goto merr;
151183234Ssimon
152280304Sjkim    r = 1;
153183234Ssimon
154280304Sjkim merr:
155280304Sjkim    if (!r)
156280304Sjkim        CMSerr(CMS_F_CMS_ADD1_RECEIPTREQUEST, ERR_R_MALLOC_FAILURE);
157183234Ssimon
158280304Sjkim    if (rrder)
159280304Sjkim        OPENSSL_free(rrder);
160183234Ssimon
161280304Sjkim    return r;
162183234Ssimon
163280304Sjkim}
164280304Sjkim
165183234Ssimonvoid CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr,
166280304Sjkim                                    ASN1_STRING **pcid,
167280304Sjkim                                    int *pallorfirst,
168280304Sjkim                                    STACK_OF(GENERAL_NAMES) **plist,
169280304Sjkim                                    STACK_OF(GENERAL_NAMES) **prto)
170280304Sjkim{
171280304Sjkim    if (pcid)
172280304Sjkim        *pcid = rr->signedContentIdentifier;
173280304Sjkim    if (rr->receiptsFrom->type == 0) {
174280304Sjkim        if (pallorfirst)
175280304Sjkim            *pallorfirst = (int)rr->receiptsFrom->d.allOrFirstTier;
176280304Sjkim        if (plist)
177280304Sjkim            *plist = NULL;
178280304Sjkim    } else {
179280304Sjkim        if (pallorfirst)
180280304Sjkim            *pallorfirst = -1;
181280304Sjkim        if (plist)
182280304Sjkim            *plist = rr->receiptsFrom->d.receiptList;
183280304Sjkim    }
184280304Sjkim    if (prto)
185280304Sjkim        *prto = rr->receiptsTo;
186280304Sjkim}
187183234Ssimon
188183234Ssimon/* Digest a SignerInfo structure for msgSigDigest attribute processing */
189183234Ssimon
190183234Ssimonstatic int cms_msgSigDigest(CMS_SignerInfo *si,
191280304Sjkim                            unsigned char *dig, unsigned int *diglen)
192280304Sjkim{
193280304Sjkim    const EVP_MD *md;
194280304Sjkim    md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
195280304Sjkim    if (md == NULL)
196280304Sjkim        return 0;
197280304Sjkim    if (!ASN1_item_digest(ASN1_ITEM_rptr(CMS_Attributes_Verify), md,
198280304Sjkim                          si->signedAttrs, dig, diglen))
199280304Sjkim        return 0;
200280304Sjkim    return 1;
201280304Sjkim}
202183234Ssimon
203183234Ssimon/* Add a msgSigDigest attribute to a SignerInfo */
204183234Ssimon
205183234Ssimonint cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src)
206280304Sjkim{
207280304Sjkim    unsigned char dig[EVP_MAX_MD_SIZE];
208280304Sjkim    unsigned int diglen;
209280304Sjkim    if (!cms_msgSigDigest(src, dig, &diglen)) {
210280304Sjkim        CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, CMS_R_MSGSIGDIGEST_ERROR);
211280304Sjkim        return 0;
212280304Sjkim    }
213280304Sjkim    if (!CMS_signed_add1_attr_by_NID(dest, NID_id_smime_aa_msgSigDigest,
214280304Sjkim                                     V_ASN1_OCTET_STRING, dig, diglen)) {
215280304Sjkim        CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, ERR_R_MALLOC_FAILURE);
216280304Sjkim        return 0;
217280304Sjkim    }
218280304Sjkim    return 1;
219280304Sjkim}
220183234Ssimon
221183234Ssimon/* Verify signed receipt after it has already passed normal CMS verify */
222183234Ssimon
223183234Ssimonint cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms)
224280304Sjkim{
225280304Sjkim    int r = 0, i;
226280304Sjkim    CMS_ReceiptRequest *rr = NULL;
227280304Sjkim    CMS_Receipt *rct = NULL;
228280304Sjkim    STACK_OF(CMS_SignerInfo) *sis, *osis;
229280304Sjkim    CMS_SignerInfo *si, *osi = NULL;
230280304Sjkim    ASN1_OCTET_STRING *msig, **pcont;
231280304Sjkim    ASN1_OBJECT *octype;
232280304Sjkim    unsigned char dig[EVP_MAX_MD_SIZE];
233280304Sjkim    unsigned int diglen;
234183234Ssimon
235280304Sjkim    /* Get SignerInfos, also checks SignedData content type */
236280304Sjkim    osis = CMS_get0_SignerInfos(req_cms);
237280304Sjkim    sis = CMS_get0_SignerInfos(cms);
238280304Sjkim    if (!osis || !sis)
239280304Sjkim        goto err;
240183234Ssimon
241280304Sjkim    if (sk_CMS_SignerInfo_num(sis) != 1) {
242280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NEED_ONE_SIGNER);
243280304Sjkim        goto err;
244280304Sjkim    }
245183234Ssimon
246280304Sjkim    /* Check receipt content type */
247280304Sjkim    if (OBJ_obj2nid(CMS_get0_eContentType(cms)) != NID_id_smime_ct_receipt) {
248280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NOT_A_SIGNED_RECEIPT);
249280304Sjkim        goto err;
250280304Sjkim    }
251183234Ssimon
252280304Sjkim    /* Extract and decode receipt content */
253280304Sjkim    pcont = CMS_get0_content(cms);
254280304Sjkim    if (!pcont || !*pcont) {
255280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT);
256280304Sjkim        goto err;
257280304Sjkim    }
258183234Ssimon
259280304Sjkim    rct = ASN1_item_unpack(*pcont, ASN1_ITEM_rptr(CMS_Receipt));
260183234Ssimon
261280304Sjkim    if (!rct) {
262280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_RECEIPT_DECODE_ERROR);
263280304Sjkim        goto err;
264280304Sjkim    }
265183234Ssimon
266280304Sjkim    /* Locate original request */
267183234Ssimon
268280304Sjkim    for (i = 0; i < sk_CMS_SignerInfo_num(osis); i++) {
269280304Sjkim        osi = sk_CMS_SignerInfo_value(osis, i);
270280304Sjkim        if (!ASN1_STRING_cmp(osi->signature, rct->originatorSignatureValue))
271280304Sjkim            break;
272280304Sjkim    }
273183234Ssimon
274280304Sjkim    if (i == sk_CMS_SignerInfo_num(osis)) {
275280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MATCHING_SIGNATURE);
276280304Sjkim        goto err;
277280304Sjkim    }
278183234Ssimon
279280304Sjkim    si = sk_CMS_SignerInfo_value(sis, 0);
280183234Ssimon
281280304Sjkim    /* Get msgSigDigest value and compare */
282183234Ssimon
283280304Sjkim    msig = CMS_signed_get0_data_by_OBJ(si,
284280304Sjkim                                       OBJ_nid2obj
285280304Sjkim                                       (NID_id_smime_aa_msgSigDigest), -3,
286280304Sjkim                                       V_ASN1_OCTET_STRING);
287183234Ssimon
288280304Sjkim    if (!msig) {
289280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MSGSIGDIGEST);
290280304Sjkim        goto err;
291280304Sjkim    }
292183234Ssimon
293280304Sjkim    if (!cms_msgSigDigest(osi, dig, &diglen)) {
294280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_ERROR);
295280304Sjkim        goto err;
296280304Sjkim    }
297183234Ssimon
298280304Sjkim    if (diglen != (unsigned int)msig->length) {
299280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_WRONG_LENGTH);
300280304Sjkim        goto err;
301280304Sjkim    }
302183234Ssimon
303280304Sjkim    if (memcmp(dig, msig->data, diglen)) {
304280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY,
305280304Sjkim               CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE);
306280304Sjkim        goto err;
307280304Sjkim    }
308183234Ssimon
309280304Sjkim    /* Compare content types */
310183234Ssimon
311280304Sjkim    octype = CMS_signed_get0_data_by_OBJ(osi,
312280304Sjkim                                         OBJ_nid2obj(NID_pkcs9_contentType),
313280304Sjkim                                         -3, V_ASN1_OBJECT);
314280304Sjkim    if (!octype) {
315280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT_TYPE);
316280304Sjkim        goto err;
317280304Sjkim    }
318183234Ssimon
319280304Sjkim    /* Compare details in receipt request */
320183234Ssimon
321280304Sjkim    if (OBJ_cmp(octype, rct->contentType)) {
322280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENT_TYPE_MISMATCH);
323280304Sjkim        goto err;
324280304Sjkim    }
325183234Ssimon
326280304Sjkim    /* Get original receipt request details */
327183234Ssimon
328280304Sjkim    if (CMS_get1_ReceiptRequest(osi, &rr) <= 0) {
329280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_RECEIPT_REQUEST);
330280304Sjkim        goto err;
331280304Sjkim    }
332183234Ssimon
333280304Sjkim    if (ASN1_STRING_cmp(rr->signedContentIdentifier,
334280304Sjkim                        rct->signedContentIdentifier)) {
335280304Sjkim        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENTIDENTIFIER_MISMATCH);
336280304Sjkim        goto err;
337280304Sjkim    }
338183234Ssimon
339280304Sjkim    r = 1;
340183234Ssimon
341280304Sjkim err:
342280304Sjkim    if (rr)
343280304Sjkim        CMS_ReceiptRequest_free(rr);
344280304Sjkim    if (rct)
345280304Sjkim        M_ASN1_free_of(rct, CMS_Receipt);
346183234Ssimon
347280304Sjkim    return r;
348183234Ssimon
349280304Sjkim}
350183234Ssimon
351280304Sjkim/*
352280304Sjkim * Encode a Receipt into an OCTET STRING read for including into content of a
353280304Sjkim * SignedData ContentInfo.
354183234Ssimon */
355183234Ssimon
356183234SsimonASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si)
357280304Sjkim{
358280304Sjkim    CMS_Receipt rct;
359280304Sjkim    CMS_ReceiptRequest *rr = NULL;
360280304Sjkim    ASN1_OBJECT *ctype;
361280304Sjkim    ASN1_OCTET_STRING *os = NULL;
362183234Ssimon
363280304Sjkim    /* Get original receipt request */
364183234Ssimon
365280304Sjkim    /* Get original receipt request details */
366183234Ssimon
367280304Sjkim    if (CMS_get1_ReceiptRequest(si, &rr) <= 0) {
368280304Sjkim        CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_RECEIPT_REQUEST);
369280304Sjkim        goto err;
370280304Sjkim    }
371183234Ssimon
372280304Sjkim    /* Get original content type */
373183234Ssimon
374280304Sjkim    ctype = CMS_signed_get0_data_by_OBJ(si,
375280304Sjkim                                        OBJ_nid2obj(NID_pkcs9_contentType),
376280304Sjkim                                        -3, V_ASN1_OBJECT);
377280304Sjkim    if (!ctype) {
378280304Sjkim        CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_CONTENT_TYPE);
379280304Sjkim        goto err;
380280304Sjkim    }
381183234Ssimon
382280304Sjkim    rct.version = 1;
383280304Sjkim    rct.contentType = ctype;
384280304Sjkim    rct.signedContentIdentifier = rr->signedContentIdentifier;
385280304Sjkim    rct.originatorSignatureValue = si->signature;
386183234Ssimon
387280304Sjkim    os = ASN1_item_pack(&rct, ASN1_ITEM_rptr(CMS_Receipt), NULL);
388183234Ssimon
389280304Sjkim err:
390280304Sjkim    if (rr)
391280304Sjkim        CMS_ReceiptRequest_free(rr);
392183234Ssimon
393280304Sjkim    return os;
394183234Ssimon
395280304Sjkim}
396