1183234Ssimon/* crypto/cms/cms_ess.c */
2296465Sdelphij/*
3296465Sdelphij * 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
14296465Sdelphij *    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
67183234SsimonIMPLEMENT_ASN1_FUNCTIONS_const(CMS_ReceiptRequest)
68183234Ssimon
69183234Ssimon/* ESS services: for now just Signed Receipt related */
70183234Ssimon
71183234Ssimonint CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr)
72296465Sdelphij{
73296465Sdelphij    ASN1_STRING *str;
74296465Sdelphij    CMS_ReceiptRequest *rr = NULL;
75296465Sdelphij    if (prr)
76296465Sdelphij        *prr = NULL;
77296465Sdelphij    str = CMS_signed_get0_data_by_OBJ(si,
78296465Sdelphij                                      OBJ_nid2obj
79296465Sdelphij                                      (NID_id_smime_aa_receiptRequest), -3,
80296465Sdelphij                                      V_ASN1_SEQUENCE);
81296465Sdelphij    if (!str)
82296465Sdelphij        return 0;
83183234Ssimon
84296465Sdelphij    rr = ASN1_item_unpack(str, ASN1_ITEM_rptr(CMS_ReceiptRequest));
85296465Sdelphij    if (!rr)
86296465Sdelphij        return -1;
87296465Sdelphij    if (prr)
88296465Sdelphij        *prr = rr;
89296465Sdelphij    else
90296465Sdelphij        CMS_ReceiptRequest_free(rr);
91296465Sdelphij    return 1;
92296465Sdelphij}
93183234Ssimon
94183234SsimonCMS_ReceiptRequest *CMS_ReceiptRequest_create0(unsigned char *id, int idlen,
95296465Sdelphij                                               int allorfirst,
96296465Sdelphij                                               STACK_OF(GENERAL_NAMES)
97296465Sdelphij                                               *receiptList, STACK_OF(GENERAL_NAMES)
98296465Sdelphij                                               *receiptsTo)
99296465Sdelphij{
100296465Sdelphij    CMS_ReceiptRequest *rr = NULL;
101183234Ssimon
102296465Sdelphij    rr = CMS_ReceiptRequest_new();
103296465Sdelphij    if (!rr)
104296465Sdelphij        goto merr;
105296465Sdelphij    if (id)
106296465Sdelphij        ASN1_STRING_set0(rr->signedContentIdentifier, id, idlen);
107296465Sdelphij    else {
108296465Sdelphij        if (!ASN1_STRING_set(rr->signedContentIdentifier, NULL, 32))
109296465Sdelphij            goto merr;
110296465Sdelphij        if (RAND_pseudo_bytes(rr->signedContentIdentifier->data, 32)
111296465Sdelphij            <= 0)
112296465Sdelphij            goto err;
113296465Sdelphij    }
114183234Ssimon
115296465Sdelphij    sk_GENERAL_NAMES_pop_free(rr->receiptsTo, GENERAL_NAMES_free);
116296465Sdelphij    rr->receiptsTo = receiptsTo;
117183234Ssimon
118296465Sdelphij    if (receiptList) {
119296465Sdelphij        rr->receiptsFrom->type = 1;
120296465Sdelphij        rr->receiptsFrom->d.receiptList = receiptList;
121296465Sdelphij    } else {
122296465Sdelphij        rr->receiptsFrom->type = 0;
123296465Sdelphij        rr->receiptsFrom->d.allOrFirstTier = allorfirst;
124296465Sdelphij    }
125183234Ssimon
126296465Sdelphij    return rr;
127183234Ssimon
128296465Sdelphij merr:
129296465Sdelphij    CMSerr(CMS_F_CMS_RECEIPTREQUEST_CREATE0, ERR_R_MALLOC_FAILURE);
130183234Ssimon
131296465Sdelphij err:
132296465Sdelphij    if (rr)
133296465Sdelphij        CMS_ReceiptRequest_free(rr);
134183234Ssimon
135296465Sdelphij    return NULL;
136183234Ssimon
137296465Sdelphij}
138296465Sdelphij
139183234Ssimonint CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr)
140296465Sdelphij{
141296465Sdelphij    unsigned char *rrder = NULL;
142296465Sdelphij    int rrderlen, r = 0;
143183234Ssimon
144296465Sdelphij    rrderlen = i2d_CMS_ReceiptRequest(rr, &rrder);
145296465Sdelphij    if (rrderlen < 0)
146296465Sdelphij        goto merr;
147183234Ssimon
148296465Sdelphij    if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_receiptRequest,
149296465Sdelphij                                     V_ASN1_SEQUENCE, rrder, rrderlen))
150296465Sdelphij        goto merr;
151183234Ssimon
152296465Sdelphij    r = 1;
153183234Ssimon
154296465Sdelphij merr:
155296465Sdelphij    if (!r)
156296465Sdelphij        CMSerr(CMS_F_CMS_ADD1_RECEIPTREQUEST, ERR_R_MALLOC_FAILURE);
157183234Ssimon
158296465Sdelphij    if (rrder)
159296465Sdelphij        OPENSSL_free(rrder);
160183234Ssimon
161296465Sdelphij    return r;
162183234Ssimon
163296465Sdelphij}
164296465Sdelphij
165183234Ssimonvoid CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr,
166296465Sdelphij                                    ASN1_STRING **pcid,
167296465Sdelphij                                    int *pallorfirst,
168296465Sdelphij                                    STACK_OF(GENERAL_NAMES) **plist,
169296465Sdelphij                                    STACK_OF(GENERAL_NAMES) **prto)
170296465Sdelphij{
171296465Sdelphij    if (pcid)
172296465Sdelphij        *pcid = rr->signedContentIdentifier;
173296465Sdelphij    if (rr->receiptsFrom->type == 0) {
174296465Sdelphij        if (pallorfirst)
175296465Sdelphij            *pallorfirst = (int)rr->receiptsFrom->d.allOrFirstTier;
176296465Sdelphij        if (plist)
177296465Sdelphij            *plist = NULL;
178296465Sdelphij    } else {
179296465Sdelphij        if (pallorfirst)
180296465Sdelphij            *pallorfirst = -1;
181296465Sdelphij        if (plist)
182296465Sdelphij            *plist = rr->receiptsFrom->d.receiptList;
183296465Sdelphij    }
184296465Sdelphij    if (prto)
185296465Sdelphij        *prto = rr->receiptsTo;
186296465Sdelphij}
187183234Ssimon
188183234Ssimon/* Digest a SignerInfo structure for msgSigDigest attribute processing */
189183234Ssimon
190183234Ssimonstatic int cms_msgSigDigest(CMS_SignerInfo *si,
191296465Sdelphij                            unsigned char *dig, unsigned int *diglen)
192296465Sdelphij{
193296465Sdelphij    const EVP_MD *md;
194296465Sdelphij    md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
195296465Sdelphij    if (md == NULL)
196296465Sdelphij        return 0;
197296465Sdelphij    if (!ASN1_item_digest(ASN1_ITEM_rptr(CMS_Attributes_Verify), md,
198296465Sdelphij                          si->signedAttrs, dig, diglen))
199296465Sdelphij        return 0;
200296465Sdelphij    return 1;
201296465Sdelphij}
202183234Ssimon
203183234Ssimon/* Add a msgSigDigest attribute to a SignerInfo */
204183234Ssimon
205183234Ssimonint cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src)
206296465Sdelphij{
207296465Sdelphij    unsigned char dig[EVP_MAX_MD_SIZE];
208296465Sdelphij    unsigned int diglen;
209296465Sdelphij    if (!cms_msgSigDigest(src, dig, &diglen)) {
210296465Sdelphij        CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, CMS_R_MSGSIGDIGEST_ERROR);
211296465Sdelphij        return 0;
212296465Sdelphij    }
213296465Sdelphij    if (!CMS_signed_add1_attr_by_NID(dest, NID_id_smime_aa_msgSigDigest,
214296465Sdelphij                                     V_ASN1_OCTET_STRING, dig, diglen)) {
215296465Sdelphij        CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, ERR_R_MALLOC_FAILURE);
216296465Sdelphij        return 0;
217296465Sdelphij    }
218296465Sdelphij    return 1;
219296465Sdelphij}
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)
224296465Sdelphij{
225296465Sdelphij    int r = 0, i;
226296465Sdelphij    CMS_ReceiptRequest *rr = NULL;
227296465Sdelphij    CMS_Receipt *rct = NULL;
228296465Sdelphij    STACK_OF(CMS_SignerInfo) *sis, *osis;
229296465Sdelphij    CMS_SignerInfo *si, *osi = NULL;
230296465Sdelphij    ASN1_OCTET_STRING *msig, **pcont;
231296465Sdelphij    ASN1_OBJECT *octype;
232296465Sdelphij    unsigned char dig[EVP_MAX_MD_SIZE];
233296465Sdelphij    unsigned int diglen;
234183234Ssimon
235296465Sdelphij    /* Get SignerInfos, also checks SignedData content type */
236296465Sdelphij    osis = CMS_get0_SignerInfos(req_cms);
237296465Sdelphij    sis = CMS_get0_SignerInfos(cms);
238296465Sdelphij    if (!osis || !sis)
239296465Sdelphij        goto err;
240183234Ssimon
241296465Sdelphij    if (sk_CMS_SignerInfo_num(sis) != 1) {
242296465Sdelphij        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NEED_ONE_SIGNER);
243296465Sdelphij        goto err;
244296465Sdelphij    }
245183234Ssimon
246296465Sdelphij    /* Check receipt content type */
247296465Sdelphij    if (OBJ_obj2nid(CMS_get0_eContentType(cms)) != NID_id_smime_ct_receipt) {
248296465Sdelphij        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NOT_A_SIGNED_RECEIPT);
249296465Sdelphij        goto err;
250296465Sdelphij    }
251183234Ssimon
252296465Sdelphij    /* Extract and decode receipt content */
253296465Sdelphij    pcont = CMS_get0_content(cms);
254296465Sdelphij    if (!pcont || !*pcont) {
255296465Sdelphij        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT);
256296465Sdelphij        goto err;
257296465Sdelphij    }
258183234Ssimon
259296465Sdelphij    rct = ASN1_item_unpack(*pcont, ASN1_ITEM_rptr(CMS_Receipt));
260183234Ssimon
261296465Sdelphij    if (!rct) {
262296465Sdelphij        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_RECEIPT_DECODE_ERROR);
263296465Sdelphij        goto err;
264296465Sdelphij    }
265183234Ssimon
266296465Sdelphij    /* Locate original request */
267183234Ssimon
268296465Sdelphij    for (i = 0; i < sk_CMS_SignerInfo_num(osis); i++) {
269296465Sdelphij        osi = sk_CMS_SignerInfo_value(osis, i);
270296465Sdelphij        if (!ASN1_STRING_cmp(osi->signature, rct->originatorSignatureValue))
271296465Sdelphij            break;
272296465Sdelphij    }
273183234Ssimon
274296465Sdelphij    if (i == sk_CMS_SignerInfo_num(osis)) {
275296465Sdelphij        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MATCHING_SIGNATURE);
276296465Sdelphij        goto err;
277296465Sdelphij    }
278183234Ssimon
279296465Sdelphij    si = sk_CMS_SignerInfo_value(sis, 0);
280183234Ssimon
281296465Sdelphij    /* Get msgSigDigest value and compare */
282183234Ssimon
283296465Sdelphij    msig = CMS_signed_get0_data_by_OBJ(si,
284296465Sdelphij                                       OBJ_nid2obj
285296465Sdelphij                                       (NID_id_smime_aa_msgSigDigest), -3,
286296465Sdelphij                                       V_ASN1_OCTET_STRING);
287183234Ssimon
288296465Sdelphij    if (!msig) {
289296465Sdelphij        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MSGSIGDIGEST);
290296465Sdelphij        goto err;
291296465Sdelphij    }
292183234Ssimon
293296465Sdelphij    if (!cms_msgSigDigest(osi, dig, &diglen)) {
294296465Sdelphij        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_ERROR);
295296465Sdelphij        goto err;
296296465Sdelphij    }
297183234Ssimon
298296465Sdelphij    if (diglen != (unsigned int)msig->length) {
299296465Sdelphij        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_WRONG_LENGTH);
300296465Sdelphij        goto err;
301296465Sdelphij    }
302183234Ssimon
303296465Sdelphij    if (memcmp(dig, msig->data, diglen)) {
304296465Sdelphij        CMSerr(CMS_F_CMS_RECEIPT_VERIFY,
305296465Sdelphij               CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE);
306296465Sdelphij        goto err;
307296465Sdelphij    }
308183234Ssimon
309296465Sdelphij    /* Compare content types */
310183234Ssimon
311296465Sdelphij    octype = CMS_signed_get0_data_by_OBJ(osi,
312296465Sdelphij                                         OBJ_nid2obj(NID_pkcs9_contentType),
313296465Sdelphij                                         -3, V_ASN1_OBJECT);
314296465Sdelphij    if (!octype) {
315296465Sdelphij        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT_TYPE);
316296465Sdelphij        goto err;
317296465Sdelphij    }
318183234Ssimon
319296465Sdelphij    /* Compare details in receipt request */
320183234Ssimon
321296465Sdelphij    if (OBJ_cmp(octype, rct->contentType)) {
322296465Sdelphij        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENT_TYPE_MISMATCH);
323296465Sdelphij        goto err;
324296465Sdelphij    }
325183234Ssimon
326296465Sdelphij    /* Get original receipt request details */
327183234Ssimon
328296465Sdelphij    if (CMS_get1_ReceiptRequest(osi, &rr) <= 0) {
329296465Sdelphij        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_RECEIPT_REQUEST);
330296465Sdelphij        goto err;
331296465Sdelphij    }
332183234Ssimon
333296465Sdelphij    if (ASN1_STRING_cmp(rr->signedContentIdentifier,
334296465Sdelphij                        rct->signedContentIdentifier)) {
335296465Sdelphij        CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENTIDENTIFIER_MISMATCH);
336296465Sdelphij        goto err;
337296465Sdelphij    }
338183234Ssimon
339296465Sdelphij    r = 1;
340183234Ssimon
341296465Sdelphij err:
342296465Sdelphij    if (rr)
343296465Sdelphij        CMS_ReceiptRequest_free(rr);
344296465Sdelphij    if (rct)
345296465Sdelphij        M_ASN1_free_of(rct, CMS_Receipt);
346183234Ssimon
347296465Sdelphij    return r;
348183234Ssimon
349296465Sdelphij}
350183234Ssimon
351296465Sdelphij/*
352296465Sdelphij * Encode a Receipt into an OCTET STRING read for including into content of a
353296465Sdelphij * SignedData ContentInfo.
354183234Ssimon */
355183234Ssimon
356183234SsimonASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si)
357296465Sdelphij{
358296465Sdelphij    CMS_Receipt rct;
359296465Sdelphij    CMS_ReceiptRequest *rr = NULL;
360296465Sdelphij    ASN1_OBJECT *ctype;
361296465Sdelphij    ASN1_OCTET_STRING *os = NULL;
362183234Ssimon
363296465Sdelphij    /* Get original receipt request */
364183234Ssimon
365296465Sdelphij    /* Get original receipt request details */
366183234Ssimon
367296465Sdelphij    if (CMS_get1_ReceiptRequest(si, &rr) <= 0) {
368296465Sdelphij        CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_RECEIPT_REQUEST);
369296465Sdelphij        goto err;
370296465Sdelphij    }
371183234Ssimon
372296465Sdelphij    /* Get original content type */
373183234Ssimon
374296465Sdelphij    ctype = CMS_signed_get0_data_by_OBJ(si,
375296465Sdelphij                                        OBJ_nid2obj(NID_pkcs9_contentType),
376296465Sdelphij                                        -3, V_ASN1_OBJECT);
377296465Sdelphij    if (!ctype) {
378296465Sdelphij        CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_CONTENT_TYPE);
379296465Sdelphij        goto err;
380296465Sdelphij    }
381183234Ssimon
382296465Sdelphij    rct.version = 1;
383296465Sdelphij    rct.contentType = ctype;
384296465Sdelphij    rct.signedContentIdentifier = rr->signedContentIdentifier;
385296465Sdelphij    rct.originatorSignatureValue = si->signature;
386183234Ssimon
387296465Sdelphij    os = ASN1_item_pack(&rct, ASN1_ITEM_rptr(CMS_Receipt), NULL);
388183234Ssimon
389296465Sdelphij err:
390296465Sdelphij    if (rr)
391296465Sdelphij        CMS_ReceiptRequest_free(rr);
392183234Ssimon
393296465Sdelphij    return os;
394183234Ssimon
395296465Sdelphij}
396