1 /* $OpenBSD: pkey.c,v 1.17 2022/01/14 10:17:30 tb Exp $ */ 2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3 * project 2006 4 */ 5 /* ==================================================================== 6 * Copyright (c) 2006 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 68 static struct { 69 int check; 70 const EVP_CIPHER *cipher; 71 char *infile; 72 int informat; 73 int noout; 74 char *outfile; 75 int outformat; 76 char *passargin; 77 char *passargout; 78 int pubcheck; 79 int pubin; 80 int pubout; 81 int pubtext; 82 int text; 83 } pkey_config; 84 85 static int 86 pkey_opt_cipher(int argc, char **argv, int *argsused) 87 { 88 char *name = argv[0]; 89 90 if (*name++ != '-') 91 return (1); 92 93 if ((pkey_config.cipher = EVP_get_cipherbyname(name)) == NULL) { 94 BIO_printf(bio_err, "Unknown cipher %s\n", name); 95 return (1); 96 } 97 98 *argsused = 1; 99 return (0); 100 } 101 102 static const struct option pkey_options[] = { 103 { 104 .name = "check", 105 .desc = "Check validity of key", 106 .type = OPTION_FLAG, 107 .opt.flag = &pkey_config.check, 108 }, 109 { 110 .name = "in", 111 .argname = "file", 112 .desc = "Input file (default stdin)", 113 .type = OPTION_ARG, 114 .opt.arg = &pkey_config.infile, 115 }, 116 { 117 .name = "inform", 118 .argname = "format", 119 .desc = "Input format (DER or PEM (default))", 120 .type = OPTION_ARG_FORMAT, 121 .opt.value = &pkey_config.informat, 122 }, 123 { 124 .name = "noout", 125 .desc = "Do not print encoded version of the key", 126 .type = OPTION_FLAG, 127 .opt.flag = &pkey_config.noout, 128 }, 129 { 130 .name = "out", 131 .argname = "file", 132 .desc = "Output file (default stdout)", 133 .type = OPTION_ARG, 134 .opt.arg = &pkey_config.outfile, 135 }, 136 { 137 .name = "outform", 138 .argname = "format", 139 .desc = "Output format (DER or PEM (default))", 140 .type = OPTION_ARG_FORMAT, 141 .opt.value = &pkey_config.outformat, 142 }, 143 { 144 .name = "passin", 145 .argname = "src", 146 .desc = "Input file passphrase source", 147 .type = OPTION_ARG, 148 .opt.arg = &pkey_config.passargin, 149 }, 150 { 151 .name = "passout", 152 .argname = "src", 153 .desc = "Output file passphrase source", 154 .type = OPTION_ARG, 155 .opt.arg = &pkey_config.passargout, 156 }, 157 { 158 .name = "pubcheck", 159 .desc = "Check validity of public key", 160 .type = OPTION_FLAG, 161 .opt.flag = &pkey_config.pubcheck, 162 }, 163 { 164 .name = "pubin", 165 .desc = "Expect a public key (default private key)", 166 .type = OPTION_VALUE, 167 .value = 1, 168 .opt.value = &pkey_config.pubin, 169 }, 170 { 171 .name = "pubout", 172 .desc = "Output a public key (default private key)", 173 .type = OPTION_VALUE, 174 .value = 1, 175 .opt.value = &pkey_config.pubout, 176 }, 177 { 178 .name = "text", 179 .desc = "Print the public/private key in plain text", 180 .type = OPTION_FLAG, 181 .opt.flag = &pkey_config.text, 182 }, 183 { 184 .name = "text_pub", 185 .desc = "Print out only public key in plain text", 186 .type = OPTION_FLAG, 187 .opt.flag = &pkey_config.pubtext, 188 }, 189 { 190 .name = NULL, 191 .type = OPTION_ARGV_FUNC, 192 .opt.argvfunc = pkey_opt_cipher, 193 }, 194 { NULL } 195 }; 196 197 static void 198 pkey_usage() 199 { 200 int n = 0; 201 202 fprintf(stderr, 203 "usage: pkey [-check] [-ciphername] [-in file] [-inform fmt] " 204 "[-noout] [-out file]\n" 205 " [-outform fmt] [-passin src] [-passout src] [-pubcheck] " 206 "[-pubin] [-pubout]\n" 207 " [-text] [-text_pub]\n\n"); 208 options_usage(pkey_options); 209 fprintf(stderr, "\n"); 210 211 fprintf(stderr, "Valid ciphername values:\n\n"); 212 OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, show_cipher, &n); 213 fprintf(stderr, "\n"); 214 } 215 216 int 217 pkey_main(int argc, char **argv) 218 { 219 BIO *in = NULL, *out = NULL; 220 EVP_PKEY *pkey = NULL; 221 char *passin = NULL, *passout = NULL; 222 int ret = 1; 223 224 if (single_execution) { 225 if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { 226 perror("pledge"); 227 exit(1); 228 } 229 } 230 231 memset(&pkey_config, 0, sizeof(pkey_config)); 232 pkey_config.informat = FORMAT_PEM; 233 pkey_config.outformat = FORMAT_PEM; 234 235 if (options_parse(argc, argv, pkey_options, NULL, NULL) != 0) { 236 pkey_usage(); 237 goto end; 238 } 239 240 if (pkey_config.pubtext) 241 pkey_config.text = 1; 242 if (pkey_config.pubin) 243 pkey_config.pubout = pkey_config.pubtext = 1; 244 245 if (!app_passwd(bio_err, pkey_config.passargin, pkey_config.passargout, 246 &passin, &passout)) { 247 BIO_printf(bio_err, "Error getting passwords\n"); 248 goto end; 249 } 250 if (pkey_config.outfile) { 251 if (!(out = BIO_new_file(pkey_config.outfile, "wb"))) { 252 BIO_printf(bio_err, 253 "Can't open output file %s\n", pkey_config.outfile); 254 goto end; 255 } 256 } else { 257 out = BIO_new_fp(stdout, BIO_NOCLOSE); 258 } 259 260 if (pkey_config.pubin) 261 pkey = load_pubkey(bio_err, pkey_config.infile, 262 pkey_config.informat, 1, passin, "Public Key"); 263 else 264 pkey = load_key(bio_err, pkey_config.infile, 265 pkey_config.informat, 1, passin, "key"); 266 if (!pkey) 267 goto end; 268 269 if (pkey_config.check) { 270 if (!pkey_check(out, pkey, EVP_PKEY_check, "Key pair")) 271 goto end; 272 } else if (pkey_config.pubcheck) { 273 if (!pkey_check(out, pkey, EVP_PKEY_public_check, "Public key")) 274 goto end; 275 } 276 277 if (!pkey_config.noout) { 278 if (pkey_config.outformat == FORMAT_PEM) { 279 if (pkey_config.pubout) 280 PEM_write_bio_PUBKEY(out, pkey); 281 else 282 PEM_write_bio_PrivateKey(out, pkey, 283 pkey_config.cipher, NULL, 0, NULL, passout); 284 } else if (pkey_config.outformat == FORMAT_ASN1) { 285 if (pkey_config.pubout) 286 i2d_PUBKEY_bio(out, pkey); 287 else 288 i2d_PrivateKey_bio(out, pkey); 289 } else { 290 BIO_printf(bio_err, "Bad format specified for key\n"); 291 goto end; 292 } 293 294 } 295 if (pkey_config.text) { 296 if (pkey_config.pubtext) 297 EVP_PKEY_print_public(out, pkey, 0, NULL); 298 else 299 EVP_PKEY_print_private(out, pkey, 0, NULL); 300 } 301 ret = 0; 302 303 end: 304 EVP_PKEY_free(pkey); 305 BIO_free_all(out); 306 BIO_free(in); 307 free(passin); 308 free(passout); 309 310 return ret; 311 } 312