]>
Commit | Line | Data |
---|---|---|
0f113f3e | 1 | /* |
4333b89f | 2 | * Copyright 2008-2021 The OpenSSL Project Authors. All Rights Reserved. |
f4cc56f4 | 3 | * |
08ddd302 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
b1322259 RS |
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 | |
f4cc56f4 DSH |
8 | */ |
9 | ||
b39fc560 | 10 | #include "internal/cryptlib.h" |
f4cc56f4 DSH |
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> | |
e85d19c6 | 17 | #include <openssl/ess.h> |
25f2138b | 18 | #include "crypto/ess.h" |
c1669f41 SL |
19 | #include "crypto/x509.h" |
20 | #include "cms_local.h" | |
f4cc56f4 | 21 | |
f4cc56f4 DSH |
22 | IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest) |
23 | ||
e85d19c6 | 24 | /* ESS services */ |
f4cc56f4 DSH |
25 | |
26 | int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr) | |
0f113f3e MC |
27 | { |
28 | ASN1_STRING *str; | |
9e3c510b F |
29 | CMS_ReceiptRequest *rr; |
30 | ASN1_OBJECT *obj = OBJ_nid2obj(NID_id_smime_aa_receiptRequest); | |
31 | ||
32 | if (prr != NULL) | |
0f113f3e | 33 | *prr = NULL; |
9e3c510b F |
34 | str = CMS_signed_get0_data_by_OBJ(si, obj, -3, V_ASN1_SEQUENCE); |
35 | if (str == NULL) | |
0f113f3e MC |
36 | return 0; |
37 | ||
38 | rr = ASN1_item_unpack(str, ASN1_ITEM_rptr(CMS_ReceiptRequest)); | |
9e3c510b | 39 | if (rr == NULL) |
0f113f3e | 40 | return -1; |
9e3c510b | 41 | if (prr != NULL) |
0f113f3e MC |
42 | *prr = rr; |
43 | else | |
44 | CMS_ReceiptRequest_free(rr); | |
45 | return 1; | |
46 | } | |
f4cc56f4 | 47 | |
4189dc37 DDO |
48 | /* |
49 | * Returns 0 if attribute is not found, 1 if found, | |
50 | * or -1 on attribute parsing failure. | |
51 | */ | |
52 | static int ossl_cms_signerinfo_get_signing_cert(const CMS_SignerInfo *si, | |
53 | ESS_SIGNING_CERT **psc) | |
54 | { | |
55 | ASN1_STRING *str; | |
56 | ESS_SIGNING_CERT *sc; | |
57 | ASN1_OBJECT *obj = OBJ_nid2obj(NID_id_smime_aa_signingCertificate); | |
58 | ||
59 | if (psc != NULL) | |
60 | *psc = NULL; | |
61 | str = CMS_signed_get0_data_by_OBJ(si, obj, -3, V_ASN1_SEQUENCE); | |
62 | if (str == NULL) | |
63 | return 0; | |
64 | ||
65 | sc = ASN1_item_unpack(str, ASN1_ITEM_rptr(ESS_SIGNING_CERT)); | |
66 | if (sc == NULL) | |
67 | return -1; | |
68 | if (psc != NULL) | |
69 | *psc = sc; | |
70 | else | |
71 | ESS_SIGNING_CERT_free(sc); | |
72 | return 1; | |
73 | } | |
74 | ||
75 | /* | |
76 | * Returns 0 if attribute is not found, 1 if found, | |
77 | * or -1 on attribute parsing failure. | |
78 | */ | |
79 | static int ossl_cms_signerinfo_get_signing_cert_v2(const CMS_SignerInfo *si, | |
80 | ESS_SIGNING_CERT_V2 **psc) | |
81 | { | |
82 | ASN1_STRING *str; | |
83 | ESS_SIGNING_CERT_V2 *sc; | |
84 | ASN1_OBJECT *obj = OBJ_nid2obj(NID_id_smime_aa_signingCertificateV2); | |
85 | ||
86 | if (psc != NULL) | |
87 | *psc = NULL; | |
88 | str = CMS_signed_get0_data_by_OBJ(si, obj, -3, V_ASN1_SEQUENCE); | |
89 | if (str == NULL) | |
90 | return 0; | |
91 | ||
92 | sc = ASN1_item_unpack(str, ASN1_ITEM_rptr(ESS_SIGNING_CERT_V2)); | |
93 | if (sc == NULL) | |
94 | return -1; | |
95 | if (psc != NULL) | |
96 | *psc = sc; | |
97 | else | |
98 | ESS_SIGNING_CERT_V2_free(sc); | |
99 | return 1; | |
100 | } | |
101 | ||
63b64f19 DDO |
102 | int ossl_cms_check_signing_certs(const CMS_SignerInfo *si, |
103 | const STACK_OF(X509) *chain) | |
9e3c510b F |
104 | { |
105 | ESS_SIGNING_CERT *ss = NULL; | |
106 | ESS_SIGNING_CERT_V2 *ssv2 = NULL; | |
63b64f19 DDO |
107 | int ret = ossl_cms_signerinfo_get_signing_cert(si, &ss) >= 0 |
108 | && ossl_cms_signerinfo_get_signing_cert_v2(si, &ssv2) >= 0 | |
1751768c | 109 | && OSSL_ESS_check_signing_certs(ss, ssv2, chain, 1) > 0; |
9e3c510b F |
110 | |
111 | ESS_SIGNING_CERT_free(ss); | |
112 | ESS_SIGNING_CERT_V2_free(ssv2); | |
113 | return ret; | |
114 | } | |
115 | ||
d8652be0 | 116 | CMS_ReceiptRequest *CMS_ReceiptRequest_create0_ex( |
c1669f41 SL |
117 | unsigned char *id, int idlen, int allorfirst, |
118 | STACK_OF(GENERAL_NAMES) *receiptList, STACK_OF(GENERAL_NAMES) *receiptsTo, | |
078fa35c | 119 | OSSL_LIB_CTX *libctx) |
0f113f3e | 120 | { |
9e3c510b | 121 | CMS_ReceiptRequest *rr; |
0f113f3e MC |
122 | |
123 | rr = CMS_ReceiptRequest_new(); | |
90945fa3 | 124 | if (rr == NULL) |
0f113f3e MC |
125 | goto merr; |
126 | if (id) | |
127 | ASN1_STRING_set0(rr->signedContentIdentifier, id, idlen); | |
128 | else { | |
129 | if (!ASN1_STRING_set(rr->signedContentIdentifier, NULL, 32)) | |
130 | goto merr; | |
c1669f41 | 131 | if (RAND_bytes_ex(libctx, rr->signedContentIdentifier->data, 32) <= 0) |
0f113f3e MC |
132 | goto err; |
133 | } | |
134 | ||
135 | sk_GENERAL_NAMES_pop_free(rr->receiptsTo, GENERAL_NAMES_free); | |
136 | rr->receiptsTo = receiptsTo; | |
137 | ||
c1669f41 | 138 | if (receiptList != NULL) { |
0f113f3e MC |
139 | rr->receiptsFrom->type = 1; |
140 | rr->receiptsFrom->d.receiptList = receiptList; | |
141 | } else { | |
142 | rr->receiptsFrom->type = 0; | |
143 | rr->receiptsFrom->d.allOrFirstTier = allorfirst; | |
144 | } | |
145 | ||
146 | return rr; | |
147 | ||
148 | merr: | |
9311d0c4 | 149 | ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE); |
0f113f3e MC |
150 | |
151 | err: | |
25aaa98a | 152 | CMS_ReceiptRequest_free(rr); |
0f113f3e MC |
153 | return NULL; |
154 | ||
155 | } | |
f5e2354c | 156 | |
c1669f41 SL |
157 | CMS_ReceiptRequest *CMS_ReceiptRequest_create0( |
158 | unsigned char *id, int idlen, int allorfirst, | |
159 | STACK_OF(GENERAL_NAMES) *receiptList, STACK_OF(GENERAL_NAMES) *receiptsTo) | |
160 | { | |
d8652be0 | 161 | return CMS_ReceiptRequest_create0_ex(id, idlen, allorfirst, receiptList, |
078fa35c | 162 | receiptsTo, NULL); |
c1669f41 SL |
163 | } |
164 | ||
f5e2354c | 165 | int CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr) |
0f113f3e MC |
166 | { |
167 | unsigned char *rrder = NULL; | |
168 | int rrderlen, r = 0; | |
f5e2354c | 169 | |
0f113f3e MC |
170 | rrderlen = i2d_CMS_ReceiptRequest(rr, &rrder); |
171 | if (rrderlen < 0) | |
172 | goto merr; | |
f5e2354c | 173 | |
0f113f3e MC |
174 | if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_receiptRequest, |
175 | V_ASN1_SEQUENCE, rrder, rrderlen)) | |
176 | goto merr; | |
f5e2354c | 177 | |
0f113f3e | 178 | r = 1; |
f5e2354c | 179 | |
0f113f3e MC |
180 | merr: |
181 | if (!r) | |
9311d0c4 | 182 | ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE); |
f5e2354c | 183 | |
b548a1f1 | 184 | OPENSSL_free(rrder); |
f4cc56f4 | 185 | |
0f113f3e MC |
186 | return r; |
187 | ||
188 | } | |
f4cc56f4 DSH |
189 | |
190 | void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr, | |
0f113f3e MC |
191 | ASN1_STRING **pcid, |
192 | int *pallorfirst, | |
193 | STACK_OF(GENERAL_NAMES) **plist, | |
194 | STACK_OF(GENERAL_NAMES) **prto) | |
195 | { | |
c1669f41 | 196 | if (pcid != NULL) |
0f113f3e MC |
197 | *pcid = rr->signedContentIdentifier; |
198 | if (rr->receiptsFrom->type == 0) { | |
c1669f41 | 199 | if (pallorfirst != NULL) |
0f113f3e | 200 | *pallorfirst = (int)rr->receiptsFrom->d.allOrFirstTier; |
c1669f41 | 201 | if (plist != NULL) |
0f113f3e MC |
202 | *plist = NULL; |
203 | } else { | |
c1669f41 | 204 | if (pallorfirst != NULL) |
0f113f3e | 205 | *pallorfirst = -1; |
c1669f41 | 206 | if (plist != NULL) |
0f113f3e MC |
207 | *plist = rr->receiptsFrom->d.receiptList; |
208 | } | |
c1669f41 | 209 | if (prto != NULL) |
0f113f3e MC |
210 | *prto = rr->receiptsTo; |
211 | } | |
f4cc56f4 | 212 | |
36309aa2 DSH |
213 | /* Digest a SignerInfo structure for msgSigDigest attribute processing */ |
214 | ||
eb9d8d8c | 215 | static int cms_msgSigDigest(CMS_SignerInfo *si, |
0f113f3e MC |
216 | unsigned char *dig, unsigned int *diglen) |
217 | { | |
c1669f41 | 218 | const EVP_MD *md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm); |
9e3c510b | 219 | |
0f113f3e MC |
220 | if (md == NULL) |
221 | return 0; | |
adf7e6d1 SL |
222 | if (!ossl_asn1_item_digest_ex(ASN1_ITEM_rptr(CMS_Attributes_Verify), md, |
223 | si->signedAttrs, dig, diglen, | |
224 | ossl_cms_ctx_get0_libctx(si->cms_ctx), | |
225 | ossl_cms_ctx_get0_propq(si->cms_ctx))) | |
0f113f3e MC |
226 | return 0; |
227 | return 1; | |
228 | } | |
eb9d8d8c | 229 | |
36309aa2 DSH |
230 | /* Add a msgSigDigest attribute to a SignerInfo */ |
231 | ||
53155f1c | 232 | int ossl_cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src) |
0f113f3e MC |
233 | { |
234 | unsigned char dig[EVP_MAX_MD_SIZE]; | |
235 | unsigned int diglen; | |
9e3c510b | 236 | |
0f113f3e | 237 | if (!cms_msgSigDigest(src, dig, &diglen)) { |
9311d0c4 | 238 | ERR_raise(ERR_LIB_CMS, CMS_R_MSGSIGDIGEST_ERROR); |
0f113f3e MC |
239 | return 0; |
240 | } | |
241 | if (!CMS_signed_add1_attr_by_NID(dest, NID_id_smime_aa_msgSigDigest, | |
242 | V_ASN1_OCTET_STRING, dig, diglen)) { | |
9311d0c4 | 243 | ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE); |
0f113f3e MC |
244 | return 0; |
245 | } | |
246 | return 1; | |
247 | } | |
36309aa2 | 248 | |
eb9d8d8c DSH |
249 | /* Verify signed receipt after it has already passed normal CMS verify */ |
250 | ||
53155f1c | 251 | int ossl_cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms) |
0f113f3e MC |
252 | { |
253 | int r = 0, i; | |
254 | CMS_ReceiptRequest *rr = NULL; | |
255 | CMS_Receipt *rct = NULL; | |
256 | STACK_OF(CMS_SignerInfo) *sis, *osis; | |
257 | CMS_SignerInfo *si, *osi = NULL; | |
258 | ASN1_OCTET_STRING *msig, **pcont; | |
259 | ASN1_OBJECT *octype; | |
260 | unsigned char dig[EVP_MAX_MD_SIZE]; | |
261 | unsigned int diglen; | |
262 | ||
263 | /* Get SignerInfos, also checks SignedData content type */ | |
264 | osis = CMS_get0_SignerInfos(req_cms); | |
265 | sis = CMS_get0_SignerInfos(cms); | |
266 | if (!osis || !sis) | |
267 | goto err; | |
268 | ||
269 | if (sk_CMS_SignerInfo_num(sis) != 1) { | |
9311d0c4 | 270 | ERR_raise(ERR_LIB_CMS, CMS_R_NEED_ONE_SIGNER); |
0f113f3e MC |
271 | goto err; |
272 | } | |
273 | ||
274 | /* Check receipt content type */ | |
275 | if (OBJ_obj2nid(CMS_get0_eContentType(cms)) != NID_id_smime_ct_receipt) { | |
9311d0c4 | 276 | ERR_raise(ERR_LIB_CMS, CMS_R_NOT_A_SIGNED_RECEIPT); |
0f113f3e MC |
277 | goto err; |
278 | } | |
279 | ||
280 | /* Extract and decode receipt content */ | |
281 | pcont = CMS_get0_content(cms); | |
12a765a5 | 282 | if (pcont == NULL || *pcont == NULL) { |
9311d0c4 | 283 | ERR_raise(ERR_LIB_CMS, CMS_R_NO_CONTENT); |
0f113f3e MC |
284 | goto err; |
285 | } | |
286 | ||
287 | rct = ASN1_item_unpack(*pcont, ASN1_ITEM_rptr(CMS_Receipt)); | |
288 | ||
289 | if (!rct) { | |
9311d0c4 | 290 | ERR_raise(ERR_LIB_CMS, CMS_R_RECEIPT_DECODE_ERROR); |
0f113f3e MC |
291 | goto err; |
292 | } | |
293 | ||
294 | /* Locate original request */ | |
295 | ||
296 | for (i = 0; i < sk_CMS_SignerInfo_num(osis); i++) { | |
297 | osi = sk_CMS_SignerInfo_value(osis, i); | |
298 | if (!ASN1_STRING_cmp(osi->signature, rct->originatorSignatureValue)) | |
299 | break; | |
300 | } | |
301 | ||
302 | if (i == sk_CMS_SignerInfo_num(osis)) { | |
9311d0c4 | 303 | ERR_raise(ERR_LIB_CMS, CMS_R_NO_MATCHING_SIGNATURE); |
0f113f3e MC |
304 | goto err; |
305 | } | |
306 | ||
307 | si = sk_CMS_SignerInfo_value(sis, 0); | |
308 | ||
309 | /* Get msgSigDigest value and compare */ | |
310 | ||
311 | msig = CMS_signed_get0_data_by_OBJ(si, | |
312 | OBJ_nid2obj | |
313 | (NID_id_smime_aa_msgSigDigest), -3, | |
314 | V_ASN1_OCTET_STRING); | |
315 | ||
316 | if (!msig) { | |
9311d0c4 | 317 | ERR_raise(ERR_LIB_CMS, CMS_R_NO_MSGSIGDIGEST); |
0f113f3e MC |
318 | goto err; |
319 | } | |
320 | ||
321 | if (!cms_msgSigDigest(osi, dig, &diglen)) { | |
9311d0c4 | 322 | ERR_raise(ERR_LIB_CMS, CMS_R_MSGSIGDIGEST_ERROR); |
0f113f3e MC |
323 | goto err; |
324 | } | |
325 | ||
326 | if (diglen != (unsigned int)msig->length) { | |
9311d0c4 | 327 | ERR_raise(ERR_LIB_CMS, CMS_R_MSGSIGDIGEST_WRONG_LENGTH); |
0f113f3e MC |
328 | goto err; |
329 | } | |
330 | ||
331 | if (memcmp(dig, msig->data, diglen)) { | |
9311d0c4 | 332 | ERR_raise(ERR_LIB_CMS, CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE); |
0f113f3e MC |
333 | goto err; |
334 | } | |
335 | ||
336 | /* Compare content types */ | |
337 | ||
338 | octype = CMS_signed_get0_data_by_OBJ(osi, | |
339 | OBJ_nid2obj(NID_pkcs9_contentType), | |
340 | -3, V_ASN1_OBJECT); | |
341 | if (!octype) { | |
9311d0c4 | 342 | ERR_raise(ERR_LIB_CMS, CMS_R_NO_CONTENT_TYPE); |
0f113f3e MC |
343 | goto err; |
344 | } | |
345 | ||
346 | /* Compare details in receipt request */ | |
347 | ||
348 | if (OBJ_cmp(octype, rct->contentType)) { | |
9311d0c4 | 349 | ERR_raise(ERR_LIB_CMS, CMS_R_CONTENT_TYPE_MISMATCH); |
0f113f3e MC |
350 | goto err; |
351 | } | |
352 | ||
353 | /* Get original receipt request details */ | |
354 | ||
355 | if (CMS_get1_ReceiptRequest(osi, &rr) <= 0) { | |
9311d0c4 | 356 | ERR_raise(ERR_LIB_CMS, CMS_R_NO_RECEIPT_REQUEST); |
0f113f3e MC |
357 | goto err; |
358 | } | |
359 | ||
360 | if (ASN1_STRING_cmp(rr->signedContentIdentifier, | |
361 | rct->signedContentIdentifier)) { | |
9311d0c4 | 362 | ERR_raise(ERR_LIB_CMS, CMS_R_CONTENTIDENTIFIER_MISMATCH); |
0f113f3e MC |
363 | goto err; |
364 | } | |
365 | ||
366 | r = 1; | |
367 | ||
368 | err: | |
25aaa98a | 369 | CMS_ReceiptRequest_free(rr); |
2ace7450 | 370 | M_ASN1_free_of(rct, CMS_Receipt); |
0f113f3e MC |
371 | return r; |
372 | ||
373 | } | |
374 | ||
375 | /* | |
376 | * Encode a Receipt into an OCTET STRING read for including into content of a | |
377 | * SignedData ContentInfo. | |
36309aa2 DSH |
378 | */ |
379 | ||
53155f1c | 380 | ASN1_OCTET_STRING *ossl_cms_encode_Receipt(CMS_SignerInfo *si) |
0f113f3e MC |
381 | { |
382 | CMS_Receipt rct; | |
383 | CMS_ReceiptRequest *rr = NULL; | |
384 | ASN1_OBJECT *ctype; | |
385 | ASN1_OCTET_STRING *os = NULL; | |
36309aa2 | 386 | |
0f113f3e | 387 | /* Get original receipt request */ |
36309aa2 | 388 | |
0f113f3e | 389 | /* Get original receipt request details */ |
36309aa2 | 390 | |
0f113f3e | 391 | if (CMS_get1_ReceiptRequest(si, &rr) <= 0) { |
9311d0c4 | 392 | ERR_raise(ERR_LIB_CMS, CMS_R_NO_RECEIPT_REQUEST); |
0f113f3e MC |
393 | goto err; |
394 | } | |
36309aa2 | 395 | |
0f113f3e | 396 | /* Get original content type */ |
36309aa2 | 397 | |
0f113f3e MC |
398 | ctype = CMS_signed_get0_data_by_OBJ(si, |
399 | OBJ_nid2obj(NID_pkcs9_contentType), | |
400 | -3, V_ASN1_OBJECT); | |
401 | if (!ctype) { | |
9311d0c4 | 402 | ERR_raise(ERR_LIB_CMS, CMS_R_NO_CONTENT_TYPE); |
0f113f3e MC |
403 | goto err; |
404 | } | |
36309aa2 | 405 | |
0f113f3e MC |
406 | rct.version = 1; |
407 | rct.contentType = ctype; | |
408 | rct.signedContentIdentifier = rr->signedContentIdentifier; | |
409 | rct.originatorSignatureValue = si->signature; | |
36309aa2 | 410 | |
0f113f3e | 411 | os = ASN1_item_pack(&rct, ASN1_ITEM_rptr(CMS_Receipt), NULL); |
36309aa2 | 412 | |
0f113f3e | 413 | err: |
25aaa98a | 414 | CMS_ReceiptRequest_free(rr); |
0f113f3e | 415 | return os; |
0f113f3e | 416 | } |