diff options
author | Dr. David von Oheimb <David.von.Oheimb@siemens.com> | 2021-03-10 17:27:13 +0100 |
---|---|---|
committer | Dr. David von Oheimb <dev@ddvo.net> | 2021-03-13 11:16:13 +0100 |
commit | f62846b703d163265176fe960ec7d087b4c3fa96 (patch) | |
tree | fc5a92d8f17b5cd7da56add4be96fa6a088ba79d | |
parent | TS ESS: Let TS_RESP_verify_signature() make use of untrusted certs also from ... (diff) | |
download | openssl-f62846b703d163265176fe960ec7d087b4c3fa96.tar.xz openssl-f62846b703d163265176fe960ec7d087b4c3fa96.zip |
apps/ts.c: Allow -untrusted arg to refer to multiple sources
This requires moving generally useful functions from apps/cmp.c to apps/lib/apps.c
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14504)
-rw-r--r-- | apps/cmp.c | 174 | ||||
-rw-r--r-- | apps/include/apps.h | 9 | ||||
-rw-r--r-- | apps/lib/apps.c | 158 | ||||
-rw-r--r-- | apps/ts.c | 31 | ||||
-rw-r--r-- | doc/man1/openssl-ts.pod.in | 7 |
5 files changed, 201 insertions, 178 deletions
diff --git a/apps/cmp.c b/apps/cmp.c index 519e0bc2a5..2112df0186 100644 --- a/apps/cmp.c +++ b/apps/cmp.c @@ -618,25 +618,6 @@ static int set_verbosity(int level) return 1; } -static char *next_item(char *opt) /* in list separated by comma and/or space */ -{ - /* advance to separator (comma or whitespace), if any */ - while (*opt != ',' && !isspace(*opt) && *opt != '\0') { - if (*opt == '\\' && opt[1] != '\0') - /* skip and unescape '\' escaped char */ - memmove(opt, opt + 1, strlen(opt)); - opt++; - } - if (*opt != '\0') { - /* terminate current item */ - *opt++ = '\0'; - /* skip over any whitespace after separator */ - while (isspace(*opt)) - opt++; - } - return *opt == '\0' ? NULL : opt; /* NULL indicates end of input */ -} - static EVP_PKEY *load_key_pwd(const char *uri, int format, const char *pass, ENGINE *eng, const char *desc) { @@ -689,63 +670,6 @@ static X509_REQ *load_csr_autofmt(const char *infile, const char *desc) return csr; } -static void warn_cert_msg(const char *uri, X509 *cert, const char *msg) -{ - char *subj = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); - - CMP_warn3("certificate from '%s' with subject '%s' %s", uri, subj, msg); - OPENSSL_free(subj); -} - -static void warn_cert(const char *uri, X509 *cert, int warn_EE) -{ - uint32_t ex_flags = X509_get_extension_flags(cert); - int res = X509_cmp_timeframe(vpm, X509_get0_notBefore(cert), - X509_get0_notAfter(cert)); - - if (res != 0) - warn_cert_msg(uri, cert, res > 0 ? "has expired" : "not yet valid"); - if (warn_EE && (ex_flags & EXFLAG_V1) == 0 && (ex_flags & EXFLAG_CA) == 0) - warn_cert_msg(uri, cert, "is not a CA cert"); -} - -static void warn_certs(const char *uri, STACK_OF(X509) *certs, int warn_EE) -{ - int i; - - for (i = 0; i < sk_X509_num(certs); i++) - warn_cert(uri, sk_X509_value(certs, i), warn_EE); -} - -/* TODO potentially move this and related functions to apps/lib/apps.c */ -static int load_cert_certs(const char *uri, - X509 **pcert, STACK_OF(X509) **pcerts, - int exclude_http, const char *pass, const char *desc) -{ - int ret = 0; - char *pass_string; - - if (exclude_http && (strncasecmp(uri, "http://", 7) == 0 - || strncasecmp(uri, "https://", 8) == 0)) { - BIO_printf(bio_err, "error: HTTP retrieval not allowed for %s\n", desc); - return ret; - } - pass_string = get_passwd(pass, desc); - ret = load_key_certs_crls(uri, 0, pass_string, desc, NULL, NULL, NULL, - pcert, pcerts, NULL, NULL); - clear_free(pass_string); - - if (ret) { - if (pcert != NULL) - warn_cert(uri, *pcert, 0); - warn_certs(uri, *pcerts, 1); - } else { - sk_X509_pop_free(*pcerts, X509_free); - *pcerts = NULL; - } - return ret; -} - /* set expected host name/IP addr and clears the email addr in the given ts */ static int truststore_set_host_etc(X509_STORE *ts, char *host) { @@ -763,24 +687,6 @@ static int truststore_set_host_etc(X509_STORE *ts, char *host) || X509_VERIFY_PARAM_set1_host(ts_vpm, host, 0); } -static X509_STORE *sk_X509_to_store(X509_STORE *store /* may be NULL */, - const STACK_OF(X509) *certs /* may NULL */) -{ - int i; - - if (store == NULL) - store = X509_STORE_new(); - if (store == NULL) - return NULL; - for (i = 0; i < sk_X509_num(certs); i++) { - if (!X509_STORE_add_cert(store, sk_X509_value(certs, i))) { - X509_STORE_free(store); - return NULL; - } - } - return store; -} - /* write OSSL_CMP_MSG DER-encoded to the specified file name item */ static int write_PKIMESSAGE(const OSSL_CMP_MSG *msg, char **filenames) { @@ -952,37 +858,9 @@ static int set_gennames(OSSL_CMP_CTX *ctx, char *names, const char *desc) return 1; } -/* TODO potentially move to apps/lib/apps.c */ -/* - * create cert store structure with certificates read from given file(s) - * returns pointer to created X509_STORE on success, NULL on error - */ -static X509_STORE *load_certstore(char *input, const char *desc) -{ - X509_STORE *store = NULL; - STACK_OF(X509) *certs = NULL; - - while (input != NULL) { - char *next = next_item(input); - int ok; - - if (!load_cert_certs(input, NULL, &certs, 1, opt_otherpass, desc)) { - X509_STORE_free(store); - return NULL; - } - ok = (store = sk_X509_to_store(store, certs)) != NULL; - sk_X509_pop_free(certs, X509_free); - certs = NULL; - if (!ok) - return NULL; - input = next; - } - return store; -} - static X509_STORE *load_trusted(char *input, int for_new_cert, const char *desc) { - X509_STORE *ts = load_certstore(input, desc); + X509_STORE *ts = load_certstore(input, opt_otherpass, desc, vpm); if (ts == NULL) return NULL; @@ -998,40 +876,6 @@ static X509_STORE *load_trusted(char *input, int for_new_cert, const char *desc) return NULL; } -/* TODO potentially move to apps/lib/apps.c */ -static STACK_OF(X509) *load_certs_multifile(char *files, - const char *pass, const char *desc) -{ - STACK_OF(X509) *certs = NULL; - STACK_OF(X509) *result = sk_X509_new_null(); - - if (files == NULL) - goto err; - if (result == NULL) - goto oom; - - while (files != NULL) { - char *next = next_item(files); - - if (!load_cert_certs(files, NULL, &certs, 0, pass, desc)) - goto err; - if (!X509_add_certs(result, certs, - X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP)) - goto oom; - sk_X509_pop_free(certs, X509_free); - certs = NULL; - files = next; - } - return result; - - oom: - BIO_printf(bio_err, "out of memory\n"); - err: - sk_X509_pop_free(certs, X509_free); - sk_X509_pop_free(result, X509_free); - return NULL; -} - typedef int (*add_X509_stack_fn_t)(void *ctx, const STACK_OF(X509) *certs); static int setup_certs(char *files, const char *desc, void *ctx, @@ -1042,7 +886,7 @@ static int setup_certs(char *files, const char *desc, void *ctx, if (files == NULL) return 1; - if ((certs = load_certs_multifile(files, opt_otherpass, desc)) == NULL) + if ((certs = load_certs_multifile(files, opt_otherpass, desc, vpm)) == NULL) return 0; ok = (*set1_fn)(ctx, certs); sk_X509_pop_free(certs, X509_free); @@ -1350,8 +1194,9 @@ static SSL_CTX *setup_ssl_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY); if (opt_tls_trusted != NULL) { - if ((trust_store = load_certstore(opt_tls_trusted, - "trusted TLS certificates")) == NULL) + trust_store = load_certstore(opt_tls_trusted, opt_otherpass, + "trusted TLS certificates", vpm); + if (trust_store == NULL) goto err; SSL_CTX_set_cert_store(ssl_ctx, trust_store); /* for improved diagnostics on SSL_CTX_build_cert_chain() errors: */ @@ -1364,7 +1209,8 @@ static SSL_CTX *setup_ssl_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) int ok; if (!load_cert_certs(opt_tls_cert, &cert, &certs, 0, opt_tls_keypass, - "TLS client certificate (optionally with chain)")) + "TLS client certificate (optionally with chain)", + vpm)) /* need opt_tls_keypass if opt_tls_cert is encrypted PKCS#12 file */ goto err; @@ -1418,7 +1264,8 @@ static SSL_CTX *setup_ssl_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) if (opt_tls_extra != NULL) { STACK_OF(X509) *tls_extra = load_certs_multifile(opt_tls_extra, opt_otherpass, - "extra certificates for TLS"); + "extra certificates for TLS", + vpm); int res = 1; if (tls_extra == NULL) @@ -1541,7 +1388,8 @@ static int setup_protection_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) int ok; if (!load_cert_certs(opt_cert, &cert, &certs, 0, opt_keypass, - "CMP client certificate (optionally with chain)")) + "CMP client certificate (optionally with chain)", + vpm)) /* opt_keypass is needed if opt_cert is an encrypted PKCS#12 file */ return 0; ok = OSSL_CMP_CTX_set1_cert(ctx, cert); diff --git a/apps/include/apps.h b/apps/include/apps.h index 8c365c44bd..416e1d2568 100644 --- a/apps/include/apps.h +++ b/apps/include/apps.h @@ -120,6 +120,15 @@ EVP_PKEY *load_pubkey(const char *uri, int format, int maybe_stdin, const char *pass, ENGINE *e, const char *desc); EVP_PKEY *load_keyparams(const char *uri, int maybe_stdin, const char *keytype, const char *desc); +char *next_item(char *opt); /* in list separated by comma and/or space */ +int load_cert_certs(const char *uri, + X509 **pcert, STACK_OF(X509) **pcerts, + int exclude_http, const char *pass, const char *desc, + X509_VERIFY_PARAM *vpm); +STACK_OF(X509) *load_certs_multifile(char *files, const char *pass, + const char *desc, X509_VERIFY_PARAM *vpm); +X509_STORE *load_certstore(char *input, const char *pass, const char *desc, + X509_VERIFY_PARAM *vpm); int load_certs(const char *uri, STACK_OF(X509) **certs, const char *pass, const char *desc); int load_crls(const char *uri, STACK_OF(X509_CRL) **crls, diff --git a/apps/lib/apps.c b/apps/lib/apps.c index 2938e91620..f114f0b10c 100644 --- a/apps/lib/apps.c +++ b/apps/lib/apps.c @@ -638,6 +638,164 @@ void* app_malloc(int sz, const char *what) return vp; } +char *next_item(char *opt) /* in list separated by comma and/or space */ +{ + /* advance to separator (comma or whitespace), if any */ + while (*opt != ',' && !isspace(*opt) && *opt != '\0') { + if (*opt == '\\' && opt[1] != '\0') + /* skip and unescape '\' escaped char */ + memmove(opt, opt + 1, strlen(opt)); + opt++; + } + if (*opt != '\0') { + /* terminate current item */ + *opt++ = '\0'; + /* skip over any whitespace after separator */ + while (isspace(*opt)) + opt++; + } + return *opt == '\0' ? NULL : opt; /* NULL indicates end of input */ +} + +static void warn_cert_msg(const char *uri, X509 *cert, const char *msg) +{ + char *subj = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); + + BIO_printf(bio_err, "Warning: certificate from '%s' with subject '%s' %s", + uri, subj, msg); + OPENSSL_free(subj); +} + +static void warn_cert(const char *uri, X509 *cert, int warn_EE, + X509_VERIFY_PARAM *vpm) +{ + uint32_t ex_flags = X509_get_extension_flags(cert); + int res = X509_cmp_timeframe(vpm, X509_get0_notBefore(cert), + X509_get0_notAfter(cert)); + + if (res != 0) + warn_cert_msg(uri, cert, res > 0 ? "has expired" : "not yet valid"); + if (warn_EE && (ex_flags & EXFLAG_V1) == 0 && (ex_flags & EXFLAG_CA) == 0) + warn_cert_msg(uri, cert, "is not a CA cert"); +} + +static void warn_certs(const char *uri, STACK_OF(X509) *certs, int warn_EE, + X509_VERIFY_PARAM *vpm) +{ + int i; + + for (i = 0; i < sk_X509_num(certs); i++) + warn_cert(uri, sk_X509_value(certs, i), warn_EE, vpm); +} + +int load_cert_certs(const char *uri, + X509 **pcert, STACK_OF(X509) **pcerts, + int exclude_http, const char *pass, const char *desc, + X509_VERIFY_PARAM *vpm) +{ + int ret = 0; + char *pass_string; + + if (exclude_http && (strncasecmp(uri, "http://", 7) == 0 + || strncasecmp(uri, "https://", 8) == 0)) { + BIO_printf(bio_err, "error: HTTP retrieval not allowed for %s\n", desc); + return ret; + } + pass_string = get_passwd(pass, desc); + ret = load_key_certs_crls(uri, 0, pass_string, desc, NULL, NULL, NULL, + pcert, pcerts, NULL, NULL); + clear_free(pass_string); + + if (ret) { + if (pcert != NULL) + warn_cert(uri, *pcert, 0, vpm); + warn_certs(uri, *pcerts, 1, vpm); + } else { + sk_X509_pop_free(*pcerts, X509_free); + *pcerts = NULL; + } + return ret; +} + +STACK_OF(X509) *load_certs_multifile(char *files, const char *pass, + const char *desc, X509_VERIFY_PARAM *vpm) +{ + STACK_OF(X509) *certs = NULL; + STACK_OF(X509) *result = sk_X509_new_null(); + + if (files == NULL) + goto err; + if (result == NULL) + goto oom; + + while (files != NULL) { + char *next = next_item(files); + + if (!load_cert_certs(files, NULL, &certs, 0, pass, desc, vpm)) + goto err; + if (!X509_add_certs(result, certs, + X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP)) + goto oom; + sk_X509_pop_free(certs, X509_free); + certs = NULL; + files = next; + } + return result; + + oom: + BIO_printf(bio_err, "out of memory\n"); + err: + sk_X509_pop_free(certs, X509_free); + sk_X509_pop_free(result, X509_free); + return NULL; +} + +static X509_STORE *sk_X509_to_store(X509_STORE *store /* may be NULL */, + const STACK_OF(X509) *certs /* may NULL */) +{ + int i; + + if (store == NULL) + store = X509_STORE_new(); + if (store == NULL) + return NULL; + for (i = 0; i < sk_X509_num(certs); i++) { + if (!X509_STORE_add_cert(store, sk_X509_value(certs, i))) { + X509_STORE_free(store); + return NULL; + } + } + return store; +} + +/* + * Create cert store structure with certificates read from given file(s). + * Returns pointer to created X509_STORE on success, NULL on error. + */ +X509_STORE *load_certstore(char *input, const char *pass, const char *desc, + X509_VERIFY_PARAM *vpm) +{ + X509_STORE *store = NULL; + STACK_OF(X509) *certs = NULL; + + while (input != NULL) { + char *next = next_item(input); + int ok; + + if (!load_cert_certs(input, NULL, &certs, 1, pass, desc, vpm)) { + X509_STORE_free(store); + return NULL; + } + ok = (store = sk_X509_to_store(store, certs)) != NULL; + sk_X509_pop_free(certs, X509_free); + certs = NULL; + if (!ok) + return NULL; + input = next; + } + return store; +} + /* * Initialize or extend, if *certs != NULL, a certificate stack. * The caller is responsible for freeing *certs if its value is left not NULL. @@ -65,12 +65,12 @@ static int verify_command(const char *data, const char *digest, const char *quer const char *in, int token_in, const char *CApath, const char *CAfile, const char *CAstore, - const char *untrusted, X509_VERIFY_PARAM *vpm); + char *untrusted, X509_VERIFY_PARAM *vpm); static TS_VERIFY_CTX *create_verify_ctx(const char *data, const char *digest, const char *queryfile, const char *CApath, const char *CAfile, const char *CAstore, - const char *untrusted, + char *untrusted, X509_VERIFY_PARAM *vpm); static X509_STORE *create_cert_store(const char *CApath, const char *CAfile, const char *CAstore, X509_VERIFY_PARAM *vpm); @@ -100,7 +100,7 @@ const OPTIONS ts_options[] = { {"CAfile", OPT_CAFILE, '<', "File with trusted CA certs"}, {"CApath", OPT_CAPATH, '/', "Path to trusted CA files"}, {"CAstore", OPT_CASTORE, ':', "URI to trusted CA store"}, - {"untrusted", OPT_UNTRUSTED, '<', "File with untrusted certs"}, + {"untrusted", OPT_UNTRUSTED, '<', "Extra untrusted certs"}, {"token_in", OPT_TOKEN_IN, '-', "Input is a PKCS#7 file"}, {"token_out", OPT_TOKEN_OUT, '-', "Output is a PKCS#7 file"}, {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, @@ -149,16 +149,17 @@ static char* opt_helplist[] = { " [-text]", #endif "", - " openssl ts -verify -CApath dir -CAfile file.pem -CAstore uri", - " -untrusted file.pem [-data file] [-digest hexstring]", - " [-queryfile file] -in file [-token_in] ...", + " openssl ts -verify -CApath dir -CAfile root-cert.pem -CAstore uri", + " -untrusted extra-certs.pem [-data file] [-digest hexstring]", + " [-queryfile request.tsq] -in response.tsr [-token_in] ...", NULL, }; int ts_main(int argc, char **argv) { CONF *conf = NULL; - const char *CAfile = NULL, *untrusted = NULL, *prog; + const char *CAfile = NULL, *prog; + char *untrusted = NULL; const char *configfile = default_config_file, *engine = NULL; const char *section = NULL, *digestname = NULL; char **helpp; @@ -842,7 +843,7 @@ static int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial) static int verify_command(const char *data, const char *digest, const char *queryfile, const char *in, int token_in, const char *CApath, const char *CAfile, - const char *CAstore, const char *untrusted, + const char *CAstore, char *untrusted, X509_VERIFY_PARAM *vpm) { BIO *in_bio = NULL; @@ -890,10 +891,11 @@ static TS_VERIFY_CTX *create_verify_ctx(const char *data, const char *digest, const char *queryfile, const char *CApath, const char *CAfile, const char *CAstore, - const char *untrusted, + char *untrusted, X509_VERIFY_PARAM *vpm) { TS_VERIFY_CTX *ctx = NULL; + STACK_OF(X509) *certs; BIO *input = NULL; TS_REQ *request = NULL; int ret = 0; @@ -943,10 +945,13 @@ static TS_VERIFY_CTX *create_verify_ctx(const char *data, const char *digest, == NULL) goto err; - /* Loading untrusted certificates. */ - if (untrusted - && TS_VERIFY_CTX_set_certs(ctx, TS_CONF_load_certs(untrusted)) == NULL) - goto err; + /* Loading any extra untrusted certificates. */ + if (untrusted != NULL) { + certs = load_certs_multifile(untrusted, NULL, "extra untrusted certs", + vpm); + if (certs == NULL || TS_VERIFY_CTX_set_certs(ctx, certs) == NULL) + goto err; + } ret = 1; err: diff --git a/doc/man1/openssl-ts.pod.in b/doc/man1/openssl-ts.pod.in index 56670752f1..402a7a879a 100644 --- a/doc/man1/openssl-ts.pod.in +++ b/doc/man1/openssl-ts.pod.in @@ -50,7 +50,7 @@ B<-verify> [B<-queryfile> I<request.tsq>] [B<-in> I<response.tsr>] [B<-token_in>] -[B<-untrusted> I<file>] +[B<-untrusted> I<files>|I<uris>] [B<-CAfile> I<file>] [B<-CApath> I<dir>] [B<-CAstore> I<uri>] @@ -326,7 +326,7 @@ This flag can be used together with the B<-in> option and indicates that the input is a DER encoded timestamp token (ContentInfo) instead of a timestamp response (TimeStampResp). (Optional) -=item B<-untrusted> I<file> +=item B<-untrusted> I<files>|I<uris> A set of additional untrusted certificates which may be needed when building the certificate chain for the TSA's signing certificate. @@ -334,6 +334,9 @@ These do not need to contain the TSA signing certificate and intermediate CA certificates as far as the response already includes them. (Optional) +Multiple sources may be given, separated by commas and/or whitespace. +Each file may contain multiple certificates. + =item B<-CAfile> I<file>, B<-CApath> I<dir>, B<-CAstore> I<uri> See L<openssl-verification-options(1)/Trusted Certificate Options> for details. |