1 | /* |
2 | * Copyright 2008-2019 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 "cms_local.h" |
19 | #include "crypto/ess.h" |
20 | #include "crypto/cms.h" |
21 | |
22 | IMPLEMENT_ASN1_FUNCTIONS(CMS_ReceiptRequest) |
23 | |
24 | /* ESS services */ |
25 | |
26 | int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr) |
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 | } |
48 | |
49 | CMS_ReceiptRequest *CMS_ReceiptRequest_create0(unsigned char *id, int idlen, |
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(); |
58 | if (rr == NULL) |
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; |
65 | if (RAND_bytes(rr->signedContentIdentifier->data, 32) <= 0) |
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: |
86 | CMS_ReceiptRequest_free(rr); |
87 | return NULL; |
88 | |
89 | } |
90 | |
91 | int CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr) |
92 | { |
93 | unsigned char *rrder = NULL; |
94 | int rrderlen, r = 0; |
95 | |
96 | rrderlen = i2d_CMS_ReceiptRequest(rr, &rrder); |
97 | if (rrderlen < 0) |
98 | goto merr; |
99 | |
100 | if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_receiptRequest, |
101 | V_ASN1_SEQUENCE, rrder, rrderlen)) |
102 | goto merr; |
103 | |
104 | r = 1; |
105 | |
106 | merr: |
107 | if (!r) |
108 | CMSerr(CMS_F_CMS_ADD1_RECEIPTREQUEST, ERR_R_MALLOC_FAILURE); |
109 | |
110 | OPENSSL_free(rrder); |
111 | |
112 | return r; |
113 | |
114 | } |
115 | |
116 | void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr, |
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 | } |
138 | |
139 | /* Digest a SignerInfo structure for msgSigDigest attribute processing */ |
140 | |
141 | static int cms_msgSigDigest(CMS_SignerInfo *si, |
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 | } |
153 | |
154 | /* Add a msgSigDigest attribute to a SignerInfo */ |
155 | |
156 | int cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src) |
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 | } |
171 | |
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) |
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 == NULL || *pcont == NULL) { |
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: |
293 | CMS_ReceiptRequest_free(rr); |
294 | M_ASN1_free_of(rct, CMS_Receipt); |
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. |
302 | */ |
303 | |
304 | ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si) |
305 | { |
306 | CMS_Receipt rct; |
307 | CMS_ReceiptRequest *rr = NULL; |
308 | ASN1_OBJECT *ctype; |
309 | ASN1_OCTET_STRING *os = NULL; |
310 | |
311 | /* Get original receipt request */ |
312 | |
313 | /* Get original receipt request details */ |
314 | |
315 | if (CMS_get1_ReceiptRequest(si, &rr) <= 0) { |
316 | CMSerr(CMS_F_CMS_ENCODE_RECEIPT, CMS_R_NO_RECEIPT_REQUEST); |
317 | goto err; |
318 | } |
319 | |
320 | /* Get original content type */ |
321 | |
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 | } |
329 | |
330 | rct.version = 1; |
331 | rct.contentType = ctype; |
332 | rct.signedContentIdentifier = rr->signedContentIdentifier; |
333 | rct.originatorSignatureValue = si->signature; |
334 | |
335 | os = ASN1_item_pack(&rct, ASN1_ITEM_rptr(CMS_Receipt), NULL); |
336 | |
337 | err: |
338 | CMS_ReceiptRequest_free(rr); |
339 | return os; |
340 | } |
341 | |
342 | /* |
343 | * Add signer certificate's V2 digest |sc| to a SignerInfo structure |si| |
344 | */ |
345 | |
346 | int cms_add1_signing_cert_v2(CMS_SignerInfo *si, ESS_SIGNING_CERT_V2 *sc) |
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 | /* |
375 | * Add signer certificate's digest |sc| to a SignerInfo structure |si| |
376 | */ |
377 | |
378 | int cms_add1_signing_cert(CMS_SignerInfo *si, ESS_SIGNING_CERT *sc) |
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 | } |
405 | |