1/* $OpenBSD: pkey.c,v 1.20 2023/07/23 11:39:29 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 68static 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} cfg; 84 85static int 86pkey_opt_cipher(int argc, char **argv, int *argsused) 87{ 88 char *name = argv[0]; 89 90 if (*name++ != '-') 91 return (1); 92 93 if ((cfg.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 102static const struct option pkey_options[] = { 103 { 104 .name = "check", 105 .desc = "Check validity of key", 106 .type = OPTION_FLAG, 107 .opt.flag = &cfg.check, 108 }, 109 { 110 .name = "in", 111 .argname = "file", 112 .desc = "Input file (default stdin)", 113 .type = OPTION_ARG, 114 .opt.arg = &cfg.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 = &cfg.informat, 122 }, 123 { 124 .name = "noout", 125 .desc = "Do not print encoded version of the key", 126 .type = OPTION_FLAG, 127 .opt.flag = &cfg.noout, 128 }, 129 { 130 .name = "out", 131 .argname = "file", 132 .desc = "Output file (default stdout)", 133 .type = OPTION_ARG, 134 .opt.arg = &cfg.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 = &cfg.outformat, 142 }, 143 { 144 .name = "passin", 145 .argname = "src", 146 .desc = "Input file passphrase source", 147 .type = OPTION_ARG, 148 .opt.arg = &cfg.passargin, 149 }, 150 { 151 .name = "passout", 152 .argname = "src", 153 .desc = "Output file passphrase source", 154 .type = OPTION_ARG, 155 .opt.arg = &cfg.passargout, 156 }, 157 { 158 .name = "pubcheck", 159 .desc = "Check validity of public key", 160 .type = OPTION_FLAG, 161 .opt.flag = &cfg.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 = &cfg.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 = &cfg.pubout, 176 }, 177 { 178 .name = "text", 179 .desc = "Print the public/private key in plain text", 180 .type = OPTION_FLAG, 181 .opt.flag = &cfg.text, 182 }, 183 { 184 .name = "text_pub", 185 .desc = "Print out only public key in plain text", 186 .type = OPTION_FLAG, 187 .opt.flag = &cfg.pubtext, 188 }, 189 { 190 .name = NULL, 191 .type = OPTION_ARGV_FUNC, 192 .opt.argvfunc = pkey_opt_cipher, 193 }, 194 { NULL } 195}; 196 197static void 198pkey_usage(void) 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 216int 217pkey_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 (pledge("stdio cpath wpath rpath tty", NULL) == -1) { 225 perror("pledge"); 226 exit(1); 227 } 228 229 memset(&cfg, 0, sizeof(cfg)); 230 cfg.informat = FORMAT_PEM; 231 cfg.outformat = FORMAT_PEM; 232 233 if (options_parse(argc, argv, pkey_options, NULL, NULL) != 0) { 234 pkey_usage(); 235 goto end; 236 } 237 238 if (cfg.pubtext) 239 cfg.text = 1; 240 if (cfg.pubin) 241 cfg.pubout = cfg.pubtext = 1; 242 243 if (!app_passwd(bio_err, cfg.passargin, cfg.passargout, 244 &passin, &passout)) { 245 BIO_printf(bio_err, "Error getting passwords\n"); 246 goto end; 247 } 248 if (cfg.outfile) { 249 if (!(out = BIO_new_file(cfg.outfile, "wb"))) { 250 BIO_printf(bio_err, 251 "Can't open output file %s\n", cfg.outfile); 252 goto end; 253 } 254 } else { 255 out = BIO_new_fp(stdout, BIO_NOCLOSE); 256 } 257 258 if (cfg.pubin) 259 pkey = load_pubkey(bio_err, cfg.infile, 260 cfg.informat, 1, passin, "Public Key"); 261 else 262 pkey = load_key(bio_err, cfg.infile, 263 cfg.informat, 1, passin, "key"); 264 if (!pkey) 265 goto end; 266 267 if (cfg.check) { 268 if (!pkey_check(out, pkey, EVP_PKEY_check, "Key pair")) 269 goto end; 270 } else if (cfg.pubcheck) { 271 if (!pkey_check(out, pkey, EVP_PKEY_public_check, "Public key")) 272 goto end; 273 } 274 275 if (!cfg.noout) { 276 if (cfg.outformat == FORMAT_PEM) { 277 if (cfg.pubout) 278 PEM_write_bio_PUBKEY(out, pkey); 279 else 280 PEM_write_bio_PrivateKey(out, pkey, 281 cfg.cipher, NULL, 0, NULL, passout); 282 } else if (cfg.outformat == FORMAT_ASN1) { 283 if (cfg.pubout) 284 i2d_PUBKEY_bio(out, pkey); 285 else 286 i2d_PrivateKey_bio(out, pkey); 287 } else { 288 BIO_printf(bio_err, "Bad format specified for key\n"); 289 goto end; 290 } 291 292 } 293 if (cfg.text) { 294 if (cfg.pubtext) 295 EVP_PKEY_print_public(out, pkey, 0, NULL); 296 else 297 EVP_PKEY_print_private(out, pkey, 0, NULL); 298 } 299 ret = 0; 300 301 end: 302 EVP_PKEY_free(pkey); 303 BIO_free_all(out); 304 BIO_free(in); 305 free(passin); 306 free(passout); 307 308 return ret; 309} 310