|
1 /* smime.c */ |
|
2 /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL |
|
3 * project. |
|
4 */ |
|
5 /* ==================================================================== |
|
6 * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved. |
|
7 * |
|
8 * Redistribution and use in source and binary forms, with or without |
|
9 * modification, are permitted provided that the following conditions |
|
10 * are met: |
|
11 * |
|
12 * 1. Redistributions of source code must retain the above copyright |
|
13 * notice, this list of conditions and the following disclaimer. |
|
14 * |
|
15 * 2. Redistributions in binary form must reproduce the above copyright |
|
16 * notice, this list of conditions and the following disclaimer in |
|
17 * the documentation and/or other materials provided with the |
|
18 * distribution. |
|
19 * |
|
20 * 3. All advertising materials mentioning features or use of this |
|
21 * software must display the following acknowledgment: |
|
22 * "This product includes software developed by the OpenSSL Project |
|
23 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" |
|
24 * |
|
25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to |
|
26 * endorse or promote products derived from this software without |
|
27 * prior written permission. For written permission, please contact |
|
28 * licensing@OpenSSL.org. |
|
29 * |
|
30 * 5. Products derived from this software may not be called "OpenSSL" |
|
31 * nor may "OpenSSL" appear in their names without prior written |
|
32 * permission of the OpenSSL Project. |
|
33 * |
|
34 * 6. Redistributions of any form whatsoever must retain the following |
|
35 * acknowledgment: |
|
36 * "This product includes software developed by the OpenSSL Project |
|
37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" |
|
38 * |
|
39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY |
|
40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR |
|
43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|
45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
|
48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
|
50 * OF THE POSSIBILITY OF SUCH DAMAGE. |
|
51 * ==================================================================== |
|
52 * |
|
53 * This product includes cryptographic software written by Eric Young |
|
54 * (eay@cryptsoft.com). This product includes software written by Tim |
|
55 * Hudson (tjh@cryptsoft.com). |
|
56 * |
|
57 */ |
|
58 |
|
59 /* S/MIME utility function */ |
|
60 |
|
61 #include <stdio.h> |
|
62 #include <string.h> |
|
63 #include "apps.h" |
|
64 #include <openssl/crypto.h> |
|
65 #include <openssl/pem.h> |
|
66 #include <openssl/err.h> |
|
67 #include <openssl/x509_vfy.h> |
|
68 #include <openssl/x509v3.h> |
|
69 |
|
70 #undef PROG |
|
71 #define PROG smime_main |
|
72 static int save_certs(char *signerfile, STACK_OF(X509) *signers); |
|
73 static int smime_cb(int ok, X509_STORE_CTX *ctx); |
|
74 |
|
75 #define SMIME_OP 0x10 |
|
76 #define SMIME_ENCRYPT (1 | SMIME_OP) |
|
77 #define SMIME_DECRYPT 2 |
|
78 #define SMIME_SIGN (3 | SMIME_OP) |
|
79 #define SMIME_VERIFY 4 |
|
80 #define SMIME_PK7OUT 5 |
|
81 |
|
82 |
|
83 int MAIN(int, char **); |
|
84 |
|
85 int MAIN(int argc, char **argv) |
|
86 { |
|
87 ENGINE *e = NULL; |
|
88 int operation = 0; |
|
89 int ret = 0; |
|
90 char **args; |
|
91 const char *inmode = "r", *outmode = "w"; |
|
92 char *infile = NULL, *outfile = NULL; |
|
93 char *signerfile = NULL, *recipfile = NULL; |
|
94 char *certfile = NULL, *keyfile = NULL, *contfile=NULL; |
|
95 const EVP_CIPHER *cipher = NULL; |
|
96 PKCS7 *p7 = NULL; |
|
97 X509_STORE *store = NULL; |
|
98 X509 *cert = NULL, *recip = NULL, *signer = NULL; |
|
99 EVP_PKEY *key = NULL; |
|
100 STACK_OF(X509) *encerts = NULL, *other = NULL; |
|
101 BIO *in = NULL, *out = NULL, *indata = NULL; |
|
102 int badarg = 0; |
|
103 int flags = PKCS7_DETACHED; |
|
104 char *to = NULL, *from = NULL, *subject = NULL; |
|
105 char *CAfile = NULL, *CApath = NULL; |
|
106 char *passargin = NULL, *passin = NULL; |
|
107 char *inrand = NULL; |
|
108 int need_rand = 0; |
|
109 int informat = FORMAT_SMIME, outformat = FORMAT_SMIME; |
|
110 int keyform = FORMAT_PEM; |
|
111 #ifndef OPENSSL_NO_ENGINE |
|
112 char *engine=NULL; |
|
113 #endif |
|
114 |
|
115 X509_VERIFY_PARAM *vpm = NULL; |
|
116 |
|
117 args = argv + 1; |
|
118 ret = 1; |
|
119 |
|
120 apps_startup(); |
|
121 |
|
122 if (bio_err == NULL) |
|
123 { |
|
124 if ((bio_err = BIO_new(BIO_s_file())) != NULL) |
|
125 BIO_set_fp(bio_err, stderr, BIO_NOCLOSE|BIO_FP_TEXT); |
|
126 |
|
127 } |
|
128 |
|
129 if (!load_config(bio_err, NULL)) |
|
130 goto end; |
|
131 |
|
132 while (!badarg && *args && *args[0] == '-') |
|
133 { |
|
134 if (!strcmp (*args, "-encrypt")) |
|
135 operation = SMIME_ENCRYPT; |
|
136 else if (!strcmp (*args, "-decrypt")) |
|
137 operation = SMIME_DECRYPT; |
|
138 else if (!strcmp (*args, "-sign")) |
|
139 operation = SMIME_SIGN; |
|
140 else if (!strcmp (*args, "-verify")) |
|
141 operation = SMIME_VERIFY; |
|
142 else if (!strcmp (*args, "-pk7out")) |
|
143 operation = SMIME_PK7OUT; |
|
144 #ifndef OPENSSL_NO_DES |
|
145 else if (!strcmp (*args, "-des3")) |
|
146 cipher = EVP_des_ede3_cbc(); |
|
147 else if (!strcmp (*args, "-des")) |
|
148 cipher = EVP_des_cbc(); |
|
149 #endif |
|
150 #ifndef OPENSSL_NO_RC2 |
|
151 else if (!strcmp (*args, "-rc2-40")) |
|
152 cipher = EVP_rc2_40_cbc(); |
|
153 else if (!strcmp (*args, "-rc2-128")) |
|
154 cipher = EVP_rc2_cbc(); |
|
155 else if (!strcmp (*args, "-rc2-64")) |
|
156 cipher = EVP_rc2_64_cbc(); |
|
157 #endif |
|
158 #ifndef OPENSSL_NO_AES |
|
159 else if (!strcmp(*args,"-aes128")) |
|
160 cipher = EVP_aes_128_cbc(); |
|
161 else if (!strcmp(*args,"-aes192")) |
|
162 cipher = EVP_aes_192_cbc(); |
|
163 else if (!strcmp(*args,"-aes256")) |
|
164 cipher = EVP_aes_256_cbc(); |
|
165 #endif |
|
166 else if (!strcmp (*args, "-text")) |
|
167 flags |= PKCS7_TEXT; |
|
168 else if (!strcmp (*args, "-nointern")) |
|
169 flags |= PKCS7_NOINTERN; |
|
170 else if (!strcmp (*args, "-noverify")) |
|
171 flags |= PKCS7_NOVERIFY; |
|
172 else if (!strcmp (*args, "-nochain")) |
|
173 flags |= PKCS7_NOCHAIN; |
|
174 else if (!strcmp (*args, "-nocerts")) |
|
175 flags |= PKCS7_NOCERTS; |
|
176 else if (!strcmp (*args, "-noattr")) |
|
177 flags |= PKCS7_NOATTR; |
|
178 else if (!strcmp (*args, "-nodetach")) |
|
179 flags &= ~PKCS7_DETACHED; |
|
180 else if (!strcmp (*args, "-nosmimecap")) |
|
181 flags |= PKCS7_NOSMIMECAP; |
|
182 else if (!strcmp (*args, "-binary")) |
|
183 flags |= PKCS7_BINARY; |
|
184 else if (!strcmp (*args, "-nosigs")) |
|
185 flags |= PKCS7_NOSIGS; |
|
186 else if (!strcmp (*args, "-nooldmime")) |
|
187 flags |= PKCS7_NOOLDMIMETYPE; |
|
188 else if (!strcmp (*args, "-crlfeol")) |
|
189 flags |= PKCS7_CRLFEOL; |
|
190 else if (!strcmp(*args,"-rand")) |
|
191 { |
|
192 if (args[1]) |
|
193 { |
|
194 args++; |
|
195 inrand = *args; |
|
196 } |
|
197 else |
|
198 badarg = 1; |
|
199 need_rand = 1; |
|
200 } |
|
201 #ifndef OPENSSL_NO_ENGINE |
|
202 else if (!strcmp(*args,"-engine")) |
|
203 { |
|
204 if (args[1]) |
|
205 { |
|
206 args++; |
|
207 engine = *args; |
|
208 } |
|
209 else badarg = 1; |
|
210 } |
|
211 #endif |
|
212 else if (!strcmp(*args,"-passin")) |
|
213 { |
|
214 if (args[1]) |
|
215 { |
|
216 args++; |
|
217 passargin = *args; |
|
218 } |
|
219 else |
|
220 badarg = 1; |
|
221 } |
|
222 else if (!strcmp (*args, "-to")) |
|
223 { |
|
224 if (args[1]) |
|
225 { |
|
226 args++; |
|
227 to = *args; |
|
228 } |
|
229 else |
|
230 badarg = 1; |
|
231 } |
|
232 else if (!strcmp (*args, "-from")) |
|
233 { |
|
234 if (args[1]) |
|
235 { |
|
236 args++; |
|
237 from = *args; |
|
238 } |
|
239 else badarg = 1; |
|
240 } |
|
241 else if (!strcmp (*args, "-subject")) |
|
242 { |
|
243 if (args[1]) |
|
244 { |
|
245 args++; |
|
246 subject = *args; |
|
247 } |
|
248 else |
|
249 badarg = 1; |
|
250 } |
|
251 else if (!strcmp (*args, "-signer")) |
|
252 { |
|
253 if (args[1]) |
|
254 { |
|
255 args++; |
|
256 signerfile = *args; |
|
257 } |
|
258 else |
|
259 badarg = 1; |
|
260 } |
|
261 else if (!strcmp (*args, "-recip")) |
|
262 { |
|
263 if (args[1]) |
|
264 { |
|
265 args++; |
|
266 recipfile = *args; |
|
267 } |
|
268 else badarg = 1; |
|
269 } |
|
270 else if (!strcmp (*args, "-inkey")) |
|
271 { |
|
272 if (args[1]) |
|
273 { |
|
274 args++; |
|
275 keyfile = *args; |
|
276 } |
|
277 else |
|
278 badarg = 1; |
|
279 } |
|
280 else if (!strcmp (*args, "-keyform")) |
|
281 { |
|
282 if (args[1]) |
|
283 { |
|
284 args++; |
|
285 keyform = str2fmt(*args); |
|
286 } |
|
287 else |
|
288 badarg = 1; |
|
289 } |
|
290 else if (!strcmp (*args, "-certfile")) |
|
291 { |
|
292 if (args[1]) |
|
293 { |
|
294 args++; |
|
295 certfile = *args; |
|
296 } |
|
297 else |
|
298 badarg = 1; |
|
299 } |
|
300 else if (!strcmp (*args, "-CAfile")) |
|
301 { |
|
302 if (args[1]) |
|
303 { |
|
304 args++; |
|
305 CAfile = *args; |
|
306 } |
|
307 else |
|
308 badarg = 1; |
|
309 } |
|
310 else if (!strcmp (*args, "-CApath")) |
|
311 { |
|
312 if (args[1]) |
|
313 { |
|
314 args++; |
|
315 CApath = *args; |
|
316 } |
|
317 else |
|
318 badarg = 1; |
|
319 } |
|
320 else if (!strcmp (*args, "-in")) |
|
321 { |
|
322 if (args[1]) |
|
323 { |
|
324 args++; |
|
325 infile = *args; |
|
326 } |
|
327 else |
|
328 badarg = 1; |
|
329 } |
|
330 else if (!strcmp (*args, "-inform")) |
|
331 { |
|
332 if (args[1]) |
|
333 { |
|
334 args++; |
|
335 informat = str2fmt(*args); |
|
336 } |
|
337 else |
|
338 badarg = 1; |
|
339 } |
|
340 else if (!strcmp (*args, "-outform")) |
|
341 { |
|
342 if (args[1]) |
|
343 { |
|
344 args++; |
|
345 outformat = str2fmt(*args); |
|
346 } |
|
347 else |
|
348 badarg = 1; |
|
349 } |
|
350 else if (!strcmp (*args, "-out")) |
|
351 { |
|
352 if (args[1]) |
|
353 { |
|
354 args++; |
|
355 outfile = *args; |
|
356 } |
|
357 else |
|
358 badarg = 1; |
|
359 } |
|
360 else if (!strcmp (*args, "-content")) |
|
361 { |
|
362 if (args[1]) |
|
363 { |
|
364 args++; |
|
365 contfile = *args; |
|
366 } |
|
367 else |
|
368 badarg = 1; |
|
369 } |
|
370 else if (args_verify(&args, NULL, &badarg, bio_err, &vpm)) |
|
371 continue; |
|
372 else |
|
373 badarg = 1; |
|
374 args++; |
|
375 } |
|
376 |
|
377 |
|
378 if (operation == SMIME_SIGN) |
|
379 { |
|
380 if (!signerfile) |
|
381 { |
|
382 BIO_printf(bio_err, "No signer certificate specified\n"); |
|
383 badarg = 1; |
|
384 } |
|
385 need_rand = 1; |
|
386 } |
|
387 else if (operation == SMIME_DECRYPT) |
|
388 { |
|
389 if (!recipfile && !keyfile) |
|
390 { |
|
391 BIO_printf(bio_err, "No recipient certificate or key specified\n"); |
|
392 badarg = 1; |
|
393 } |
|
394 } |
|
395 else if (operation == SMIME_ENCRYPT) |
|
396 { |
|
397 if (!*args) |
|
398 { |
|
399 BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n"); |
|
400 badarg = 1; |
|
401 } |
|
402 need_rand = 1; |
|
403 } |
|
404 else if (!operation) |
|
405 badarg = 1; |
|
406 |
|
407 if (badarg) |
|
408 { |
|
409 BIO_printf (bio_err, "Usage smime [options] cert.pem ...\n"); |
|
410 BIO_printf (bio_err, "where options are\n"); |
|
411 BIO_printf (bio_err, "-encrypt encrypt message\n"); |
|
412 BIO_printf (bio_err, "-decrypt decrypt encrypted message\n"); |
|
413 BIO_printf (bio_err, "-sign sign message\n"); |
|
414 BIO_printf (bio_err, "-verify verify signed message\n"); |
|
415 BIO_printf (bio_err, "-pk7out output PKCS#7 structure\n"); |
|
416 #ifndef OPENSSL_NO_DES |
|
417 BIO_printf (bio_err, "-des3 encrypt with triple DES\n"); |
|
418 BIO_printf (bio_err, "-des encrypt with DES\n"); |
|
419 #endif |
|
420 #ifndef OPENSSL_NO_RC2 |
|
421 BIO_printf (bio_err, "-rc2-40 encrypt with RC2-40 (default)\n"); |
|
422 BIO_printf (bio_err, "-rc2-64 encrypt with RC2-64\n"); |
|
423 BIO_printf (bio_err, "-rc2-128 encrypt with RC2-128\n"); |
|
424 #endif |
|
425 #ifndef OPENSSL_NO_AES |
|
426 BIO_printf (bio_err, "-aes128, -aes192, -aes256\n"); |
|
427 BIO_printf (bio_err, " encrypt PEM output with cbc aes\n"); |
|
428 #endif |
|
429 BIO_printf (bio_err, "-nointern don't search certificates in message for signer\n"); |
|
430 BIO_printf (bio_err, "-nosigs don't verify message signature\n"); |
|
431 BIO_printf (bio_err, "-noverify don't verify signers certificate\n"); |
|
432 BIO_printf (bio_err, "-nocerts don't include signers certificate when signing\n"); |
|
433 BIO_printf (bio_err, "-nodetach use opaque signing\n"); |
|
434 BIO_printf (bio_err, "-noattr don't include any signed attributes\n"); |
|
435 BIO_printf (bio_err, "-binary don't translate message to text\n"); |
|
436 BIO_printf (bio_err, "-certfile file other certificates file\n"); |
|
437 BIO_printf (bio_err, "-signer file signer certificate file\n"); |
|
438 BIO_printf (bio_err, "-recip file recipient certificate file for decryption\n"); |
|
439 BIO_printf (bio_err, "-in file input file\n"); |
|
440 BIO_printf (bio_err, "-inform arg input format SMIME (default), PEM or DER\n"); |
|
441 BIO_printf (bio_err, "-inkey file input private key (if not signer or recipient)\n"); |
|
442 BIO_printf (bio_err, "-keyform arg input private key format (PEM or ENGINE)\n"); |
|
443 BIO_printf (bio_err, "-out file output file\n"); |
|
444 BIO_printf (bio_err, "-outform arg output format SMIME (default), PEM or DER\n"); |
|
445 BIO_printf (bio_err, "-content file supply or override content for detached signature\n"); |
|
446 BIO_printf (bio_err, "-to addr to address\n"); |
|
447 BIO_printf (bio_err, "-from ad from address\n"); |
|
448 BIO_printf (bio_err, "-subject s subject\n"); |
|
449 BIO_printf (bio_err, "-text include or delete text MIME headers\n"); |
|
450 BIO_printf (bio_err, "-CApath dir trusted certificates directory\n"); |
|
451 BIO_printf (bio_err, "-CAfile file trusted certificates file\n"); |
|
452 BIO_printf (bio_err, "-crl_check check revocation status of signer's certificate using CRLs\n"); |
|
453 BIO_printf (bio_err, "-crl_check_all check revocation status of signer's certificate chain using CRLs\n"); |
|
454 #ifndef OPENSSL_NO_ENGINE |
|
455 BIO_printf (bio_err, "-engine e use engine e, possibly a hardware device.\n"); |
|
456 #endif |
|
457 BIO_printf (bio_err, "-passin arg input file pass phrase source\n"); |
|
458 BIO_printf(bio_err, "-rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR); |
|
459 BIO_printf(bio_err, " load the file (or the files in the directory) into\n"); |
|
460 BIO_printf(bio_err, " the random number generator\n"); |
|
461 BIO_printf (bio_err, "cert.pem recipient certificate(s) for encryption\n"); |
|
462 goto end; |
|
463 } |
|
464 |
|
465 #ifndef OPENSSL_NO_ENGINE |
|
466 e = setup_engine(bio_err, engine, 0); |
|
467 #endif |
|
468 |
|
469 if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) |
|
470 { |
|
471 BIO_printf(bio_err, "Error getting password\n"); |
|
472 goto end; |
|
473 } |
|
474 |
|
475 if (need_rand) |
|
476 { |
|
477 app_RAND_load_file(NULL, bio_err, (inrand != NULL)); |
|
478 if (inrand != NULL) |
|
479 BIO_printf(bio_err,"%ld semi-random bytes loaded\n", |
|
480 app_RAND_load_files(inrand)); |
|
481 } |
|
482 |
|
483 ret = 2; |
|
484 |
|
485 if (operation != SMIME_SIGN) |
|
486 flags &= ~PKCS7_DETACHED; |
|
487 |
|
488 if (operation & SMIME_OP) |
|
489 { |
|
490 if (flags & PKCS7_BINARY) |
|
491 inmode = "rb"; |
|
492 if (outformat == FORMAT_ASN1) |
|
493 outmode = "wb"; |
|
494 } |
|
495 else |
|
496 { |
|
497 if (flags & PKCS7_BINARY) |
|
498 outmode = "wb"; |
|
499 if (informat == FORMAT_ASN1) |
|
500 inmode = "rb"; |
|
501 } |
|
502 |
|
503 if (operation == SMIME_ENCRYPT) |
|
504 { |
|
505 if (!cipher) |
|
506 { |
|
507 #ifndef OPENSSL_NO_RC2 |
|
508 cipher = EVP_rc2_40_cbc(); |
|
509 #else |
|
510 BIO_printf(bio_err, "No cipher selected\n"); |
|
511 goto end; |
|
512 #endif |
|
513 } |
|
514 encerts = sk_X509_new_null(); |
|
515 while (*args) |
|
516 { |
|
517 if (!(cert = load_cert(bio_err,*args,FORMAT_PEM, |
|
518 NULL, e, "recipient certificate file"))) |
|
519 { |
|
520 #if 0 /* An appropriate message is already printed */ |
|
521 BIO_printf(bio_err, "Can't read recipient certificate file %s\n", *args); |
|
522 #endif |
|
523 goto end; |
|
524 } |
|
525 sk_X509_push(encerts, cert); |
|
526 cert = NULL; |
|
527 args++; |
|
528 } |
|
529 } |
|
530 |
|
531 if (signerfile && (operation == SMIME_SIGN)) |
|
532 { |
|
533 if (!(signer = load_cert(bio_err,signerfile,FORMAT_PEM, NULL, |
|
534 e, "signer certificate"))) |
|
535 { |
|
536 #if 0 /* An appropri message has already been printed */ |
|
537 BIO_printf(bio_err, "Can't read signer certificate file %s\n", signerfile); |
|
538 #endif |
|
539 goto end; |
|
540 } |
|
541 } |
|
542 |
|
543 if (certfile) |
|
544 { |
|
545 if (!(other = load_certs(bio_err,certfile,FORMAT_PEM, NULL, |
|
546 e, "certificate file"))) |
|
547 { |
|
548 #if 0 /* An appropriate message has already been printed */ |
|
549 BIO_printf(bio_err, "Can't read certificate file %s\n", certfile); |
|
550 #endif |
|
551 ERR_print_errors(bio_err); |
|
552 goto end; |
|
553 } |
|
554 } |
|
555 |
|
556 if (recipfile && (operation == SMIME_DECRYPT)) |
|
557 { |
|
558 if (!(recip = load_cert(bio_err,recipfile,FORMAT_PEM,NULL, |
|
559 e, "recipient certificate file"))) |
|
560 { |
|
561 #if 0 /* An appropriate message has alrady been printed */ |
|
562 BIO_printf(bio_err, "Can't read recipient certificate file %s\n", recipfile); |
|
563 #endif |
|
564 ERR_print_errors(bio_err); |
|
565 goto end; |
|
566 } |
|
567 } |
|
568 |
|
569 if (operation == SMIME_DECRYPT) |
|
570 { |
|
571 if (!keyfile) |
|
572 keyfile = recipfile; |
|
573 } |
|
574 else if (operation == SMIME_SIGN) |
|
575 { |
|
576 if (!keyfile) |
|
577 keyfile = signerfile; |
|
578 } |
|
579 else keyfile = NULL; |
|
580 |
|
581 if (keyfile) |
|
582 { |
|
583 key = load_key(bio_err, keyfile, keyform, 0, passin, e, |
|
584 "signing key file"); |
|
585 if (!key) |
|
586 goto end; |
|
587 } |
|
588 |
|
589 if (infile) |
|
590 { |
|
591 if (!(in = BIO_new_file(infile, inmode))) |
|
592 { |
|
593 BIO_printf (bio_err, |
|
594 "Can't open input file %s\n", infile); |
|
595 goto end; |
|
596 } |
|
597 } |
|
598 else |
|
599 in = BIO_new_fp(stdin, BIO_NOCLOSE); |
|
600 |
|
601 |
|
602 if (outfile) |
|
603 { |
|
604 if (!(out = BIO_new_file(outfile, outmode))) |
|
605 { |
|
606 BIO_printf (bio_err, |
|
607 "Can't open output file %s\n", outfile); |
|
608 goto end; |
|
609 } |
|
610 } |
|
611 else |
|
612 { |
|
613 out = BIO_new_fp(stdout, BIO_NOCLOSE); |
|
614 |
|
615 #ifdef OPENSSL_SYS_VMS |
|
616 { |
|
617 BIO *tmpbio = BIO_new(BIO_f_linebuffer()); |
|
618 out = BIO_push(tmpbio, out); |
|
619 } |
|
620 #endif |
|
621 } |
|
622 |
|
623 if (operation == SMIME_VERIFY) |
|
624 { |
|
625 if (!(store = setup_verify(bio_err, CAfile, CApath))) |
|
626 goto end; |
|
627 X509_STORE_set_verify_cb_func(store, smime_cb); |
|
628 if (vpm) |
|
629 X509_STORE_set1_param(store, vpm); |
|
630 } |
|
631 |
|
632 |
|
633 ret = 3; |
|
634 |
|
635 if (operation == SMIME_ENCRYPT) |
|
636 p7 = PKCS7_encrypt(encerts, in, cipher, flags); |
|
637 else if (operation == SMIME_SIGN) |
|
638 { |
|
639 /* If detached data and SMIME output enable partial |
|
640 * signing. |
|
641 */ |
|
642 if ((flags & PKCS7_DETACHED) && (outformat == FORMAT_SMIME)) |
|
643 flags |= PKCS7_STREAM; |
|
644 p7 = PKCS7_sign(signer, key, other, in, flags); |
|
645 } |
|
646 else |
|
647 { |
|
648 if (informat == FORMAT_SMIME) |
|
649 p7 = SMIME_read_PKCS7(in, &indata); |
|
650 else if (informat == FORMAT_PEM) |
|
651 p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL); |
|
652 else if (informat == FORMAT_ASN1) |
|
653 p7 = d2i_PKCS7_bio(in, NULL); |
|
654 else |
|
655 { |
|
656 BIO_printf(bio_err, "Bad input format for PKCS#7 file\n"); |
|
657 goto end; |
|
658 } |
|
659 |
|
660 if (!p7) |
|
661 { |
|
662 BIO_printf(bio_err, "Error reading S/MIME message\n"); |
|
663 goto end; |
|
664 } |
|
665 if (contfile) |
|
666 { |
|
667 BIO_free(indata); |
|
668 if (!(indata = BIO_new_file(contfile, "rb"))) |
|
669 { |
|
670 BIO_printf(bio_err, "Can't read content file %s\n", contfile); |
|
671 goto end; |
|
672 } |
|
673 } |
|
674 } |
|
675 |
|
676 if (!p7) |
|
677 { |
|
678 BIO_printf(bio_err, "Error creating PKCS#7 structure\n"); |
|
679 goto end; |
|
680 } |
|
681 |
|
682 ret = 4; |
|
683 if (operation == SMIME_DECRYPT) |
|
684 { |
|
685 if (!PKCS7_decrypt(p7, key, recip, out, flags)) |
|
686 { |
|
687 BIO_printf(bio_err, "Error decrypting PKCS#7 structure\n"); |
|
688 goto end; |
|
689 } |
|
690 } |
|
691 else if (operation == SMIME_VERIFY) |
|
692 { |
|
693 STACK_OF(X509) *signers; |
|
694 if (PKCS7_verify(p7, other, store, indata, out, flags)) |
|
695 BIO_printf(bio_err, "Verification successful\n"); |
|
696 else |
|
697 { |
|
698 BIO_printf(bio_err, "Verification failure\n"); |
|
699 goto end; |
|
700 } |
|
701 signers = PKCS7_get0_signers(p7, other, flags); |
|
702 if (!save_certs(signerfile, signers)) |
|
703 { |
|
704 BIO_printf(bio_err, "Error writing signers to %s\n", |
|
705 signerfile); |
|
706 ret = 5; |
|
707 goto end; |
|
708 } |
|
709 sk_X509_free(signers); |
|
710 } |
|
711 else if (operation == SMIME_PK7OUT) |
|
712 PEM_write_bio_PKCS7(out, p7); |
|
713 else |
|
714 { |
|
715 if (to) |
|
716 BIO_printf(out, "To: %s\n", to); |
|
717 if (from) |
|
718 BIO_printf(out, "From: %s\n", from); |
|
719 if (subject) |
|
720 BIO_printf(out, "Subject: %s\n", subject); |
|
721 if (outformat == FORMAT_SMIME) |
|
722 SMIME_write_PKCS7(out, p7, in, flags); |
|
723 else if (outformat == FORMAT_PEM) |
|
724 PEM_write_bio_PKCS7(out,p7); |
|
725 else if (outformat == FORMAT_ASN1) |
|
726 i2d_PKCS7_bio(out,p7); |
|
727 else |
|
728 { |
|
729 BIO_printf(bio_err, "Bad output format for PKCS#7 file\n"); |
|
730 goto end; |
|
731 } |
|
732 } |
|
733 ret = 0; |
|
734 end: |
|
735 if (need_rand) |
|
736 app_RAND_write_file(NULL, bio_err); |
|
737 if (ret) ERR_print_errors(bio_err); |
|
738 sk_X509_pop_free(encerts, X509_free); |
|
739 sk_X509_pop_free(other, X509_free); |
|
740 if (vpm) |
|
741 X509_VERIFY_PARAM_free(vpm); |
|
742 X509_STORE_free(store); |
|
743 X509_free(cert); |
|
744 X509_free(recip); |
|
745 X509_free(signer); |
|
746 EVP_PKEY_free(key); |
|
747 PKCS7_free(p7); |
|
748 BIO_free(in); |
|
749 BIO_free(indata); |
|
750 BIO_free_all(out); |
|
751 if (passin) OPENSSL_free(passin); |
|
752 return (ret); |
|
753 } |
|
754 |
|
755 static int save_certs(char *signerfile, STACK_OF(X509) *signers) |
|
756 { |
|
757 int i; |
|
758 BIO *tmp; |
|
759 if (!signerfile) |
|
760 return 1; |
|
761 tmp = BIO_new_file(signerfile, "w"); |
|
762 if (!tmp) return 0; |
|
763 for(i = 0; i < sk_X509_num(signers); i++) |
|
764 PEM_write_bio_X509(tmp, sk_X509_value(signers, i)); |
|
765 BIO_free(tmp); |
|
766 return 1; |
|
767 } |
|
768 |
|
769 |
|
770 /* Minimal callback just to output policy info (if any) */ |
|
771 |
|
772 static int smime_cb(int ok, X509_STORE_CTX *ctx) |
|
773 { |
|
774 int error; |
|
775 |
|
776 error = X509_STORE_CTX_get_error(ctx); |
|
777 |
|
778 if ((error != X509_V_ERR_NO_EXPLICIT_POLICY) |
|
779 && ((error != X509_V_OK) || (ok != 2))) |
|
780 return ok; |
|
781 |
|
782 policies_print(NULL, ctx); |
|
783 |
|
784 return ok; |
|
785 |
|
786 } |