pkcs8.c 11.4 KB
Newer Older
1
/*
M
Matt Caswell 已提交
2
 * Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
R
Rich Salz 已提交
5 6 7
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
8
 */
R
Rich Salz 已提交
9

10
#include <stdio.h>
11
#include <stdlib.h>
U
Ulf Möller 已提交
12
#include <string.h>
13
#include "apps.h"
14
#include "progs.h"
15 16 17 18 19
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pkcs12.h>

20 21 22
typedef enum OPTION_choice {
    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
    OPT_INFORM, OPT_OUTFORM, OPT_ENGINE, OPT_IN, OPT_OUT,
23
    OPT_TOPK8, OPT_NOITER, OPT_NOCRYPT,
R
Rich Salz 已提交
24 25 26
#ifndef OPENSSL_NO_SCRYPT
    OPT_SCRYPT, OPT_SCRYPT_N, OPT_SCRYPT_R, OPT_SCRYPT_P,
#endif
27
    OPT_V2, OPT_V1, OPT_V2PRF, OPT_ITER, OPT_PASSIN, OPT_PASSOUT,
R
Rich Salz 已提交
28 29
    OPT_TRADITIONAL,
    OPT_R_ENUM
30
} OPTION_CHOICE;
31

F
FdaSilvaYY 已提交
32
const OPTIONS pkcs8_options[] = {
R
Rich Salz 已提交
33
    OPT_SECTION("General"),
34
    {"help", OPT_HELP, '-', "Display this summary"},
R
Rich Salz 已提交
35 36 37
#ifndef OPENSSL_NO_ENGINE
    {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
#endif
38
    {"v1", OPT_V1, 's', "Use PKCS#5 v1.5 and cipher"},
R
Rich Salz 已提交
39
    {"v2", OPT_V2, 's', "Use PKCS#5 v2.0 and cipher"},
40
    {"v2prf", OPT_V2PRF, 's', "Set the PRF algorithm to use with PKCS#5 v2.0"},
R
Rich Salz 已提交
41 42 43 44

    OPT_SECTION("Input"),
    {"in", OPT_IN, '<', "Input file"},
    {"inform", OPT_INFORM, 'F', "Input format (DER or PEM)"},
45
    {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
R
Rich Salz 已提交
46 47 48 49 50 51
    {"nocrypt", OPT_NOCRYPT, '-', "Use or expect unencrypted private key"},

    OPT_SECTION("Output"),
    {"out", OPT_OUT, '>', "Output file"},
    {"outform", OPT_OUTFORM, 'F', "Output format (DER or PEM)"},
    {"topk8", OPT_TOPK8, '-', "Output PKCS8 file"},
52
    {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"},
53
    {"traditional", OPT_TRADITIONAL, '-', "use traditional format private key"},
R
Rich Salz 已提交
54 55 56
    {"iter", OPT_ITER, 'p', "Specify the iteration count"},
    {"noiter", OPT_NOITER, '-', "Use 1 as iteration count"},

R
Rich Salz 已提交
57
#ifndef OPENSSL_NO_SCRYPT
R
Rich Salz 已提交
58
    OPT_SECTION("Scrypt"),
D
Dr. Stephen Henson 已提交
59 60 61 62
    {"scrypt", OPT_SCRYPT, '-', "Use scrypt algorithm"},
    {"scrypt_N", OPT_SCRYPT_N, 's', "Set scrypt N parameter"},
    {"scrypt_r", OPT_SCRYPT_R, 's', "Set scrypt r parameter"},
    {"scrypt_p", OPT_SCRYPT_P, 's', "Set scrypt p parameter"},
R
Rich Salz 已提交
63
#endif
R
Rich Salz 已提交
64 65

    OPT_R_OPTIONS,
66 67
    {NULL}
};
68

69
int pkcs8_main(int argc, char **argv)
70 71
{
    BIO *in = NULL, *out = NULL;
72
    ENGINE *e = NULL;
73
    EVP_PKEY *pkey = NULL;
74 75 76
    PKCS8_PRIV_KEY_INFO *p8inf = NULL;
    X509_SIG *p8 = NULL;
    const EVP_CIPHER *cipher = NULL;
R
Rich Salz 已提交
77
    char *infile = NULL, *outfile = NULL;
78
    char *passinarg = NULL, *passoutarg = NULL, *prog;
79
#ifndef OPENSSL_NO_UI_CONSOLE
80
    char pass[APP_PASS_LEN];
R
Richard Levitte 已提交
81 82
#endif
    char *passin = NULL, *passout = NULL, *p8pass = NULL;
83
    OPTION_CHOICE o;
84
    int nocrypt = 0, ret = 1, iter = PKCS12_DEFAULT_ITER;
R
Rich Salz 已提交
85
    int informat = FORMAT_PEM, outformat = FORMAT_PEM, topk8 = 0, pbe_nid = -1;
86
    int private = 0, traditional = 0;
R
Rich Salz 已提交
87
#ifndef OPENSSL_NO_SCRYPT
R
Rich Salz 已提交
88
    long scrypt_N = 0, scrypt_r = 0, scrypt_p = 0;
R
Rich Salz 已提交
89
#endif
D
Dr. Stephen Henson 已提交
90

91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
    prog = opt_init(argc, argv, pkcs8_options);
    while ((o = opt_next()) != OPT_EOF) {
        switch (o) {
        case OPT_EOF:
        case OPT_ERR:
 opthelp:
            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
            goto end;
        case OPT_HELP:
            opt_help(pkcs8_options);
            ret = 0;
            goto end;
        case OPT_INFORM:
            if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat))
                goto opthelp;
            break;
        case OPT_IN:
            infile = opt_arg();
            break;
        case OPT_OUTFORM:
            if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
                goto opthelp;
            break;
        case OPT_OUT:
            outfile = opt_arg();
            break;
        case OPT_TOPK8:
118
            topk8 = 1;
119 120
            break;
        case OPT_NOITER:
121
            iter = 1;
122 123
            break;
        case OPT_NOCRYPT:
124
            nocrypt = 1;
125
            break;
R
Rich Salz 已提交
126 127 128 129
        case OPT_R_CASES:
            if (!opt_rand(o))
                goto end;
            break;
130 131 132
        case OPT_TRADITIONAL:
            traditional = 1;
            break;
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
        case OPT_V2:
            if (!opt_cipher(opt_arg(), &cipher))
                goto opthelp;
            break;
        case OPT_V1:
            pbe_nid = OBJ_txt2nid(opt_arg());
            if (pbe_nid == NID_undef) {
                BIO_printf(bio_err,
                           "%s: Unknown PBE algorithm %s\n", prog, opt_arg());
                goto opthelp;
            }
            break;
        case OPT_V2PRF:
            pbe_nid = OBJ_txt2nid(opt_arg());
            if (!EVP_PBE_find(EVP_PBE_TYPE_PRF, pbe_nid, NULL, NULL, 0)) {
                BIO_printf(bio_err,
                           "%s: Unknown PRF algorithm %s\n", prog, opt_arg());
                goto opthelp;
            }
D
Dr. Stephen Henson 已提交
152 153
            if (cipher == NULL)
                cipher = EVP_aes_256_cbc();
154 155 156 157 158 159 160 161 162 163 164 165
            break;
        case OPT_ITER:
            if (!opt_int(opt_arg(), &iter))
                goto opthelp;
            break;
        case OPT_PASSIN:
            passinarg = opt_arg();
            break;
        case OPT_PASSOUT:
            passoutarg = opt_arg();
            break;
        case OPT_ENGINE:
R
Rich Salz 已提交
166
            e = setup_engine(opt_arg(), 0);
167
            break;
R
Rich Salz 已提交
168
#ifndef OPENSSL_NO_SCRYPT
D
Dr. Stephen Henson 已提交
169
        case OPT_SCRYPT:
170
            scrypt_N = 16384;
D
Dr. Stephen Henson 已提交
171
            scrypt_r = 8;
172
            scrypt_p = 1;
D
Dr. Stephen Henson 已提交
173 174 175 176
            if (cipher == NULL)
                cipher = EVP_aes_256_cbc();
            break;
        case OPT_SCRYPT_N:
R
Rich Salz 已提交
177
            if (!opt_long(opt_arg(), &scrypt_N) || scrypt_N <= 0)
D
Dr. Stephen Henson 已提交
178 179 180
                goto opthelp;
            break;
        case OPT_SCRYPT_R:
R
Rich Salz 已提交
181
            if (!opt_long(opt_arg(), &scrypt_r) || scrypt_r <= 0)
D
Dr. Stephen Henson 已提交
182 183 184
                goto opthelp;
            break;
        case OPT_SCRYPT_P:
R
Rich Salz 已提交
185
            if (!opt_long(opt_arg(), &scrypt_p) || scrypt_p <= 0)
D
Dr. Stephen Henson 已提交
186 187
                goto opthelp;
            break;
R
Rich Salz 已提交
188
#endif
189 190
        }
    }
191
    argc = opt_num_rest();
K
Kurt Roeckx 已提交
192 193 194
    if (argc != 0)
        goto opthelp;

195
    private = 1;
196

197
    if (!app_passwd(passinarg, passoutarg, &passin, &passout)) {
198 199 200
        BIO_printf(bio_err, "Error getting passwords\n");
        goto end;
    }
D
Dr. Stephen Henson 已提交
201

D
Dr. Stephen Henson 已提交
202 203
    if ((pbe_nid == -1) && cipher == NULL)
        cipher = EVP_aes_256_cbc();
204

205
    in = bio_open_default(infile, 'r', informat);
206 207
    if (in == NULL)
        goto end;
208
    out = bio_open_owner(outfile, outformat, private);
209 210
    if (out == NULL)
        goto end;
211

212
    if (topk8) {
213
        pkey = load_key(infile, informat, 1, passin, e, "key");
214
        if (pkey == NULL)
215
            goto end;
216
        if ((p8inf = EVP_PKEY2PKCS8(pkey)) == NULL) {
217 218 219 220 221
            BIO_printf(bio_err, "Error converting key\n");
            ERR_print_errors(bio_err);
            goto end;
        }
        if (nocrypt) {
222
            assert(private);
223
            if (outformat == FORMAT_PEM) {
224
                PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8inf);
225
            } else if (outformat == FORMAT_ASN1) {
226
                i2d_PKCS8_PRIV_KEY_INFO_bio(out, p8inf);
227
            } else {
228 229 230 231
                BIO_printf(bio_err, "Bad format specified for key\n");
                goto end;
            }
        } else {
D
Dr. Stephen Henson 已提交
232
            X509_ALGOR *pbe;
D
Dr. Stephen Henson 已提交
233
            if (cipher) {
R
Rich Salz 已提交
234
#ifndef OPENSSL_NO_SCRYPT
D
Dr. Stephen Henson 已提交
235 236 237 238
                if (scrypt_N && scrypt_r && scrypt_p)
                    pbe = PKCS5_pbe2_set_scrypt(cipher, NULL, 0, NULL,
                                                scrypt_N, scrypt_r, scrypt_p);
                else
R
Rich Salz 已提交
239
#endif
D
Dr. Stephen Henson 已提交
240 241 242
                    pbe = PKCS5_pbe2_set_iv(cipher, iter, NULL, 0, NULL,
                                            pbe_nid);
            } else {
D
Dr. Stephen Henson 已提交
243
                pbe = PKCS5_pbe_set(pbe_nid, iter, NULL, 0);
D
Dr. Stephen Henson 已提交
244
            }
D
Dr. Stephen Henson 已提交
245 246 247 248 249
            if (pbe == NULL) {
                BIO_printf(bio_err, "Error setting PBE algorithm\n");
                ERR_print_errors(bio_err);
                goto end;
            }
250
            if (passout != NULL) {
251
                p8pass = passout;
252 253
            } else if (1) {
                /* To avoid bit rot */
254
#ifndef OPENSSL_NO_UI_CONSOLE
255 256
                p8pass = pass;
                if (EVP_read_pw_string
R
Rich Salz 已提交
257
                    (pass, sizeof(pass), "Enter Encryption Password:", 1)) {
D
Dr. Stephen Henson 已提交
258
                    X509_ALGOR_free(pbe);
259
                    goto end;
D
Dr. Stephen Henson 已提交
260
                }
R
Richard Levitte 已提交
261 262 263 264
            } else {
#endif
                BIO_printf(bio_err, "Password required\n");
                goto end;
265
            }
D
Dr. Stephen Henson 已提交
266 267 268
            p8 = PKCS8_set0_pbe(p8pass, strlen(p8pass), p8inf, pbe);
            if (p8 == NULL) {
                X509_ALGOR_free(pbe);
269 270 271 272
                BIO_printf(bio_err, "Error encrypting key\n");
                ERR_print_errors(bio_err);
                goto end;
            }
273
            assert(private);
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
            if (outformat == FORMAT_PEM)
                PEM_write_bio_PKCS8(out, p8);
            else if (outformat == FORMAT_ASN1)
                i2d_PKCS8_bio(out, p8);
            else {
                BIO_printf(bio_err, "Bad format specified for key\n");
                goto end;
            }
        }

        ret = 0;
        goto end;
    }

    if (nocrypt) {
289
        if (informat == FORMAT_PEM) {
290
            p8inf = PEM_read_bio_PKCS8_PRIV_KEY_INFO(in, NULL, NULL, NULL);
291
        } else if (informat == FORMAT_ASN1) {
292
            p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(in, NULL);
293
        } else {
294 295 296 297
            BIO_printf(bio_err, "Bad format specified for key\n");
            goto end;
        }
    } else {
298
        if (informat == FORMAT_PEM) {
299
            p8 = PEM_read_bio_PKCS8(in, NULL, NULL, NULL);
300
        } else if (informat == FORMAT_ASN1) {
301
            p8 = d2i_PKCS8_bio(in, NULL);
302
        } else {
303 304 305
            BIO_printf(bio_err, "Bad format specified for key\n");
            goto end;
        }
D
Dr. Stephen Henson 已提交
306

307
        if (p8 == NULL) {
308 309 310 311
            BIO_printf(bio_err, "Error reading key\n");
            ERR_print_errors(bio_err);
            goto end;
        }
312
        if (passin != NULL) {
313
            p8pass = passin;
314
        } else if (1) {
315
#ifndef OPENSSL_NO_UI_CONSOLE
316
            p8pass = pass;
R
Rich Salz 已提交
317
            if (EVP_read_pw_string(pass, sizeof(pass), "Enter Password:", 0)) {
318 319 320
                BIO_printf(bio_err, "Can't read Password\n");
                goto end;
            }
R
Richard Levitte 已提交
321 322 323 324
        } else {
#endif
            BIO_printf(bio_err, "Password required\n");
            goto end;
325 326 327
        }
        p8inf = PKCS8_decrypt(p8, p8pass, strlen(p8pass));
    }
328

329
    if (p8inf == NULL) {
330 331 332 333
        BIO_printf(bio_err, "Error decrypting key\n");
        ERR_print_errors(bio_err);
        goto end;
    }
334

335
    if ((pkey = EVP_PKCS82PKEY(p8inf)) == NULL) {
336 337 338 339
        BIO_printf(bio_err, "Error converting key\n");
        ERR_print_errors(bio_err);
        goto end;
    }
340

341
    assert(private);
342 343 344 345 346 347 348
    if (outformat == FORMAT_PEM) {
        if (traditional)
            PEM_write_bio_PrivateKey_traditional(out, pkey, NULL, NULL, 0,
                                                 NULL, passout);
        else
            PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, passout);
    } else if (outformat == FORMAT_ASN1) {
349
        i2d_PrivateKey_bio(out, pkey);
350
    } else {
351 352 353 354
        BIO_printf(bio_err, "Bad format specified for key\n");
        goto end;
    }
    ret = 0;
355

356 357 358 359
 end:
    X509_SIG_free(p8);
    PKCS8_PRIV_KEY_INFO_free(p8inf);
    EVP_PKEY_free(pkey);
360
    release_engine(e);
361 362
    BIO_free_all(out);
    BIO_free(in);
R
Rich Salz 已提交
363 364
    OPENSSL_free(passin);
    OPENSSL_free(passout);
365

366 367
    return ret;
}