]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/cms/cms_ess.c
9903c444fa6ee3194fc6816c051ccac483a276c9
[thirdparty/openssl.git] / crypto / cms / cms_ess.c
1 /*
2 * Copyright 2008-2020 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include "internal/cryptlib.h"
11 #include <openssl/asn1t.h>
12 #include <openssl/pem.h>
13 #include <openssl/rand.h>
14 #include <openssl/x509v3.h>
15 #include <openssl/err.h>
16 #include <openssl/cms.h>
17 #include <openssl/ess.h>
18 #include "crypto/ess.h"
19 #include "crypto/cms.h"
20 #include "crypto/x509.h"
21 #include "cms_local.h"
22
23 DEFINE_STACK_OF(ESS_CERT_ID)
24 DEFINE_STACK_OF(ESS_CERT_ID_V2)
25
26 IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest)
27
28 /* ESS services */
29
30 int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr)
31 {
32 ASN1_STRING *str;
33 CMS_ReceiptRequest *rr;
34 ASN1_OBJECT *obj = OBJ_nid2obj(NID_id_smime_aa_receiptRequest);
35
36 if (prr != NULL)
37 *prr = NULL;
38 str = CMS_signed_get0_data_by_OBJ(si, obj, -3, V_ASN1_SEQUENCE);
39 if (str == NULL)
40 return 0;
41
42 rr = ASN1_item_unpack(str, ASN1_ITEM_rptr(CMS_ReceiptRequest));
43 if (rr == NULL)
44 return -1;
45 if (prr != NULL)
46 *prr = rr;
47 else
48 CMS_ReceiptRequest_free(rr);
49 return 1;
50 }
51
52 /*
53 First, get the ESS_SIGNING_CERT(V2) signed attribute from |si|.
54 Then check matching of each cert of trust |chain| with one of
55 the |cert_ids|(Hash+IssuerID) list from this ESS_SIGNING_CERT.
56 Derived from ts_check_signing_certs()
57 */
58 int ess_check_signing_certs(CMS_SignerInfo *si, STACK_OF(X509) *chain)
59 {
60 ESS_SIGNING_CERT *ss = NULL;
61 ESS_SIGNING_CERT_V2 *ssv2 = NULL;
62 X509 *cert;
63 int i = 0, ret = 0;
64
65 if (cms_signerinfo_get_signing_cert(si, &ss) > 0 && ss->cert_ids != NULL) {
66 STACK_OF(ESS_CERT_ID) *cert_ids = ss->cert_ids;
67
68 cert = sk_X509_value(chain, 0);
69 if (ess_find_cert(cert_ids, cert) != 0)
70 goto err;
71
72 /*
73 * Check the other certificates of the chain.
74 * Fail if no signing certificate ids found for each certificate.
75 */
76 if (sk_ESS_CERT_ID_num(cert_ids) > 1) {
77 /* for each chain cert, try to find its cert id */
78 for (i = 1; i < sk_X509_num(chain); ++i) {
79 cert = sk_X509_value(chain, i);
80 if (ess_find_cert(cert_ids, cert) < 0)
81 goto err;
82 }
83 }
84 } else if (cms_signerinfo_get_signing_cert_v2(si, &ssv2) > 0
85 && ssv2->cert_ids!= NULL) {
86 STACK_OF(ESS_CERT_ID_V2) *cert_ids_v2 = ssv2->cert_ids;
87
88 cert = sk_X509_value(chain, 0);
89 if (ess_find_cert_v2(cert_ids_v2, cert) != 0)
90 goto err;
91
92 /*
93 * Check the other certificates of the chain.
94 * Fail if no signing certificate ids found for each certificate.
95 */
96 if (sk_ESS_CERT_ID_V2_num(cert_ids_v2) > 1) {
97 /* for each chain cert, try to find its cert id */
98 for (i = 1; i < sk_X509_num(chain); ++i) {
99 cert = sk_X509_value(chain, i);
100 if (ess_find_cert_v2(cert_ids_v2, cert) < 0)
101 goto err;
102 }
103 }
104 } else {
105 CMSerr(CMS_F_ESS_CHECK_SIGNING_CERTS,
106 CMS_R_ESS_NO_SIGNING_CERTID_ATTRIBUTE);
107 return 0;
108 }
109 ret = 1;
110 err:
111 if (!ret)
112 CMSerr(CMS_F_ESS_CHECK_SIGNING_CERTS,
113 CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR);
114
115 ESS_SIGNING_CERT_free(ss);
116 ESS_SIGNING_CERT_V2_free(ssv2);
117 return ret;
118 }
119
120 CMS_ReceiptRequest *CMS_ReceiptRequest_create0_with_libctx(
121 unsigned char *id, int idlen, int allorfirst,
122 STACK_OF(GENERAL_NAMES) *receiptList, STACK_OF(GENERAL_NAMES) *receiptsTo,
123 OPENSSL_CTX *libctx, const char *propq)
124 {
125 CMS_ReceiptRequest *rr;
126
127 rr = CMS_ReceiptRequest_new();
128 if (rr == NULL)
129 goto merr;
130 if (id)
131 ASN1_STRING_set0(rr->signedContentIdentifier, id, idlen);
132 else {
133 if (!ASN1_STRING_set(rr->signedContentIdentifier, NULL, 32))
134 goto merr;
135 if (RAND_bytes_ex(libctx, rr->signedContentIdentifier->data, 32) <= 0)
136 goto err;
137 }
138
139 sk_GENERAL_NAMES_pop_free(rr->receiptsTo, GENERAL_NAMES_free);
140 rr->receiptsTo = receiptsTo;
141
142 if (receiptList != NULL) {
143 rr->receiptsFrom->type = 1;
144 rr->receiptsFrom->d.receiptList = receiptList;
145 } else {
146 rr->receiptsFrom->type = 0;
147 rr->receiptsFrom->d.allOrFirstTier = allorfirst;
148 }
149
150 return rr;
151
152 merr:
153 CMSerr(0, ERR_R_MALLOC_FAILURE);
154
155 err:
156 CMS_ReceiptRequest_free(rr);
157 return NULL;
158
159 }
160
161 CMS_ReceiptRequest *CMS_ReceiptRequest_create0(
162 unsigned char *id, int idlen, int allorfirst,
163 STACK_OF(GENERAL_NAMES) *receiptList, STACK_OF(GENERAL_NAMES) *receiptsTo)
164 {
165 return CMS_ReceiptRequest_create0_with_libctx(id, idlen, allorfirst,
166 receiptList, receiptsTo,
167 NULL, NULL);
168 }
169
170 int CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr)
171 {
172 unsigned char *rrder = NULL;
173 int rrderlen, r = 0;
174
175 rrderlen = i2d_CMS_ReceiptRequest(rr, &rrder);
176 if (rrderlen < 0)
177 goto merr;
178
179 if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_receiptRequest,
180 V_ASN1_SEQUENCE, rrder, rrderlen))
181 goto merr;
182
183 r = 1;
184
185 merr:
186 if (!r)
187 CMSerr(CMS_F_CMS_ADD1_RECEIPTREQUEST, ERR_R_MALLOC_FAILURE);
188
189 OPENSSL_free(rrder);
190
191 return r;
192
193 }
194
195 void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr,
196 ASN1_STRING **pcid,
197 int *pallorfirst,
198 STACK_OF(GENERAL_NAMES) **plist,
199 STACK_OF(GENERAL_NAMES) **prto)
200 {
201 if (pcid != NULL)
202 *pcid = rr->signedContentIdentifier;
203 if (rr->receiptsFrom->type == 0) {
204 if (pallorfirst != NULL)
205 *pallorfirst = (int)rr->receiptsFrom->d.allOrFirstTier;
206 if (plist != NULL)
207 *plist = NULL;
208 } else {
209 if (pallorfirst != NULL)
210 *pallorfirst = -1;
211 if (plist != NULL)
212 *plist = rr->receiptsFrom->d.receiptList;
213 }
214 if (prto != NULL)
215 *prto = rr->receiptsTo;
216 }
217
218 /* Digest a SignerInfo structure for msgSigDigest attribute processing */
219
220 static int cms_msgSigDigest(CMS_SignerInfo *si,
221 unsigned char *dig, unsigned int *diglen)
222 {
223 const EVP_MD *md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
224
225 if (md == NULL)
226 return 0;
227 if (!asn1_item_digest_with_libctx(ASN1_ITEM_rptr(CMS_Attributes_Verify), md,
228 si->signedAttrs, dig, diglen,
229 si->cms_ctx->libctx, si->cms_ctx->propq))
230 return 0;
231 return 1;
232 }
233
234 /* Add a msgSigDigest attribute to a SignerInfo */
235
236 int cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src)
237 {
238 unsigned char dig[EVP_MAX_MD_SIZE];
239 unsigned int diglen;
240
241 if (!cms_msgSigDigest(src, dig, &diglen)) {
242 CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, CMS_R_MSGSIGDIGEST_ERROR);
243 return 0;
244 }
245 if (!CMS_signed_add1_attr_by_NID(dest, NID_id_smime_aa_msgSigDigest,
246 V_ASN1_OCTET_STRING, dig, diglen)) {
247 CMSerr(CMS_F_CMS_MSGSIGDIGEST_ADD1, ERR_R_MALLOC_FAILURE);
248 return 0;
249 }
250 return 1;
251 }
252
253 /* Verify signed receipt after it has already passed normal CMS verify */
254
255 int cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms)
256 {
257 int r = 0, i;
258 CMS_ReceiptRequest *rr = NULL;
259 CMS_Receipt *rct = NULL;
260 STACK_OF(CMS_SignerInfo) *sis, *osis;
261 CMS_SignerInfo *si, *osi = NULL;
262 ASN1_OCTET_STRING *msig, **pcont;
263 ASN1_OBJECT *octype;
264 unsigned char dig[EVP_MAX_MD_SIZE];
265 unsigned int diglen;
266
267 /* Get SignerInfos, also checks SignedData content type */
268 osis = CMS_get0_SignerInfos(req_cms);
269 sis = CMS_get0_SignerInfos(cms);
270 if (!osis || !sis)
271 goto err;
272
273 if (sk_CMS_SignerInfo_num(sis) != 1) {
274 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NEED_ONE_SIGNER);
275 goto err;
276 }
277
278 /* Check receipt content type */
279 if (OBJ_obj2nid(CMS_get0_eContentType(cms)) != NID_id_smime_ct_receipt) {
280 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NOT_A_SIGNED_RECEIPT);
281 goto err;
282 }
283
284 /* Extract and decode receipt content */
285 pcont = CMS_get0_content(cms);
286 if (pcont == NULL || *pcont == NULL) {
287 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT);
288 goto err;
289 }
290
291 rct = ASN1_item_unpack(*pcont, ASN1_ITEM_rptr(CMS_Receipt));
292
293 if (!rct) {
294 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_RECEIPT_DECODE_ERROR);
295 goto err;
296 }
297
298 /* Locate original request */
299
300 for (i = 0; i < sk_CMS_SignerInfo_num(osis); i++) {
301 osi = sk_CMS_SignerInfo_value(osis, i);
302 if (!ASN1_STRING_cmp(osi->signature, rct->originatorSignatureValue))
303 break;
304 }
305
306 if (i == sk_CMS_SignerInfo_num(osis)) {
307 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MATCHING_SIGNATURE);
308 goto err;
309 }
310
311 si = sk_CMS_SignerInfo_value(sis, 0);
312
313 /* Get msgSigDigest value and compare */
314
315 msig = CMS_signed_get0_data_by_OBJ(si,
316 OBJ_nid2obj
317 (NID_id_smime_aa_msgSigDigest), -3,
318 V_ASN1_OCTET_STRING);
319
320 if (!msig) {
321 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_MSGSIGDIGEST);
322 goto err;
323 }
324
325 if (!cms_msgSigDigest(osi, dig, &diglen)) {
326 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_ERROR);
327 goto err;
328 }
329
330 if (diglen != (unsigned int)msig->length) {
331 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_MSGSIGDIGEST_WRONG_LENGTH);
332 goto err;
333 }
334
335 if (memcmp(dig, msig->data, diglen)) {
336 CMSerr(CMS_F_CMS_RECEIPT_VERIFY,
337 CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE);
338 goto err;
339 }
340
341 /* Compare content types */
342
343 octype = CMS_signed_get0_data_by_OBJ(osi,
344 OBJ_nid2obj(NID_pkcs9_contentType),
345 -3, V_ASN1_OBJECT);
346 if (!octype) {
347 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_CONTENT_TYPE);
348 goto err;
349 }
350
351 /* Compare details in receipt request */
352
353 if (OBJ_cmp(octype, rct->contentType)) {
354 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENT_TYPE_MISMATCH);
355 goto err;
356 }
357
358 /* Get original receipt request details */
359
360 if (CMS_get1_ReceiptRequest(osi, &rr) <= 0) {
361 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_NO_RECEIPT_REQUEST);
362 goto err;
363 }
364
365 if (ASN1_STRING_cmp(rr->signedContentIdentifier,
366 rct->signedContentIdentifier)) {
367 CMSerr(CMS_F_CMS_RECEIPT_VERIFY, CMS_R_CONTENTIDENTIFIER_MISMATCH);
368 goto err;
369 }
370
371 r = 1;
372
373 err:
374 CMS_ReceiptRequest_free(rr);
375 M_ASN1_free_of(rct, CMS_Receipt);
376 return r;
377
378 }
379
380 /*
381 * Encode a Receipt into an OCTET STRING read for including into content of a
382 * SignedData ContentInfo.
383 */
384
385 ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si)
386 {
387 CMS_Receipt rct;
388 CMS_ReceiptRequest *rr = NULL;
389 ASN1_OBJECT *ctype;
390 ASN1_OCTET_STRING *os = NULL;
391
392 /* Get original receipt request */
393
394 /* Get original receipt request details */
395
396 if (CMS_get1_ReceiptRequest(si, &rr) <= 0) {
397 CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_RECEIPT_REQUEST);
398 goto err;
399 }
400
401 /* Get original content type */
402
403 ctype = CMS_signed_get0_data_by_OBJ(si,
404 OBJ_nid2obj(NID_pkcs9_contentType),
405 -3, V_ASN1_OBJECT);
406 if (!ctype) {
407 CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_CONTENT_TYPE);
408 goto err;
409 }
410
411 rct.version = 1;
412 rct.contentType = ctype;
413 rct.signedContentIdentifier = rr->signedContentIdentifier;
414 rct.originatorSignatureValue = si->signature;
415
416 os = ASN1_item_pack(&rct, ASN1_ITEM_rptr(CMS_Receipt), NULL);
417
418 err:
419 CMS_ReceiptRequest_free(rr);
420 return os;
421 }
422
423 /*
424 * Add signer certificate's V2 digest |sc| to a SignerInfo structure |si|
425 */
426
427 int cms_add1_signing_cert_v2(CMS_SignerInfo *si, ESS_SIGNING_CERT_V2 *sc)
428 {
429 ASN1_STRING *seq = NULL;
430 unsigned char *p, *pp = NULL;
431 int len;
432
433 /* Add SigningCertificateV2 signed attribute to the signer info. */
434 len = i2d_ESS_SIGNING_CERT_V2(sc, NULL);
435 if (len <= 0 || (pp = OPENSSL_malloc(len)) == NULL)
436 goto err;
437 p = pp;
438 i2d_ESS_SIGNING_CERT_V2(sc, &p);
439 if (!(seq = ASN1_STRING_new()) || !ASN1_STRING_set(seq, pp, len))
440 goto err;
441 OPENSSL_free(pp);
442 pp = NULL;
443 if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_signingCertificateV2,
444 V_ASN1_SEQUENCE, seq, -1))
445 goto err;
446 ASN1_STRING_free(seq);
447 return 1;
448 err:
449 CMSerr(CMS_F_CMS_ADD1_SIGNING_CERT_V2, ERR_R_MALLOC_FAILURE);
450 ASN1_STRING_free(seq);
451 OPENSSL_free(pp);
452 return 0;
453 }
454
455 /*
456 * Add signer certificate's digest |sc| to a SignerInfo structure |si|
457 */
458
459 int cms_add1_signing_cert(CMS_SignerInfo *si, ESS_SIGNING_CERT *sc)
460 {
461 ASN1_STRING *seq = NULL;
462 unsigned char *p, *pp = NULL;
463 int len;
464
465 /* Add SigningCertificate signed attribute to the signer info. */
466 len = i2d_ESS_SIGNING_CERT(sc, NULL);
467 if (len <= 0 || (pp = OPENSSL_malloc(len)) == NULL)
468 goto err;
469 p = pp;
470 i2d_ESS_SIGNING_CERT(sc, &p);
471 if (!(seq = ASN1_STRING_new()) || !ASN1_STRING_set(seq, pp, len))
472 goto err;
473 OPENSSL_free(pp);
474 pp = NULL;
475 if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_signingCertificate,
476 V_ASN1_SEQUENCE, seq, -1))
477 goto err;
478 ASN1_STRING_free(seq);
479 return 1;
480 err:
481 CMSerr(CMS_F_CMS_ADD1_SIGNING_CERT, ERR_R_MALLOC_FAILURE);
482 ASN1_STRING_free(seq);
483 OPENSSL_free(pp);
484 return 0;
485 }