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_IN, OPT_OUT, OPT_TEXT, OPT_NOOUT,
21    OPT_ENGINE, OPT_CHECK
22} OPTION_CHOICE;
23
24const OPTIONS pkeyparam_options[] = {
25    {"help", OPT_HELP, '-', "Display this summary"},
26    {"in", OPT_IN, '<', "Input file"},
27    {"out", OPT_OUT, '>', "Output file"},
28    {"text", OPT_TEXT, '-', "Print parameters as text"},
29    {"noout", OPT_NOOUT, '-', "Don't output encoded parameters"},
30#ifndef OPENSSL_NO_ENGINE
31    {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
32#endif
33    {"check", OPT_CHECK, '-', "Check key param consistency"},
34    {NULL}
35};
36
37int pkeyparam_main(int argc, char **argv)
38{
39    ENGINE *e = NULL;
40    BIO *in = NULL, *out = NULL;
41    EVP_PKEY *pkey = NULL;
42    int text = 0, noout = 0, ret = 1, check = 0;
43    OPTION_CHOICE o;
44    char *infile = NULL, *outfile = NULL, *prog;
45
46    prog = opt_init(argc, argv, pkeyparam_options);
47    while ((o = opt_next()) != OPT_EOF) {
48        switch (o) {
49        case OPT_EOF:
50        case OPT_ERR:
51 opthelp:
52            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
53            goto end;
54        case OPT_HELP:
55            opt_help(pkeyparam_options);
56            ret = 0;
57            goto end;
58        case OPT_IN:
59            infile = opt_arg();
60            break;
61        case OPT_OUT:
62            outfile = opt_arg();
63            break;
64        case OPT_ENGINE:
65            e = setup_engine(opt_arg(), 0);
66            break;
67        case OPT_TEXT:
68            text = 1;
69            break;
70        case OPT_NOOUT:
71            noout = 1;
72            break;
73        case OPT_CHECK:
74            check = 1;
75            break;
76        }
77    }
78    argc = opt_num_rest();
79    if (argc != 0)
80        goto opthelp;
81
82    in = bio_open_default(infile, 'r', FORMAT_PEM);
83    if (in == NULL)
84        goto end;
85    out = bio_open_default(outfile, 'w', FORMAT_PEM);
86    if (out == NULL)
87        goto end;
88    pkey = PEM_read_bio_Parameters(in, NULL);
89    if (pkey == NULL) {
90        BIO_printf(bio_err, "Error reading parameters\n");
91        ERR_print_errors(bio_err);
92        goto end;
93    }
94
95    if (check) {
96        int r;
97        EVP_PKEY_CTX *ctx;
98
99        ctx = EVP_PKEY_CTX_new(pkey, e);
100        if (ctx == NULL) {
101            ERR_print_errors(bio_err);
102            goto end;
103        }
104
105        r = EVP_PKEY_param_check(ctx);
106
107        if (r == 1) {
108            BIO_printf(out, "Parameters are valid\n");
109        } else {
110            /*
111             * Note: at least for RSA keys if this function returns
112             * -1, there will be no error reasons.
113             */
114            unsigned long err;
115
116            BIO_printf(out, "Parameters are invalid\n");
117
118            while ((err = ERR_peek_error()) != 0) {
119                BIO_printf(out, "Detailed error: %s\n",
120                           ERR_reason_error_string(err));
121                ERR_get_error(); /* remove err from error stack */
122            }
123        }
124        EVP_PKEY_CTX_free(ctx);
125    }
126
127    if (!noout)
128        PEM_write_bio_Parameters(out, pkey);
129
130    if (text)
131        EVP_PKEY_print_params(out, pkey, 0, NULL);
132
133    ret = 0;
134
135 end:
136    EVP_PKEY_free(pkey);
137    release_engine(e);
138    BIO_free_all(out);
139    BIO_free(in);
140
141    return ret;
142}
143