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