[BACK]Return to pkcs8.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / openssl

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: }