From 3b172dd5f48297da85e31f5a01353e1e10ea1935 Mon Sep 17 00:00:00 2001 From: Kevin McCarthy Date: Thu, 9 Mar 2017 10:56:21 -0800 Subject: [PATCH] Prevent skipped certs from showing a second time. (see #3916) OpenSSL sometimes passes a skipped certificate to ssl_verify_callback() a second time, with preverify_ok=1. From OpenSSL's viewpoint there is nothing wrong with this, but mutt will end up showing the certificate in the interactive prompt again. Cache the last cert and position, and compare with the latest when skip_mode and preverify_ok are both set. --- mutt_ssl.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/mutt_ssl.c b/mutt_ssl.c index bec92489f..b12e7d515 100644 --- a/mutt_ssl.c +++ b/mutt_ssl.c @@ -1042,6 +1042,12 @@ static int ssl_verify_callback (int preverify_ok, X509_STORE_CTX *ctx) X509 *cert; SSL *ssl; int skip_mode; +#ifdef HAVE_SSL_PARTIAL_CHAIN + static int last_pos = 0; + static X509 *last_cert = NULL; + unsigned char last_cert_md[EVP_MAX_MD_SIZE]; + unsigned int last_cert_mdlen; +#endif if (! (ssl = X509_STORE_CTX_get_ex_data (ctx, SSL_get_ex_data_X509_STORE_CTX_idx ()))) { @@ -1070,6 +1076,30 @@ static int ssl_verify_callback (int preverify_ok, X509_STORE_CTX *ctx) X509_NAME_oneline (X509_get_subject_name (cert), buf, sizeof (buf)), preverify_ok, skip_mode); +#ifdef HAVE_SSL_PARTIAL_CHAIN + /* Sometimes, when a certificate is (s)kipped, OpenSSL will pass it + * a second time with preverify_ok = 1. Don't show it or the user + * will think their "s" key is broken. + */ + if (option (OPTSSLVERIFYPARTIAL)) + { + if (skip_mode && preverify_ok && (pos == last_pos) && last_cert) + { + if (X509_digest (last_cert, EVP_sha1(), last_cert_md, &last_cert_mdlen) && + !compare_certificates (cert, last_cert, last_cert_md, last_cert_mdlen)) + { + mutt_debug (2, "ssl_verify_callback: ignoring duplicate skipped certificate.\n"); + return 1; + } + } + + last_pos = pos; + if (last_cert) + X509_free (last_cert); + last_cert = X509_dup (cert); + } +#endif + /* check session cache first */ if (check_certificate_cache (cert)) { -- 2.40.0