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)
This commit is contained in:
Dr. David von Oheimb 2021-03-10 17:27:13 +01:00 committed by Dr. David von Oheimb
parent c89fd035d5
commit f62846b703
5 changed files with 201 additions and 178 deletions

View File

@ -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);

View File

@ -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,

View File

@ -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.

View File

@ -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:

View File

@ -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.