From: Kevin McCarthy Date: Sun, 12 Feb 2017 17:59:41 +0000 (-0800) Subject: Filter expired local certs for OpenSSL verification. X-Git-Tag: neomutt-20170225~2^2~19 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0cdf2defe99913471e07625704de8376f7efb72e;p=neomutt Filter expired local certs for OpenSSL verification. OpenSSL has trouble establishing the chain and verifying when duplicate expired certs are loaded in from $certificate_file. A warning about this is mentioned in SSL_CTX_load_verify_locations(3SSL). Filter out expired certs when loading verify certs. Note that the full certicates file is still used for verification in check_certificate_by_digest(). --- diff --git a/mutt_ssl.c b/mutt_ssl.c index 0deca6626..17ba746ca 100644 --- a/mutt_ssl.c +++ b/mutt_ssl.c @@ -86,6 +86,47 @@ static void ssl_get_client_cert(sslsockdata *ssldata, CONNECTION *conn); static int ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata); static int ssl_negotiate (CONNECTION *conn, sslsockdata*); +/* ssl certificate verification can behave strangely if there are expired + * certs loaded into the trusted store. This function filters out expired + * certs. + * Previously the code used this form: + * SSL_CTX_load_verify_locations (ssldata->ctx, SslCertFile, NULL); + */ +static int ssl_load_certificates (SSL_CTX *ctx) +{ + FILE *fp; + X509 *cert; + X509_STORE *store; + char buf[STRING]; + + dprint (2, (debugfile, "ssl_load_certificates: loading trusted certificates\n")); + store = SSL_CTX_get_cert_store (ctx); + if (!store) + { + store = X509_STORE_new (); + SSL_CTX_set_cert_store (ctx, store); + } + + if ((fp = fopen (SslCertFile, "rt")) == NULL) + return 0; + + while ((cert = PEM_read_X509 (fp, NULL, NULL, NULL)) != NULL) + { + if ((X509_cmp_current_time (X509_get_notBefore (cert)) >= 0) || + (X509_cmp_current_time (X509_get_notAfter (cert)) <= 0)) + { + dprint (2, (debugfile, "ssl_load_certificates: filtering expired cert: %s\n", + X509_NAME_oneline (X509_get_subject_name (cert), buf, sizeof (buf)))); + X509_free (cert); + } + else + X509_STORE_add_cert (store, cert); + } + safe_fclose (&fp); + + return 1; +} + /* mutt_ssl_starttls: Negotiate TLS over an already opened connection. * TODO: Merge this code better with ssl_socket_open. */ int mutt_ssl_starttls (CONNECTION* conn) @@ -144,7 +185,7 @@ int mutt_ssl_starttls (CONNECTION* conn) } } - if (SslCertFile && ! SSL_CTX_load_verify_locations (ssldata->ctx, SslCertFile, NULL)) + if (SslCertFile && !ssl_load_certificates (ssldata->ctx)) dprint (1, (debugfile, "mutt_ssl_starttls: Error loading trusted certificates\n")); ssl_get_client_cert(ssldata, conn); @@ -394,7 +435,7 @@ static int ssl_socket_open (CONNECTION * conn) } } - if (SslCertFile && ! SSL_CTX_load_verify_locations (data->ctx, SslCertFile, NULL)) + if (SslCertFile && !ssl_load_certificates (data->ctx)) dprint (1, (debugfile, "ssl_socket_open: Error loading trusted certificates\n")); ssl_get_client_cert(data, conn); @@ -704,7 +745,7 @@ static int check_certificate_by_digest (X509 *peercert) } if (X509_cmp_current_time (X509_get_notAfter (peercert)) <= 0) { - dprint (2, (debugfile, "Server certificate has expired")); + dprint (2, (debugfile, "Server certificate has expired\n")); mutt_error (_("Server certificate has expired")); mutt_sleep (2); return 0;