diff options
author | Dr. David von Oheimb <David.von.Oheimb@siemens.com> | 2020-02-15 14:57:32 +0100 |
---|---|---|
committer | Dr. David von Oheimb <David.von.Oheimb@siemens.com> | 2020-02-17 07:43:58 +0100 |
commit | 31b28ad96aa841ae39d4009ebb15d90f2a2afdab (patch) | |
tree | 1c35d270dec05defdb07028911a67dbba82fe65c /crypto/x509 | |
parent | 235595c402bd7815f07f1f3f3babe9fcc247a206 (diff) |
chunk 7 of CMP contribution to OpenSSL
add CMP message validation and related tests; while doing so:
* add ERR_add_error_mem_bio() to crypto/err/err_prn.c
* move ossl_cmp_add_error_txt() as ERR_add_error_txt() to crypto/err/err_prn.c
* add X509_STORE_CTX_print_verify_cb() to crypto/x509/t_x509.c,
adding internally x509_print_ex_brief(), print_certs(), and print_store_certs()
* move {ossl_cmp_,}X509_STORE_get1_certs() to crypto/x509/x509_lu.c
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Bernd Edlinger <bernd.edlinger@hotmail.de>
(Merged from https://github.com/openssl/openssl/pull/10620)
Diffstat (limited to 'crypto/x509')
-rw-r--r-- | crypto/x509/t_x509.c | 105 | ||||
-rw-r--r-- | crypto/x509/x509_err.c | 2 | ||||
-rw-r--r-- | crypto/x509/x509_lu.c | 35 |
3 files changed, 142 insertions, 0 deletions
diff --git a/crypto/x509/t_x509.c b/crypto/x509/t_x509.c index 4969bb34bf..eac299c09a 100644 --- a/crypto/x509/t_x509.c +++ b/crypto/x509/t_x509.c @@ -15,6 +15,7 @@ #include <openssl/x509.h> #include <openssl/x509v3.h> #include "crypto/asn1.h" +#include "crypto/x509.h" #ifndef OPENSSL_NO_STDIO int X509_print_fp(FILE *fp, X509 *x) @@ -380,3 +381,107 @@ int X509_aux_print(BIO *out, X509 *x, int indent) } return 1; } + +/* + * Helper functions for improving certificate verification error diagnostics + */ + +int x509_print_ex_brief(BIO *bio, X509 *cert, unsigned long neg_cflags) +{ + unsigned long flags = ASN1_STRFLGS_RFC2253 | ASN1_STRFLGS_ESC_QUOTE | + XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_FN_SN; + + if (cert == NULL) + return BIO_printf(bio, " (no certificate)\n") > 0; + if (BIO_printf(bio, " certificate\n") <= 0 + || !X509_print_ex(bio, cert, flags, ~X509_FLAG_NO_SUBJECT)) + return 0; + if (X509_check_issued((X509 *)cert, cert) == X509_V_OK) { + if (BIO_printf(bio, " self-issued\n") <= 0) + return 0; + } else { + if (BIO_printf(bio, " ") <= 0 + || !X509_print_ex(bio, cert, flags, ~X509_FLAG_NO_ISSUER)) + return 0; + } + if (!X509_print_ex(bio, cert, flags, + ~(X509_FLAG_NO_SERIAL | X509_FLAG_NO_VALIDITY))) + return 0; + if (X509_cmp_current_time(X509_get0_notBefore(cert)) > 0) + if (BIO_printf(bio, " not yet valid\n") <= 0) + return 0; + if (X509_cmp_current_time(X509_get0_notAfter(cert)) < 0) + if (BIO_printf(bio, " no more valid\n") <= 0) + return 0; + return X509_print_ex(bio, cert, flags, ~(neg_cflags)); +} + +static int print_certs(BIO *bio, const STACK_OF(X509) *certs) +{ + int i; + + if (certs == NULL || sk_X509_num(certs) <= 0) + return BIO_printf(bio, " (no certificates)\n") >= 0; + + for (i = 0; i < sk_X509_num(certs); i++) { + X509 *cert = sk_X509_value(certs, i); + if (cert != NULL && !x509_print_ex_brief(bio, cert, 0)) + return 0; + } + return 1; +} + +static int print_store_certs(BIO *bio, X509_STORE *store) +{ + if (store != NULL) { + STACK_OF(X509) *certs = X509_STORE_get1_all_certs(store); + int ret = print_certs(bio, certs); + + sk_X509_pop_free(certs, X509_free); + return ret; + } else { + return BIO_printf(bio, " (no trusted store)\n") >= 0; + } +} + +/* Extend the error queue with details on a failed cert verification */ +int X509_STORE_CTX_print_verify_cb(int ok, X509_STORE_CTX *ctx) +{ + if (ok == 0 && ctx != NULL) { + int cert_error = X509_STORE_CTX_get_error(ctx); + int depth = X509_STORE_CTX_get_error_depth(ctx); + X509 *cert = X509_STORE_CTX_get_current_cert(ctx); + BIO *bio = BIO_new(BIO_s_mem()); /* may be NULL */ + + BIO_printf(bio, "%s at depth=%d error=%d (%s)\n", + X509_STORE_CTX_get0_parent_ctx(ctx) != NULL + ? "CRL path validation" : "certificate verification", + depth, cert_error, + X509_verify_cert_error_string(cert_error)); + BIO_printf(bio, "failure for:\n"); + x509_print_ex_brief(bio, cert, X509_FLAG_NO_EXTENSIONS); + if (cert_error == X509_V_ERR_CERT_UNTRUSTED + || cert_error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT + || cert_error == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN + || cert_error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT + || cert_error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY + || cert_error == X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER + || cert_error == X509_V_ERR_STORE_LOOKUP) { + BIO_printf(bio, "non-trusted certs:\n"); + print_certs(bio, X509_STORE_CTX_get0_untrusted(ctx)); + BIO_printf(bio, "certs in trust store:\n"); + print_store_certs(bio, X509_STORE_CTX_get0_store(ctx)); + } + CMPerr(0, X509_R_CERTIFICATE_VERIFICATION_FAILED); + ERR_add_error_mem_bio("\n", bio); + BIO_free(bio); + } + + /* + * TODO we could check policies here too, e.g.: + * if (cert_error == X509_V_OK && ok == 2) + * policies_print(NULL, ctx); + */ + + return ok; +} diff --git a/crypto/x509/x509_err.c b/crypto/x509/x509_err.c index 1b01fd0131..59ffbee6d8 100644 --- a/crypto/x509/x509_err.c +++ b/crypto/x509/x509_err.c @@ -22,6 +22,8 @@ static const ERR_STRING_DATA X509_str_reasons[] = { {ERR_PACK(ERR_LIB_X509, 0, X509_R_CANT_CHECK_DH_KEY), "cant check dh key"}, {ERR_PACK(ERR_LIB_X509, 0, X509_R_CERT_ALREADY_IN_HASH_TABLE), "cert already in hash table"}, + {ERR_PACK(ERR_LIB_X509, 0, X509_R_CERTIFICATE_VERIFICATION_FAILED), + "certificate verification failed"}, {ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_ALREADY_DELTA), "crl already delta"}, {ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_VERIFY_FAILURE), "crl verify failure"}, diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c index 016b4b304f..9018d6e114 100644 --- a/crypto/x509/x509_lu.c +++ b/crypto/x509/x509_lu.c @@ -532,6 +532,41 @@ STACK_OF(X509_OBJECT) *X509_STORE_get0_objects(X509_STORE *v) return v->objs; } +STACK_OF(X509) *X509_STORE_get1_all_certs(X509_STORE *store) +{ + STACK_OF(X509) *sk; + STACK_OF(X509_OBJECT) *objs; + int i; + + if (store == NULL) { + X509err(0, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + if ((sk = sk_X509_new_null()) == NULL) + return NULL; + X509_STORE_lock(store); + objs = X509_STORE_get0_objects(store); + for (i = 0; i < sk_X509_OBJECT_num(objs); i++) { + X509 *cert = X509_OBJECT_get0_X509(sk_X509_OBJECT_value(objs, i)); + + if (cert != NULL) { + if (!X509_up_ref(cert)) + goto err; + if (!sk_X509_push(sk, cert)) { + X509_free(cert); + goto err; + } + } + } + X509_STORE_unlock(store); + return sk; + + err: + X509_STORE_unlock(store); + sk_X509_pop_free(sk, X509_free); + return NULL; +} + STACK_OF(X509) *X509_STORE_CTX_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm) { int i, idx, cnt; |