From d572171b8095782ac2f775fdf1f184638843f16d Mon Sep 17 00:00:00 2001 From: inoguchi Date: Thu, 24 Mar 2022 11:27:45 +0000 Subject: [PATCH] Convert openssl(1) ts option handling Apply new option handling to openssl(1) ts, and there is no functional changes here. usage strings are comes from manual page. comments and ok jsing@ --- usr.bin/openssl/ts.c | 438 ++++++++++++++++++++++++++++--------------- 1 file changed, 285 insertions(+), 153 deletions(-) diff --git a/usr.bin/openssl/ts.c b/usr.bin/openssl/ts.c index 40c1a49b238..e4d299d726a 100644 --- a/usr.bin/openssl/ts.c +++ b/usr.bin/openssl/ts.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ts.c,v 1.17 2021/12/12 20:22:59 tb Exp $ */ +/* $OpenBSD: ts.c,v 1.18 2022/03/24 11:27:45 inoguchi Exp $ */ /* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL * project 2002. */ @@ -116,38 +116,271 @@ static TS_VERIFY_CTX *create_verify_ctx(char *data, char *digest, static X509_STORE *create_cert_store(char *ca_path, char *ca_file); static int verify_cb(int ok, X509_STORE_CTX * ctx); +enum mode { + CMD_NONE, CMD_QUERY, CMD_REPLY, CMD_VERIFY +}; + +static struct { + char *ca_file; + char *ca_path; + int cert; + char *chain; + char *configfile; + char *data; + char *digest; + char *in; + char *inkey; + const EVP_MD *md; + int mode; + int no_nonce; + char *out; + char *passin; + char *policy; + char *queryfile; + char *section; + char *signer; + int text; + int token_in; + int token_out; + char *untrusted; +} ts_config; + +static int +ts_opt_md(int argc, char **argv, int *argsused) +{ + char *name = argv[0]; + + if (*name++ != '-') + return (1); + + if ((ts_config.md = EVP_get_digestbyname(name)) == NULL) + return (1); + + *argsused = 1; + return (0); +} + +static int +ts_opt_query(void) +{ + if (ts_config.mode != CMD_NONE) + return (1); + ts_config.mode = CMD_QUERY; + return (0); +} + +static int +ts_opt_reply(void) +{ + if (ts_config.mode != CMD_NONE) + return (1); + ts_config.mode = CMD_REPLY; + return (0); +} + +static int +ts_opt_verify(void) +{ + if (ts_config.mode != CMD_NONE) + return (1); + ts_config.mode = CMD_VERIFY; + return (0); +} + +static const struct option ts_options[] = { + { + .name = "CAfile", + .argname = "file", + .desc = "Certificate Authority file", + .type = OPTION_ARG, + .opt.arg = &ts_config.ca_file, + }, + { + .name = "CApath", + .argname = "path", + .desc = "Certificate Authority path", + .type = OPTION_ARG, + .opt.arg = &ts_config.ca_path, + }, + { + .name = "cert", + .desc = "Include signing certificate in the response", + .type = OPTION_FLAG, + .opt.flag = &ts_config.cert, + }, + { + .name = "chain", + .argname = "file", + .desc = "PEM certificates that will be included in the response", + .type = OPTION_ARG, + .opt.arg = &ts_config.chain, + }, + { + .name = "config", + .argname = "file", + .desc = "Specify an alternative configuration file", + .type = OPTION_ARG, + .opt.arg = &ts_config.configfile, + }, + { + .name = "data", + .argname = "file", + .desc = "Data file for which the time stamp request needs to be created", + .type = OPTION_ARG, + .opt.arg = &ts_config.data, + }, + { + .name = "digest", + .argname = "arg", + .desc = "Specify the message imprint explicitly without the data file", + .type = OPTION_ARG, + .opt.arg = &ts_config.digest, + }, + { + .name = "in", + .argname = "file", + .desc = "Input file", + .type = OPTION_ARG, + .opt.arg = &ts_config.in, + }, + { + .name = "inkey", + .argname = "file", + .desc = "Input key file", + .type = OPTION_ARG, + .opt.arg = &ts_config.inkey, + }, + { + .name = "no_nonce", + .desc = "Specify no nonce in the request", + .type = OPTION_FLAG, + .opt.flag = &ts_config.no_nonce, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file", + .type = OPTION_ARG, + .opt.arg = &ts_config.out, + }, + { + .name = "passin", + .argname = "src", + .desc = "Private key password source", + .type = OPTION_ARG, + .opt.arg = &ts_config.passin, + }, + { + .name = "policy", + .argname = "object_id", + .desc = "Policy for the TSA to use when creating the time stamp token", + .type = OPTION_ARG, + .opt.arg = &ts_config.policy, + }, + { + .name = "query", + .desc = "Create and print a time stamp request", + .type = OPTION_FUNC, + .opt.func = ts_opt_query, + }, + { + .name = "queryfile", + .argname = "file", + .desc = "File containing a DER-encoded time stamp request", + .type = OPTION_ARG, + .opt.arg = &ts_config.queryfile, + }, + { + .name = "reply", + .desc = "Create a time stamp response", + .type = OPTION_FUNC, + .opt.func = ts_opt_reply, + }, + { + .name = "section", + .argname = "arg", + .desc = "TSA section containing the settings for response generation", + .type = OPTION_ARG, + .opt.arg = &ts_config.section, + }, + { + .name = "signer", + .argname = "file", + .desc = "Signer certificate file", + .type = OPTION_ARG, + .opt.arg = &ts_config.signer, + }, + { + .name = "text", + .desc = "Output in human-readable text format", + .type = OPTION_FLAG, + .opt.flag = &ts_config.text, + }, + { + .name = "token_in", + .desc = "Input is a DER-encoded time stamp token", + .type = OPTION_FLAG, + .opt.flag = &ts_config.token_in, + }, + { + .name = "token_out", + .desc = "Output is a DER-encoded time stamp token", + .type = OPTION_FLAG, + .opt.flag = &ts_config.token_out, + }, + { + .name = "untrusted", + .argname = "file", + .desc = "File containing untrusted certificates", + .type = OPTION_ARG, + .opt.arg = &ts_config.untrusted, + }, + { + .name = "verify", + .desc = "Verify a time stamp response", + .type = OPTION_FUNC, + .opt.func = ts_opt_verify, + }, + { + .name = NULL, + .desc = "", + .type = OPTION_ARGV_FUNC, + .opt.argvfunc = ts_opt_md, + }, + { NULL }, +}; + +static void +ts_usage(void) +{ + fprintf(stderr, "usage:\n" + "ts -query [-md4 | -md5 | -ripemd160 | -sha1] [-cert]\n" + " [-config configfile] [-data file_to_hash]\n" + " [-digest digest_bytes] [-in request.tsq] [-no_nonce]\n" + " [-out request.tsq] [-policy object_id] [-text]\n"); + fprintf(stderr, "\n" + "ts -reply [-chain certs_file.pem] [-config configfile]\n" + " [-in response.tsr] [-inkey private.pem] [-out response.tsr]\n" + " [-passin arg] [-policy object_id] [-queryfile request.tsq]\n" + " [-section tsa_section] [-signer tsa_cert.pem] [-text]\n" + " [-token_in] [-token_out]\n"); + fprintf(stderr, "\n" + "ts -verify [-CAfile trusted_certs.pem]\n" + " [-CApath trusted_cert_path] [-data file_to_hash]\n" + " [-digest digest_bytes] [-in response.tsr]\n" + " [-queryfile request.tsq] [-token_in]\n" + " [-untrusted cert_file.pem]\n"); + fprintf(stderr, "\n"); + options_usage(ts_options); + fprintf(stderr, "\n"); +} + int ts_main(int argc, char **argv) { int ret = 1; - char *configfile = NULL; - char *section = NULL; CONF *conf = NULL; - enum mode { - CMD_NONE, CMD_QUERY, CMD_REPLY, CMD_VERIFY - } mode = CMD_NONE; - char *data = NULL; - char *digest = NULL; - const EVP_MD *md = NULL; - char *policy = NULL; - int no_nonce = 0; - int cert = 0; - char *in = NULL; - char *out = NULL; - int text = 0; - char *queryfile = NULL; - char *passin = NULL; /* Password source. */ char *password = NULL; /* Password itself. */ - char *inkey = NULL; - char *signer = NULL; - char *chain = NULL; - char *ca_path = NULL; - char *ca_file = NULL; - char *untrusted = NULL; - /* Input is ContentInfo instead of TimeStampResp. */ - int token_in = 0; - /* Output is ContentInfo instead of TimeStampResp. */ - int token_out = 0; if (single_execution) { if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { @@ -156,98 +389,15 @@ ts_main(int argc, char **argv) } } - for (argc--, argv++; argc > 0; argc--, argv++) { - if (strcmp(*argv, "-config") == 0) { - if (argc-- < 1) - goto usage; - configfile = *++argv; - } else if (strcmp(*argv, "-section") == 0) { - if (argc-- < 1) - goto usage; - section = *++argv; - } else if (strcmp(*argv, "-query") == 0) { - if (mode != CMD_NONE) - goto usage; - mode = CMD_QUERY; - } else if (strcmp(*argv, "-data") == 0) { - if (argc-- < 1) - goto usage; - data = *++argv; - } else if (strcmp(*argv, "-digest") == 0) { - if (argc-- < 1) - goto usage; - digest = *++argv; - } else if (strcmp(*argv, "-policy") == 0) { - if (argc-- < 1) - goto usage; - policy = *++argv; - } else if (strcmp(*argv, "-no_nonce") == 0) { - no_nonce = 1; - } else if (strcmp(*argv, "-cert") == 0) { - cert = 1; - } else if (strcmp(*argv, "-in") == 0) { - if (argc-- < 1) - goto usage; - in = *++argv; - } else if (strcmp(*argv, "-token_in") == 0) { - token_in = 1; - } else if (strcmp(*argv, "-out") == 0) { - if (argc-- < 1) - goto usage; - out = *++argv; - } else if (strcmp(*argv, "-token_out") == 0) { - token_out = 1; - } else if (strcmp(*argv, "-text") == 0) { - text = 1; - } else if (strcmp(*argv, "-reply") == 0) { - if (mode != CMD_NONE) - goto usage; - mode = CMD_REPLY; - } else if (strcmp(*argv, "-queryfile") == 0) { - if (argc-- < 1) - goto usage; - queryfile = *++argv; - } else if (strcmp(*argv, "-passin") == 0) { - if (argc-- < 1) - goto usage; - passin = *++argv; - } else if (strcmp(*argv, "-inkey") == 0) { - if (argc-- < 1) - goto usage; - inkey = *++argv; - } else if (strcmp(*argv, "-signer") == 0) { - if (argc-- < 1) - goto usage; - signer = *++argv; - } else if (strcmp(*argv, "-chain") == 0) { - if (argc-- < 1) - goto usage; - chain = *++argv; - } else if (strcmp(*argv, "-verify") == 0) { - if (mode != CMD_NONE) - goto usage; - mode = CMD_VERIFY; - } else if (strcmp(*argv, "-CApath") == 0) { - if (argc-- < 1) - goto usage; - ca_path = *++argv; - } else if (strcmp(*argv, "-CAfile") == 0) { - if (argc-- < 1) - goto usage; - ca_file = *++argv; - } else if (strcmp(*argv, "-untrusted") == 0) { - if (argc-- < 1) - goto usage; - untrusted = *++argv; - } else if ((md = EVP_get_digestbyname(*argv + 1)) != NULL) { - /* empty. */ - } else - goto usage; - } + memset(&ts_config, 0, sizeof(ts_config)); + ts_config.mode = CMD_NONE; + + if (options_parse(argc, argv, ts_options, NULL, NULL) != 0) + goto usage; /* Get the password if required. */ - if (mode == CMD_REPLY && passin && - !app_passwd(bio_err, passin, NULL, &password, NULL)) { + if (ts_config.mode == CMD_REPLY && ts_config.passin && + !app_passwd(bio_err, ts_config.passin, NULL, &password, NULL)) { BIO_printf(bio_err, "Error getting password.\n"); goto cleanup; } @@ -255,7 +405,7 @@ ts_main(int argc, char **argv) * Check consistency of parameters and execute the appropriate * function. */ - switch (mode) { + switch (ts_config.mode) { case CMD_NONE: goto usage; case CMD_QUERY: @@ -263,64 +413,46 @@ ts_main(int argc, char **argv) * Data file and message imprint cannot be specified at the * same time. */ - ret = data != NULL && digest != NULL; + ret = ts_config.data != NULL && ts_config.digest != NULL; if (ret) goto usage; /* Load the config file for possible policy OIDs. */ - conf = load_config_file(configfile); - ret = !query_command(data, digest, md, policy, no_nonce, cert, - in, out, text); + conf = load_config_file(ts_config.configfile); + ret = !query_command(ts_config.data, ts_config.digest, ts_config.md, ts_config.policy, ts_config.no_nonce, ts_config.cert, + ts_config.in, ts_config.out, ts_config.text); break; case CMD_REPLY: - conf = load_config_file(configfile); - if (in == NULL) { - ret = !(queryfile != NULL && conf != NULL && !token_in); + conf = load_config_file(ts_config.configfile); + if (ts_config.in == NULL) { + ret = !(ts_config.queryfile != NULL && conf != NULL && !ts_config.token_in); if (ret) goto usage; } else { /* 'in' and 'queryfile' are exclusive. */ - ret = !(queryfile == NULL); + ret = !(ts_config.queryfile == NULL); if (ret) goto usage; } - ret = !reply_command(conf, section, queryfile, - password, inkey, signer, chain, policy, - in, token_in, out, token_out, text); + ret = !reply_command(conf, ts_config.section, ts_config.queryfile, + password, ts_config.inkey, ts_config.signer, ts_config.chain, ts_config.policy, + ts_config.in, ts_config.token_in, ts_config.out, ts_config.token_out, ts_config.text); break; case CMD_VERIFY: - ret = !(((queryfile && !data && !digest) || - (!queryfile && data && !digest) || - (!queryfile && !data && digest)) && in != NULL); + ret = !(((ts_config.queryfile && !ts_config.data && !ts_config.digest) || + (!ts_config.queryfile && ts_config.data && !ts_config.digest) || + (!ts_config.queryfile && !ts_config.data && ts_config.digest)) && ts_config.in != NULL); if (ret) goto usage; - ret = !verify_command(data, digest, queryfile, in, token_in, - ca_path, ca_file, untrusted); + ret = !verify_command(ts_config.data, ts_config.digest, ts_config.queryfile, ts_config.in, ts_config.token_in, + ts_config.ca_path, ts_config.ca_file, ts_config.untrusted); } goto cleanup; usage: - BIO_printf(bio_err, "usage:\n" - "ts -query [-config configfile] " - "[-data file_to_hash] [-digest digest_bytes]" - "[-md4|-md5|-sha1|-ripemd160] " - "[-policy object_id] [-no_nonce] [-cert] " - "[-in request.tsq] [-out request.tsq] [-text]\n"); - BIO_printf(bio_err, "or\n" - "ts -reply [-config configfile] [-section tsa_section] " - "[-queryfile request.tsq] [-passin password] " - "[-signer tsa_cert.pem] [-inkey private_key.pem] " - "[-chain certs_file.pem] [-policy object_id] " - "[-in response.tsr] [-token_in] " - "[-out response.tsr] [-token_out] [-text]\n"); - BIO_printf(bio_err, "or\n" - "ts -verify [-data file_to_hash] [-digest digest_bytes] " - "[-queryfile request.tsq] " - "-in response.tsr [-token_in] " - "-CApath ca_path -CAfile ca_file.pem " - "-untrusted cert_file.pem\n"); + ts_usage(); cleanup: /* Clean up. */ -- 2.20.1