1 /* $OpenBSD: cms_ess.c,v 1.26 2024/11/01 18:53:35 tb Exp $ */
2 /*
3 * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4 * project.
5 */
6 /* ====================================================================
7 * Copyright (c) 2008 The OpenSSL Project. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. All advertising materials mentioning features or use of this
22 * software must display the following acknowledgment:
23 * "This product includes software developed by the OpenSSL Project
24 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25 *
26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27 * endorse or promote products derived from this software without
28 * prior written permission. For written permission, please contact
29 * licensing@OpenSSL.org.
30 *
31 * 5. Products derived from this software may not be called "OpenSSL"
32 * nor may "OpenSSL" appear in their names without prior written
33 * permission of the OpenSSL Project.
34 *
35 * 6. Redistributions of any form whatsoever must retain the following
36 * acknowledgment:
37 * "This product includes software developed by the OpenSSL Project
38 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51 * OF THE POSSIBILITY OF SUCH DAMAGE.
52 * ====================================================================
53 */
54
55 #include <stdlib.h>
56 #include <string.h>
57
58 #include <openssl/asn1.h>
59 #include <openssl/cms.h>
60 #include <openssl/err.h>
61 #include <openssl/evp.h>
62 #include <openssl/objects.h>
63 #include <openssl/x509.h>
64 #include <openssl/x509v3.h>
65
66 #include "cms_local.h"
67
68 CMS_ReceiptRequest *
d2i_CMS_ReceiptRequest(CMS_ReceiptRequest ** a,const unsigned char ** in,long len)69 d2i_CMS_ReceiptRequest(CMS_ReceiptRequest **a, const unsigned char **in, long len)
70 {
71 return (CMS_ReceiptRequest *)ASN1_item_d2i((ASN1_VALUE **)a, in, len,
72 &CMS_ReceiptRequest_it);
73 }
74 LCRYPTO_ALIAS(d2i_CMS_ReceiptRequest);
75
76 int
i2d_CMS_ReceiptRequest(CMS_ReceiptRequest * a,unsigned char ** out)77 i2d_CMS_ReceiptRequest(CMS_ReceiptRequest *a, unsigned char **out)
78 {
79 return ASN1_item_i2d((ASN1_VALUE *)a, out, &CMS_ReceiptRequest_it);
80 }
81 LCRYPTO_ALIAS(i2d_CMS_ReceiptRequest);
82
83 CMS_ReceiptRequest *
CMS_ReceiptRequest_new(void)84 CMS_ReceiptRequest_new(void)
85 {
86 return (CMS_ReceiptRequest *)ASN1_item_new(&CMS_ReceiptRequest_it);
87 }
88 LCRYPTO_ALIAS(CMS_ReceiptRequest_new);
89
90 void
CMS_ReceiptRequest_free(CMS_ReceiptRequest * a)91 CMS_ReceiptRequest_free(CMS_ReceiptRequest *a)
92 {
93 ASN1_item_free((ASN1_VALUE *)a, &CMS_ReceiptRequest_it);
94 }
95 LCRYPTO_ALIAS(CMS_ReceiptRequest_free);
96
97 /* ESS services: for now just Signed Receipt related */
98
99 int
CMS_get1_ReceiptRequest(CMS_SignerInfo * si,CMS_ReceiptRequest ** prr)100 CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr)
101 {
102 ASN1_STRING *str;
103 CMS_ReceiptRequest *rr = NULL;
104
105 if (prr)
106 *prr = NULL;
107 str = CMS_signed_get0_data_by_OBJ(si,
108 OBJ_nid2obj(NID_id_smime_aa_receiptRequest), -3, V_ASN1_SEQUENCE);
109 if (!str)
110 return 0;
111
112 rr = ASN1_item_unpack(str, &CMS_ReceiptRequest_it);
113 if (!rr)
114 return -1;
115 if (prr)
116 *prr = rr;
117 else
118 CMS_ReceiptRequest_free(rr);
119
120 return 1;
121 }
122 LCRYPTO_ALIAS(CMS_get1_ReceiptRequest);
123
124 CMS_ReceiptRequest *
CMS_ReceiptRequest_create0(unsigned char * id,int idlen,int allorfirst,STACK_OF (GENERAL_NAMES)* receiptList,STACK_OF (GENERAL_NAMES)* receiptsTo)125 CMS_ReceiptRequest_create0(unsigned char *id, int idlen, int allorfirst,
126 STACK_OF(GENERAL_NAMES) *receiptList, STACK_OF(GENERAL_NAMES) *receiptsTo)
127 {
128 CMS_ReceiptRequest *rr = NULL;
129
130 rr = CMS_ReceiptRequest_new();
131 if (rr == NULL)
132 goto merr;
133 if (id)
134 ASN1_STRING_set0(rr->signedContentIdentifier, id, idlen);
135 else {
136 if (!ASN1_STRING_set(rr->signedContentIdentifier, NULL, 32))
137 goto merr;
138 arc4random_buf(rr->signedContentIdentifier->data, 32);
139 }
140
141 sk_GENERAL_NAMES_pop_free(rr->receiptsTo, GENERAL_NAMES_free);
142 rr->receiptsTo = receiptsTo;
143
144 if (receiptList) {
145 rr->receiptsFrom->type = 1;
146 rr->receiptsFrom->d.receiptList = receiptList;
147 } else {
148 rr->receiptsFrom->type = 0;
149 rr->receiptsFrom->d.allOrFirstTier = allorfirst;
150 }
151
152 return rr;
153
154 merr:
155 CMSerror(ERR_R_MALLOC_FAILURE);
156 CMS_ReceiptRequest_free(rr);
157
158 return NULL;
159 }
160 LCRYPTO_ALIAS(CMS_ReceiptRequest_create0);
161
162 int
CMS_add1_ReceiptRequest(CMS_SignerInfo * si,CMS_ReceiptRequest * rr)163 CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr)
164 {
165 unsigned char *rrder = NULL;
166 int rrderlen, r = 0;
167
168 rrderlen = i2d_CMS_ReceiptRequest(rr, &rrder);
169 if (rrderlen < 0)
170 goto merr;
171
172 if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_receiptRequest,
173 V_ASN1_SEQUENCE, rrder, rrderlen))
174 goto merr;
175
176 r = 1;
177
178 merr:
179 if (!r)
180 CMSerror(ERR_R_MALLOC_FAILURE);
181
182 free(rrder);
183
184 return r;
185 }
186 LCRYPTO_ALIAS(CMS_add1_ReceiptRequest);
187
188 void
CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest * rr,ASN1_STRING ** pcid,int * pallorfirst,STACK_OF (GENERAL_NAMES)** plist,STACK_OF (GENERAL_NAMES)** prto)189 CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr, ASN1_STRING **pcid,
190 int *pallorfirst, STACK_OF(GENERAL_NAMES) **plist,
191 STACK_OF(GENERAL_NAMES) **prto)
192 {
193 if (pcid)
194 *pcid = rr->signedContentIdentifier;
195 if (rr->receiptsFrom->type == 0) {
196 if (pallorfirst)
197 *pallorfirst = (int)rr->receiptsFrom->d.allOrFirstTier;
198 if (plist)
199 *plist = NULL;
200 } else {
201 if (pallorfirst)
202 *pallorfirst = -1;
203 if (plist)
204 *plist = rr->receiptsFrom->d.receiptList;
205 }
206 if (prto)
207 *prto = rr->receiptsTo;
208 }
209 LCRYPTO_ALIAS(CMS_ReceiptRequest_get0_values);
210
211 /* Digest a SignerInfo structure for msgSigDigest attribute processing */
212
213 static int
cms_msgSigDigest(CMS_SignerInfo * si,unsigned char * dig,unsigned int * diglen)214 cms_msgSigDigest(CMS_SignerInfo *si, unsigned char *dig, unsigned int *diglen)
215 {
216 const EVP_MD *md;
217
218 md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
219 if (md == NULL)
220 return 0;
221 if (!ASN1_item_digest(&CMS_Attributes_Verify_it, md,
222 si->signedAttrs, dig, diglen))
223 return 0;
224
225 return 1;
226 }
227
228 /* Add a msgSigDigest attribute to a SignerInfo */
229
230 int
cms_msgSigDigest_add1(CMS_SignerInfo * dest,CMS_SignerInfo * src)231 cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src)
232 {
233 unsigned char dig[EVP_MAX_MD_SIZE];
234 unsigned int diglen;
235
236 if (!cms_msgSigDigest(src, dig, &diglen)) {
237 CMSerror(CMS_R_MSGSIGDIGEST_ERROR);
238 return 0;
239 }
240 if (!CMS_signed_add1_attr_by_NID(dest, NID_id_smime_aa_msgSigDigest,
241 V_ASN1_OCTET_STRING, dig, diglen)) {
242 CMSerror(ERR_R_MALLOC_FAILURE);
243 return 0;
244 }
245
246 return 1;
247 }
248
249 /* Verify signed receipt after it has already passed normal CMS verify */
250
251 int
cms_Receipt_verify(CMS_ContentInfo * cms,CMS_ContentInfo * req_cms)252 cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms)
253 {
254 int r = 0, i;
255 CMS_ReceiptRequest *rr = NULL;
256 CMS_Receipt *rct = NULL;
257 STACK_OF(CMS_SignerInfo) *sis, *osis;
258 CMS_SignerInfo *si, *osi = NULL;
259 ASN1_OCTET_STRING *msig, **pcont;
260 ASN1_OBJECT *octype;
261 unsigned char dig[EVP_MAX_MD_SIZE];
262 unsigned int diglen;
263
264 /* Get SignerInfos, also checks SignedData content type */
265 osis = CMS_get0_SignerInfos(req_cms);
266 sis = CMS_get0_SignerInfos(cms);
267 if (!osis || !sis)
268 goto err;
269
270 if (sk_CMS_SignerInfo_num(sis) != 1) {
271 CMSerror(CMS_R_NEED_ONE_SIGNER);
272 goto err;
273 }
274
275 /* Check receipt content type */
276 if (OBJ_obj2nid(CMS_get0_eContentType(cms)) != NID_id_smime_ct_receipt) {
277 CMSerror(CMS_R_NOT_A_SIGNED_RECEIPT);
278 goto err;
279 }
280
281 /* Extract and decode receipt content */
282 pcont = CMS_get0_content(cms);
283 if (!pcont || !*pcont) {
284 CMSerror(CMS_R_NO_CONTENT);
285 goto err;
286 }
287
288 rct = ASN1_item_unpack(*pcont, &CMS_Receipt_it);
289
290 if (!rct) {
291 CMSerror(CMS_R_RECEIPT_DECODE_ERROR);
292 goto err;
293 }
294
295 /* Locate original request */
296
297 for (i = 0; i < sk_CMS_SignerInfo_num(osis); i++) {
298 osi = sk_CMS_SignerInfo_value(osis, i);
299 if (!ASN1_STRING_cmp(osi->signature, rct->originatorSignatureValue))
300 break;
301 }
302
303 if (i == sk_CMS_SignerInfo_num(osis)) {
304 CMSerror(CMS_R_NO_MATCHING_SIGNATURE);
305 goto err;
306 }
307
308 si = sk_CMS_SignerInfo_value(sis, 0);
309
310 /* Get msgSigDigest value and compare */
311
312 msig = CMS_signed_get0_data_by_OBJ(si,
313 OBJ_nid2obj(NID_id_smime_aa_msgSigDigest), -3, V_ASN1_OCTET_STRING);
314
315 if (!msig) {
316 CMSerror(CMS_R_NO_MSGSIGDIGEST);
317 goto err;
318 }
319
320 if (!cms_msgSigDigest(osi, dig, &diglen)) {
321 CMSerror(CMS_R_MSGSIGDIGEST_ERROR);
322 goto err;
323 }
324
325 if (diglen != (unsigned int)msig->length) {
326 CMSerror(CMS_R_MSGSIGDIGEST_WRONG_LENGTH);
327 goto err;
328 }
329
330 if (memcmp(dig, msig->data, diglen)) {
331 CMSerror(CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE);
332 goto err;
333 }
334
335 /* Compare content types */
336
337 octype = CMS_signed_get0_data_by_OBJ(osi,
338 OBJ_nid2obj(NID_pkcs9_contentType), -3, V_ASN1_OBJECT);
339 if (!octype) {
340 CMSerror(CMS_R_NO_CONTENT_TYPE);
341 goto err;
342 }
343
344 /* Compare details in receipt request */
345
346 if (OBJ_cmp(octype, rct->contentType)) {
347 CMSerror(CMS_R_CONTENT_TYPE_MISMATCH);
348 goto err;
349 }
350
351 /* Get original receipt request details */
352
353 if (CMS_get1_ReceiptRequest(osi, &rr) <= 0) {
354 CMSerror(CMS_R_NO_RECEIPT_REQUEST);
355 goto err;
356 }
357
358 if (ASN1_STRING_cmp(rr->signedContentIdentifier,
359 rct->signedContentIdentifier)) {
360 CMSerror(CMS_R_CONTENTIDENTIFIER_MISMATCH);
361 goto err;
362 }
363
364 r = 1;
365
366 err:
367 CMS_ReceiptRequest_free(rr);
368 ASN1_item_free((ASN1_VALUE *)rct, &CMS_Receipt_it);
369 return r;
370 }
371
372 /*
373 * Encode a Receipt into an OCTET STRING read for including into content of a
374 * SignedData ContentInfo.
375 */
376
377 ASN1_OCTET_STRING *
cms_encode_Receipt(CMS_SignerInfo * si)378 cms_encode_Receipt(CMS_SignerInfo *si)
379 {
380 CMS_Receipt rct;
381 CMS_ReceiptRequest *rr = NULL;
382 ASN1_OBJECT *ctype;
383 ASN1_OCTET_STRING *os = NULL;
384
385 /* Get original receipt request */
386
387 /* Get original receipt request details */
388
389 if (CMS_get1_ReceiptRequest(si, &rr) <= 0) {
390 CMSerror(CMS_R_NO_RECEIPT_REQUEST);
391 goto err;
392 }
393
394 /* Get original content type */
395
396 ctype = CMS_signed_get0_data_by_OBJ(si,
397 OBJ_nid2obj(NID_pkcs9_contentType), -3, V_ASN1_OBJECT);
398 if (!ctype) {
399 CMSerror(CMS_R_NO_CONTENT_TYPE);
400 goto err;
401 }
402
403 rct.version = 1;
404 rct.contentType = ctype;
405 rct.signedContentIdentifier = rr->signedContentIdentifier;
406 rct.originatorSignatureValue = si->signature;
407
408 os = ASN1_item_pack(&rct, &CMS_Receipt_it, NULL);
409
410 err:
411 CMS_ReceiptRequest_free(rr);
412 return os;
413 }
414