Annotation of src/usr.bin/openssl/pkcs8.c, Revision 1.4
1.4 ! doug 1: /* $OpenBSD: pkcs8.c,v 1.3 2014/08/28 14:25:48 jsing Exp $ */
1.1 jsing 2: /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3: * project 1999-2004.
4: */
5: /* ====================================================================
6: * Copyright (c) 1999 The OpenSSL Project. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: *
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: *
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in
17: * the documentation and/or other materials provided with the
18: * distribution.
19: *
20: * 3. All advertising materials mentioning features or use of this
21: * software must display the following acknowledgment:
22: * "This product includes software developed by the OpenSSL Project
23: * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24: *
25: * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26: * endorse or promote products derived from this software without
27: * prior written permission. For written permission, please contact
28: * licensing@OpenSSL.org.
29: *
30: * 5. Products derived from this software may not be called "OpenSSL"
31: * nor may "OpenSSL" appear in their names without prior written
32: * permission of the OpenSSL Project.
33: *
34: * 6. Redistributions of any form whatsoever must retain the following
35: * acknowledgment:
36: * "This product includes software developed by the OpenSSL Project
37: * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38: *
39: * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40: * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
43: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50: * OF THE POSSIBILITY OF SUCH DAMAGE.
51: * ====================================================================
52: *
53: * This product includes cryptographic software written by Eric Young
54: * (eay@cryptsoft.com). This product includes software written by Tim
55: * Hudson (tjh@cryptsoft.com).
56: *
57: */
58:
59: #include <stdio.h>
60: #include <string.h>
61:
62: #include "apps.h"
63:
64: #include <openssl/err.h>
65: #include <openssl/evp.h>
66: #include <openssl/pem.h>
67: #include <openssl/pkcs12.h>
68:
1.4 ! doug 69: static struct {
! 70: const EVP_CIPHER *cipher;
! 71: #ifndef OPENSSL_NO_ENGINE
! 72: char *engine;
! 73: #endif
! 74: char *infile;
! 75: int informat;
! 76: int iter;
! 77: int nocrypt;
! 78: char *outfile;
! 79: int outformat;
! 80: int p8_broken;
! 81: char *passargin;
! 82: char *passargout;
! 83: int pbe_nid;
! 84: int topk8;
! 85: } pkcs8_config;
! 86:
! 87: static int
! 88: pkcs8_opt_v1(char *arg)
! 89: {
! 90: if ((pkcs8_config.pbe_nid = OBJ_txt2nid(arg)) == NID_undef) {
! 91: fprintf(stderr, "Unknown PBE algorithm '%s'\n", arg);
! 92: return (1);
! 93: }
! 94:
! 95: return (0);
! 96: }
! 97:
! 98: static int
! 99: pkcs8_opt_v2(char *arg)
! 100: {
! 101: if ((pkcs8_config.cipher = EVP_get_cipherbyname(arg)) == NULL) {
! 102: fprintf(stderr, "Unknown cipher '%s'\n", arg);
! 103: return (1);
! 104: }
! 105:
! 106: return (0);
! 107: }
! 108:
! 109: static struct option pkcs8_options[] = {
! 110: {
! 111: .name = "embed",
! 112: .desc = "Generate DSA keys in a broken format",
! 113: .type = OPTION_VALUE,
! 114: .value = PKCS8_EMBEDDED_PARAM,
! 115: .opt.value = &pkcs8_config.p8_broken,
! 116: },
! 117: #ifndef OPENSSL_NO_ENGINE
! 118: {
! 119: .name = "engine",
! 120: .argname = "id",
! 121: .desc = "Use the engine specified by the given identifier",
! 122: .type = OPTION_ARG,
! 123: .opt.arg = &pkcs8_config.engine,
! 124: },
! 125: #endif
! 126: {
! 127: .name = "in",
! 128: .argname = "file",
! 129: .desc = "Input file (default stdin)",
! 130: .type = OPTION_ARG,
! 131: .opt.arg = &pkcs8_config.infile,
! 132: },
! 133: {
! 134: .name = "inform",
! 135: .argname = "format",
! 136: .desc = "Input format (DER or PEM (default))",
! 137: .type = OPTION_ARG_FORMAT,
! 138: .opt.value = &pkcs8_config.informat,
! 139: },
! 140: {
! 141: .name = "nocrypt",
! 142: .desc = "Use or expect unencrypted private key",
! 143: .type = OPTION_FLAG,
! 144: .opt.flag = &pkcs8_config.nocrypt,
! 145: },
! 146: {
! 147: .name = "noiter",
! 148: .desc = "Use 1 as iteration count",
! 149: .type = OPTION_VALUE,
! 150: .value = 1,
! 151: .opt.value = &pkcs8_config.iter,
! 152: },
! 153: {
! 154: .name = "nooct",
! 155: .desc = "Generate RSA keys in a broken format (no octet)",
! 156: .type = OPTION_VALUE,
! 157: .value = PKCS8_NO_OCTET,
! 158: .opt.value = &pkcs8_config.p8_broken,
! 159: },
! 160: {
! 161: .name = "nsdb",
! 162: .desc = "Generate DSA keys in the broken Netscape DB format",
! 163: .type = OPTION_VALUE,
! 164: .value = PKCS8_NS_DB,
! 165: .opt.value = &pkcs8_config.p8_broken,
! 166: },
! 167: {
! 168: .name = "out",
! 169: .argname = "file",
! 170: .desc = "Output file (default stdout)",
! 171: .type = OPTION_ARG,
! 172: .opt.arg = &pkcs8_config.outfile,
! 173: },
! 174: {
! 175: .name = "outform",
! 176: .argname = "format",
! 177: .desc = "Output format (DER or PEM (default))",
! 178: .type = OPTION_ARG_FORMAT,
! 179: .opt.value = &pkcs8_config.outformat,
! 180: },
! 181: {
! 182: .name = "passin",
! 183: .argname = "source",
! 184: .desc = "Input file passphrase source",
! 185: .type = OPTION_ARG,
! 186: .opt.arg = &pkcs8_config.passargin,
! 187: },
! 188: {
! 189: .name = "passout",
! 190: .argname = "source",
! 191: .desc = "Output file passphrase source",
! 192: .type = OPTION_ARG,
! 193: .opt.arg = &pkcs8_config.passargout,
! 194: },
! 195: {
! 196: .name = "topk8",
! 197: .desc = "Read traditional format key and write PKCS#8 format"
! 198: " key",
! 199: .type = OPTION_FLAG,
! 200: .opt.flag = &pkcs8_config.topk8,
! 201: },
! 202: {
! 203: .name = "v1",
! 204: .argname = "algorithm",
! 205: .desc = "Use PKCS#5 v1.5 or PKCS#12 with given algorithm",
! 206: .type = OPTION_ARG_FUNC,
! 207: .opt.argfunc = pkcs8_opt_v1,
! 208: },
! 209: {
! 210: .name = "v2",
! 211: .argname = "cipher",
! 212: .desc = "Use PKCS#5 v2.0 with given cipher",
! 213: .type = OPTION_ARG_FUNC,
! 214: .opt.argfunc = pkcs8_opt_v2,
! 215: },
! 216: { NULL },
! 217: };
! 218:
! 219: static void
! 220: pkcs8_usage()
! 221: {
! 222: fprintf(stderr, "usage: pkcs8 [-embed] [-engine id] [-in file] "
! 223: "[-inform fmt] [-nocrypt]\n"
! 224: " [-noiter] [-nooct] [-nsdb] [-out file] [-outform fmt] "
! 225: "[-passin src]\n"
! 226: " [-passout src] [-topk8] [-v1 alg] [-v2 alg]\n\n");
! 227: options_usage(pkcs8_options);
! 228: }
1.1 jsing 229:
230: int
231: pkcs8_main(int argc, char **argv)
232: {
233: ENGINE *e = NULL;
234: BIO *in = NULL, *out = NULL;
235: X509_SIG *p8 = NULL;
236: PKCS8_PRIV_KEY_INFO *p8inf = NULL;
237: EVP_PKEY *pkey = NULL;
238: char pass[50], *passin = NULL, *passout = NULL, *p8pass = NULL;
239: int ret = 1;
240:
1.4 ! doug 241: memset(&pkcs8_config, 0, sizeof(pkcs8_config));
1.1 jsing 242:
1.4 ! doug 243: pkcs8_config.iter = PKCS12_DEFAULT_ITER;
! 244: pkcs8_config.informat = FORMAT_PEM;
! 245: pkcs8_config.outformat = FORMAT_PEM;
! 246: pkcs8_config.p8_broken = PKCS8_OK;
! 247: pkcs8_config.pbe_nid = -1;
! 248:
! 249: if (options_parse(argc, argv, pkcs8_options, NULL, NULL) != 0) {
! 250: pkcs8_usage();
! 251: return (1);
1.1 jsing 252: }
253:
254: #ifndef OPENSSL_NO_ENGINE
1.4 ! doug 255: e = setup_engine(bio_err, pkcs8_config.engine, 0);
1.1 jsing 256: #endif
257:
1.4 ! doug 258: if (!app_passwd(bio_err, pkcs8_config.passargin,
! 259: pkcs8_config.passargout, &passin, &passout)) {
1.1 jsing 260: BIO_printf(bio_err, "Error getting passwords\n");
261: goto end;
262: }
1.4 ! doug 263: if ((pkcs8_config.pbe_nid == -1) && !pkcs8_config.cipher)
! 264: pkcs8_config.pbe_nid = NID_pbeWithMD5AndDES_CBC;
1.1 jsing 265:
1.4 ! doug 266: if (pkcs8_config.infile) {
! 267: if (!(in = BIO_new_file(pkcs8_config.infile, "rb"))) {
1.1 jsing 268: BIO_printf(bio_err,
1.4 ! doug 269: "Can't open input file '%s'\n",
! 270: pkcs8_config.infile);
1.1 jsing 271: goto end;
272: }
273: } else
274: in = BIO_new_fp(stdin, BIO_NOCLOSE);
275:
1.4 ! doug 276: if (pkcs8_config.outfile) {
! 277: if (!(out = BIO_new_file(pkcs8_config.outfile, "wb"))) {
! 278: BIO_printf(bio_err, "Can't open output file '%s'\n",
! 279: pkcs8_config.outfile);
1.1 jsing 280: goto end;
281: }
282: } else {
283: out = BIO_new_fp(stdout, BIO_NOCLOSE);
284: }
1.4 ! doug 285: if (pkcs8_config.topk8) {
! 286: pkey = load_key(bio_err, pkcs8_config.infile,
! 287: pkcs8_config.informat, 1, passin, e, "key");
1.1 jsing 288: if (!pkey)
289: goto end;
1.4 ! doug 290: if (!(p8inf = EVP_PKEY2PKCS8_broken(pkey,
! 291: pkcs8_config.p8_broken))) {
1.1 jsing 292: BIO_printf(bio_err, "Error converting key\n");
293: ERR_print_errors(bio_err);
294: goto end;
295: }
1.4 ! doug 296: if (pkcs8_config.nocrypt) {
! 297: if (pkcs8_config.outformat == FORMAT_PEM)
1.1 jsing 298: PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8inf);
1.4 ! doug 299: else if (pkcs8_config.outformat == FORMAT_ASN1)
1.1 jsing 300: i2d_PKCS8_PRIV_KEY_INFO_bio(out, p8inf);
301: else {
1.4 ! doug 302: BIO_printf(bio_err,
! 303: "Bad format specified for key\n");
1.1 jsing 304: goto end;
305: }
306: } else {
307: if (passout)
308: p8pass = passout;
309: else {
310: p8pass = pass;
1.4 ! doug 311: if (EVP_read_pw_string(pass, sizeof pass,
! 312: "Enter Encryption Password:", 1))
1.1 jsing 313: goto end;
314: }
1.4 ! doug 315: if (!(p8 = PKCS8_encrypt(pkcs8_config.pbe_nid,
! 316: pkcs8_config.cipher, p8pass, strlen(p8pass),
! 317: NULL, 0, pkcs8_config.iter, p8inf))) {
1.1 jsing 318: BIO_printf(bio_err, "Error encrypting key\n");
319: ERR_print_errors(bio_err);
320: goto end;
321: }
1.4 ! doug 322: if (pkcs8_config.outformat == FORMAT_PEM)
1.1 jsing 323: PEM_write_bio_PKCS8(out, p8);
1.4 ! doug 324: else if (pkcs8_config.outformat == FORMAT_ASN1)
1.1 jsing 325: i2d_PKCS8_bio(out, p8);
326: else {
1.4 ! doug 327: BIO_printf(bio_err,
! 328: "Bad format specified for key\n");
1.1 jsing 329: goto end;
330: }
331: }
332:
333: ret = 0;
334: goto end;
335: }
1.4 ! doug 336: if (pkcs8_config.nocrypt) {
! 337: if (pkcs8_config.informat == FORMAT_PEM)
! 338: p8inf = PEM_read_bio_PKCS8_PRIV_KEY_INFO(in, NULL,
! 339: NULL, NULL);
! 340: else if (pkcs8_config.informat == FORMAT_ASN1)
1.1 jsing 341: p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(in, NULL);
342: else {
343: BIO_printf(bio_err, "Bad format specified for key\n");
344: goto end;
345: }
346: } else {
1.4 ! doug 347: if (pkcs8_config.informat == FORMAT_PEM)
1.1 jsing 348: p8 = PEM_read_bio_PKCS8(in, NULL, NULL, NULL);
1.4 ! doug 349: else if (pkcs8_config.informat == FORMAT_ASN1)
1.1 jsing 350: p8 = d2i_PKCS8_bio(in, NULL);
351: else {
352: BIO_printf(bio_err, "Bad format specified for key\n");
353: goto end;
354: }
355:
356: if (!p8) {
357: BIO_printf(bio_err, "Error reading key\n");
358: ERR_print_errors(bio_err);
359: goto end;
360: }
361: if (passin)
362: p8pass = passin;
363: else {
364: p8pass = pass;
1.4 ! doug 365: EVP_read_pw_string(pass, sizeof pass,
! 366: "Enter Password:", 0);
1.1 jsing 367: }
368: p8inf = PKCS8_decrypt(p8, p8pass, strlen(p8pass));
369: }
370:
371: if (!p8inf) {
372: BIO_printf(bio_err, "Error decrypting key\n");
373: ERR_print_errors(bio_err);
374: goto end;
375: }
376: if (!(pkey = EVP_PKCS82PKEY(p8inf))) {
377: BIO_printf(bio_err, "Error converting key\n");
378: ERR_print_errors(bio_err);
379: goto end;
380: }
381: if (p8inf->broken) {
382: BIO_printf(bio_err, "Warning: broken key encoding: ");
383: switch (p8inf->broken) {
384: case PKCS8_NO_OCTET:
385: BIO_printf(bio_err, "No Octet String in PrivateKey\n");
386: break;
387:
388: case PKCS8_EMBEDDED_PARAM:
1.4 ! doug 389: BIO_printf(bio_err,
! 390: "DSA parameters included in PrivateKey\n");
1.1 jsing 391: break;
392:
393: case PKCS8_NS_DB:
1.4 ! doug 394: BIO_printf(bio_err,
! 395: "DSA public key include in PrivateKey\n");
1.1 jsing 396: break;
397:
398: case PKCS8_NEG_PRIVKEY:
399: BIO_printf(bio_err, "DSA private key value is negative\n");
400: break;
401:
402: default:
403: BIO_printf(bio_err, "Unknown broken type\n");
404: break;
405: }
406: }
1.4 ! doug 407: if (pkcs8_config.outformat == FORMAT_PEM)
! 408: PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL,
! 409: passout);
! 410: else if (pkcs8_config.outformat == FORMAT_ASN1)
1.1 jsing 411: i2d_PrivateKey_bio(out, pkey);
412: else {
413: BIO_printf(bio_err, "Bad format specified for key\n");
414: goto end;
415: }
416: ret = 0;
417:
418: end:
419: X509_SIG_free(p8);
420: PKCS8_PRIV_KEY_INFO_free(p8inf);
421: EVP_PKEY_free(pkey);
422: BIO_free_all(out);
423: BIO_free(in);
424: free(passin);
425: free(passout);
426:
427: return ret;
428: }