Annotation of src/usr.bin/openssl/cms.c, Revision 1.33
1.33 ! tb 1: /* $OpenBSD: cms.c,v 1.32 2023/03/05 13:08:22 tb Exp $ */
1.1 jsing 2: /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3: * project.
4: */
5: /* ====================================================================
6: * Copyright (c) 2008 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:
54: /* CMS utility function */
55:
56: #include <stdio.h>
57: #include <string.h>
58:
59: #include "apps.h"
60:
61: #ifndef OPENSSL_NO_CMS
62:
63: #include <openssl/crypto.h>
64: #include <openssl/err.h>
65: #include <openssl/pem.h>
66: #include <openssl/x509_vfy.h>
67: #include <openssl/x509v3.h>
1.10 jsing 68:
69: #include <openssl/cms.h>
1.1 jsing 70:
1.12 jsing 71: static int save_certs(char *signerfile, STACK_OF(X509) *signers);
72: static int cms_cb(int ok, X509_STORE_CTX *ctx);
73: static void receipt_request_print(BIO *out, CMS_ContentInfo *cms);
74: static CMS_ReceiptRequest *make_receipt_request(
75: STACK_OF(OPENSSL_STRING) *rr_to, int rr_allorfirst,
76: STACK_OF(OPENSSL_STRING) *rr_from);
1.14 inoguchi 77: static int cms_set_pkey_param(EVP_PKEY_CTX *pctx,
78: STACK_OF(OPENSSL_STRING) *param);
1.1 jsing 79:
80: #define SMIME_OP 0x10
81: #define SMIME_IP 0x20
82: #define SMIME_SIGNERS 0x40
83: #define SMIME_ENCRYPT (1 | SMIME_OP)
84: #define SMIME_DECRYPT (2 | SMIME_IP)
85: #define SMIME_SIGN (3 | SMIME_OP | SMIME_SIGNERS)
86: #define SMIME_VERIFY (4 | SMIME_IP)
87: #define SMIME_CMSOUT (5 | SMIME_IP | SMIME_OP)
88: #define SMIME_RESIGN (6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS)
89: #define SMIME_DATAOUT (7 | SMIME_IP)
90: #define SMIME_DATA_CREATE (8 | SMIME_OP)
91: #define SMIME_DIGEST_VERIFY (9 | SMIME_IP)
92: #define SMIME_DIGEST_CREATE (10 | SMIME_OP)
93: #define SMIME_UNCOMPRESS (11 | SMIME_IP)
94: #define SMIME_COMPRESS (12 | SMIME_OP)
95: #define SMIME_ENCRYPTED_DECRYPT (13 | SMIME_IP)
96: #define SMIME_ENCRYPTED_ENCRYPT (14 | SMIME_OP)
97: #define SMIME_SIGN_RECEIPT (15 | SMIME_IP | SMIME_OP)
98: #define SMIME_VERIFY_RECEIPT (16 | SMIME_IP)
99:
100: int verify_err = 0;
101:
1.15 inoguchi 102: struct cms_key_param {
1.14 inoguchi 103: int idx;
104: STACK_OF(OPENSSL_STRING) *param;
1.15 inoguchi 105: struct cms_key_param *next;
1.14 inoguchi 106: };
107:
1.19 inoguchi 108: static struct {
109: char *CAfile;
110: char *CApath;
111: X509 *cert;
112: char *certfile;
113: char *certsoutfile;
114: const EVP_CIPHER *cipher;
115: char *contfile;
116: ASN1_OBJECT *econtent_type;
117: STACK_OF(X509) *encerts;
118: int flags;
119: char *from;
120: char *infile;
121: int informat;
122: struct cms_key_param *key_first;
123: struct cms_key_param *key_param;
124: char *keyfile;
125: int keyform;
126: int noout;
127: int operation;
128: char *outfile;
129: int outformat;
130: char *passargin;
131: int print;
132: unsigned char *pwri_pass;
133: int rr_allorfirst;
134: STACK_OF(OPENSSL_STRING) *rr_from;
135: int rr_print;
136: STACK_OF(OPENSSL_STRING) *rr_to;
137: char *rctfile;
138: int rctformat;
139: char *recipfile;
140: unsigned char *secret_key;
141: unsigned char *secret_keyid;
142: size_t secret_keyidlen;
143: size_t secret_keylen;
144: const EVP_MD *sign_md;
145: char *signerfile;
146: STACK_OF(OPENSSL_STRING) *skkeys;
147: STACK_OF(OPENSSL_STRING) *sksigners;
148: char *subject;
149: char *to;
150: int verify_retcode;
151: X509_VERIFY_PARAM *vpm;
1.33 ! tb 152: } cfg;
1.19 inoguchi 153:
154: static const EVP_CIPHER *
155: get_cipher_by_name(char *name)
156: {
157: if (name == NULL || strcmp(name, "") == 0)
158: return (NULL);
159: #ifndef OPENSSL_NO_AES
160: else if (strcmp(name, "aes128") == 0)
161: return EVP_aes_128_cbc();
162: else if (strcmp(name, "aes192") == 0)
163: return EVP_aes_192_cbc();
164: else if (strcmp(name, "aes256") == 0)
165: return EVP_aes_256_cbc();
166: #endif
167: #ifndef OPENSSL_NO_CAMELLIA
168: else if (strcmp(name, "camellia128") == 0)
169: return EVP_camellia_128_cbc();
170: else if (strcmp(name, "camellia192") == 0)
171: return EVP_camellia_192_cbc();
172: else if (strcmp(name, "camellia256") == 0)
173: return EVP_camellia_256_cbc();
174: #endif
175: #ifndef OPENSSL_NO_DES
176: else if (strcmp(name, "des") == 0)
177: return EVP_des_cbc();
178: else if (strcmp(name, "des3") == 0)
179: return EVP_des_ede3_cbc();
180: #endif
181: #ifndef OPENSSL_NO_RC2
182: else if (!strcmp(name, "rc2-40"))
183: return EVP_rc2_40_cbc();
184: else if (!strcmp(name, "rc2-64"))
185: return EVP_rc2_64_cbc();
186: else if (!strcmp(name, "rc2-128"))
187: return EVP_rc2_cbc();
188: #endif
189: else
190: return (NULL);
191: }
192:
193: static int
194: cms_opt_cipher(int argc, char **argv, int *argsused)
195: {
196: char *name = argv[0];
197:
198: if (*name++ != '-')
199: return (1);
200:
1.33 ! tb 201: if ((cfg.cipher = get_cipher_by_name(name)) == NULL)
! 202: if ((cfg.cipher = EVP_get_cipherbyname(name)) == NULL)
1.19 inoguchi 203: return (1);
204:
205: *argsused = 1;
206: return (0);
207: }
208:
209: static int
210: cms_opt_econtent_type(char *arg)
211: {
1.33 ! tb 212: ASN1_OBJECT_free(cfg.econtent_type);
1.27 inoguchi 213:
1.33 ! tb 214: if ((cfg.econtent_type = OBJ_txt2obj(arg, 0)) == NULL) {
1.19 inoguchi 215: BIO_printf(bio_err, "Invalid OID %s\n", arg);
216: return (1);
217: }
218: return (0);
219: }
220:
221: static int
222: cms_opt_inkey(char *arg)
223: {
1.33 ! tb 224: if (cfg.keyfile == NULL) {
! 225: cfg.keyfile = arg;
1.20 inoguchi 226: return (0);
227: }
1.32 tb 228:
1.33 ! tb 229: if (cfg.signerfile == NULL) {
1.20 inoguchi 230: BIO_puts(bio_err, "Illegal -inkey without -signer\n");
231: return (1);
232: }
233:
1.33 ! tb 234: if (cfg.sksigners == NULL)
! 235: cfg.sksigners = sk_OPENSSL_STRING_new_null();
! 236: if (cfg.sksigners == NULL)
1.20 inoguchi 237: return (1);
1.33 ! tb 238: if (!sk_OPENSSL_STRING_push(cfg.sksigners, cfg.signerfile))
1.20 inoguchi 239: return (1);
1.19 inoguchi 240:
1.33 ! tb 241: cfg.signerfile = NULL;
1.19 inoguchi 242:
1.33 ! tb 243: if (cfg.skkeys == NULL)
! 244: cfg.skkeys = sk_OPENSSL_STRING_new_null();
! 245: if (cfg.skkeys == NULL)
1.20 inoguchi 246: return (1);
1.33 ! tb 247: if (!sk_OPENSSL_STRING_push(cfg.skkeys, cfg.keyfile))
1.20 inoguchi 248: return (1);
1.19 inoguchi 249:
1.33 ! tb 250: cfg.keyfile = arg;
1.19 inoguchi 251: return (0);
252: }
253:
254: static int
255: cms_opt_keyopt(char *arg)
256: {
257: int keyidx = -1;
258:
1.33 ! tb 259: if (cfg.operation == SMIME_ENCRYPT) {
! 260: if (cfg.encerts != NULL)
! 261: keyidx += sk_X509_num(cfg.encerts);
1.19 inoguchi 262: } else {
1.33 ! tb 263: if (cfg.keyfile != NULL || cfg.signerfile != NULL)
1.19 inoguchi 264: keyidx++;
1.33 ! tb 265: if (cfg.skkeys != NULL)
! 266: keyidx += sk_OPENSSL_STRING_num(cfg.skkeys);
1.19 inoguchi 267: }
268:
269: if (keyidx < 0) {
270: BIO_printf(bio_err, "No key specified\n");
271: return (1);
272: }
273:
1.33 ! tb 274: if (cfg.key_param == NULL ||
! 275: cfg.key_param->idx != keyidx) {
1.19 inoguchi 276: struct cms_key_param *nparam;
277:
1.21 inoguchi 278: if ((nparam = calloc(1, sizeof(struct cms_key_param))) == NULL)
1.19 inoguchi 279: return (1);
280:
281: nparam->idx = keyidx;
282: if ((nparam->param = sk_OPENSSL_STRING_new_null()) == NULL) {
283: free(nparam);
284: return (1);
285: }
286:
287: nparam->next = NULL;
1.33 ! tb 288: if (cfg.key_first == NULL)
! 289: cfg.key_first = nparam;
1.19 inoguchi 290: else
1.33 ! tb 291: cfg.key_param->next = nparam;
1.19 inoguchi 292:
1.33 ! tb 293: cfg.key_param = nparam;
1.19 inoguchi 294: }
295:
1.33 ! tb 296: if (!sk_OPENSSL_STRING_push(cfg.key_param->param, arg))
1.19 inoguchi 297: return (1);
298:
299: return (0);
300: }
301:
302: static int
303: cms_opt_md(char *arg)
304: {
1.33 ! tb 305: if ((cfg.sign_md = EVP_get_digestbyname(arg)) == NULL) {
1.19 inoguchi 306: BIO_printf(bio_err, "Unknown digest %s\n", arg);
307: return (1);
308: }
309: return (0);
310: }
311:
312: static int
313: cms_opt_print(void)
314: {
1.33 ! tb 315: cfg.noout = 1;
! 316: cfg.print = 1;
1.19 inoguchi 317: return (0);
318: }
319:
320: static int
321: cms_opt_pwri_pass(char *arg)
322: {
1.33 ! tb 323: cfg.pwri_pass = (unsigned char *)arg;
1.19 inoguchi 324: return (0);
325: }
326:
327: static int
328: cms_opt_recip(char *arg)
329: {
1.33 ! tb 330: if (cfg.operation == SMIME_ENCRYPT) {
! 331: if (cfg.encerts == NULL) {
! 332: if ((cfg.encerts = sk_X509_new_null()) == NULL)
1.19 inoguchi 333: return (1);
334: }
335:
1.33 ! tb 336: cfg.cert = load_cert(bio_err, arg, FORMAT_PEM,
1.19 inoguchi 337: NULL, "recipient certificate file");
1.33 ! tb 338: if (cfg.cert == NULL)
1.19 inoguchi 339: return (1);
340:
1.33 ! tb 341: if (!sk_X509_push(cfg.encerts, cfg.cert))
1.19 inoguchi 342: return (1);
343:
1.33 ! tb 344: cfg.cert = NULL;
1.19 inoguchi 345: } else {
1.33 ! tb 346: cfg.recipfile = arg;
1.19 inoguchi 347: }
348: return (0);
349: }
350:
351: static int
352: cms_opt_receipt_request_from(char *arg)
353: {
1.33 ! tb 354: if (cfg.rr_from == NULL)
! 355: cfg.rr_from = sk_OPENSSL_STRING_new_null();
! 356: if (cfg.rr_from == NULL)
1.19 inoguchi 357: return (1);
1.33 ! tb 358: if (!sk_OPENSSL_STRING_push(cfg.rr_from, arg))
1.19 inoguchi 359: return (1);
360:
361: return (0);
362: }
363:
364: static int
365: cms_opt_receipt_request_to(char *arg)
366: {
1.33 ! tb 367: if (cfg.rr_to == NULL)
! 368: cfg.rr_to = sk_OPENSSL_STRING_new_null();
! 369: if (cfg.rr_to == NULL)
1.19 inoguchi 370: return (1);
1.33 ! tb 371: if (!sk_OPENSSL_STRING_push(cfg.rr_to, arg))
1.19 inoguchi 372: return (1);
373:
374: return (0);
375: }
376:
377: static int
378: cms_opt_secretkey(char *arg)
379: {
380: long ltmp;
381:
1.33 ! tb 382: free(cfg.secret_key);
1.27 inoguchi 383:
1.33 ! tb 384: if ((cfg.secret_key = string_to_hex(arg, <mp)) == NULL) {
1.19 inoguchi 385: BIO_printf(bio_err, "Invalid key %s\n", arg);
386: return (1);
387: }
1.33 ! tb 388: cfg.secret_keylen = (size_t)ltmp;
1.19 inoguchi 389: return (0);
390: }
391:
392: static int
393: cms_opt_secretkeyid(char *arg)
394: {
395: long ltmp;
1.27 inoguchi 396:
1.33 ! tb 397: free(cfg.secret_keyid);
1.19 inoguchi 398:
1.33 ! tb 399: if ((cfg.secret_keyid = string_to_hex(arg, <mp)) == NULL) {
1.19 inoguchi 400: BIO_printf(bio_err, "Invalid id %s\n", arg);
401: return (1);
402: }
1.33 ! tb 403: cfg.secret_keyidlen = (size_t)ltmp;
1.19 inoguchi 404: return (0);
405: }
406:
407: static int
408: cms_opt_signer(char *arg)
409: {
1.33 ! tb 410: if (cfg.signerfile == NULL) {
! 411: cfg.signerfile = arg;
1.20 inoguchi 412: return (0);
413: }
414:
1.33 ! tb 415: if (cfg.sksigners == NULL)
! 416: cfg.sksigners = sk_OPENSSL_STRING_new_null();
! 417: if (cfg.sksigners == NULL)
1.20 inoguchi 418: return (1);
1.33 ! tb 419: if (!sk_OPENSSL_STRING_push(cfg.sksigners, cfg.signerfile))
1.20 inoguchi 420: return (1);
421:
1.33 ! tb 422: if (cfg.keyfile == NULL)
! 423: cfg.keyfile = cfg.signerfile;
1.19 inoguchi 424:
1.33 ! tb 425: if (cfg.skkeys == NULL)
! 426: cfg.skkeys = sk_OPENSSL_STRING_new_null();
! 427: if (cfg.skkeys == NULL)
1.20 inoguchi 428: return (1);
1.33 ! tb 429: if (!sk_OPENSSL_STRING_push(cfg.skkeys, cfg.keyfile))
1.20 inoguchi 430: return (1);
1.19 inoguchi 431:
1.33 ! tb 432: cfg.keyfile = NULL;
1.19 inoguchi 433:
1.33 ! tb 434: cfg.signerfile = arg;
1.19 inoguchi 435: return (0);
436: }
437:
438: static int
439: cms_opt_verify_param(int argc, char **argv, int *argsused)
440: {
441: int oargc = argc;
442: int badarg = 0;
443:
1.33 ! tb 444: if (!args_verify(&argv, &argc, &badarg, bio_err, &cfg.vpm))
1.19 inoguchi 445: return (1);
446: if (badarg)
447: return (1);
448:
449: *argsused = oargc - argc;
450:
451: return (0);
452: }
453:
454: static int
455: cms_opt_verify_receipt(char *arg)
456: {
1.33 ! tb 457: cfg.operation = SMIME_VERIFY_RECEIPT;
! 458: cfg.rctfile = arg;
1.19 inoguchi 459: return (0);
460: }
461:
462: static const struct option cms_options[] = {
463: #ifndef OPENSSL_NO_AES
464: {
465: .name = "aes128",
466: .desc = "Encrypt PEM output with CBC AES",
467: .type = OPTION_ARGV_FUNC,
468: .opt.argvfunc = cms_opt_cipher,
469: },
470: {
471: .name = "aes192",
472: .desc = "Encrypt PEM output with CBC AES",
473: .type = OPTION_ARGV_FUNC,
474: .opt.argvfunc = cms_opt_cipher,
475: },
476: {
477: .name = "aes256",
478: .desc = "Encrypt PEM output with CBC AES",
479: .type = OPTION_ARGV_FUNC,
480: .opt.argvfunc = cms_opt_cipher,
481: },
482: #endif
483: #ifndef OPENSSL_NO_CAMELLIA
484: {
485: .name = "camellia128",
486: .desc = "Encrypt PEM output with CBC Camellia",
487: .type = OPTION_ARGV_FUNC,
488: .opt.argvfunc = cms_opt_cipher,
489: },
490: {
491: .name = "camellia192",
492: .desc = "Encrypt PEM output with CBC Camellia",
493: .type = OPTION_ARGV_FUNC,
494: .opt.argvfunc = cms_opt_cipher,
495: },
496: {
497: .name = "camellia256",
498: .desc = "Encrypt PEM output with CBC Camellia",
499: .type = OPTION_ARGV_FUNC,
500: .opt.argvfunc = cms_opt_cipher,
501: },
502: #endif
503: #ifndef OPENSSL_NO_DES
504: {
505: .name = "des",
506: .desc = "Encrypt with DES",
507: .type = OPTION_ARGV_FUNC,
508: .opt.argvfunc = cms_opt_cipher,
509: },
510: {
511: .name = "des3",
1.28 inoguchi 512: .desc = "Encrypt with triple DES (default)",
1.19 inoguchi 513: .type = OPTION_ARGV_FUNC,
514: .opt.argvfunc = cms_opt_cipher,
515: },
516: #endif
517: #ifndef OPENSSL_NO_RC2
518: {
519: .name = "rc2-40",
1.28 inoguchi 520: .desc = "Encrypt with RC2-40",
1.19 inoguchi 521: .type = OPTION_ARGV_FUNC,
522: .opt.argvfunc = cms_opt_cipher,
523: },
524: {
525: .name = "rc2-64",
526: .desc = "Encrypt with RC2-64",
527: .type = OPTION_ARGV_FUNC,
528: .opt.argvfunc = cms_opt_cipher,
529: },
530: {
531: .name = "rc2-128",
532: .desc = "Encrypt with RC2-128",
533: .type = OPTION_ARGV_FUNC,
534: .opt.argvfunc = cms_opt_cipher,
535: },
536: #endif
537: {
538: .name = "CAfile",
539: .argname = "file",
540: .desc = "Certificate Authority file",
541: .type = OPTION_ARG,
1.33 ! tb 542: .opt.arg = &cfg.CAfile,
1.19 inoguchi 543: },
544: {
545: .name = "CApath",
546: .argname = "path",
547: .desc = "Certificate Authority path",
548: .type = OPTION_ARG,
1.33 ! tb 549: .opt.arg = &cfg.CApath,
1.19 inoguchi 550: },
551: {
552: .name = "binary",
553: .desc = "Do not translate message to text",
554: .type = OPTION_VALUE_OR,
1.33 ! tb 555: .opt.value = &cfg.flags,
1.19 inoguchi 556: .value = CMS_BINARY,
557: },
558: {
559: .name = "certfile",
560: .argname = "file",
561: .desc = "Other certificates file",
562: .type = OPTION_ARG,
1.33 ! tb 563: .opt.arg = &cfg.certfile,
1.19 inoguchi 564: },
565: {
566: .name = "certsout",
567: .argname = "file",
568: .desc = "Certificate output file",
569: .type = OPTION_ARG,
1.33 ! tb 570: .opt.arg = &cfg.certsoutfile,
1.19 inoguchi 571: },
572: {
573: .name = "cmsout",
574: .desc = "Output CMS structure",
575: .type = OPTION_VALUE,
1.33 ! tb 576: .opt.value = &cfg.operation,
1.19 inoguchi 577: .value = SMIME_CMSOUT,
578: },
579: {
580: .name = "compress",
581: .desc = "Create CMS CompressedData type",
582: .type = OPTION_VALUE,
1.33 ! tb 583: .opt.value = &cfg.operation,
1.19 inoguchi 584: .value = SMIME_COMPRESS,
585: },
586: {
587: .name = "content",
588: .argname = "file",
589: .desc = "Supply or override content for detached signature",
590: .type = OPTION_ARG,
1.33 ! tb 591: .opt.arg = &cfg.contfile,
1.19 inoguchi 592: },
593: {
594: .name = "crlfeol",
595: .desc = "Use CRLF as EOL termination instead of CR only",
596: .type = OPTION_VALUE_OR,
1.33 ! tb 597: .opt.value = &cfg.flags,
1.19 inoguchi 598: .value = CMS_CRLFEOL,
599: },
600: {
601: .name = "data_create",
602: .desc = "Create CMS Data type",
603: .type = OPTION_VALUE,
1.33 ! tb 604: .opt.value = &cfg.operation,
1.19 inoguchi 605: .value = SMIME_DATA_CREATE,
606: },
607: {
608: .name = "data_out",
609: .desc = "Output content from the input CMS Data type",
610: .type = OPTION_VALUE,
1.33 ! tb 611: .opt.value = &cfg.operation,
1.19 inoguchi 612: .value = SMIME_DATAOUT,
613: },
614: {
615: .name = "debug_decrypt",
616: .desc = "Set the CMS_DEBUG_DECRYPT flag when decrypting",
617: .type = OPTION_VALUE_OR,
1.33 ! tb 618: .opt.value = &cfg.flags,
1.19 inoguchi 619: .value = CMS_DEBUG_DECRYPT,
620: },
621: {
622: .name = "decrypt",
623: .desc = "Decrypt encrypted message",
624: .type = OPTION_VALUE,
1.33 ! tb 625: .opt.value = &cfg.operation,
1.19 inoguchi 626: .value = SMIME_DECRYPT,
627: },
628: {
629: .name = "digest_create",
630: .desc = "Create CMS DigestedData type",
631: .type = OPTION_VALUE,
1.33 ! tb 632: .opt.value = &cfg.operation,
1.19 inoguchi 633: .value = SMIME_DIGEST_CREATE,
634: },
635: {
636: .name = "digest_verify",
637: .desc = "Verify CMS DigestedData type and output the content",
638: .type = OPTION_VALUE,
1.33 ! tb 639: .opt.value = &cfg.operation,
1.19 inoguchi 640: .value = SMIME_DIGEST_VERIFY,
641: },
642: {
643: .name = "econtent_type",
644: .argname = "type",
645: .desc = "Set the encapsulated content type",
646: .type = OPTION_ARG_FUNC,
647: .opt.argfunc = cms_opt_econtent_type,
648: },
649: {
650: .name = "encrypt",
651: .desc = "Encrypt message",
652: .type = OPTION_VALUE,
1.33 ! tb 653: .opt.value = &cfg.operation,
1.19 inoguchi 654: .value = SMIME_ENCRYPT,
655: },
656: {
657: .name = "EncryptedData_decrypt",
658: .desc = "Decrypt CMS EncryptedData",
659: .type = OPTION_VALUE,
1.33 ! tb 660: .opt.value = &cfg.operation,
1.19 inoguchi 661: .value = SMIME_ENCRYPTED_DECRYPT,
662: },
663: {
664: .name = "EncryptedData_encrypt",
665: .desc = "Encrypt content using supplied symmetric key and algorithm",
666: .type = OPTION_VALUE,
1.33 ! tb 667: .opt.value = &cfg.operation,
1.19 inoguchi 668: .value = SMIME_ENCRYPTED_ENCRYPT,
669: },
670: {
671: .name = "from",
672: .argname = "addr",
673: .desc = "From address",
674: .type = OPTION_ARG,
1.33 ! tb 675: .opt.arg = &cfg.from,
1.19 inoguchi 676: },
677: {
678: .name = "in",
679: .argname = "file",
680: .desc = "Input file",
681: .type = OPTION_ARG,
1.33 ! tb 682: .opt.arg = &cfg.infile,
1.19 inoguchi 683: },
684: {
685: .name = "indef",
686: .desc = "Same as -stream",
687: .type = OPTION_VALUE_OR,
1.33 ! tb 688: .opt.value = &cfg.flags,
1.19 inoguchi 689: .value = CMS_STREAM,
690: },
691: {
692: .name = "inform",
693: .argname = "fmt",
694: .desc = "Input format (DER, PEM or SMIME (default))",
695: .type = OPTION_ARG_FORMAT,
1.33 ! tb 696: .opt.value = &cfg.informat,
1.19 inoguchi 697: },
698: {
699: .name = "inkey",
700: .argname = "file",
701: .desc = "Input key file",
702: .type = OPTION_ARG_FUNC,
703: .opt.argfunc = cms_opt_inkey,
704: },
705: {
706: .name = "keyform",
707: .argname = "fmt",
708: .desc = "Input key format (DER or PEM (default))",
709: .type = OPTION_ARG_FORMAT,
1.33 ! tb 710: .opt.value = &cfg.keyform,
1.19 inoguchi 711: },
712: {
713: .name = "keyid",
714: .desc = "Use subject key identifier",
715: .type = OPTION_VALUE_OR,
1.33 ! tb 716: .opt.value = &cfg.flags,
1.19 inoguchi 717: .value = CMS_USE_KEYID,
718: },
719: {
720: .name = "keyopt",
721: .argname = "nm:v",
722: .desc = "Set public key parameters",
723: .type = OPTION_ARG_FUNC,
724: .opt.argfunc = cms_opt_keyopt,
725: },
726: {
727: .name = "md",
728: .argname = "digest",
729: .desc = "Digest to use when signing or resigning",
730: .type = OPTION_ARG_FUNC,
731: .opt.argfunc = cms_opt_md,
732: },
733: {
734: .name = "no_attr_verify",
735: .desc = "Do not verify the signer's attribute of a signature",
736: .type = OPTION_VALUE_OR,
1.33 ! tb 737: .opt.value = &cfg.flags,
1.19 inoguchi 738: .value = CMS_NO_ATTR_VERIFY,
739: },
740: {
741: .name = "no_content_verify",
742: .desc = "Do not verify the content of a signed message",
743: .type = OPTION_VALUE_OR,
1.33 ! tb 744: .opt.value = &cfg.flags,
1.19 inoguchi 745: .value = CMS_NO_CONTENT_VERIFY,
746: },
747: {
748: .name = "no_signer_cert_verify",
749: .desc = "Do not verify the signer's certificate",
750: .type = OPTION_VALUE_OR,
1.33 ! tb 751: .opt.value = &cfg.flags,
1.19 inoguchi 752: .value = CMS_NO_SIGNER_CERT_VERIFY,
753: },
754: {
755: .name = "noattr",
756: .desc = "Do not include any signed attributes",
757: .type = OPTION_VALUE_OR,
1.33 ! tb 758: .opt.value = &cfg.flags,
1.19 inoguchi 759: .value = CMS_NOATTR,
760: },
761: {
762: .name = "nocerts",
763: .desc = "Do not include signer's certificate when signing",
764: .type = OPTION_VALUE_OR,
1.33 ! tb 765: .opt.value = &cfg.flags,
1.19 inoguchi 766: .value = CMS_NOCERTS,
767: },
768: {
769: .name = "nodetach",
770: .desc = "Use opaque signing",
771: .type = OPTION_VALUE_AND,
1.33 ! tb 772: .opt.value = &cfg.flags,
1.19 inoguchi 773: .value = ~CMS_DETACHED,
774: },
775: {
776: .name = "noindef",
777: .desc = "Disable CMS streaming",
778: .type = OPTION_VALUE_AND,
1.33 ! tb 779: .opt.value = &cfg.flags,
1.19 inoguchi 780: .value = ~CMS_STREAM,
781: },
782: {
783: .name = "nointern",
784: .desc = "Do not search certificates in message for signer",
785: .type = OPTION_VALUE_OR,
1.33 ! tb 786: .opt.value = &cfg.flags,
1.19 inoguchi 787: .value = CMS_NOINTERN,
788: },
789: {
790: .name = "nooldmime",
791: .desc = "Output old S/MIME content type",
792: .type = OPTION_VALUE_OR,
1.33 ! tb 793: .opt.value = &cfg.flags,
1.19 inoguchi 794: .value = CMS_NOOLDMIMETYPE,
795: },
796: {
797: .name = "noout",
798: .desc = "Do not output the parsed CMS structure",
799: .type = OPTION_FLAG,
1.33 ! tb 800: .opt.flag = &cfg.noout,
1.19 inoguchi 801: },
802: {
803: .name = "nosigs",
804: .desc = "Do not verify message signature",
805: .type = OPTION_VALUE_OR,
1.33 ! tb 806: .opt.value = &cfg.flags,
1.19 inoguchi 807: .value = CMS_NOSIGS,
808: },
809: {
810: .name = "nosmimecap",
811: .desc = "Omit the SMIMECapabilities attribute",
812: .type = OPTION_VALUE_OR,
1.33 ! tb 813: .opt.value = &cfg.flags,
1.19 inoguchi 814: .value = CMS_NOSMIMECAP,
815: },
816: {
817: .name = "noverify",
818: .desc = "Do not verify signer's certificate",
819: .type = OPTION_VALUE_OR,
1.33 ! tb 820: .opt.value = &cfg.flags,
1.19 inoguchi 821: .value = CMS_NO_SIGNER_CERT_VERIFY,
822: },
823: {
824: .name = "out",
825: .argname = "file",
826: .desc = "Output file",
827: .type = OPTION_ARG,
1.33 ! tb 828: .opt.arg = &cfg.outfile,
1.19 inoguchi 829: },
830: {
831: .name = "outform",
832: .argname = "fmt",
833: .desc = "Output format (DER, PEM or SMIME (default))",
834: .type = OPTION_ARG_FORMAT,
1.33 ! tb 835: .opt.value = &cfg.outformat,
1.19 inoguchi 836: },
837: {
838: .name = "passin",
839: .argname = "src",
840: .desc = "Private key password source",
841: .type = OPTION_ARG,
1.33 ! tb 842: .opt.arg = &cfg.passargin,
1.19 inoguchi 843: },
844: {
845: .name = "print",
846: .desc = "Print out all fields of the CMS structure for the -cmsout",
847: .type = OPTION_FUNC,
848: .opt.func = cms_opt_print,
849: },
850: {
851: .name = "pwri_password",
852: .argname = "arg",
853: .desc = "Specify PasswordRecipientInfo (PWRI) password to use",
854: .type = OPTION_ARG_FUNC,
855: .opt.argfunc = cms_opt_pwri_pass,
856: },
857: {
858: .name = "rctform",
859: .argname = "fmt",
860: .desc = "Receipt file format (DER, PEM or SMIME (default))",
861: .type = OPTION_ARG_FORMAT,
1.33 ! tb 862: .opt.value = &cfg.rctformat,
1.19 inoguchi 863: },
864: {
865: .name = "receipt_request_all",
866: .desc = "Indicate requests should be provided by all recipients",
867: .type = OPTION_VALUE,
1.33 ! tb 868: .opt.value = &cfg.rr_allorfirst,
1.19 inoguchi 869: .value = 0,
870: },
871: {
872: .name = "receipt_request_first",
873: .desc = "Indicate requests should be provided by first tier recipient",
874: .type = OPTION_VALUE,
1.33 ! tb 875: .opt.value = &cfg.rr_allorfirst,
1.19 inoguchi 876: .value = 1,
877: },
878: {
879: .name = "receipt_request_from",
880: .argname = "addr",
881: .desc = "Add explicit email address where receipts should be supplied",
882: .type = OPTION_ARG_FUNC,
883: .opt.argfunc = cms_opt_receipt_request_from,
884: },
885: {
886: .name = "receipt_request_print",
887: .desc = "Print out the contents of any signed receipt requests",
888: .type = OPTION_FLAG,
1.33 ! tb 889: .opt.flag = &cfg.rr_print,
1.19 inoguchi 890: },
891: {
892: .name = "receipt_request_to",
893: .argname = "addr",
894: .desc = "Add explicit email address where receipts should be sent to",
895: .type = OPTION_ARG_FUNC,
896: .opt.argfunc = cms_opt_receipt_request_to,
897: },
898: {
899: .name = "recip",
900: .argname = "file",
901: .desc = "Recipient certificate file for decryption",
902: .type = OPTION_ARG_FUNC,
903: .opt.argfunc = cms_opt_recip,
904: },
905: {
906: .name = "resign",
907: .desc = "Resign a signed message",
908: .type = OPTION_VALUE,
1.33 ! tb 909: .opt.value = &cfg.operation,
1.19 inoguchi 910: .value = SMIME_RESIGN,
911: },
912: {
913: .name = "secretkey",
914: .argname = "key",
915: .desc = "Specify symmetric key to use",
916: .type = OPTION_ARG_FUNC,
917: .opt.argfunc = cms_opt_secretkey,
918: },
919: {
920: .name = "secretkeyid",
921: .argname = "id",
922: .desc = "The key identifier for the supplied symmetric key",
923: .type = OPTION_ARG_FUNC,
924: .opt.argfunc = cms_opt_secretkeyid,
925: },
926: {
927: .name = "sign",
928: .desc = "Sign message",
929: .type = OPTION_VALUE,
1.33 ! tb 930: .opt.value = &cfg.operation,
1.19 inoguchi 931: .value = SMIME_SIGN,
932: },
933: {
934: .name = "sign_receipt",
935: .desc = "Generate a signed receipt for the message",
936: .type = OPTION_VALUE,
1.33 ! tb 937: .opt.value = &cfg.operation,
1.19 inoguchi 938: .value = SMIME_SIGN_RECEIPT,
939: },
940: {
941: .name = "signer",
942: .argname = "file",
943: .desc = "Signer certificate file",
944: .type = OPTION_ARG_FUNC,
945: .opt.argfunc = cms_opt_signer,
946: },
947: {
948: .name = "stream",
949: .desc = "Enable CMS streaming",
950: .type = OPTION_VALUE_OR,
1.33 ! tb 951: .opt.value = &cfg.flags,
1.19 inoguchi 952: .value = CMS_STREAM,
953: },
954: {
955: .name = "subject",
956: .argname = "s",
957: .desc = "Subject",
958: .type = OPTION_ARG,
1.33 ! tb 959: .opt.arg = &cfg.subject,
1.19 inoguchi 960: },
961: {
962: .name = "text",
963: .desc = "Include or delete text MIME headers",
964: .type = OPTION_VALUE_OR,
1.33 ! tb 965: .opt.value = &cfg.flags,
1.19 inoguchi 966: .value = CMS_TEXT,
967: },
968: {
969: .name = "to",
970: .argname = "addr",
971: .desc = "To address",
972: .type = OPTION_ARG,
1.33 ! tb 973: .opt.arg = &cfg.to,
1.19 inoguchi 974: },
975: {
976: .name = "uncompress",
977: .desc = "Uncompress CMS CompressedData type",
978: .type = OPTION_VALUE,
1.33 ! tb 979: .opt.value = &cfg.operation,
1.19 inoguchi 980: .value = SMIME_UNCOMPRESS,
981: },
982: {
983: .name = "verify",
984: .desc = "Verify signed message",
985: .type = OPTION_VALUE,
1.33 ! tb 986: .opt.value = &cfg.operation,
1.19 inoguchi 987: .value = SMIME_VERIFY,
988: },
989: {
990: .name = "verify_receipt",
991: .argname = "file",
992: .desc = "Verify a signed receipt in file",
993: .type = OPTION_ARG_FUNC,
994: .opt.argfunc = cms_opt_verify_receipt,
995: },
996: {
997: .name = "verify_retcode",
998: .desc = "Set verification error code to exit code",
999: .type = OPTION_FLAG,
1.33 ! tb 1000: .opt.flag = &cfg.verify_retcode,
1.19 inoguchi 1001: },
1002: {
1003: .name = "check_ss_sig",
1004: .type = OPTION_ARGV_FUNC,
1005: .opt.argvfunc = cms_opt_verify_param,
1006: },
1007: {
1008: .name = "crl_check",
1009: .type = OPTION_ARGV_FUNC,
1010: .opt.argvfunc = cms_opt_verify_param,
1011: },
1012: {
1013: .name = "crl_check_all",
1014: .type = OPTION_ARGV_FUNC,
1015: .opt.argvfunc = cms_opt_verify_param,
1016: },
1017: {
1018: .name = "extended_crl",
1019: .type = OPTION_ARGV_FUNC,
1020: .opt.argvfunc = cms_opt_verify_param,
1021: },
1022: {
1023: .name = "ignore_critical",
1024: .type = OPTION_ARGV_FUNC,
1025: .opt.argvfunc = cms_opt_verify_param,
1026: },
1027: {
1028: .name = "issuer_checks",
1029: .type = OPTION_ARGV_FUNC,
1030: .opt.argvfunc = cms_opt_verify_param,
1031: },
1032: {
1033: .name = "policy",
1034: .type = OPTION_ARGV_FUNC,
1035: .opt.argvfunc = cms_opt_verify_param,
1036: },
1037: {
1038: .name = "policy_check",
1039: .type = OPTION_ARGV_FUNC,
1040: .opt.argvfunc = cms_opt_verify_param,
1041: },
1042: {
1043: .name = "purpose",
1044: .type = OPTION_ARGV_FUNC,
1045: .opt.argvfunc = cms_opt_verify_param,
1046: },
1047: {
1048: .name = "x509_strict",
1049: .type = OPTION_ARGV_FUNC,
1050: .opt.argvfunc = cms_opt_verify_param,
1051: },
1052: {
1053: .name = NULL,
1054: .type = OPTION_ARGV_FUNC,
1055: .opt.argvfunc = cms_opt_cipher,
1056: },
1057: { NULL },
1058: };
1059:
1060: static const struct option verify_shared_options[] = {
1061: {
1062: .name = "check_ss_sig",
1063: .desc = "Check the root CA self-signed certificate signature",
1064: },
1065: {
1066: .name = "crl_check",
1067: .desc = "Enable CRL checking for the leaf certificate",
1068: },
1069: {
1070: .name = "crl_check_all",
1071: .desc = "Enable CRL checking for the entire certificate chain",
1072: },
1073: {
1074: .name = "extended_crl",
1075: .desc = "Enable extended CRL support",
1076: },
1077: {
1078: .name = "ignore_critical",
1079: .desc = "Disable critical extension checking",
1080: },
1081: {
1082: .name = "issuer_checks",
1083: .desc = "Enable debugging of certificate issuer checks",
1084: },
1085: {
1086: .name = "policy",
1087: .argname = "name",
1088: .desc = "Add given policy to the acceptable set",
1089: },
1090: {
1091: .name = "policy_check",
1092: .desc = "Enable certificate policy checking",
1093: },
1094: {
1095: .name = "purpose",
1096: .argname = "name",
1097: .desc = "Verify for the given purpose",
1098: },
1099: {
1100: .name = "x509_strict",
1101: .desc = "Use strict X.509 rules (disables workarounds)",
1102: },
1103: { NULL },
1104: };
1105:
1106: static void
1107: cms_usage(void)
1108: {
1109: int i;
1110:
1111: fprintf(stderr, "usage: cms "
1112: "[-aes128 | -aes192 | -aes256 | -camellia128 |\n"
1113: " -camellia192 | -camellia256 | -des | -des3 |\n"
1114: " -rc2-40 | -rc2-64 | -rc2-128] [-CAfile file]\n"
1115: " [-CApath directory] [-binary] [-certfile file]\n"
1116: " [-certsout file] [-cmsout] [-compress] [-content file]\n"
1117: " [-crlfeol] [-data_create] [-data_out] [-debug_decrypt]\n"
1118: " [-decrypt] [-digest_create] [-digest_verify]\n"
1119: " [-econtent_type type] [-encrypt] [-EncryptedData_decrypt]\n"
1120: " [-EncryptedData_encrypt] [-from addr] [-in file]\n"
1121: " [-inform der | pem | smime] [-inkey file]\n"
1122: " [-keyform der | pem] [-keyid] [-keyopt nm:v] [-md digest]\n"
1123: " [-no_attr_verify] [-no_content_verify]\n"
1124: " [-no_signer_cert_verify] [-noattr] [-nocerts] [-nodetach]\n"
1125: " [-nointern] [-nooldmime] [-noout] [-nosigs] [-nosmimecap]\n"
1126: " [-noverify] [-out file] [-outform der | pem | smime]\n"
1127: " [-passin src] [-print] [-pwri_password arg]\n"
1128: " [-rctform der | pem | smime]\n"
1129: " [-receipt_request_all | -receipt_request_first]\n"
1130: " [-receipt_request_from addr] [-receipt_request_print]\n"
1131: " [-receipt_request_to addr] [-recip file] [-resign]\n"
1132: " [-secretkey key] [-secretkeyid id] [-sign] [-sign_receipt]\n"
1133: " [-signer file] [-stream | -indef | -noindef] [-subject s]\n"
1134: " [-text] [-to addr] [-uncompress] [-verify]\n"
1135: " [-verify_receipt file] [-verify_retcode] [cert.pem ...]\n\n");
1136:
1137: options_usage(cms_options);
1138:
1139: fprintf(stderr, "\nVerification options:\n\n");
1140: options_usage(verify_shared_options);
1141:
1142: fprintf(stderr, "\nValid purposes:\n\n");
1143: for (i = 0; i < X509_PURPOSE_get_count(); i++) {
1144: X509_PURPOSE *ptmp = X509_PURPOSE_get0(i);
1145: fprintf(stderr, " %-18s%s\n", X509_PURPOSE_get0_sname(ptmp),
1146: X509_PURPOSE_get0_name(ptmp));
1147: }
1148: }
1149:
1.1 jsing 1150: int
1151: cms_main(int argc, char **argv)
1152: {
1153: int ret = 0;
1154: char **args;
1.19 inoguchi 1155: int argsused = 0;
1.1 jsing 1156: const char *inmode = "r", *outmode = "w";
1157: CMS_ContentInfo *cms = NULL, *rcms = NULL;
1158: X509_STORE *store = NULL;
1.19 inoguchi 1159: X509 *recip = NULL, *signer = NULL;
1.1 jsing 1160: EVP_PKEY *key = NULL;
1.19 inoguchi 1161: STACK_OF(X509) *other = NULL;
1.1 jsing 1162: BIO *in = NULL, *out = NULL, *indata = NULL, *rctin = NULL;
1163: int badarg = 0;
1164: CMS_ReceiptRequest *rr = NULL;
1.19 inoguchi 1165: char *passin = NULL;
1166: unsigned char *pwri_tmp = NULL;
1.4 doug 1167:
1.31 joshua 1168: if (pledge("stdio rpath wpath cpath tty", NULL) == -1) {
1169: perror("pledge");
1170: exit(1);
1.4 doug 1171: }
1.1 jsing 1172:
1.33 ! tb 1173: memset(&cfg, 0, sizeof(cfg));
! 1174: cfg.flags = CMS_DETACHED;
! 1175: cfg.rr_allorfirst = -1;
! 1176: cfg.informat = FORMAT_SMIME;
! 1177: cfg.outformat = FORMAT_SMIME;
! 1178: cfg.rctformat = FORMAT_SMIME;
! 1179: cfg.keyform = FORMAT_PEM;
1.19 inoguchi 1180: if (options_parse(argc, argv, cms_options, NULL, &argsused) != 0) {
1181: goto argerr;
1182: }
1183: args = argv + argsused;
1.1 jsing 1184: ret = 1;
1185:
1.33 ! tb 1186: if (((cfg.rr_allorfirst != -1) || cfg.rr_from != NULL) &&
! 1187: cfg.rr_to == NULL) {
1.1 jsing 1188: BIO_puts(bio_err, "No Signed Receipts Recipients\n");
1189: goto argerr;
1190: }
1.33 ! tb 1191: if (!(cfg.operation & SMIME_SIGNERS) &&
! 1192: (cfg.rr_to != NULL || cfg.rr_from != NULL)) {
1.1 jsing 1193: BIO_puts(bio_err, "Signed receipts only allowed with -sign\n");
1194: goto argerr;
1195: }
1.33 ! tb 1196: if (!(cfg.operation & SMIME_SIGNERS) &&
! 1197: (cfg.skkeys != NULL || cfg.sksigners != NULL)) {
1.1 jsing 1198: BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
1199: goto argerr;
1200: }
1.33 ! tb 1201: if (cfg.operation & SMIME_SIGNERS) {
! 1202: if (cfg.keyfile != NULL &&
! 1203: cfg.signerfile == NULL) {
1.1 jsing 1204: BIO_puts(bio_err, "Illegal -inkey without -signer\n");
1205: goto argerr;
1206: }
1207: /* Check to see if any final signer needs to be appended */
1.33 ! tb 1208: if (cfg.signerfile != NULL) {
! 1209: if (cfg.sksigners == NULL &&
! 1210: (cfg.sksigners =
1.24 inoguchi 1211: sk_OPENSSL_STRING_new_null()) == NULL)
1.16 inoguchi 1212: goto end;
1.33 ! tb 1213: if (!sk_OPENSSL_STRING_push(cfg.sksigners,
! 1214: cfg.signerfile))
1.15 inoguchi 1215: goto end;
1.33 ! tb 1216: if (cfg.skkeys == NULL &&
! 1217: (cfg.skkeys =
1.24 inoguchi 1218: sk_OPENSSL_STRING_new_null()) == NULL)
1.16 inoguchi 1219: goto end;
1.33 ! tb 1220: if (cfg.keyfile == NULL)
! 1221: cfg.keyfile = cfg.signerfile;
! 1222: if (!sk_OPENSSL_STRING_push(cfg.skkeys,
! 1223: cfg.keyfile))
1.15 inoguchi 1224: goto end;
1.1 jsing 1225: }
1.33 ! tb 1226: if (cfg.sksigners == NULL) {
1.1 jsing 1227: BIO_printf(bio_err,
1228: "No signer certificate specified\n");
1229: badarg = 1;
1230: }
1.33 ! tb 1231: cfg.signerfile = NULL;
! 1232: cfg.keyfile = NULL;
! 1233: } else if (cfg.operation == SMIME_DECRYPT) {
! 1234: if (cfg.recipfile == NULL &&
! 1235: cfg.keyfile == NULL &&
! 1236: cfg.secret_key == NULL &&
! 1237: cfg.pwri_pass == NULL) {
1.1 jsing 1238: BIO_printf(bio_err,
1239: "No recipient certificate or key specified\n");
1240: badarg = 1;
1241: }
1.33 ! tb 1242: } else if (cfg.operation == SMIME_ENCRYPT) {
! 1243: if (*args == NULL && cfg.secret_key == NULL &&
! 1244: cfg.pwri_pass == NULL &&
! 1245: cfg.encerts == NULL) {
1.1 jsing 1246: BIO_printf(bio_err,
1247: "No recipient(s) certificate(s) specified\n");
1248: badarg = 1;
1249: }
1.33 ! tb 1250: } else if (!cfg.operation) {
1.1 jsing 1251: badarg = 1;
1.24 inoguchi 1252: }
1.1 jsing 1253:
1254: if (badarg) {
1.13 jsing 1255: argerr:
1.19 inoguchi 1256: cms_usage();
1.1 jsing 1257: goto end;
1258: }
1259:
1.33 ! tb 1260: if (!app_passwd(bio_err, cfg.passargin, NULL, &passin, NULL)) {
1.1 jsing 1261: BIO_printf(bio_err, "Error getting password\n");
1262: goto end;
1263: }
1264: ret = 2;
1265:
1.33 ! tb 1266: if (!(cfg.operation & SMIME_SIGNERS))
! 1267: cfg.flags &= ~CMS_DETACHED;
1.1 jsing 1268:
1.33 ! tb 1269: if (cfg.operation & SMIME_OP) {
! 1270: if (cfg.outformat == FORMAT_ASN1)
1.1 jsing 1271: outmode = "wb";
1272: } else {
1.33 ! tb 1273: if (cfg.flags & CMS_BINARY)
1.1 jsing 1274: outmode = "wb";
1275: }
1276:
1.33 ! tb 1277: if (cfg.operation & SMIME_IP) {
! 1278: if (cfg.informat == FORMAT_ASN1)
1.1 jsing 1279: inmode = "rb";
1280: } else {
1.33 ! tb 1281: if (cfg.flags & CMS_BINARY)
1.1 jsing 1282: inmode = "rb";
1283: }
1284:
1.33 ! tb 1285: if (cfg.operation == SMIME_ENCRYPT) {
! 1286: if (cfg.cipher == NULL) {
1.1 jsing 1287: #ifndef OPENSSL_NO_DES
1.33 ! tb 1288: cfg.cipher = EVP_des_ede3_cbc();
1.1 jsing 1289: #else
1290: BIO_printf(bio_err, "No cipher selected\n");
1291: goto end;
1292: #endif
1293: }
1.33 ! tb 1294: if (cfg.secret_key != NULL &&
! 1295: cfg.secret_keyid == NULL) {
1.1 jsing 1296: BIO_printf(bio_err, "No secret key id\n");
1297: goto end;
1298: }
1.33 ! tb 1299: if (*args != NULL && cfg.encerts == NULL)
! 1300: if ((cfg.encerts = sk_X509_new_null()) == NULL)
1.16 inoguchi 1301: goto end;
1.1 jsing 1302: while (*args) {
1.33 ! tb 1303: if ((cfg.cert = load_cert(bio_err, *args,
1.24 inoguchi 1304: FORMAT_PEM, NULL,
1305: "recipient certificate file")) == NULL)
1.1 jsing 1306: goto end;
1.33 ! tb 1307: if (!sk_X509_push(cfg.encerts, cfg.cert))
1.15 inoguchi 1308: goto end;
1.33 ! tb 1309: cfg.cert = NULL;
1.1 jsing 1310: args++;
1311: }
1312: }
1.33 ! tb 1313: if (cfg.certfile != NULL) {
! 1314: if ((other = load_certs(bio_err, cfg.certfile,
1.24 inoguchi 1315: FORMAT_PEM, NULL, "certificate file")) == NULL) {
1.1 jsing 1316: ERR_print_errors(bio_err);
1317: goto end;
1318: }
1319: }
1.33 ! tb 1320: if (cfg.recipfile != NULL &&
! 1321: (cfg.operation == SMIME_DECRYPT)) {
! 1322: if ((recip = load_cert(bio_err, cfg.recipfile,
1.24 inoguchi 1323: FORMAT_PEM, NULL, "recipient certificate file")) == NULL) {
1.1 jsing 1324: ERR_print_errors(bio_err);
1325: goto end;
1326: }
1327: }
1.33 ! tb 1328: if (cfg.operation == SMIME_SIGN_RECEIPT) {
! 1329: if ((signer = load_cert(bio_err, cfg.signerfile,
1.24 inoguchi 1330: FORMAT_PEM, NULL,
1.22 inoguchi 1331: "receipt signer certificate file")) == NULL) {
1.1 jsing 1332: ERR_print_errors(bio_err);
1333: goto end;
1334: }
1335: }
1.33 ! tb 1336: if (cfg.operation == SMIME_DECRYPT) {
! 1337: if (cfg.keyfile == NULL)
! 1338: cfg.keyfile = cfg.recipfile;
! 1339: } else if ((cfg.operation == SMIME_SIGN) ||
! 1340: (cfg.operation == SMIME_SIGN_RECEIPT)) {
! 1341: if (cfg.keyfile == NULL)
! 1342: cfg.keyfile = cfg.signerfile;
1.24 inoguchi 1343: } else {
1.33 ! tb 1344: cfg.keyfile = NULL;
1.24 inoguchi 1345: }
1.1 jsing 1346:
1.33 ! tb 1347: if (cfg.keyfile != NULL) {
! 1348: key = load_key(bio_err, cfg.keyfile, cfg.keyform,
1.24 inoguchi 1349: 0, passin, "signing key file");
1.22 inoguchi 1350: if (key == NULL)
1.1 jsing 1351: goto end;
1352: }
1.33 ! tb 1353: if (cfg.infile != NULL) {
! 1354: if ((in = BIO_new_file(cfg.infile, inmode)) == NULL) {
1.1 jsing 1355: BIO_printf(bio_err,
1.33 ! tb 1356: "Can't open input file %s\n", cfg.infile);
1.1 jsing 1357: goto end;
1358: }
1.24 inoguchi 1359: } else {
1.23 inoguchi 1360: if ((in = BIO_new_fp(stdin, BIO_NOCLOSE)) == NULL)
1361: goto end;
1.24 inoguchi 1362: }
1.1 jsing 1363:
1.33 ! tb 1364: if (cfg.operation & SMIME_IP) {
! 1365: if (cfg.informat == FORMAT_SMIME)
1.1 jsing 1366: cms = SMIME_read_CMS(in, &indata);
1.33 ! tb 1367: else if (cfg.informat == FORMAT_PEM)
1.1 jsing 1368: cms = PEM_read_bio_CMS(in, NULL, NULL, NULL);
1.33 ! tb 1369: else if (cfg.informat == FORMAT_ASN1)
1.1 jsing 1370: cms = d2i_CMS_bio(in, NULL);
1371: else {
1372: BIO_printf(bio_err, "Bad input format for CMS file\n");
1373: goto end;
1374: }
1375:
1.22 inoguchi 1376: if (cms == NULL) {
1.1 jsing 1377: BIO_printf(bio_err, "Error reading S/MIME message\n");
1378: goto end;
1379: }
1.33 ! tb 1380: if (cfg.contfile != NULL) {
1.1 jsing 1381: BIO_free(indata);
1.33 ! tb 1382: if ((indata = BIO_new_file(cfg.contfile,
1.24 inoguchi 1383: "rb")) == NULL) {
1.1 jsing 1384: BIO_printf(bio_err,
1.24 inoguchi 1385: "Can't read content file %s\n",
1.33 ! tb 1386: cfg.contfile);
1.1 jsing 1387: goto end;
1388: }
1389: }
1.33 ! tb 1390: if (cfg.certsoutfile != NULL) {
1.12 jsing 1391: STACK_OF(X509) *allcerts;
1.17 inoguchi 1392: if ((allcerts = CMS_get1_certs(cms)) == NULL)
1393: goto end;
1.33 ! tb 1394: if (!save_certs(cfg.certsoutfile, allcerts)) {
1.1 jsing 1395: BIO_printf(bio_err,
1396: "Error writing certs to %s\n",
1.33 ! tb 1397: cfg.certsoutfile);
1.29 inoguchi 1398: sk_X509_pop_free(allcerts, X509_free);
1.1 jsing 1399: ret = 5;
1400: goto end;
1401: }
1402: sk_X509_pop_free(allcerts, X509_free);
1403: }
1404: }
1.33 ! tb 1405: if (cfg.rctfile != NULL) {
! 1406: char *rctmode = (cfg.rctformat == FORMAT_ASN1) ?
1.24 inoguchi 1407: "rb" : "r";
1.33 ! tb 1408: if ((rctin = BIO_new_file(cfg.rctfile, rctmode)) == NULL) {
1.1 jsing 1409: BIO_printf(bio_err,
1.33 ! tb 1410: "Can't open receipt file %s\n", cfg.rctfile);
1.1 jsing 1411: goto end;
1412: }
1.33 ! tb 1413: if (cfg.rctformat == FORMAT_SMIME)
1.1 jsing 1414: rcms = SMIME_read_CMS(rctin, NULL);
1.33 ! tb 1415: else if (cfg.rctformat == FORMAT_PEM)
1.1 jsing 1416: rcms = PEM_read_bio_CMS(rctin, NULL, NULL, NULL);
1.33 ! tb 1417: else if (cfg.rctformat == FORMAT_ASN1)
1.1 jsing 1418: rcms = d2i_CMS_bio(rctin, NULL);
1419: else {
1420: BIO_printf(bio_err, "Bad input format for receipt\n");
1421: goto end;
1422: }
1423:
1.22 inoguchi 1424: if (rcms == NULL) {
1.1 jsing 1425: BIO_printf(bio_err, "Error reading receipt\n");
1426: goto end;
1427: }
1428: }
1.33 ! tb 1429: if (cfg.outfile != NULL) {
! 1430: if ((out = BIO_new_file(cfg.outfile, outmode)) == NULL) {
1.1 jsing 1431: BIO_printf(bio_err,
1.33 ! tb 1432: "Can't open output file %s\n", cfg.outfile);
1.1 jsing 1433: goto end;
1434: }
1435: } else {
1.23 inoguchi 1436: if ((out = BIO_new_fp(stdout, BIO_NOCLOSE)) == NULL)
1437: goto end;
1.1 jsing 1438: }
1439:
1.33 ! tb 1440: if ((cfg.operation == SMIME_VERIFY) ||
! 1441: (cfg.operation == SMIME_VERIFY_RECEIPT)) {
! 1442: if ((store = setup_verify(bio_err, cfg.CAfile,
! 1443: cfg.CApath)) == NULL)
1.1 jsing 1444: goto end;
1445: X509_STORE_set_verify_cb(store, cms_cb);
1.33 ! tb 1446: if (cfg.vpm != NULL) {
! 1447: if (!X509_STORE_set1_param(store, cfg.vpm))
1.23 inoguchi 1448: goto end;
1449: }
1.1 jsing 1450: }
1451: ret = 3;
1452:
1.33 ! tb 1453: if (cfg.operation == SMIME_DATA_CREATE) {
! 1454: cms = CMS_data_create(in, cfg.flags);
! 1455: } else if (cfg.operation == SMIME_DIGEST_CREATE) {
! 1456: cms = CMS_digest_create(in, cfg.sign_md,
! 1457: cfg.flags);
! 1458: } else if (cfg.operation == SMIME_COMPRESS) {
! 1459: cms = CMS_compress(in, -1, cfg.flags);
! 1460: } else if (cfg.operation == SMIME_ENCRYPT) {
1.14 inoguchi 1461: int i;
1.33 ! tb 1462: cfg.flags |= CMS_PARTIAL;
! 1463: cms = CMS_encrypt(NULL, in, cfg.cipher,
! 1464: cfg.flags);
1.14 inoguchi 1465: if (cms == NULL)
1.1 jsing 1466: goto end;
1.33 ! tb 1467: for (i = 0; i < sk_X509_num(cfg.encerts); i++) {
1.14 inoguchi 1468: CMS_RecipientInfo *ri;
1.15 inoguchi 1469: struct cms_key_param *kparam;
1.33 ! tb 1470: int tflags = cfg.flags;
1.23 inoguchi 1471: X509 *x;
1.32 tb 1472:
1.33 ! tb 1473: if ((x = sk_X509_value(cfg.encerts, i)) == NULL)
1.23 inoguchi 1474: goto end;
1.33 ! tb 1475: for (kparam = cfg.key_first; kparam != NULL;
1.24 inoguchi 1476: kparam = kparam->next) {
1.14 inoguchi 1477: if (kparam->idx == i) {
1478: tflags |= CMS_KEY_PARAM;
1479: break;
1480: }
1481: }
1482: ri = CMS_add1_recipient_cert(cms, x, tflags);
1483: if (ri == NULL)
1484: goto end;
1485: if (kparam != NULL) {
1486: EVP_PKEY_CTX *pctx;
1.24 inoguchi 1487: if ((pctx = CMS_RecipientInfo_get0_pkey_ctx(
1488: ri)) == NULL)
1.17 inoguchi 1489: goto end;
1.14 inoguchi 1490: if (!cms_set_pkey_param(pctx, kparam->param))
1491: goto end;
1492: }
1493: }
1494:
1.33 ! tb 1495: if (cfg.secret_key != NULL) {
1.24 inoguchi 1496: if (CMS_add0_recipient_key(cms, NID_undef,
1.33 ! tb 1497: cfg.secret_key, cfg.secret_keylen,
! 1498: cfg.secret_keyid, cfg.secret_keyidlen,
1.22 inoguchi 1499: NULL, NULL, NULL) == NULL)
1.1 jsing 1500: goto end;
1501: /* NULL these because call absorbs them */
1.33 ! tb 1502: cfg.secret_key = NULL;
! 1503: cfg.secret_keyid = NULL;
1.1 jsing 1504: }
1.33 ! tb 1505: if (cfg.pwri_pass != NULL) {
! 1506: pwri_tmp = strdup(cfg.pwri_pass);
1.22 inoguchi 1507: if (pwri_tmp == NULL)
1.1 jsing 1508: goto end;
1.22 inoguchi 1509: if (CMS_add0_recipient_password(cms, -1, NID_undef,
1510: NID_undef, pwri_tmp, -1, NULL) == NULL)
1.1 jsing 1511: goto end;
1512: pwri_tmp = NULL;
1513: }
1.33 ! tb 1514: if (!(cfg.flags & CMS_STREAM)) {
! 1515: if (!CMS_final(cms, in, NULL, cfg.flags))
1.1 jsing 1516: goto end;
1517: }
1.33 ! tb 1518: } else if (cfg.operation == SMIME_ENCRYPTED_ENCRYPT) {
! 1519: cms = CMS_EncryptedData_encrypt(in, cfg.cipher,
! 1520: cfg.secret_key, cfg.secret_keylen,
! 1521: cfg.flags);
1.1 jsing 1522:
1.33 ! tb 1523: } else if (cfg.operation == SMIME_SIGN_RECEIPT) {
1.1 jsing 1524: CMS_ContentInfo *srcms = NULL;
1.12 jsing 1525: STACK_OF(CMS_SignerInfo) *sis;
1.1 jsing 1526: CMS_SignerInfo *si;
1527: sis = CMS_get0_SignerInfos(cms);
1.22 inoguchi 1528: if (sis == NULL)
1.1 jsing 1529: goto end;
1530: si = sk_CMS_SignerInfo_value(sis, 0);
1.23 inoguchi 1531: if (si == NULL)
1532: goto end;
1.24 inoguchi 1533: srcms = CMS_sign_receipt(si, signer, key, other,
1.33 ! tb 1534: cfg.flags);
1.22 inoguchi 1535: if (srcms == NULL)
1.1 jsing 1536: goto end;
1537: CMS_ContentInfo_free(cms);
1538: cms = srcms;
1.33 ! tb 1539: } else if (cfg.operation & SMIME_SIGNERS) {
1.1 jsing 1540: int i;
1541: /*
1542: * If detached data content we enable streaming if S/MIME
1543: * output format.
1544: */
1.33 ! tb 1545: if (cfg.operation == SMIME_SIGN) {
1.1 jsing 1546:
1.33 ! tb 1547: if (cfg.flags & CMS_DETACHED) {
! 1548: if (cfg.outformat == FORMAT_SMIME)
! 1549: cfg.flags |= CMS_STREAM;
1.1 jsing 1550: }
1.33 ! tb 1551: cfg.flags |= CMS_PARTIAL;
! 1552: cms = CMS_sign(NULL, NULL, other, in, cfg.flags);
1.22 inoguchi 1553: if (cms == NULL)
1.1 jsing 1554: goto end;
1.33 ! tb 1555: if (cfg.econtent_type != NULL)
1.24 inoguchi 1556: if (!CMS_set1_eContentType(cms,
1.33 ! tb 1557: cfg.econtent_type))
1.17 inoguchi 1558: goto end;
1.1 jsing 1559:
1.33 ! tb 1560: if (cfg.rr_to != NULL) {
! 1561: rr = make_receipt_request(cfg.rr_to,
! 1562: cfg.rr_allorfirst,
! 1563: cfg.rr_from);
1.22 inoguchi 1564: if (rr == NULL) {
1.1 jsing 1565: BIO_puts(bio_err,
1566: "Signed Receipt Request Creation Error\n");
1567: goto end;
1568: }
1569: }
1.24 inoguchi 1570: } else {
1.33 ! tb 1571: cfg.flags |= CMS_REUSE_DIGEST;
1.24 inoguchi 1572: }
1573:
1.33 ! tb 1574: for (i = 0; i < sk_OPENSSL_STRING_num(cfg.sksigners); i++) {
1.1 jsing 1575: CMS_SignerInfo *si;
1.15 inoguchi 1576: struct cms_key_param *kparam;
1.33 ! tb 1577: int tflags = cfg.flags;
1.14 inoguchi 1578:
1.33 ! tb 1579: cfg.signerfile = sk_OPENSSL_STRING_value(
! 1580: cfg.sksigners, i);
! 1581: cfg.keyfile = sk_OPENSSL_STRING_value(
! 1582: cfg.skkeys, i);
1.24 inoguchi 1583:
1.33 ! tb 1584: signer = load_cert(bio_err, cfg.signerfile,
1.24 inoguchi 1585: FORMAT_PEM, NULL, "signer certificate");
1.22 inoguchi 1586: if (signer == NULL)
1.1 jsing 1587: goto end;
1.33 ! tb 1588: key = load_key(bio_err, cfg.keyfile,
! 1589: cfg.keyform, 0, passin, "signing key file");
1.22 inoguchi 1590: if (key == NULL)
1.1 jsing 1591: goto end;
1.33 ! tb 1592: for (kparam = cfg.key_first; kparam != NULL;
1.24 inoguchi 1593: kparam = kparam->next) {
1.14 inoguchi 1594: if (kparam->idx == i) {
1595: tflags |= CMS_KEY_PARAM;
1596: break;
1597: }
1598: }
1.24 inoguchi 1599: si = CMS_add1_signer(cms, signer, key,
1.33 ! tb 1600: cfg.sign_md, tflags);
1.14 inoguchi 1601: if (si == NULL)
1.1 jsing 1602: goto end;
1.14 inoguchi 1603: if (kparam != NULL) {
1604: EVP_PKEY_CTX *pctx;
1.24 inoguchi 1605: if ((pctx = CMS_SignerInfo_get0_pkey_ctx(
1606: si)) == NULL)
1.17 inoguchi 1607: goto end;
1.14 inoguchi 1608: if (!cms_set_pkey_param(pctx, kparam->param))
1609: goto end;
1610: }
1.22 inoguchi 1611: if (rr != NULL && !CMS_add1_ReceiptRequest(si, rr))
1.1 jsing 1612: goto end;
1613: X509_free(signer);
1614: signer = NULL;
1615: EVP_PKEY_free(key);
1616: key = NULL;
1617: }
1618: /* If not streaming or resigning finalize structure */
1.33 ! tb 1619: if ((cfg.operation == SMIME_SIGN) &&
! 1620: !(cfg.flags & CMS_STREAM)) {
! 1621: if (!CMS_final(cms, in, NULL, cfg.flags))
1.1 jsing 1622: goto end;
1623: }
1624: }
1.22 inoguchi 1625: if (cms == NULL) {
1.1 jsing 1626: BIO_printf(bio_err, "Error creating CMS structure\n");
1627: goto end;
1628: }
1629: ret = 4;
1.33 ! tb 1630: if (cfg.operation == SMIME_DECRYPT) {
! 1631: if (cfg.flags & CMS_DEBUG_DECRYPT)
1.24 inoguchi 1632: CMS_decrypt(cms, NULL, NULL, NULL, NULL,
1.33 ! tb 1633: cfg.flags);
1.19 inoguchi 1634:
1.33 ! tb 1635: if (cfg.secret_key != NULL) {
! 1636: if (!CMS_decrypt_set1_key(cms, cfg.secret_key,
! 1637: cfg.secret_keylen, cfg.secret_keyid,
! 1638: cfg.secret_keyidlen)) {
1.1 jsing 1639: BIO_puts(bio_err,
1640: "Error decrypting CMS using secret key\n");
1641: goto end;
1642: }
1643: }
1.22 inoguchi 1644: if (key != NULL) {
1.1 jsing 1645: if (!CMS_decrypt_set1_pkey(cms, key, recip)) {
1646: BIO_puts(bio_err,
1647: "Error decrypting CMS using private key\n");
1648: goto end;
1649: }
1650: }
1.33 ! tb 1651: if (cfg.pwri_pass != NULL) {
1.24 inoguchi 1652: if (!CMS_decrypt_set1_password(cms,
1.33 ! tb 1653: cfg.pwri_pass, -1)) {
1.1 jsing 1654: BIO_puts(bio_err,
1655: "Error decrypting CMS using password\n");
1656: goto end;
1657: }
1658: }
1.24 inoguchi 1659: if (!CMS_decrypt(cms, NULL, NULL, indata, out,
1.33 ! tb 1660: cfg.flags)) {
1.1 jsing 1661: BIO_printf(bio_err, "Error decrypting CMS structure\n");
1662: goto end;
1663: }
1.33 ! tb 1664: } else if (cfg.operation == SMIME_DATAOUT) {
! 1665: if (!CMS_data(cms, out, cfg.flags))
1.1 jsing 1666: goto end;
1.33 ! tb 1667: } else if (cfg.operation == SMIME_UNCOMPRESS) {
! 1668: if (!CMS_uncompress(cms, indata, out, cfg.flags))
1.1 jsing 1669: goto end;
1.33 ! tb 1670: } else if (cfg.operation == SMIME_DIGEST_VERIFY) {
! 1671: if (CMS_digest_verify(cms, indata, out, cfg.flags) > 0)
1.1 jsing 1672: BIO_printf(bio_err, "Verification successful\n");
1673: else {
1674: BIO_printf(bio_err, "Verification failure\n");
1675: goto end;
1676: }
1.33 ! tb 1677: } else if (cfg.operation == SMIME_ENCRYPTED_DECRYPT) {
! 1678: if (!CMS_EncryptedData_decrypt(cms, cfg.secret_key,
! 1679: cfg.secret_keylen, indata, out, cfg.flags))
1.1 jsing 1680: goto end;
1.33 ! tb 1681: } else if (cfg.operation == SMIME_VERIFY) {
1.24 inoguchi 1682: if (CMS_verify(cms, other, store, indata, out,
1.33 ! tb 1683: cfg.flags) > 0) {
1.1 jsing 1684: BIO_printf(bio_err, "Verification successful\n");
1.24 inoguchi 1685: } else {
1.1 jsing 1686: BIO_printf(bio_err, "Verification failure\n");
1.33 ! tb 1687: if (cfg.verify_retcode)
1.1 jsing 1688: ret = verify_err + 32;
1689: goto end;
1690: }
1.33 ! tb 1691: if (cfg.signerfile != NULL) {
1.12 jsing 1692: STACK_OF(X509) *signers;
1.17 inoguchi 1693: if ((signers = CMS_get0_signers(cms)) == NULL)
1694: goto end;
1.33 ! tb 1695: if (!save_certs(cfg.signerfile, signers)) {
1.1 jsing 1696: BIO_printf(bio_err,
1697: "Error writing signers to %s\n",
1.33 ! tb 1698: cfg.signerfile);
1.29 inoguchi 1699: sk_X509_free(signers);
1.1 jsing 1700: ret = 5;
1701: goto end;
1702: }
1703: sk_X509_free(signers);
1704: }
1.33 ! tb 1705: if (cfg.rr_print)
1.1 jsing 1706: receipt_request_print(bio_err, cms);
1707:
1.33 ! tb 1708: } else if (cfg.operation == SMIME_VERIFY_RECEIPT) {
1.24 inoguchi 1709: if (CMS_verify_receipt(rcms, cms, other, store,
1.33 ! tb 1710: cfg.flags) > 0) {
1.1 jsing 1711: BIO_printf(bio_err, "Verification successful\n");
1.24 inoguchi 1712: } else {
1.1 jsing 1713: BIO_printf(bio_err, "Verification failure\n");
1714: goto end;
1715: }
1716: } else {
1.33 ! tb 1717: if (cfg.noout) {
! 1718: if (cfg.print &&
1.17 inoguchi 1719: !CMS_ContentInfo_print_ctx(out, cms, 0, NULL))
1720: goto end;
1.33 ! tb 1721: } else if (cfg.outformat == FORMAT_SMIME) {
! 1722: if (cfg.to != NULL)
! 1723: BIO_printf(out, "To: %s\n", cfg.to);
! 1724: if (cfg.from != NULL)
! 1725: BIO_printf(out, "From: %s\n", cfg.from);
! 1726: if (cfg.subject != NULL)
1.24 inoguchi 1727: BIO_printf(out, "Subject: %s\n",
1.33 ! tb 1728: cfg.subject);
! 1729: if (cfg.operation == SMIME_RESIGN)
1.24 inoguchi 1730: ret = SMIME_write_CMS(out, cms, indata,
1.33 ! tb 1731: cfg.flags);
1.1 jsing 1732: else
1.24 inoguchi 1733: ret = SMIME_write_CMS(out, cms, in,
1.33 ! tb 1734: cfg.flags);
! 1735: } else if (cfg.outformat == FORMAT_PEM) {
1.24 inoguchi 1736: ret = PEM_write_bio_CMS_stream(out, cms, in,
1.33 ! tb 1737: cfg.flags);
! 1738: } else if (cfg.outformat == FORMAT_ASN1) {
! 1739: ret = i2d_CMS_bio_stream(out, cms, in, cfg.flags);
1.24 inoguchi 1740: } else {
1.1 jsing 1741: BIO_printf(bio_err, "Bad output format for CMS file\n");
1742: goto end;
1743: }
1744: if (ret <= 0) {
1745: ret = 6;
1746: goto end;
1747: }
1748: }
1749: ret = 0;
1750:
1.13 jsing 1751: end:
1.1 jsing 1752: if (ret)
1753: ERR_print_errors(bio_err);
1.11 jsing 1754:
1.33 ! tb 1755: sk_X509_pop_free(cfg.encerts, X509_free);
1.1 jsing 1756: sk_X509_pop_free(other, X509_free);
1.33 ! tb 1757: X509_VERIFY_PARAM_free(cfg.vpm);
! 1758: sk_OPENSSL_STRING_free(cfg.sksigners);
! 1759: sk_OPENSSL_STRING_free(cfg.skkeys);
! 1760: free(cfg.secret_key);
! 1761: free(cfg.secret_keyid);
1.1 jsing 1762: free(pwri_tmp);
1.33 ! tb 1763: ASN1_OBJECT_free(cfg.econtent_type);
1.11 jsing 1764: CMS_ReceiptRequest_free(rr);
1.33 ! tb 1765: sk_OPENSSL_STRING_free(cfg.rr_to);
! 1766: sk_OPENSSL_STRING_free(cfg.rr_from);
! 1767: for (cfg.key_param = cfg.key_first; cfg.key_param;) {
1.15 inoguchi 1768: struct cms_key_param *tparam;
1.33 ! tb 1769: sk_OPENSSL_STRING_free(cfg.key_param->param);
! 1770: tparam = cfg.key_param->next;
! 1771: free(cfg.key_param);
! 1772: cfg.key_param = tparam;
1.14 inoguchi 1773: }
1.1 jsing 1774: X509_STORE_free(store);
1.33 ! tb 1775: X509_free(cfg.cert);
1.1 jsing 1776: X509_free(recip);
1777: X509_free(signer);
1778: EVP_PKEY_free(key);
1779: CMS_ContentInfo_free(cms);
1780: CMS_ContentInfo_free(rcms);
1781: BIO_free(rctin);
1782: BIO_free(in);
1783: BIO_free(indata);
1784: BIO_free_all(out);
1785: free(passin);
1.11 jsing 1786:
1.1 jsing 1787: return (ret);
1788: }
1789:
1790: static int
1.12 jsing 1791: save_certs(char *signerfile, STACK_OF(X509) *signers)
1.1 jsing 1792: {
1793: int i;
1794: BIO *tmp;
1795:
1.22 inoguchi 1796: if (signerfile == NULL)
1.1 jsing 1797: return 1;
1798: tmp = BIO_new_file(signerfile, "w");
1.22 inoguchi 1799: if (tmp == NULL)
1.1 jsing 1800: return 0;
1801: for (i = 0; i < sk_X509_num(signers); i++)
1802: PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
1803: BIO_free(tmp);
1804: return 1;
1805: }
1806:
1807: /* Minimal callback just to output policy info (if any) */
1808:
1809: static int
1.12 jsing 1810: cms_cb(int ok, X509_STORE_CTX *ctx)
1.1 jsing 1811: {
1812: int error;
1813:
1814: error = X509_STORE_CTX_get_error(ctx);
1815:
1816: verify_err = error;
1817:
1818: if ((error != X509_V_ERR_NO_EXPLICIT_POLICY) &&
1819: ((error != X509_V_OK) || (ok != 2)))
1820: return ok;
1821:
1822: policies_print(NULL, ctx);
1823:
1824: return ok;
1825: }
1826:
1827: static void
1.12 jsing 1828: gnames_stack_print(BIO *out, STACK_OF(GENERAL_NAMES) *gns)
1.1 jsing 1829: {
1.12 jsing 1830: STACK_OF(GENERAL_NAME) *gens;
1.1 jsing 1831: GENERAL_NAME *gen;
1832: int i, j;
1833:
1834: for (i = 0; i < sk_GENERAL_NAMES_num(gns); i++) {
1835: gens = sk_GENERAL_NAMES_value(gns, i);
1836: for (j = 0; j < sk_GENERAL_NAME_num(gens); j++) {
1837: gen = sk_GENERAL_NAME_value(gens, j);
1838: BIO_puts(out, " ");
1839: GENERAL_NAME_print(out, gen);
1840: BIO_puts(out, "\n");
1841: }
1842: }
1843: return;
1844: }
1845:
1846: static void
1.12 jsing 1847: receipt_request_print(BIO *out, CMS_ContentInfo *cms)
1.1 jsing 1848: {
1.12 jsing 1849: STACK_OF(CMS_SignerInfo) *sis;
1.1 jsing 1850: CMS_SignerInfo *si;
1851: CMS_ReceiptRequest *rr;
1852: int allorfirst;
1.12 jsing 1853: STACK_OF(GENERAL_NAMES) *rto, *rlist;
1.1 jsing 1854: ASN1_STRING *scid;
1855: int i, rv;
1856:
1.17 inoguchi 1857: if ((sis = CMS_get0_SignerInfos(cms)) == NULL)
1858: return;
1.1 jsing 1859: for (i = 0; i < sk_CMS_SignerInfo_num(sis); i++) {
1.23 inoguchi 1860: if ((si = sk_CMS_SignerInfo_value(sis, i)) == NULL)
1861: return;
1.1 jsing 1862: rv = CMS_get1_ReceiptRequest(si, &rr);
1863: BIO_printf(bio_err, "Signer %d:\n", i + 1);
1.24 inoguchi 1864: if (rv == 0) {
1.1 jsing 1865: BIO_puts(bio_err, " No Receipt Request\n");
1.24 inoguchi 1866: } else if (rv < 0) {
1.1 jsing 1867: BIO_puts(bio_err, " Receipt Request Parse Error\n");
1868: ERR_print_errors(bio_err);
1869: } else {
1870: char *id;
1871: int idlen;
1.24 inoguchi 1872:
1.1 jsing 1873: CMS_ReceiptRequest_get0_values(rr, &scid, &allorfirst,
1874: &rlist, &rto);
1875: BIO_puts(out, " Signed Content ID:\n");
1876: idlen = ASN1_STRING_length(scid);
1877: id = (char *) ASN1_STRING_data(scid);
1878: BIO_dump_indent(out, id, idlen, 4);
1879: BIO_puts(out, " Receipts From");
1.22 inoguchi 1880: if (rlist != NULL) {
1.1 jsing 1881: BIO_puts(out, " List:\n");
1882: gnames_stack_print(out, rlist);
1.24 inoguchi 1883: } else if (allorfirst == 1) {
1.1 jsing 1884: BIO_puts(out, ": First Tier\n");
1.24 inoguchi 1885: } else if (allorfirst == 0) {
1.1 jsing 1886: BIO_puts(out, ": All\n");
1.24 inoguchi 1887: } else {
1.1 jsing 1888: BIO_printf(out, " Unknown (%d)\n", allorfirst);
1.24 inoguchi 1889: }
1.1 jsing 1890: BIO_puts(out, " Receipts To:\n");
1891: gnames_stack_print(out, rto);
1892: }
1.25 inoguchi 1893: CMS_ReceiptRequest_free(rr);
1.1 jsing 1894: }
1895: }
1896:
1897: static STACK_OF(GENERAL_NAMES) *
1.12 jsing 1898: make_names_stack(STACK_OF(OPENSSL_STRING) *ns)
1.1 jsing 1899: {
1900: int i;
1.12 jsing 1901: STACK_OF(GENERAL_NAMES) *ret;
1.1 jsing 1902: GENERAL_NAMES *gens = NULL;
1903: GENERAL_NAME *gen = NULL;
1.22 inoguchi 1904:
1.16 inoguchi 1905: if ((ret = sk_GENERAL_NAMES_new_null()) == NULL)
1.1 jsing 1906: goto err;
1907: for (i = 0; i < sk_OPENSSL_STRING_num(ns); i++) {
1908: char *str = sk_OPENSSL_STRING_value(ns, i);
1909: gen = a2i_GENERAL_NAME(NULL, NULL, NULL, GEN_EMAIL, str, 0);
1.22 inoguchi 1910: if (gen == NULL)
1.1 jsing 1911: goto err;
1912: gens = GENERAL_NAMES_new();
1.22 inoguchi 1913: if (gens == NULL)
1.1 jsing 1914: goto err;
1915: if (!sk_GENERAL_NAME_push(gens, gen))
1916: goto err;
1917: gen = NULL;
1918: if (!sk_GENERAL_NAMES_push(ret, gens))
1919: goto err;
1920: gens = NULL;
1921: }
1922:
1923: return ret;
1924:
1.13 jsing 1925: err:
1.11 jsing 1926: sk_GENERAL_NAMES_pop_free(ret, GENERAL_NAMES_free);
1927: GENERAL_NAMES_free(gens);
1928: GENERAL_NAME_free(gen);
1929:
1.1 jsing 1930: return NULL;
1931: }
1932:
1933:
1934: static CMS_ReceiptRequest *
1.12 jsing 1935: make_receipt_request(STACK_OF(OPENSSL_STRING) *rr_to, int rr_allorfirst,
1936: STACK_OF(OPENSSL_STRING) *rr_from)
1.1 jsing 1937: {
1.26 inoguchi 1938: STACK_OF(GENERAL_NAMES) *rct_to = NULL, *rct_from = NULL;
1.1 jsing 1939: CMS_ReceiptRequest *rr;
1940:
1941: rct_to = make_names_stack(rr_to);
1.22 inoguchi 1942: if (rct_to == NULL)
1.1 jsing 1943: goto err;
1.22 inoguchi 1944: if (rr_from != NULL) {
1.1 jsing 1945: rct_from = make_names_stack(rr_from);
1.22 inoguchi 1946: if (rct_from == NULL)
1.1 jsing 1947: goto err;
1.24 inoguchi 1948: } else {
1.1 jsing 1949: rct_from = NULL;
1.24 inoguchi 1950: }
1.17 inoguchi 1951:
1952: if ((rr = CMS_ReceiptRequest_create0(NULL, -1, rr_allorfirst, rct_from,
1953: rct_to)) == NULL)
1954: goto err;
1955:
1.1 jsing 1956: return rr;
1957:
1.13 jsing 1958: err:
1.26 inoguchi 1959: sk_GENERAL_NAMES_pop_free(rct_to, GENERAL_NAMES_free);
1960: sk_GENERAL_NAMES_pop_free(rct_from, GENERAL_NAMES_free);
1.1 jsing 1961: return NULL;
1.14 inoguchi 1962: }
1963:
1964: static int
1965: cms_set_pkey_param(EVP_PKEY_CTX *pctx, STACK_OF(OPENSSL_STRING) *param)
1966: {
1967: char *keyopt;
1968: int i;
1.15 inoguchi 1969:
1.14 inoguchi 1970: if (sk_OPENSSL_STRING_num(param) <= 0)
1971: return 1;
1972: for (i = 0; i < sk_OPENSSL_STRING_num(param); i++) {
1973: keyopt = sk_OPENSSL_STRING_value(param, i);
1974: if (pkey_ctrl_string(pctx, keyopt) <= 0) {
1975: BIO_printf(bio_err, "parameter error \"%s\"\n", keyopt);
1976: ERR_print_errors(bio_err);
1977: return 0;
1978: }
1979: }
1980: return 1;
1.1 jsing 1981: }
1982:
1983: #endif