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