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