1/*
2 * Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the OpenSSL license (the "License").  You may not use
5 * this file except in compliance with the License.  You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10#include <stdio.h>
11#include <string.h>
12#include "apps.h"
13#include "progs.h"
14#include <openssl/pem.h>
15#include <openssl/err.h>
16#include <openssl/evp.h>
17
18typedef enum OPTION_choice {
19    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
20    OPT_INFORM, OPT_OUTFORM, OPT_PASSIN, OPT_PASSOUT, OPT_ENGINE,
21    OPT_IN, OPT_OUT, OPT_PUBIN, OPT_PUBOUT, OPT_TEXT_PUB,
22    OPT_TEXT, OPT_NOOUT, OPT_MD, OPT_TRADITIONAL, OPT_CHECK, OPT_PUB_CHECK
23} OPTION_CHOICE;
24
25const OPTIONS pkey_options[] = {
26    {"help", OPT_HELP, '-', "Display this summary"},
27    {"inform", OPT_INFORM, 'f', "Input format (DER or PEM)"},
28    {"outform", OPT_OUTFORM, 'F', "Output format (DER or PEM)"},
29    {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
30    {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"},
31    {"in", OPT_IN, 's', "Input key"},
32    {"out", OPT_OUT, '>', "Output file"},
33    {"pubin", OPT_PUBIN, '-',
34     "Read public key from input (default is private key)"},
35    {"pubout", OPT_PUBOUT, '-', "Output public key, not private"},
36    {"text_pub", OPT_TEXT_PUB, '-', "Only output public key components"},
37    {"text", OPT_TEXT, '-', "Output in plaintext as well"},
38    {"noout", OPT_NOOUT, '-', "Don't output the key"},
39    {"", OPT_MD, '-', "Any supported cipher"},
40    {"traditional", OPT_TRADITIONAL, '-',
41     "Use traditional format for private keys"},
42#ifndef OPENSSL_NO_ENGINE
43    {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
44#endif
45    {"check", OPT_CHECK, '-', "Check key consistency"},
46    {"pubcheck", OPT_PUB_CHECK, '-', "Check public key consistency"},
47    {NULL}
48};
49
50int pkey_main(int argc, char **argv)
51{
52    BIO *in = NULL, *out = NULL;
53    ENGINE *e = NULL;
54    EVP_PKEY *pkey = NULL;
55    const EVP_CIPHER *cipher = NULL;
56    char *infile = NULL, *outfile = NULL, *passin = NULL, *passout = NULL;
57    char *passinarg = NULL, *passoutarg = NULL, *prog;
58    OPTION_CHOICE o;
59    int informat = FORMAT_PEM, outformat = FORMAT_PEM;
60    int pubin = 0, pubout = 0, pubtext = 0, text = 0, noout = 0, ret = 1;
61    int private = 0, traditional = 0, check = 0, pub_check = 0;
62
63    prog = opt_init(argc, argv, pkey_options);
64    while ((o = opt_next()) != OPT_EOF) {
65        switch (o) {
66        case OPT_EOF:
67        case OPT_ERR:
68 opthelp:
69            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
70            goto end;
71        case OPT_HELP:
72            opt_help(pkey_options);
73            ret = 0;
74            goto end;
75        case OPT_INFORM:
76            if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat))
77                goto opthelp;
78            break;
79        case OPT_OUTFORM:
80            if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
81                goto opthelp;
82            break;
83        case OPT_PASSIN:
84            passinarg = opt_arg();
85            break;
86        case OPT_PASSOUT:
87            passoutarg = opt_arg();
88            break;
89        case OPT_ENGINE:
90            e = setup_engine(opt_arg(), 0);
91            break;
92        case OPT_IN:
93            infile = opt_arg();
94            break;
95        case OPT_OUT:
96            outfile = opt_arg();
97            break;
98        case OPT_PUBIN:
99            pubin = pubout = pubtext = 1;
100            break;
101        case OPT_PUBOUT:
102            pubout = 1;
103            break;
104        case OPT_TEXT_PUB:
105            pubtext = text = 1;
106            break;
107        case OPT_TEXT:
108            text = 1;
109            break;
110        case OPT_NOOUT:
111            noout = 1;
112            break;
113        case OPT_TRADITIONAL:
114            traditional = 1;
115            break;
116        case OPT_CHECK:
117            check = 1;
118            break;
119        case OPT_PUB_CHECK:
120            pub_check = 1;
121            break;
122        case OPT_MD:
123            if (!opt_cipher(opt_unknown(), &cipher))
124                goto opthelp;
125        }
126    }
127    argc = opt_num_rest();
128    if (argc != 0)
129        goto opthelp;
130
131    private = !noout && !pubout ? 1 : 0;
132    if (text && !pubtext)
133        private = 1;
134
135    if (!app_passwd(passinarg, passoutarg, &passin, &passout)) {
136        BIO_printf(bio_err, "Error getting passwords\n");
137        goto end;
138    }
139
140    out = bio_open_owner(outfile, outformat, private);
141    if (out == NULL)
142        goto end;
143
144    if (pubin)
145        pkey = load_pubkey(infile, informat, 1, passin, e, "Public Key");
146    else
147        pkey = load_key(infile, informat, 1, passin, e, "key");
148    if (pkey == NULL)
149        goto end;
150
151    if (check || pub_check) {
152        int r;
153        EVP_PKEY_CTX *ctx;
154
155        ctx = EVP_PKEY_CTX_new(pkey, e);
156        if (ctx == NULL) {
157            ERR_print_errors(bio_err);
158            goto end;
159        }
160
161        if (check)
162            r = EVP_PKEY_check(ctx);
163        else
164            r = EVP_PKEY_public_check(ctx);
165
166        if (r == 1) {
167            BIO_printf(out, "Key is valid\n");
168        } else {
169            /*
170             * Note: at least for RSA keys if this function returns
171             * -1, there will be no error reasons.
172             */
173            unsigned long err;
174
175            BIO_printf(out, "Key is invalid\n");
176
177            while ((err = ERR_peek_error()) != 0) {
178                BIO_printf(out, "Detailed error: %s\n",
179                           ERR_reason_error_string(err));
180                ERR_get_error(); /* remove err from error stack */
181            }
182        }
183        EVP_PKEY_CTX_free(ctx);
184    }
185
186    if (!noout) {
187        if (outformat == FORMAT_PEM) {
188            if (pubout) {
189                if (!PEM_write_bio_PUBKEY(out, pkey))
190                    goto end;
191            } else {
192                assert(private);
193                if (traditional) {
194                    if (!PEM_write_bio_PrivateKey_traditional(out, pkey, cipher,
195                                                              NULL, 0, NULL,
196                                                              passout))
197                        goto end;
198                } else {
199                    if (!PEM_write_bio_PrivateKey(out, pkey, cipher,
200                                                  NULL, 0, NULL, passout))
201                        goto end;
202                }
203            }
204        } else if (outformat == FORMAT_ASN1) {
205            if (pubout) {
206                if (!i2d_PUBKEY_bio(out, pkey))
207                    goto end;
208            } else {
209                assert(private);
210                if (!i2d_PrivateKey_bio(out, pkey))
211                    goto end;
212            }
213        } else {
214            BIO_printf(bio_err, "Bad format specified for key\n");
215            goto end;
216        }
217    }
218
219    if (text) {
220        if (pubtext) {
221            if (EVP_PKEY_print_public(out, pkey, 0, NULL) <= 0)
222                goto end;
223        } else {
224            assert(private);
225            if (EVP_PKEY_print_private(out, pkey, 0, NULL) <= 0)
226                goto end;
227        }
228    }
229
230    ret = 0;
231
232 end:
233    if (ret != 0)
234        ERR_print_errors(bio_err);
235    EVP_PKEY_free(pkey);
236    release_engine(e);
237    BIO_free_all(out);
238    BIO_free(in);
239    OPENSSL_free(passin);
240    OPENSSL_free(passout);
241
242    return ret;
243}
244