From 2ddfa293492766c0ffe64df97ce2a1344ed97f2e Mon Sep 17 00:00:00 2001 From: Brendan Cully Date: Mon, 1 Aug 2005 07:35:04 +0000 Subject: [PATCH] Cache SSL certificates that have been accepted but not saved until mutt exits. (closes #643). Create mutt_add_list_n for adding non-character data to lists, have mutt_add_list call it. --- globals.h | 1 + mutt.h | 1 + mutt_ssl.c | 85 ++++++++++++++++++++++++++++++++++++++++++------------ muttlib.c | 15 ++++++++-- 4 files changed, 80 insertions(+), 22 deletions(-) diff --git a/globals.h b/globals.h index f046ecdb6..00cfea5aa 100644 --- a/globals.h +++ b/globals.h @@ -115,6 +115,7 @@ WHERE char *SslCertFile INITVAL (NULL); #endif #ifdef USE_SSL WHERE char *SslClientCert INITVAL (NULL); +WHERE LIST *SslSessionCerts INITVAL (NULL); #endif #if defined(USE_SSL) || defined(USE_NSS) WHERE char *SslEntropyFile INITVAL (NULL); diff --git a/mutt.h b/mutt.h index e8fe0989b..ec2a4fa63 100644 --- a/mutt.h +++ b/mutt.h @@ -558,6 +558,7 @@ int mutt_matches_ignore (const char *, LIST *); /* add an element to a list */ LIST *mutt_add_list (LIST *, const char *); +LIST *mutt_add_list_n (LIST*, const void *, size_t); void mutt_init (int, LIST *); diff --git a/mutt_ssl.c b/mutt_ssl.c index bc9a523dc..52b02065f 100644 --- a/mutt_ssl.c +++ b/mutt_ssl.c @@ -359,7 +359,11 @@ static int ssl_socket_close (CONNECTION * conn) { SSL_shutdown (data->ssl); + /* hold onto this for the life of mutt, in case we want to reconnect. + * The purist in me wants a mutt_exit hook. */ +#if 0 X509_free (data->cert); +#endif SSL_free (data->ssl); SSL_CTX_free (data->ctx); FREE (&conn->sockdata); @@ -491,6 +495,52 @@ static int check_certificate_by_signer (X509 *peercert) return pass; } +static int compare_certificates (X509 *cert, X509 *peercert, + unsigned char *peermd, unsigned int peermdlen) +{ + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int mdlen; + + /* Avoid CPU-intensive digest calculation if the certificates are + * not even remotely equal. + */ + if (X509_subject_name_cmp (cert, peercert) != 0 || + X509_issuer_name_cmp (cert, peercert) != 0) + return -1; + + if (!X509_digest (cert, EVP_sha1(), md, &mdlen) || peermdlen != mdlen) + return -1; + + if (memcmp(peermd, md, mdlen) != 0) + return -1; + + return 0; +} + +static int check_certificate_cache (X509 *peercert) +{ + unsigned char peermd[EVP_MAX_MD_SIZE]; + unsigned int peermdlen; + X509 *cert; + LIST *scert; + + if (!X509_digest (peercert, EVP_sha1(), peermd, &peermdlen)) + { + return 0; + } + + for (scert = SslSessionCerts; scert; scert = scert->next) + { + cert = *(X509**)scert->data; + if (!compare_certificates (cert, peercert, peermd, peermdlen)) + { + return 1; + } + } + + return 0; +} + static int check_certificate_by_digest (X509 *peercert) { unsigned char peermd[EVP_MAX_MD_SIZE]; @@ -523,29 +573,15 @@ static int check_certificate_by_digest (X509 *peercert) fclose (fp); return 0; } - + while ((cert = READ_X509_KEY (fp, &cert)) != NULL) { - unsigned char md[EVP_MAX_MD_SIZE]; - unsigned int mdlen; - - /* Avoid CPU-intensive digest calculation if the certificates are - * not even remotely equal. - */ - if (X509_subject_name_cmp (cert, peercert) != 0 || - X509_issuer_name_cmp (cert, peercert) != 0) - continue; - - if (!X509_digest (cert, EVP_sha1(), md, &mdlen) || peermdlen != mdlen) - continue; + pass = compare_certificates (cert, peercert, peermd, peermdlen) ? 0 : 1; + X509_free (cert); - if (memcmp(peermd, md, mdlen) != 0) - continue; - - pass = 1; - break; + if (pass) + break; } - X509_free (cert); fclose (fp); return pass; @@ -562,6 +598,13 @@ static int ssl_check_certificate (sslsockdata * data) FILE *fp; char *name = NULL, *c; + /* check session cache first */ + if (check_certificate_cache (data->cert)) + { + dprint (1, (debugfile, "ssl_check_certificate: using cached certificate\n")); + return 1; + } + if (check_certificate_by_signer (data->cert)) { dprint (1, (debugfile, "ssl_check_certificate: signer check passed\n")); @@ -668,6 +711,10 @@ static int ssl_check_certificate (sslsockdata * data) /* fall through */ case OP_MAX + 2: /* accept once */ done = 2; + /* keep a handle on accepted certificates in case we want to + * open up another connection to the same server in this session */ + SslSessionCerts = mutt_add_list_n (SslSessionCerts, &data->cert, + sizeof (X509 **)); break; } } diff --git a/muttlib.c b/muttlib.c index 2a87349c1..2f28dd786 100644 --- a/muttlib.c +++ b/muttlib.c @@ -228,8 +228,15 @@ void mutt_free_parameter (PARAMETER **p) LIST *mutt_add_list (LIST *head, const char *data) { - LIST *tmp; + size_t len = mutt_strlen (data); + + return mutt_add_list_n (head, data, len ? len + 1 : 0); +} +LIST *mutt_add_list_n (LIST *head, const void *data, size_t len) +{ + LIST *tmp; + for (tmp = head; tmp && tmp->next; tmp = tmp->next) ; if (tmp) @@ -239,8 +246,10 @@ LIST *mutt_add_list (LIST *head, const char *data) } else head = tmp = safe_malloc (sizeof (LIST)); - - tmp->data = safe_strdup (data); + + tmp->data = safe_malloc (len); + if (len) + memcpy (tmp->data, data, len); tmp->next = NULL; return head; } -- 2.40.0