pkey.c 6.7 KB
Newer Older
1
/*
2
 * Copyright 2006-2017 The OpenSSL Project Authors. All Rights Reserved.
3
 *
R
Rich Salz 已提交
4 5 6 7
 * Licensed under the OpenSSL license (the "License").  You may not use
 * 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 11 12 13 14 15 16
#include <stdio.h>
#include <string.h>
#include "apps.h"
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/evp.h>

17 18 19 20
typedef enum OPTION_choice {
    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
    OPT_INFORM, OPT_OUTFORM, OPT_PASSIN, OPT_PASSOUT, OPT_ENGINE,
    OPT_IN, OPT_OUT, OPT_PUBIN, OPT_PUBOUT, OPT_TEXT_PUB,
P
Paul Yang 已提交
21
    OPT_TEXT, OPT_NOOUT, OPT_MD, OPT_TRADITIONAL, OPT_CHECK
22 23
} OPTION_CHOICE;

F
FdaSilvaYY 已提交
24
const OPTIONS pkey_options[] = {
25
    {"help", OPT_HELP, '-', "Display this summary"},
26
    {"inform", OPT_INFORM, 'f', "Input format (DER or PEM)"},
27 28 29
    {"outform", OPT_OUTFORM, 'F', "Output format (DER or PEM)"},
    {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
    {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"},
30
    {"in", OPT_IN, 's', "Input key"},
31 32 33 34 35 36 37 38
    {"out", OPT_OUT, '>', "Output file"},
    {"pubin", OPT_PUBIN, '-',
     "Read public key from input (default is private key)"},
    {"pubout", OPT_PUBOUT, '-', "Output public key, not private"},
    {"text_pub", OPT_TEXT_PUB, '-', "Only output public key components"},
    {"text", OPT_TEXT, '-', "Output in plaintext as well"},
    {"noout", OPT_NOOUT, '-', "Don't output the key"},
    {"", OPT_MD, '-', "Any supported cipher"},
39 40
    {"traditional", OPT_TRADITIONAL, '-',
     "Use traditional format for private keys"},
41 42 43
#ifndef OPENSSL_NO_ENGINE
    {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
#endif
P
Paul Yang 已提交
44
    {"check", OPT_CHECK, '-', "Check key consistency"},
45 46
    {NULL}
};
47

48
int pkey_main(int argc, char **argv)
49 50
{
    BIO *in = NULL, *out = NULL;
51
    ENGINE *e = NULL;
52
    EVP_PKEY *pkey = NULL;
53 54
    const EVP_CIPHER *cipher = NULL;
    char *infile = NULL, *outfile = NULL, *passin = NULL, *passout = NULL;
R
Rich Salz 已提交
55
    char *passinarg = NULL, *passoutarg = NULL, *prog;
56 57 58
    OPTION_CHOICE o;
    int informat = FORMAT_PEM, outformat = FORMAT_PEM;
    int pubin = 0, pubout = 0, pubtext = 0, text = 0, noout = 0, ret = 1;
P
Paul Yang 已提交
59
    int private = 0, traditional = 0, check = 0;
60 61 62 63 64 65 66 67 68 69 70 71 72 73

    prog = opt_init(argc, argv, pkey_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(pkey_options);
            ret = 0;
            goto end;
        case OPT_INFORM:
74
            if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat))
75 76 77 78 79 80 81 82 83 84 85 86 87
                goto opthelp;
            break;
        case OPT_OUTFORM:
            if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
                goto opthelp;
            break;
        case OPT_PASSIN:
            passinarg = opt_arg();
            break;
        case OPT_PASSOUT:
            passoutarg = opt_arg();
            break;
        case OPT_ENGINE:
R
Rich Salz 已提交
88
            e = setup_engine(opt_arg(), 0);
89 90 91 92 93 94 95 96 97 98 99
            break;
        case OPT_IN:
            infile = opt_arg();
            break;
        case OPT_OUT:
            outfile = opt_arg();
            break;
        case OPT_PUBIN:
            pubin = pubout = pubtext = 1;
            break;
        case OPT_PUBOUT:
100
            pubout = 1;
101 102 103 104 105
            break;
        case OPT_TEXT_PUB:
            pubtext = text = 1;
            break;
        case OPT_TEXT:
106
            text = 1;
107 108
            break;
        case OPT_NOOUT:
109
            noout = 1;
110
            break;
111 112 113
        case OPT_TRADITIONAL:
            traditional = 1;
            break;
P
Paul Yang 已提交
114 115 116
        case OPT_CHECK:
            check = 1;
            break;
117 118 119
        case OPT_MD:
            if (!opt_cipher(opt_unknown(), &cipher))
                goto opthelp;
120 121
        }
    }
122
    argc = opt_num_rest();
K
Kurt Roeckx 已提交
123 124 125
    if (argc != 0)
        goto opthelp;

126 127 128
    private = !noout && !pubout ? 1 : 0;
    if (text && !pubtext)
        private = 1;
129

130
    if (!app_passwd(passinarg, passoutarg, &passin, &passout)) {
131 132 133 134
        BIO_printf(bio_err, "Error getting passwords\n");
        goto end;
    }

135
    out = bio_open_owner(outfile, outformat, private);
136 137
    if (out == NULL)
        goto end;
138 139

    if (pubin)
140
        pkey = load_pubkey(infile, informat, 1, passin, e, "Public Key");
141
    else
142
        pkey = load_key(infile, informat, 1, passin, e, "key");
143
    if (pkey == NULL)
144 145
        goto end;

P
Paul Yang 已提交
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
    if (check) {
        int r;
        EVP_PKEY_CTX *ctx;

        ctx = EVP_PKEY_CTX_new(pkey, e);
        if (ctx == NULL) {
            ERR_print_errors(bio_err);
            goto end;
        }

        r = EVP_PKEY_check(ctx);

        if (r == 1) {
            BIO_printf(out, "Key is valid\n");
        } else {
            /*
             * Note: at least for RSA keys if this function returns
             * -1, there will be no error reasons.
             */
            unsigned long err;

            BIO_printf(out, "Key is invalid\n");

            while ((err = ERR_peek_error()) != 0) {
                BIO_printf(out, "Detailed error: %s\n",
                           ERR_reason_error_string(err));
                ERR_get_error(); /* remove e from error stack */
            }
        }
        EVP_PKEY_CTX_free(ctx);
    }

178 179
    if (!noout) {
        if (outformat == FORMAT_PEM) {
180
            if (pubout) {
181
                PEM_write_bio_PUBKEY(out, pkey);
182
            } else {
183
                assert(private);
184 185 186 187 188 189 190
                if (traditional)
                    PEM_write_bio_PrivateKey_traditional(out, pkey, cipher,
                                                         NULL, 0, NULL,
                                                         passout);
                else
                    PEM_write_bio_PrivateKey(out, pkey, cipher,
                                             NULL, 0, NULL, passout);
191
            }
192
        } else if (outformat == FORMAT_ASN1) {
193
            if (pubout) {
194
                i2d_PUBKEY_bio(out, pkey);
195
            } else {
196
                assert(private);
197
                i2d_PrivateKey_bio(out, pkey);
198
            }
199 200 201 202 203 204 205
        } else {
            BIO_printf(bio_err, "Bad format specified for key\n");
            goto end;
        }
    }

    if (text) {
206
        if (pubtext) {
207
            EVP_PKEY_print_public(out, pkey, 0, NULL);
208
        } else {
209
            assert(private);
210
            EVP_PKEY_print_private(out, pkey, 0, NULL);
211
        }
212 213 214 215 216
    }

    ret = 0;

 end:
217 218
    if (ret != 0)
        ERR_print_errors(bio_err);
219
    EVP_PKEY_free(pkey);
220
    release_engine(e);
221 222
    BIO_free_all(out);
    BIO_free(in);
R
Rich Salz 已提交
223 224
    OPENSSL_free(passin);
    OPENSSL_free(passout);
225 226 227

    return ret;
}