]>
Commit | Line | Data |
---|---|---|
0f113f3e | 1 | /* |
83cf7abf | 2 | * Copyright 2008-2018 The OpenSSL Project Authors. All Rights Reserved. |
8931b30d | 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 | |
8931b30d DSH |
8 | */ |
9 | ||
b39fc560 | 10 | #include "internal/cryptlib.h" |
8931b30d DSH |
11 | #include <openssl/asn1t.h> |
12 | #include <openssl/x509.h> | |
13 | #include <openssl/x509v3.h> | |
14 | #include <openssl/err.h> | |
15 | #include <openssl/cms.h> | |
16 | #include "cms_lcl.h" | |
25f2138b | 17 | #include "crypto/asn1.h" |
8931b30d | 18 | |
cd30f03a | 19 | static BIO *cms_get_text_bio(BIO *out, unsigned int flags) |
0f113f3e MC |
20 | { |
21 | BIO *rbio; | |
22 | if (out == NULL) | |
23 | rbio = BIO_new(BIO_s_null()); | |
24 | else if (flags & CMS_TEXT) { | |
25 | rbio = BIO_new(BIO_s_mem()); | |
26 | BIO_set_mem_eof_return(rbio, 0); | |
27 | } else | |
28 | rbio = out; | |
29 | return rbio; | |
30 | } | |
cd30f03a DSH |
31 | |
32 | static int cms_copy_content(BIO *out, BIO *in, unsigned int flags) | |
0f113f3e MC |
33 | { |
34 | unsigned char buf[4096]; | |
35 | int r = 0, i; | |
36 | BIO *tmpout; | |
37 | ||
38 | tmpout = cms_get_text_bio(out, flags); | |
39 | ||
90945fa3 | 40 | if (tmpout == NULL) { |
0f113f3e MC |
41 | CMSerr(CMS_F_CMS_COPY_CONTENT, ERR_R_MALLOC_FAILURE); |
42 | goto err; | |
43 | } | |
44 | ||
45 | /* Read all content through chain to process digest, decrypt etc */ | |
46 | for (;;) { | |
47 | i = BIO_read(in, buf, sizeof(buf)); | |
48 | if (i <= 0) { | |
49 | if (BIO_method_type(in) == BIO_TYPE_CIPHER) { | |
50 | if (!BIO_get_cipher_status(in)) | |
51 | goto err; | |
52 | } | |
53 | if (i < 0) | |
54 | goto err; | |
55 | break; | |
56 | } | |
57 | ||
58 | if (tmpout && (BIO_write(tmpout, buf, i) != i)) | |
59 | goto err; | |
60 | } | |
61 | ||
62 | if (flags & CMS_TEXT) { | |
63 | if (!SMIME_text(tmpout, out)) { | |
64 | CMSerr(CMS_F_CMS_COPY_CONTENT, CMS_R_SMIME_TEXT_ERROR); | |
65 | goto err; | |
66 | } | |
67 | } | |
68 | ||
69 | r = 1; | |
70 | ||
71 | err: | |
ca3a82c3 | 72 | if (tmpout != out) |
0f113f3e MC |
73 | BIO_free(tmpout); |
74 | return r; | |
75 | ||
76 | } | |
8931b30d | 77 | |
4f1aa191 | 78 | static int check_content(CMS_ContentInfo *cms) |
0f113f3e MC |
79 | { |
80 | ASN1_OCTET_STRING **pos = CMS_get0_content(cms); | |
81 | if (!pos || !*pos) { | |
82 | CMSerr(CMS_F_CHECK_CONTENT, CMS_R_NO_CONTENT); | |
83 | return 0; | |
84 | } | |
85 | return 1; | |
86 | } | |
4f1aa191 | 87 | |
852bd350 | 88 | static void do_free_upto(BIO *f, BIO *upto) |
0f113f3e MC |
89 | { |
90 | if (upto) { | |
91 | BIO *tbio; | |
92 | do { | |
93 | tbio = BIO_pop(f); | |
94 | BIO_free(f); | |
95 | f = tbio; | |
96 | } | |
97 | while (f && f != upto); | |
98 | } else | |
99 | BIO_free_all(f); | |
100 | } | |
852bd350 | 101 | |
8931b30d | 102 | int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags) |
0f113f3e MC |
103 | { |
104 | BIO *cont; | |
105 | int r; | |
106 | if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_data) { | |
107 | CMSerr(CMS_F_CMS_DATA, CMS_R_TYPE_NOT_DATA); | |
108 | return 0; | |
109 | } | |
110 | cont = CMS_dataInit(cms, NULL); | |
111 | if (!cont) | |
112 | return 0; | |
113 | r = cms_copy_content(out, cont, flags); | |
114 | BIO_free_all(cont); | |
115 | return r; | |
116 | } | |
8931b30d DSH |
117 | |
118 | CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags) | |
0f113f3e MC |
119 | { |
120 | CMS_ContentInfo *cms; | |
121 | cms = cms_Data_create(); | |
122 | if (!cms) | |
123 | return NULL; | |
8931b30d | 124 | |
0f113f3e MC |
125 | if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) |
126 | return cms; | |
8931b30d | 127 | |
0f113f3e | 128 | CMS_ContentInfo_free(cms); |
8931b30d | 129 | |
0f113f3e MC |
130 | return NULL; |
131 | } | |
8931b30d DSH |
132 | |
133 | int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out, | |
0f113f3e MC |
134 | unsigned int flags) |
135 | { | |
136 | BIO *cont; | |
137 | int r; | |
138 | if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_digest) { | |
139 | CMSerr(CMS_F_CMS_DIGEST_VERIFY, CMS_R_TYPE_NOT_DIGESTED_DATA); | |
140 | return 0; | |
141 | } | |
142 | ||
143 | if (!dcont && !check_content(cms)) | |
144 | return 0; | |
145 | ||
146 | cont = CMS_dataInit(cms, dcont); | |
147 | if (!cont) | |
148 | return 0; | |
149 | r = cms_copy_content(out, cont, flags); | |
150 | if (r) | |
151 | r = cms_DigestedData_do_final(cms, cont, 1); | |
152 | do_free_upto(cont, dcont); | |
153 | return r; | |
154 | } | |
8931b30d DSH |
155 | |
156 | CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md, | |
0f113f3e MC |
157 | unsigned int flags) |
158 | { | |
159 | CMS_ContentInfo *cms; | |
160 | if (!md) | |
161 | md = EVP_sha1(); | |
162 | cms = cms_DigestedData_create(md); | |
163 | if (!cms) | |
164 | return NULL; | |
8931b30d | 165 | |
0f113f3e MC |
166 | if (!(flags & CMS_DETACHED)) |
167 | CMS_set_detached(cms, 0); | |
8931b30d | 168 | |
0f113f3e MC |
169 | if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) |
170 | return cms; | |
8931b30d | 171 | |
0f113f3e MC |
172 | CMS_ContentInfo_free(cms); |
173 | return NULL; | |
174 | } | |
8931b30d | 175 | |
b820455c | 176 | int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms, |
0f113f3e MC |
177 | const unsigned char *key, size_t keylen, |
178 | BIO *dcont, BIO *out, unsigned int flags) | |
179 | { | |
180 | BIO *cont; | |
181 | int r; | |
182 | if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_encrypted) { | |
183 | CMSerr(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT, | |
184 | CMS_R_TYPE_NOT_ENCRYPTED_DATA); | |
185 | return 0; | |
186 | } | |
187 | ||
188 | if (!dcont && !check_content(cms)) | |
189 | return 0; | |
190 | ||
191 | if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0) | |
192 | return 0; | |
193 | cont = CMS_dataInit(cms, dcont); | |
194 | if (!cont) | |
195 | return 0; | |
196 | r = cms_copy_content(out, cont, flags); | |
197 | do_free_upto(cont, dcont); | |
198 | return r; | |
199 | } | |
b820455c | 200 | |
320bfc1b | 201 | CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher, |
0f113f3e MC |
202 | const unsigned char *key, |
203 | size_t keylen, unsigned int flags) | |
204 | { | |
205 | CMS_ContentInfo *cms; | |
206 | if (!cipher) { | |
207 | CMSerr(CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT, CMS_R_NO_CIPHER); | |
208 | return NULL; | |
209 | } | |
210 | cms = CMS_ContentInfo_new(); | |
90945fa3 | 211 | if (cms == NULL) |
0f113f3e MC |
212 | return NULL; |
213 | if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen)) | |
214 | return NULL; | |
215 | ||
216 | if (!(flags & CMS_DETACHED)) | |
217 | CMS_set_detached(cms, 0); | |
218 | ||
219 | if ((flags & (CMS_STREAM | CMS_PARTIAL)) | |
220 | || CMS_final(cms, in, NULL, flags)) | |
221 | return cms; | |
222 | ||
223 | CMS_ContentInfo_free(cms); | |
224 | return NULL; | |
225 | } | |
320bfc1b | 226 | |
8931b30d | 227 | static int cms_signerinfo_verify_cert(CMS_SignerInfo *si, |
0f113f3e MC |
228 | X509_STORE *store, |
229 | STACK_OF(X509) *certs, | |
a773b52a | 230 | STACK_OF(X509_CRL) *crls) |
0f113f3e | 231 | { |
f0e0fd51 | 232 | X509_STORE_CTX *ctx = X509_STORE_CTX_new(); |
0f113f3e MC |
233 | X509 *signer; |
234 | int i, j, r = 0; | |
f0e0fd51 RS |
235 | |
236 | if (ctx == NULL) { | |
237 | CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, ERR_R_MALLOC_FAILURE); | |
238 | goto err; | |
239 | } | |
0f113f3e | 240 | CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL); |
f0e0fd51 | 241 | if (!X509_STORE_CTX_init(ctx, store, signer, certs)) { |
0f113f3e MC |
242 | CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, CMS_R_STORE_INIT_ERROR); |
243 | goto err; | |
244 | } | |
f0e0fd51 | 245 | X509_STORE_CTX_set_default(ctx, "smime_sign"); |
0f113f3e | 246 | if (crls) |
f0e0fd51 | 247 | X509_STORE_CTX_set0_crls(ctx, crls); |
0f113f3e | 248 | |
f0e0fd51 | 249 | i = X509_verify_cert(ctx); |
0f113f3e | 250 | if (i <= 0) { |
f0e0fd51 | 251 | j = X509_STORE_CTX_get_error(ctx); |
0f113f3e MC |
252 | CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, |
253 | CMS_R_CERTIFICATE_VERIFY_ERROR); | |
254 | ERR_add_error_data(2, "Verify error:", | |
255 | X509_verify_cert_error_string(j)); | |
256 | goto err; | |
257 | } | |
258 | r = 1; | |
259 | err: | |
f0e0fd51 | 260 | X509_STORE_CTX_free(ctx); |
0f113f3e MC |
261 | return r; |
262 | ||
263 | } | |
8931b30d DSH |
264 | |
265 | int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, | |
0f113f3e MC |
266 | X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags) |
267 | { | |
268 | CMS_SignerInfo *si; | |
269 | STACK_OF(CMS_SignerInfo) *sinfos; | |
270 | STACK_OF(X509) *cms_certs = NULL; | |
271 | STACK_OF(X509_CRL) *crls = NULL; | |
272 | X509 *signer; | |
273 | int i, scount = 0, ret = 0; | |
274 | BIO *cmsbio = NULL, *tmpin = NULL, *tmpout = NULL; | |
275 | ||
276 | if (!dcont && !check_content(cms)) | |
277 | return 0; | |
278 | if (dcont && !(flags & CMS_BINARY)) { | |
279 | const ASN1_OBJECT *coid = CMS_get0_eContentType(cms); | |
280 | if (OBJ_obj2nid(coid) == NID_id_ct_asciiTextWithCRLF) | |
281 | flags |= CMS_ASCIICRLF; | |
282 | } | |
283 | ||
284 | /* Attempt to find all signer certificates */ | |
285 | ||
286 | sinfos = CMS_get0_SignerInfos(cms); | |
287 | ||
288 | if (sk_CMS_SignerInfo_num(sinfos) <= 0) { | |
289 | CMSerr(CMS_F_CMS_VERIFY, CMS_R_NO_SIGNERS); | |
290 | goto err; | |
291 | } | |
292 | ||
293 | for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { | |
294 | si = sk_CMS_SignerInfo_value(sinfos, i); | |
295 | CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL); | |
296 | if (signer) | |
297 | scount++; | |
298 | } | |
299 | ||
300 | if (scount != sk_CMS_SignerInfo_num(sinfos)) | |
301 | scount += CMS_set1_signers_certs(cms, certs, flags); | |
302 | ||
303 | if (scount != sk_CMS_SignerInfo_num(sinfos)) { | |
304 | CMSerr(CMS_F_CMS_VERIFY, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND); | |
305 | goto err; | |
306 | } | |
307 | ||
308 | /* Attempt to verify all signers certs */ | |
309 | ||
310 | if (!(flags & CMS_NO_SIGNER_CERT_VERIFY)) { | |
311 | cms_certs = CMS_get1_certs(cms); | |
312 | if (!(flags & CMS_NOCRL)) | |
313 | crls = CMS_get1_crls(cms); | |
314 | for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { | |
315 | si = sk_CMS_SignerInfo_value(sinfos, i); | |
a773b52a | 316 | if (!cms_signerinfo_verify_cert(si, store, cms_certs, crls)) |
0f113f3e MC |
317 | goto err; |
318 | } | |
319 | } | |
320 | ||
321 | /* Attempt to verify all SignerInfo signed attribute signatures */ | |
322 | ||
323 | if (!(flags & CMS_NO_ATTR_VERIFY)) { | |
324 | for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { | |
325 | si = sk_CMS_SignerInfo_value(sinfos, i); | |
326 | if (CMS_signed_get_attr_count(si) < 0) | |
327 | continue; | |
328 | if (CMS_SignerInfo_verify(si) <= 0) | |
329 | goto err; | |
330 | } | |
331 | } | |
332 | ||
333 | /* | |
334 | * Performance optimization: if the content is a memory BIO then store | |
335 | * its contents in a temporary read only memory BIO. This avoids | |
336 | * potentially large numbers of slow copies of data which will occur when | |
337 | * reading from a read write memory BIO when signatures are calculated. | |
338 | */ | |
339 | ||
340 | if (dcont && (BIO_method_type(dcont) == BIO_TYPE_MEM)) { | |
341 | char *ptr; | |
342 | long len; | |
343 | len = BIO_get_mem_data(dcont, &ptr); | |
344 | tmpin = BIO_new_mem_buf(ptr, len); | |
345 | if (tmpin == NULL) { | |
346 | CMSerr(CMS_F_CMS_VERIFY, ERR_R_MALLOC_FAILURE); | |
7fba8407 | 347 | goto err2; |
0f113f3e MC |
348 | } |
349 | } else | |
350 | tmpin = dcont; | |
351 | /* | |
352 | * If not binary mode and detached generate digests by *writing* through | |
353 | * the BIO. That makes it possible to canonicalise the input. | |
354 | */ | |
355 | if (!(flags & SMIME_BINARY) && dcont) { | |
356 | /* | |
357 | * Create output BIO so we can either handle text or to ensure | |
358 | * included content doesn't override detached content. | |
359 | */ | |
360 | tmpout = cms_get_text_bio(out, flags); | |
361 | if (!tmpout) { | |
362 | CMSerr(CMS_F_CMS_VERIFY, ERR_R_MALLOC_FAILURE); | |
363 | goto err; | |
364 | } | |
365 | cmsbio = CMS_dataInit(cms, tmpout); | |
366 | if (!cmsbio) | |
367 | goto err; | |
368 | /* | |
369 | * Don't use SMIME_TEXT for verify: it adds headers and we want to | |
370 | * remove them. | |
371 | */ | |
372 | SMIME_crlf_copy(dcont, cmsbio, flags & ~SMIME_TEXT); | |
373 | ||
374 | if (flags & CMS_TEXT) { | |
375 | if (!SMIME_text(tmpout, out)) { | |
376 | CMSerr(CMS_F_CMS_VERIFY, CMS_R_SMIME_TEXT_ERROR); | |
377 | goto err; | |
378 | } | |
379 | } | |
380 | } else { | |
381 | cmsbio = CMS_dataInit(cms, tmpin); | |
382 | if (!cmsbio) | |
383 | goto err; | |
384 | ||
385 | if (!cms_copy_content(out, cmsbio, flags)) | |
386 | goto err; | |
387 | ||
388 | } | |
389 | if (!(flags & CMS_NO_CONTENT_VERIFY)) { | |
390 | for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) { | |
391 | si = sk_CMS_SignerInfo_value(sinfos, i); | |
392 | if (CMS_SignerInfo_verify_content(si, cmsbio) <= 0) { | |
393 | CMSerr(CMS_F_CMS_VERIFY, CMS_R_CONTENT_VERIFY_ERROR); | |
394 | goto err; | |
395 | } | |
396 | } | |
397 | } | |
398 | ||
399 | ret = 1; | |
400 | ||
401 | err: | |
402 | if (!(flags & SMIME_BINARY) && dcont) { | |
403 | do_free_upto(cmsbio, tmpout); | |
404 | if (tmpin != dcont) | |
405 | BIO_free(tmpin); | |
406 | } else { | |
0f113f3e MC |
407 | if (dcont && (tmpin == dcont)) |
408 | do_free_upto(cmsbio, dcont); | |
409 | else | |
410 | BIO_free_all(cmsbio); | |
411 | } | |
412 | ||
ca3a82c3 | 413 | if (out != tmpout) |
0f113f3e MC |
414 | BIO_free_all(tmpout); |
415 | ||
7fba8407 | 416 | err2: |
222561fe RS |
417 | sk_X509_pop_free(cms_certs, X509_free); |
418 | sk_X509_CRL_pop_free(crls, X509_CRL_free); | |
0f113f3e MC |
419 | |
420 | return ret; | |
421 | } | |
8931b30d | 422 | |
eb9d8d8c | 423 | int CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms, |
0f113f3e MC |
424 | STACK_OF(X509) *certs, |
425 | X509_STORE *store, unsigned int flags) | |
426 | { | |
427 | int r; | |
428 | flags &= ~(CMS_DETACHED | CMS_TEXT); | |
429 | r = CMS_verify(rcms, certs, store, NULL, NULL, flags); | |
430 | if (r <= 0) | |
431 | return r; | |
432 | return cms_Receipt_verify(rcms, ocms); | |
433 | } | |
434 | ||
435 | CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, | |
436 | STACK_OF(X509) *certs, BIO *data, | |
437 | unsigned int flags) | |
438 | { | |
439 | CMS_ContentInfo *cms; | |
440 | int i; | |
441 | ||
442 | cms = CMS_ContentInfo_new(); | |
90945fa3 | 443 | if (cms == NULL || !CMS_SignedData_init(cms)) |
0f113f3e MC |
444 | goto merr; |
445 | if (flags & CMS_ASCIICRLF | |
446 | && !CMS_set1_eContentType(cms, | |
447 | OBJ_nid2obj(NID_id_ct_asciiTextWithCRLF))) | |
448 | goto err; | |
449 | ||
450 | if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags)) { | |
451 | CMSerr(CMS_F_CMS_SIGN, CMS_R_ADD_SIGNER_ERROR); | |
452 | goto err; | |
453 | } | |
454 | ||
455 | for (i = 0; i < sk_X509_num(certs); i++) { | |
456 | X509 *x = sk_X509_value(certs, i); | |
457 | if (!CMS_add1_cert(cms, x)) | |
458 | goto merr; | |
459 | } | |
460 | ||
461 | if (!(flags & CMS_DETACHED)) | |
462 | CMS_set_detached(cms, 0); | |
463 | ||
464 | if ((flags & (CMS_STREAM | CMS_PARTIAL)) | |
465 | || CMS_final(cms, data, NULL, flags)) | |
466 | return cms; | |
467 | else | |
468 | goto err; | |
469 | ||
470 | merr: | |
471 | CMSerr(CMS_F_CMS_SIGN, ERR_R_MALLOC_FAILURE); | |
472 | ||
473 | err: | |
25aaa98a | 474 | CMS_ContentInfo_free(cms); |
0f113f3e MC |
475 | return NULL; |
476 | } | |
8931b30d | 477 | |
36309aa2 | 478 | CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si, |
0f113f3e MC |
479 | X509 *signcert, EVP_PKEY *pkey, |
480 | STACK_OF(X509) *certs, unsigned int flags) | |
481 | { | |
482 | CMS_SignerInfo *rct_si; | |
483 | CMS_ContentInfo *cms = NULL; | |
484 | ASN1_OCTET_STRING **pos, *os; | |
485 | BIO *rct_cont = NULL; | |
486 | int r = 0; | |
487 | ||
488 | flags &= ~(CMS_STREAM | CMS_TEXT); | |
489 | /* Not really detached but avoids content being allocated */ | |
490 | flags |= CMS_PARTIAL | CMS_BINARY | CMS_DETACHED; | |
491 | if (!pkey || !signcert) { | |
492 | CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_NO_KEY_OR_CERT); | |
493 | return NULL; | |
494 | } | |
495 | ||
496 | /* Initialize signed data */ | |
497 | ||
498 | cms = CMS_sign(NULL, NULL, certs, NULL, flags); | |
499 | if (!cms) | |
500 | goto err; | |
501 | ||
502 | /* Set inner content type to signed receipt */ | |
503 | if (!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_smime_ct_receipt))) | |
504 | goto err; | |
505 | ||
506 | rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags); | |
507 | if (!rct_si) { | |
508 | CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_ADD_SIGNER_ERROR); | |
509 | goto err; | |
510 | } | |
511 | ||
512 | os = cms_encode_Receipt(si); | |
513 | ||
514 | if (!os) | |
515 | goto err; | |
516 | ||
517 | /* Set content to digest */ | |
518 | rct_cont = BIO_new_mem_buf(os->data, os->length); | |
519 | if (!rct_cont) | |
520 | goto err; | |
521 | ||
522 | /* Add msgSigDigest attribute */ | |
523 | ||
524 | if (!cms_msgSigDigest_add1(rct_si, si)) | |
525 | goto err; | |
526 | ||
527 | /* Finalize structure */ | |
528 | if (!CMS_final(cms, rct_cont, NULL, flags)) | |
529 | goto err; | |
530 | ||
531 | /* Set embedded content */ | |
532 | pos = CMS_get0_content(cms); | |
533 | *pos = os; | |
534 | ||
535 | r = 1; | |
536 | ||
537 | err: | |
ca3a82c3 | 538 | BIO_free(rct_cont); |
0f113f3e MC |
539 | if (r) |
540 | return cms; | |
541 | CMS_ContentInfo_free(cms); | |
542 | return NULL; | |
543 | ||
544 | } | |
36309aa2 | 545 | |
761ffa72 | 546 | CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data, |
0f113f3e MC |
547 | const EVP_CIPHER *cipher, unsigned int flags) |
548 | { | |
549 | CMS_ContentInfo *cms; | |
550 | int i; | |
551 | X509 *recip; | |
552 | cms = CMS_EnvelopedData_create(cipher); | |
553 | if (!cms) | |
554 | goto merr; | |
555 | for (i = 0; i < sk_X509_num(certs); i++) { | |
556 | recip = sk_X509_value(certs, i); | |
557 | if (!CMS_add1_recipient_cert(cms, recip, flags)) { | |
558 | CMSerr(CMS_F_CMS_ENCRYPT, CMS_R_RECIPIENT_ERROR); | |
559 | goto err; | |
560 | } | |
561 | } | |
562 | ||
563 | if (!(flags & CMS_DETACHED)) | |
564 | CMS_set_detached(cms, 0); | |
565 | ||
566 | if ((flags & (CMS_STREAM | CMS_PARTIAL)) | |
567 | || CMS_final(cms, data, NULL, flags)) | |
568 | return cms; | |
569 | else | |
570 | goto err; | |
571 | ||
572 | merr: | |
573 | CMSerr(CMS_F_CMS_ENCRYPT, ERR_R_MALLOC_FAILURE); | |
574 | err: | |
25aaa98a | 575 | CMS_ContentInfo_free(cms); |
0f113f3e MC |
576 | return NULL; |
577 | } | |
eeb9cdfc | 578 | |
17c2764d | 579 | static int cms_kari_set1_pkey(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, |
0f113f3e MC |
580 | EVP_PKEY *pk, X509 *cert) |
581 | { | |
582 | int i; | |
583 | STACK_OF(CMS_RecipientEncryptedKey) *reks; | |
584 | CMS_RecipientEncryptedKey *rek; | |
585 | reks = CMS_RecipientInfo_kari_get0_reks(ri); | |
0f113f3e MC |
586 | for (i = 0; i < sk_CMS_RecipientEncryptedKey_num(reks); i++) { |
587 | int rv; | |
588 | rek = sk_CMS_RecipientEncryptedKey_value(reks, i); | |
3f1d1704 | 589 | if (cert != NULL && CMS_RecipientEncryptedKey_cert_cmp(rek, cert)) |
0f113f3e MC |
590 | continue; |
591 | CMS_RecipientInfo_kari_set0_pkey(ri, pk); | |
592 | rv = CMS_RecipientInfo_kari_decrypt(cms, ri, rek); | |
593 | CMS_RecipientInfo_kari_set0_pkey(ri, NULL); | |
594 | if (rv > 0) | |
595 | return 1; | |
3f1d1704 | 596 | return cert == NULL ? 0 : -1; |
0f113f3e MC |
597 | } |
598 | return 0; | |
599 | } | |
17c2764d | 600 | |
eeb9cdfc | 601 | int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert) |
0f113f3e MC |
602 | { |
603 | STACK_OF(CMS_RecipientInfo) *ris; | |
604 | CMS_RecipientInfo *ri; | |
605 | int i, r, ri_type; | |
606 | int debug = 0, match_ri = 0; | |
607 | ris = CMS_get0_RecipientInfos(cms); | |
608 | if (ris) | |
609 | debug = cms->d.envelopedData->encryptedContentInfo->debug; | |
610 | ri_type = cms_pkey_get_ri_type(pk); | |
611 | if (ri_type == CMS_RECIPINFO_NONE) { | |
612 | CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, | |
613 | CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); | |
614 | return 0; | |
615 | } | |
616 | ||
617 | for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { | |
618 | ri = sk_CMS_RecipientInfo_value(ris, i); | |
619 | if (CMS_RecipientInfo_type(ri) != ri_type) | |
620 | continue; | |
621 | match_ri = 1; | |
622 | if (ri_type == CMS_RECIPINFO_AGREE) { | |
623 | r = cms_kari_set1_pkey(cms, ri, pk, cert); | |
624 | if (r > 0) | |
625 | return 1; | |
626 | if (r < 0) | |
627 | return 0; | |
628 | } | |
629 | /* | |
630 | * If we have a cert try matching RecipientInfo otherwise try them | |
631 | * all. | |
632 | */ | |
633 | else if (!cert || !CMS_RecipientInfo_ktri_cert_cmp(ri, cert)) { | |
3d551b20 | 634 | EVP_PKEY_up_ref(pk); |
0f113f3e MC |
635 | CMS_RecipientInfo_set0_pkey(ri, pk); |
636 | r = CMS_RecipientInfo_decrypt(cms, ri); | |
637 | CMS_RecipientInfo_set0_pkey(ri, NULL); | |
638 | if (cert) { | |
639 | /* | |
640 | * If not debugging clear any error and return success to | |
641 | * avoid leaking of information useful to MMA | |
642 | */ | |
643 | if (!debug) { | |
644 | ERR_clear_error(); | |
645 | return 1; | |
646 | } | |
647 | if (r > 0) | |
648 | return 1; | |
649 | CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_DECRYPT_ERROR); | |
650 | return 0; | |
651 | } | |
652 | /* | |
653 | * If no cert and not debugging don't leave loop after first | |
654 | * successful decrypt. Always attempt to decrypt all recipients | |
655 | * to avoid leaking timing of a successful decrypt. | |
656 | */ | |
657 | else if (r > 0 && debug) | |
658 | return 1; | |
659 | } | |
660 | } | |
3f1d1704 DSH |
661 | /* If no cert, key transport and not debugging always return success */ |
662 | if (cert == NULL && ri_type == CMS_RECIPINFO_TRANS && match_ri && !debug) { | |
0f113f3e MC |
663 | ERR_clear_error(); |
664 | return 1; | |
665 | } | |
666 | ||
667 | CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT); | |
668 | return 0; | |
669 | ||
670 | } | |
671 | ||
672 | int CMS_decrypt_set1_key(CMS_ContentInfo *cms, | |
673 | unsigned char *key, size_t keylen, | |
c17dd597 | 674 | const unsigned char *id, size_t idlen) |
0f113f3e MC |
675 | { |
676 | STACK_OF(CMS_RecipientInfo) *ris; | |
677 | CMS_RecipientInfo *ri; | |
678 | int i, r; | |
679 | ris = CMS_get0_RecipientInfos(cms); | |
680 | for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { | |
681 | ri = sk_CMS_RecipientInfo_value(ris, i); | |
682 | if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_KEK) | |
683 | continue; | |
684 | ||
685 | /* | |
686 | * If we have an id try matching RecipientInfo otherwise try them | |
687 | * all. | |
688 | */ | |
689 | if (!id || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0)) { | |
690 | CMS_RecipientInfo_set0_key(ri, key, keylen); | |
691 | r = CMS_RecipientInfo_decrypt(cms, ri); | |
692 | CMS_RecipientInfo_set0_key(ri, NULL, 0); | |
693 | if (r > 0) | |
694 | return 1; | |
695 | if (id) { | |
696 | CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_DECRYPT_ERROR); | |
697 | return 0; | |
698 | } | |
699 | ERR_clear_error(); | |
700 | } | |
701 | } | |
702 | ||
703 | CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_NO_MATCHING_RECIPIENT); | |
704 | return 0; | |
705 | ||
706 | } | |
707 | ||
708 | int CMS_decrypt_set1_password(CMS_ContentInfo *cms, | |
709 | unsigned char *pass, ossl_ssize_t passlen) | |
710 | { | |
711 | STACK_OF(CMS_RecipientInfo) *ris; | |
712 | CMS_RecipientInfo *ri; | |
713 | int i, r; | |
714 | ris = CMS_get0_RecipientInfos(cms); | |
715 | for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { | |
716 | ri = sk_CMS_RecipientInfo_value(ris, i); | |
717 | if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_PASS) | |
718 | continue; | |
719 | CMS_RecipientInfo_set0_password(ri, pass, passlen); | |
720 | r = CMS_RecipientInfo_decrypt(cms, ri); | |
721 | CMS_RecipientInfo_set0_password(ri, NULL, 0); | |
722 | if (r > 0) | |
723 | return 1; | |
724 | } | |
725 | ||
726 | CMSerr(CMS_F_CMS_DECRYPT_SET1_PASSWORD, CMS_R_NO_MATCHING_RECIPIENT); | |
727 | return 0; | |
728 | ||
729 | } | |
730 | ||
4f1aa191 | 731 | int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, |
0f113f3e MC |
732 | BIO *dcont, BIO *out, unsigned int flags) |
733 | { | |
734 | int r; | |
735 | BIO *cont; | |
736 | if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped) { | |
737 | CMSerr(CMS_F_CMS_DECRYPT, CMS_R_TYPE_NOT_ENVELOPED_DATA); | |
738 | return 0; | |
739 | } | |
740 | if (!dcont && !check_content(cms)) | |
741 | return 0; | |
742 | if (flags & CMS_DEBUG_DECRYPT) | |
743 | cms->d.envelopedData->encryptedContentInfo->debug = 1; | |
744 | else | |
745 | cms->d.envelopedData->encryptedContentInfo->debug = 0; | |
5840ed0c BE |
746 | if (!cert) |
747 | cms->d.envelopedData->encryptedContentInfo->havenocert = 1; | |
748 | else | |
749 | cms->d.envelopedData->encryptedContentInfo->havenocert = 0; | |
0f113f3e MC |
750 | if (!pk && !cert && !dcont && !out) |
751 | return 1; | |
752 | if (pk && !CMS_decrypt_set1_pkey(cms, pk, cert)) | |
753 | return 0; | |
754 | cont = CMS_dataInit(cms, dcont); | |
755 | if (!cont) | |
756 | return 0; | |
757 | r = cms_copy_content(out, cont, flags); | |
758 | do_free_upto(cont, dcont); | |
759 | return r; | |
760 | } | |
8931b30d | 761 | |
e0fbd073 | 762 | int CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags) |
0f113f3e MC |
763 | { |
764 | BIO *cmsbio; | |
765 | int ret = 0; | |
75ebbd9a RS |
766 | |
767 | if ((cmsbio = CMS_dataInit(cms, dcont)) == NULL) { | |
a187e08d | 768 | CMSerr(CMS_F_CMS_FINAL, CMS_R_CMS_LIB); |
0f113f3e MC |
769 | return 0; |
770 | } | |
8931b30d | 771 | |
0f113f3e | 772 | SMIME_crlf_copy(data, cmsbio, flags); |
8931b30d | 773 | |
0f113f3e | 774 | (void)BIO_flush(cmsbio); |
8931b30d | 775 | |
0f113f3e MC |
776 | if (!CMS_dataFinal(cms, cmsbio)) { |
777 | CMSerr(CMS_F_CMS_FINAL, CMS_R_CMS_DATAFINAL_ERROR); | |
778 | goto err; | |
779 | } | |
8931b30d | 780 | |
0f113f3e | 781 | ret = 1; |
8931b30d | 782 | |
0f113f3e MC |
783 | err: |
784 | do_free_upto(cmsbio, dcont); | |
8931b30d | 785 | |
0f113f3e | 786 | return ret; |
8931b30d | 787 | |
0f113f3e | 788 | } |
8931b30d DSH |
789 | |
790 | #ifdef ZLIB | |
791 | ||
a5db50d0 | 792 | int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, |
0f113f3e MC |
793 | unsigned int flags) |
794 | { | |
795 | BIO *cont; | |
796 | int r; | |
797 | if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_id_smime_ct_compressedData) { | |
798 | CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_TYPE_NOT_COMPRESSED_DATA); | |
799 | return 0; | |
800 | } | |
801 | ||
802 | if (!dcont && !check_content(cms)) | |
803 | return 0; | |
804 | ||
805 | cont = CMS_dataInit(cms, dcont); | |
806 | if (!cont) | |
807 | return 0; | |
808 | r = cms_copy_content(out, cont, flags); | |
809 | do_free_upto(cont, dcont); | |
810 | return r; | |
811 | } | |
8931b30d DSH |
812 | |
813 | CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags) | |
0f113f3e MC |
814 | { |
815 | CMS_ContentInfo *cms; | |
816 | if (comp_nid <= 0) | |
817 | comp_nid = NID_zlib_compression; | |
818 | cms = cms_CompressedData_create(comp_nid); | |
819 | if (!cms) | |
820 | return NULL; | |
8931b30d | 821 | |
0f113f3e MC |
822 | if (!(flags & CMS_DETACHED)) |
823 | CMS_set_detached(cms, 0); | |
8931b30d | 824 | |
0f113f3e MC |
825 | if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags)) |
826 | return cms; | |
8931b30d | 827 | |
0f113f3e MC |
828 | CMS_ContentInfo_free(cms); |
829 | return NULL; | |
830 | } | |
8931b30d DSH |
831 | |
832 | #else | |
833 | ||
834 | int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, | |
0f113f3e MC |
835 | unsigned int flags) |
836 | { | |
837 | CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM); | |
838 | return 0; | |
839 | } | |
8931b30d DSH |
840 | |
841 | CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags) | |
0f113f3e MC |
842 | { |
843 | CMSerr(CMS_F_CMS_COMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM); | |
844 | return NULL; | |
845 | } | |
8931b30d DSH |
846 | |
847 | #endif |