=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/openssl/ts.c,v retrieving revision 1.17 retrieving revision 1.18 diff -c -r1.17 -r1.18 *** src/usr.bin/openssl/ts.c 2021/12/12 20:22:59 1.17 --- src/usr.bin/openssl/ts.c 2022/03/24 11:27:45 1.18 *************** *** 1,4 **** ! /* $OpenBSD: ts.c,v 1.17 2021/12/12 20:22:59 tb Exp $ */ /* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL * project 2002. */ --- 1,4 ---- ! /* $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,153 **** static X509_STORE *create_cert_store(char *ca_path, char *ca_file); static int verify_cb(int ok, X509_STORE_CTX * ctx); 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) { --- 116,386 ---- 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; CONF *conf = NULL; char *password = NULL; /* Password itself. */ if (single_execution) { if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { *************** *** 156,253 **** } } ! 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; ! } /* Get the password if required. */ ! if (mode == CMD_REPLY && passin && ! !app_passwd(bio_err, passin, NULL, &password, NULL)) { BIO_printf(bio_err, "Error getting password.\n"); goto cleanup; } --- 389,403 ---- } } ! 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 (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,261 **** * Check consistency of parameters and execute the appropriate * function. */ ! switch (mode) { case CMD_NONE: goto usage; case CMD_QUERY: --- 405,411 ---- * Check consistency of parameters and execute the appropriate * function. */ ! switch (ts_config.mode) { case CMD_NONE: goto usage; case CMD_QUERY: *************** *** 263,326 **** * Data file and message imprint cannot be specified at the * same time. */ ! ret = data != NULL && 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); break; case CMD_REPLY: ! conf = load_config_file(configfile); ! if (in == NULL) { ! ret = !(queryfile != NULL && conf != NULL && !token_in); if (ret) goto usage; } else { /* 'in' and 'queryfile' are exclusive. */ ! ret = !(queryfile == NULL); if (ret) goto usage; } ! ret = !reply_command(conf, section, queryfile, ! password, inkey, signer, chain, policy, ! in, token_in, out, token_out, text); break; case CMD_VERIFY: ! ret = !(((queryfile && !data && !digest) || ! (!queryfile && data && !digest) || ! (!queryfile && !data && digest)) && in != NULL); if (ret) goto usage; ! ret = !verify_command(data, digest, queryfile, in, token_in, ! ca_path, ca_file, 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"); cleanup: /* Clean up. */ --- 413,458 ---- * Data file and message imprint cannot be specified at the * same time. */ ! 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(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(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 = !(ts_config.queryfile == NULL); if (ret) goto usage; } ! 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 = !(((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(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: ! ts_usage(); cleanup: /* Clean up. */