-/* $OpenBSD: rsa.c,v 1.2 2014/08/28 14:23:52 jsing Exp $ */
+/* $OpenBSD: rsa.c,v 1.3 2015/01/24 05:48:39 doug Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
#include <openssl/opensslconf.h>
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
-/* -inform arg - input format - default PEM (one of DER, NET or PEM)
- * -outform arg - output format - default PEM
- * -in arg - input file - default stdin
- * -out arg - output file - default stdout
- * -des - encrypt output if PEM format with DES in cbc mode
- * -des3 - encrypt output if PEM format
- * -idea - encrypt output if PEM format
- * -seed - encrypt output if PEM format
- * -aes128 - encrypt output if PEM format
- * -aes192 - encrypt output if PEM format
- * -aes256 - encrypt output if PEM format
- * -camellia128 - encrypt output if PEM format
- * -camellia192 - encrypt output if PEM format
- * -camellia256 - encrypt output if PEM format
- * -text - print a text version
- * -modulus - print the RSA key modulus
- * -check - verify key consistency
- * -pubin - Expect a public key in input file.
- * -pubout - Output a public key.
- */
+static struct {
+ int check;
+ const EVP_CIPHER *enc;
+#ifndef OPENSSL_NO_ENGINE
+ char *engine;
+#endif
+ char *infile;
+ int informat;
+ int modulus;
+ int noout;
+ char *outfile;
+ int outformat;
+ char *passargin;
+ char *passargout;
+ int pubin;
+ int pubout;
+ int pvk_encr;
+ int sgckey;
+ int text;
+} rsa_config;
-int rsa_main(int, char **);
+static int
+rsa_opt_cipher(int argc, char **argv, int *argsused)
+{
+ char *name = argv[0];
+
+ if (*name++ != '-')
+ return (1);
+
+ if ((rsa_config.enc = EVP_get_cipherbyname(name)) == NULL) {
+ fprintf(stderr, "Invalid cipher '%s'\n", name);
+ return (1);
+ }
+
+ *argsused = 1;
+ return (0);
+}
+
+static struct option rsa_options[] = {
+ {
+ .name = "check",
+ .desc = "Check consistency of RSA private key",
+ .type = OPTION_FLAG,
+ .opt.flag = &rsa_config.check,
+ },
+#ifndef OPENSSL_NO_ENGINE
+ {
+ .name = "engine",
+ .argname = "id",
+ .desc = "Use the engine specified by the given identifier",
+ .type = OPTION_ARG,
+ .opt.arg = &rsa_config.engine,
+ },
+#endif
+ {
+ .name = "in",
+ .argname = "file",
+ .desc = "Input file (default stdin)",
+ .type = OPTION_ARG,
+ .opt.arg = &rsa_config.infile,
+ },
+ {
+ .name = "inform",
+ .argname = "format",
+ .desc = "Input format (DER, NET or PEM (default))",
+ .type = OPTION_ARG_FORMAT,
+ .opt.value = &rsa_config.informat,
+ },
+ {
+ .name = "modulus",
+ .desc = "Print the RSA key modulus",
+ .type = OPTION_FLAG,
+ .opt.flag = &rsa_config.modulus,
+ },
+ {
+ .name = "noout",
+ .desc = "Do not print encoded version of the key",
+ .type = OPTION_FLAG,
+ .opt.flag = &rsa_config.noout,
+ },
+ {
+ .name = "out",
+ .argname = "file",
+ .desc = "Output file (default stdout)",
+ .type = OPTION_ARG,
+ .opt.arg = &rsa_config.outfile,
+ },
+ {
+ .name = "outform",
+ .argname = "format",
+ .desc = "Output format (DER, NET or PEM (default PEM))",
+ .type = OPTION_ARG_FORMAT,
+ .opt.value = &rsa_config.outformat,
+ },
+ {
+ .name = "passin",
+ .argname = "src",
+ .desc = "Input file passphrase source",
+ .type = OPTION_ARG,
+ .opt.arg = &rsa_config.passargin,
+ },
+ {
+ .name = "passout",
+ .argname = "src",
+ .desc = "Output file passphrase source",
+ .type = OPTION_ARG,
+ .opt.arg = &rsa_config.passargout,
+ },
+ {
+ .name = "pubin",
+ .desc = "Expect a public key (default private key)",
+ .type = OPTION_VALUE,
+ .value = 1,
+ .opt.value = &rsa_config.pubin,
+ },
+ {
+ .name = "pubout",
+ .desc = "Output a public key (default private key)",
+ .type = OPTION_VALUE,
+ .value = 1,
+ .opt.value = &rsa_config.pubout,
+ },
+ {
+ .name = "pvk-none",
+ .type = OPTION_VALUE,
+ .value = 0,
+ .opt.value = &rsa_config.pvk_encr,
+ },
+ {
+ .name = "pvk-strong",
+ .type = OPTION_VALUE,
+ .value = 2,
+ .opt.value = &rsa_config.pvk_encr,
+ },
+ {
+ .name = "pvk-weak",
+ .type = OPTION_VALUE,
+ .value = 1,
+ .opt.value = &rsa_config.pvk_encr,
+ },
+ {
+ .name = "RSAPublicKey_in",
+ .type = OPTION_VALUE,
+ .value = 2,
+ .opt.value = &rsa_config.pubin,
+ },
+ {
+ .name = "RSAPublicKey_out",
+ .type = OPTION_VALUE,
+ .value = 2,
+ .opt.value = &rsa_config.pubout,
+ },
+ {
+ .name = "sgckey",
+ .desc = "Use modified NET algorithm for IIS and SGC keys",
+ .type = OPTION_FLAG,
+ .opt.flag = &rsa_config.sgckey,
+ },
+ {
+ .name = "text",
+ .desc = "Print in plain text in addition to encoded",
+ .type = OPTION_FLAG,
+ .opt.flag = &rsa_config.text,
+ },
+ {
+ .name = NULL,
+ .type = OPTION_ARGV_FUNC,
+ .opt.argvfunc = rsa_opt_cipher,
+ },
+ { NULL }
+};
+
+static void
+show_ciphers(const OBJ_NAME *name, void *arg)
+{
+ static int n;
+
+ fprintf(stderr, " -%-24s%s", name->name, (++n % 3 ? "" : "\n"));
+}
+
+static void
+rsa_usage()
+{
+ fprintf(stderr,
+ "usage: rsa [-ciphername] [-check] [-engine id] [-in file] "
+ "[-inform fmt]\n"
+ " [-modulus] [-noout] [-out file] [-outform fmt] "
+ "[-passin src]\n"
+ " [-passout src] [-pubin] [-pubout] [-sgckey] [-text]\n\n");
+ options_usage(rsa_options);
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "Valid ciphername values:\n\n");
+ OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, show_ciphers, NULL);
+ fprintf(stderr, "\n");
+}
int
rsa_main(int argc, char **argv)
ENGINE *e = NULL;
int ret = 1;
RSA *rsa = NULL;
- int i, badops = 0, sgckey = 0;
- const EVP_CIPHER *enc = NULL;
+ int i;
BIO *out = NULL;
- int informat, outformat, text = 0, check = 0, noout = 0;
- int pubin = 0, pubout = 0;
- char *infile, *outfile, *prog;
- char *passargin = NULL, *passargout = NULL;
char *passin = NULL, *passout = NULL;
-#ifndef OPENSSL_NO_ENGINE
- char *engine = NULL;
-#endif
- int modulus = 0;
- int pvk_encr = 2;
+ memset(&rsa_config, 0, sizeof(rsa_config));
+ rsa_config.pvk_encr = 2;
+ rsa_config.informat = FORMAT_PEM;
+ rsa_config.outformat = FORMAT_PEM;
- infile = NULL;
- outfile = NULL;
- informat = FORMAT_PEM;
- outformat = FORMAT_PEM;
-
- prog = argv[0];
- argc--;
- argv++;
- while (argc >= 1) {
- if (strcmp(*argv, "-inform") == 0) {
- if (--argc < 1)
- goto bad;
- informat = str2fmt(*(++argv));
- } else if (strcmp(*argv, "-outform") == 0) {
- if (--argc < 1)
- goto bad;
- outformat = str2fmt(*(++argv));
- } else if (strcmp(*argv, "-in") == 0) {
- if (--argc < 1)
- goto bad;
- infile = *(++argv);
- } else if (strcmp(*argv, "-out") == 0) {
- if (--argc < 1)
- goto bad;
- outfile = *(++argv);
- } else if (strcmp(*argv, "-passin") == 0) {
- if (--argc < 1)
- goto bad;
- passargin = *(++argv);
- } else if (strcmp(*argv, "-passout") == 0) {
- if (--argc < 1)
- goto bad;
- passargout = *(++argv);
- }
-#ifndef OPENSSL_NO_ENGINE
- else if (strcmp(*argv, "-engine") == 0) {
- if (--argc < 1)
- goto bad;
- engine = *(++argv);
- }
-#endif
- else if (strcmp(*argv, "-sgckey") == 0)
- sgckey = 1;
- else if (strcmp(*argv, "-pubin") == 0)
- pubin = 1;
- else if (strcmp(*argv, "-pubout") == 0)
- pubout = 1;
- else if (strcmp(*argv, "-RSAPublicKey_in") == 0)
- pubin = 2;
- else if (strcmp(*argv, "-RSAPublicKey_out") == 0)
- pubout = 2;
- else if (strcmp(*argv, "-pvk-strong") == 0)
- pvk_encr = 2;
- else if (strcmp(*argv, "-pvk-weak") == 0)
- pvk_encr = 1;
- else if (strcmp(*argv, "-pvk-none") == 0)
- pvk_encr = 0;
- else if (strcmp(*argv, "-noout") == 0)
- noout = 1;
- else if (strcmp(*argv, "-text") == 0)
- text = 1;
- else if (strcmp(*argv, "-modulus") == 0)
- modulus = 1;
- else if (strcmp(*argv, "-check") == 0)
- check = 1;
- else if ((enc = EVP_get_cipherbyname(&(argv[0][1]))) == NULL) {
- BIO_printf(bio_err, "unknown option %s\n", *argv);
- badops = 1;
- break;
- }
- argc--;
- argv++;
- }
-
- if (badops) {
-bad:
- BIO_printf(bio_err, "%s [options] <infile >outfile\n", prog);
- BIO_printf(bio_err, "where options are\n");
- BIO_printf(bio_err, " -inform arg input format - one of DER NET PEM\n");
- BIO_printf(bio_err, " -outform arg output format - one of DER NET PEM\n");
- BIO_printf(bio_err, " -in arg input file\n");
- BIO_printf(bio_err, " -sgckey Use IIS SGC key format\n");
- BIO_printf(bio_err, " -passin arg input file pass phrase source\n");
- BIO_printf(bio_err, " -out arg output file\n");
- BIO_printf(bio_err, " -passout arg output file pass phrase source\n");
- BIO_printf(bio_err, " -des encrypt PEM output with cbc des\n");
- BIO_printf(bio_err, " -des3 encrypt PEM output with ede cbc des using 168 bit key\n");
-#ifndef OPENSSL_NO_IDEA
- BIO_printf(bio_err, " -idea encrypt PEM output with cbc idea\n");
-#endif
-#ifndef OPENSSL_NO_AES
- BIO_printf(bio_err, " -aes128, -aes192, -aes256\n");
- BIO_printf(bio_err, " encrypt PEM output with cbc aes\n");
-#endif
-#ifndef OPENSSL_NO_CAMELLIA
- BIO_printf(bio_err, " -camellia128, -camellia192, -camellia256\n");
- BIO_printf(bio_err, " encrypt PEM output with cbc camellia\n");
-#endif
- BIO_printf(bio_err, " -text print the key in text\n");
- BIO_printf(bio_err, " -noout don't print key out\n");
- BIO_printf(bio_err, " -modulus print the RSA key modulus\n");
- BIO_printf(bio_err, " -check verify key consistency\n");
- BIO_printf(bio_err, " -pubin expect a public key in input file\n");
- BIO_printf(bio_err, " -pubout output a public key\n");
-#ifndef OPENSSL_NO_ENGINE
- BIO_printf(bio_err, " -engine e use engine e, possibly a hardware device.\n");
-#endif
+ if (options_parse(argc, argv, rsa_options, NULL, NULL) != 0) {
+ rsa_usage();
goto end;
}
#ifndef OPENSSL_NO_ENGINE
- e = setup_engine(bio_err, engine, 0);
+ e = setup_engine(bio_err, rsa_config.engine, 0);
#endif
- if (!app_passwd(bio_err, passargin, passargout, &passin, &passout)) {
+ if (!app_passwd(bio_err, rsa_config.passargin, rsa_config.passargout,
+ &passin, &passout)) {
BIO_printf(bio_err, "Error getting passwords\n");
goto end;
}
- if (check && pubin) {
+ if (rsa_config.check && rsa_config.pubin) {
BIO_printf(bio_err, "Only private keys can be checked\n");
goto end;
}
{
EVP_PKEY *pkey;
- if (pubin) {
+ if (rsa_config.pubin) {
int tmpformat = -1;
- if (pubin == 2) {
- if (informat == FORMAT_PEM)
+ if (rsa_config.pubin == 2) {
+ if (rsa_config.informat == FORMAT_PEM)
tmpformat = FORMAT_PEMRSA;
- else if (informat == FORMAT_ASN1)
+ else if (rsa_config.informat == FORMAT_ASN1)
tmpformat = FORMAT_ASN1RSA;
- } else if (informat == FORMAT_NETSCAPE && sgckey)
+ } else if (rsa_config.informat == FORMAT_NETSCAPE &&
+ rsa_config.sgckey)
tmpformat = FORMAT_IISSGC;
else
- tmpformat = informat;
+ tmpformat = rsa_config.informat;
- pkey = load_pubkey(bio_err, infile, tmpformat, 1,
- passin, e, "Public Key");
+ pkey = load_pubkey(bio_err, rsa_config.infile,
+ tmpformat, 1, passin, e, "Public Key");
} else
- pkey = load_key(bio_err, infile,
- (informat == FORMAT_NETSCAPE && sgckey ?
- FORMAT_IISSGC : informat), 1,
- passin, e, "Private Key");
+ pkey = load_key(bio_err, rsa_config.infile,
+ (rsa_config.informat == FORMAT_NETSCAPE &&
+ rsa_config.sgckey ? FORMAT_IISSGC :
+ rsa_config.informat), 1, passin, e, "Private Key");
if (pkey != NULL)
rsa = EVP_PKEY_get1_RSA(pkey);
ERR_print_errors(bio_err);
goto end;
}
- if (outfile == NULL) {
+ if (rsa_config.outfile == NULL) {
BIO_set_fp(out, stdout, BIO_NOCLOSE);
} else {
- if (BIO_write_filename(out, outfile) <= 0) {
- perror(outfile);
+ if (BIO_write_filename(out, rsa_config.outfile) <= 0) {
+ perror(rsa_config.outfile);
goto end;
}
}
- if (text)
+ if (rsa_config.text)
if (!RSA_print(out, rsa, 0)) {
- perror(outfile);
+ perror(rsa_config.outfile);
ERR_print_errors(bio_err);
goto end;
}
- if (modulus) {
+ if (rsa_config.modulus) {
BIO_printf(out, "Modulus=");
BN_print(out, rsa->n);
BIO_printf(out, "\n");
}
- if (check) {
+ if (rsa_config.check) {
int r = RSA_check_key(rsa);
if (r == 1)
ERR_GET_LIB(err) == ERR_LIB_RSA &&
ERR_GET_FUNC(err) == RSA_F_RSA_CHECK_KEY &&
ERR_GET_REASON(err) != ERR_R_MALLOC_FAILURE) {
- BIO_printf(out, "RSA key error: %s\n", ERR_reason_error_string(err));
+ BIO_printf(out, "RSA key error: %s\n",
+ ERR_reason_error_string(err));
ERR_get_error(); /* remove e from error
* stack */
}
goto end;
}
}
- if (noout) {
+ if (rsa_config.noout) {
ret = 0;
goto end;
}
BIO_printf(bio_err, "writing RSA key\n");
- if (outformat == FORMAT_ASN1) {
- if (pubout || pubin) {
- if (pubout == 2)
+ if (rsa_config.outformat == FORMAT_ASN1) {
+ if (rsa_config.pubout || rsa_config.pubin) {
+ if (rsa_config.pubout == 2)
i = i2d_RSAPublicKey_bio(out, rsa);
else
i = i2d_RSA_PUBKEY_bio(out, rsa);
i = i2d_RSAPrivateKey_bio(out, rsa);
}
#ifndef OPENSSL_NO_RC4
- else if (outformat == FORMAT_NETSCAPE) {
+ else if (rsa_config.outformat == FORMAT_NETSCAPE) {
unsigned char *p, *pp;
int size;
i = 1;
- size = i2d_RSA_NET(rsa, NULL, NULL, sgckey);
+ size = i2d_RSA_NET(rsa, NULL, NULL, rsa_config.sgckey);
if ((p = malloc(size)) == NULL) {
BIO_printf(bio_err, "Memory allocation failure\n");
goto end;
}
pp = p;
- i2d_RSA_NET(rsa, &p, NULL, sgckey);
+ i2d_RSA_NET(rsa, &p, NULL, rsa_config.sgckey);
BIO_write(out, (char *) pp, size);
free(pp);
}
#endif
- else if (outformat == FORMAT_PEM) {
- if (pubout || pubin) {
- if (pubout == 2)
+ else if (rsa_config.outformat == FORMAT_PEM) {
+ if (rsa_config.pubout || rsa_config.pubin) {
+ if (rsa_config.pubout == 2)
i = PEM_write_bio_RSAPublicKey(out, rsa);
else
i = PEM_write_bio_RSA_PUBKEY(out, rsa);
} else
i = PEM_write_bio_RSAPrivateKey(out, rsa,
- enc, NULL, 0, NULL, passout);
+ rsa_config.enc, NULL, 0, NULL, passout);
#if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4)
- } else if (outformat == FORMAT_MSBLOB || outformat == FORMAT_PVK) {
+ } else if (rsa_config.outformat == FORMAT_MSBLOB ||
+ rsa_config.outformat == FORMAT_PVK) {
EVP_PKEY *pk;
pk = EVP_PKEY_new();
EVP_PKEY_set1_RSA(pk, rsa);
- if (outformat == FORMAT_PVK)
- i = i2b_PVK_bio(out, pk, pvk_encr, 0, passout);
- else if (pubin || pubout)
+ if (rsa_config.outformat == FORMAT_PVK)
+ i = i2b_PVK_bio(out, pk, rsa_config.pvk_encr, 0,
+ passout);
+ else if (rsa_config.pubin || rsa_config.pubout)
i = i2b_PublicKey_bio(out, pk);
else
i = i2b_PrivateKey_bio(out, pk);
EVP_PKEY_free(pk);
#endif
} else {
- BIO_printf(bio_err, "bad output format specified for outfile\n");
+ BIO_printf(bio_err,
+ "bad output format specified for outfile\n");
goto end;
}
if (i <= 0) {
ERR_print_errors(bio_err);
} else
ret = 0;
+
end:
- if (out != NULL)
- BIO_free_all(out);
- if (rsa != NULL)
- RSA_free(rsa);
+ BIO_free_all(out);
+ RSA_free(rsa);
free(passin);
free(passout);