Convert openssl(1)'s rsa.c to the new option handling code.
authordoug <doug@openbsd.org>
Sat, 24 Jan 2015 05:48:39 +0000 (05:48 +0000)
committerdoug <doug@openbsd.org>
Sat, 24 Jan 2015 05:48:39 +0000 (05:48 +0000)
input + ok jsing@

usr.bin/openssl/rsa.c

index d8366aa..91a9d16 100644 (file)
@@ -1,4 +1,4 @@
-/* $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.
  *
@@ -58,7 +58,6 @@
 
 #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)
@@ -103,140 +276,30 @@ 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;
        }
@@ -245,25 +308,26 @@ bad:
        {
                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);
@@ -274,27 +338,27 @@ bad:
                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)
@@ -306,7 +370,8 @@ bad:
                            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 */
                        }
@@ -317,14 +382,14 @@ bad:
                        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);
@@ -332,46 +397,49 @@ bad:
                        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) {
@@ -379,11 +447,10 @@ bad:
                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);