APPS: Add check for multiple 'unknown' options Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com> (Merged from https://github.com/openssl/openssl/pull/16416)
diff --git a/apps/cms.c b/apps/cms.c index b49d1e3..575f8b3 100644 --- a/apps/cms.c +++ b/apps/cms.c
@@ -314,6 +314,7 @@ if (encerts == NULL || vpm == NULL) goto end; + opt_set_unknown_name("cipher"); prog = opt_init(argc, argv, cms_options); while ((o = opt_next()) != OPT_EOF) { switch (o) {
diff --git a/apps/crl.c b/apps/crl.c index 8d353ff..c8f0981 100644 --- a/apps/crl.c +++ b/apps/crl.c
@@ -98,6 +98,7 @@ int hash_old = 0; #endif + opt_set_unknown_name("digest"); prog = opt_init(argc, argv, crl_options); while ((o = opt_next()) != OPT_EOF) { switch (o) {
diff --git a/apps/dgst.c b/apps/dgst.c index e75dd72..18ba3d4 100644 --- a/apps/dgst.c +++ b/apps/dgst.c
@@ -115,6 +115,7 @@ buf = app_malloc(BUFSIZE, "I/O buffer"); md = (EVP_MD *)EVP_get_digestbyname(argv[0]); + opt_set_unknown_name("digest"); prog = opt_init(argc, argv, dgst_options); while ((o = opt_next()) != OPT_EOF) { switch (o) {
diff --git a/apps/dsa.c b/apps/dsa.c index 9605ed8..fae277b 100644 --- a/apps/dsa.c +++ b/apps/dsa.c
@@ -92,6 +92,7 @@ int selection = 0; OSSL_ENCODER_CTX *ectx = NULL; + opt_set_unknown_name("cipher"); prog = opt_init(argc, argv, dsa_options); while ((o = opt_next()) != OPT_EOF) { switch (o) {
diff --git a/apps/ec.c b/apps/ec.c index 4573300..2c350ff 100644 --- a/apps/ec.c +++ b/apps/ec.c
@@ -80,6 +80,7 @@ char *point_format = NULL; int no_public = 0; + opt_set_unknown_name("cipher"); prog = opt_init(argc, argv, ec_options); while ((o = opt_next()) != OPT_EOF) { switch (o) {
diff --git a/apps/enc.c b/apps/enc.c index e71453c..b14129d 100644 --- a/apps/enc.c +++ b/apps/enc.c
@@ -143,6 +143,7 @@ else if (strcmp(argv[0], "enc") != 0) ciphername = argv[0]; + opt_set_unknown_name("cipher"); prog = opt_init(argc, argv, enc_options); while ((o = opt_next()) != OPT_EOF) { switch (o) {
diff --git a/apps/gendsa.c b/apps/gendsa.c index b9bc2f5..c4070c9 100644 --- a/apps/gendsa.c +++ b/apps/gendsa.c
@@ -62,6 +62,7 @@ OPTION_CHOICE o; int ret = 1, private = 0, verbose = 0, nbits; + opt_set_unknown_name("cipher"); prog = opt_init(argc, argv, gendsa_options); while ((o = opt_next()) != OPT_EOF) { switch (o) {
diff --git a/apps/genpkey.c b/apps/genpkey.c index 7f70a6b..f4c8f92 100644 --- a/apps/genpkey.c +++ b/apps/genpkey.c
@@ -74,6 +74,7 @@ OSSL_LIB_CTX *libctx = app_get0_libctx(); STACK_OF(OPENSSL_STRING) *keyopt = NULL; + opt_set_unknown_name("cipher"); prog = opt_init(argc, argv, genpkey_options); keyopt = sk_OPENSSL_STRING_new_null(); if (keyopt == NULL)
diff --git a/apps/genrsa.c b/apps/genrsa.c index 1a6c673..9d0fea7 100644 --- a/apps/genrsa.c +++ b/apps/genrsa.c
@@ -93,6 +93,7 @@ if (bn == NULL || cb == NULL) goto end; + opt_set_unknown_name("cipher"); prog = opt_init(argc, argv, genrsa_options); while ((o = opt_next()) != OPT_EOF) { switch (o) {
diff --git a/apps/include/opt.h b/apps/include/opt.h index 9493901..365eae5 100644 --- a/apps/include/opt.h +++ b/apps/include/opt.h
@@ -365,6 +365,7 @@ char *opt_flag(void); char *opt_arg(void); char *opt_unknown(void); +void reset_unknown(void); int opt_cipher(const char *name, EVP_CIPHER **cipherp); int opt_cipher_any(const char *name, EVP_CIPHER **cipherp); int opt_cipher_silent(const char *name, EVP_CIPHER **cipherp); @@ -373,6 +374,7 @@ int opt_md_silent(const char *name, EVP_MD **mdp); int opt_int(const char *arg, int *result); +void opt_set_unknown_name(const char *name); int opt_int_arg(void); int opt_long(const char *arg, long *result); int opt_ulong(const char *arg, unsigned long *result);
diff --git a/apps/lib/opt.c b/apps/lib/opt.c index 7967fa7..2865a1e 100644 --- a/apps/lib/opt.c +++ b/apps/lib/opt.c
@@ -41,6 +41,7 @@ static char *arg; static char *flag; static char *dunno; +static const char *unknown_name; static const OPTIONS *unknown; static const OPTIONS *opts; static char prog[40]; @@ -166,7 +167,6 @@ opt_begin(); opts = o; unknown = NULL; - /* Make sure prog name is set for usage output */ (void)opt_progname(argv[0]); @@ -215,6 +215,7 @@ } #endif if (o->name[0] == '\0') { + OPENSSL_assert(unknown_name != NULL); OPENSSL_assert(unknown == NULL); unknown = o; OPENSSL_assert(unknown->valtype == 0 || unknown->valtype == '-'); @@ -236,6 +237,11 @@ {NULL} }; +void opt_set_unknown_name(const char *name) +{ + unknown_name = name; +} + /* Print an error message about a failed format parse. */ static int opt_format_error(const char *s, unsigned long flags) { @@ -985,6 +991,11 @@ return o->retval; } if (unknown != NULL) { + if (dunno != NULL) { + opt_printf_stderr("%s: Multiple %s or unknown options: -%s and -%s\n", + prog, unknown_name, dunno, p); + return -1; + } dunno = p; return unknown->retval; } @@ -1010,6 +1021,12 @@ return dunno; } +/* Reset the unknown option; needed by ocsp to allow multiple digest options. */ +void reset_unknown(void) +{ + dunno = NULL; +} + /* Return the rest of the arguments after parsing flags. */ char **opt_rest(void) {
diff --git a/apps/ocsp.c b/apps/ocsp.c index d8e45cc..18e7c44 100644 --- a/apps/ocsp.c +++ b/apps/ocsp.c
@@ -196,8 +196,10 @@ {"VAfile", OPT_VAFILE, '<', "Validator certificates file"}, {"verify_other", OPT_VERIFY_OTHER, '<', "Additional certificates to search for signer"}, - {"cert", OPT_CERT, '<', "Certificate to check"}, - {"serial", OPT_SERIAL, 's', "Serial number to check"}, + {"cert", OPT_CERT, '<', + "Certificate to check; may be given multiple times"}, + {"serial", OPT_SERIAL, 's', + "Serial number to check; may be given multiple times"}, {"validity_period", OPT_VALIDITY_PERIOD, 'u', "Maximum validity discrepancy in seconds"}, {"signkey", OPT_SIGNKEY, 's', "Private key to sign OCSP request with"}, @@ -261,6 +263,7 @@ || (vpm = X509_VERIFY_PARAM_new()) == NULL) goto end; + opt_set_unknown_name("digest"); prog = opt_init(argc, argv, ocsp_options); while ((o = opt_next()) != OPT_EOF) { switch (o) { @@ -436,6 +439,7 @@ goto end; break; case OPT_CERT: + reset_unknown(); X509_free(cert); cert = load_cert(opt_arg(), FORMAT_UNDEF, "certificate"); if (cert == NULL) @@ -449,6 +453,7 @@ trailing_md = 0; break; case OPT_SERIAL: + reset_unknown(); if (cert_id_md == NULL) cert_id_md = (EVP_MD *)EVP_sha1(); if (!add_ocsp_serial(&req, opt_arg(), cert_id_md, issuer, ids))
diff --git a/apps/pkcs12.c b/apps/pkcs12.c index 08af7bf..754994e 100644 --- a/apps/pkcs12.c +++ b/apps/pkcs12.c
@@ -182,6 +182,7 @@ EVP_CIPHER *enc = (EVP_CIPHER *)default_enc; OPTION_CHOICE o; + opt_set_unknown_name("cipher"); prog = opt_init(argc, argv, pkcs12_options); while ((o = opt_next()) != OPT_EOF) { switch (o) {
diff --git a/apps/pkey.c b/apps/pkey.c index 41a4c29..cfef85e 100644 --- a/apps/pkey.c +++ b/apps/pkey.c
@@ -83,6 +83,7 @@ char *point_format = NULL; #endif + opt_set_unknown_name("cipher"); prog = opt_init(argc, argv, pkey_options); while ((o = opt_next()) != OPT_EOF) { switch (o) {
diff --git a/apps/req.c b/apps/req.c index 36ac493..eaff69f 100644 --- a/apps/req.c +++ b/apps/req.c
@@ -266,6 +266,7 @@ cipher = (EVP_CIPHER *)EVP_des_ede3_cbc(); #endif + opt_set_unknown_name("digest"); prog = opt_init(argc, argv, req_options); while ((o = opt_next()) != OPT_EOF) { switch (o) {
diff --git a/apps/rsa.c b/apps/rsa.c index fb73173..08527f6 100644 --- a/apps/rsa.c +++ b/apps/rsa.c
@@ -139,6 +139,7 @@ int selection = 0; OSSL_ENCODER_CTX *ectx = NULL; + opt_set_unknown_name("cipher"); prog = opt_init(argc, argv, rsa_options); while ((o = opt_next()) != OPT_EOF) { switch (o) {
diff --git a/apps/smime.c b/apps/smime.c index 9677f05..6001d44 100644 --- a/apps/smime.c +++ b/apps/smime.c
@@ -160,6 +160,7 @@ if ((vpm = X509_VERIFY_PARAM_new()) == NULL) return 1; + opt_set_unknown_name("cipher"); prog = opt_init(argc, argv, smime_options); while ((o = opt_next()) != OPT_EOF) { switch (o) {
diff --git a/apps/storeutl.c b/apps/storeutl.c index 8d1ce3c..65444fc 100644 --- a/apps/storeutl.c +++ b/apps/storeutl.c
@@ -74,7 +74,7 @@ BIO *out = NULL; ENGINE *e = NULL; OPTION_CHOICE o; - char *prog = opt_init(argc, argv, storeutl_options); + char *prog; PW_CB_DATA pw_cb_data; int expected = 0; int criterion = 0; @@ -87,6 +87,8 @@ EVP_MD *digest = NULL; OSSL_LIB_CTX *libctx = app_get0_libctx(); + opt_set_unknown_name("digest"); + prog = opt_init(argc, argv, storeutl_options); while ((o = opt_next()) != OPT_EOF) { switch (o) { case OPT_EOF:
diff --git a/apps/ts.c b/apps/ts.c index 8e58ef0..2497c3b 100644 --- a/apps/ts.c +++ b/apps/ts.c
@@ -181,6 +181,7 @@ if ((vpm = X509_VERIFY_PARAM_new()) == NULL) goto end; + opt_set_unknown_name("digest"); prog = opt_init(argc, argv, ts_options); while ((o = opt_next()) != OPT_EOF) { switch (o) {
diff --git a/apps/x509.c b/apps/x509.c index 188bc17..29dc74c 100644 --- a/apps/x509.c +++ b/apps/x509.c
@@ -302,6 +302,7 @@ goto err; X509_STORE_set_verify_cb(ctx, callb); + opt_set_unknown_name("digest"); prog = opt_init(argc, argv, x509_options); while ((o = opt_next()) != OPT_EOF) { switch (o) { @@ -592,7 +593,6 @@ break; } } - /* No extra arguments. */ if (!opt_check_rest_arg(NULL)) goto opthelp;
diff --git a/doc/man1/openssl-ocsp.pod.in b/doc/man1/openssl-ocsp.pod.in index fbad507..37c7aeb 100644 --- a/doc/man1/openssl-ocsp.pod.in +++ b/doc/man1/openssl-ocsp.pod.in
@@ -102,15 +102,16 @@ =item B<-issuer> I<filename> -This specifies the current issuer certificate. This option can be used -multiple times. +This specifies the current issuer certificate. +This option can be used multiple times. This option B<MUST> come before any B<-cert> options. =item B<-cert> I<filename> -Add the certificate I<filename> to the request. The issuer certificate -is taken from the previous B<-issuer> option, or an error occurs if no -issuer certificate is specified. +Add the certificate I<filename> to the request. +This option can be used multiple times. +The issuer certificate is taken from the previous B<-issuer> option, +or an error occurs if no issuer certificate is specified. =item B<-no_certs>