]> granicus.if.org Git - neomutt/commitdiff
Cache SSL certificates that have been accepted but not saved until mutt
authorBrendan Cully <brendan@kublai.com>
Mon, 1 Aug 2005 07:35:04 +0000 (07:35 +0000)
committerBrendan Cully <brendan@kublai.com>
Mon, 1 Aug 2005 07:35:04 +0000 (07:35 +0000)
exits. (closes #643).
Create mutt_add_list_n for adding non-character data to lists, have
mutt_add_list call it.

globals.h
mutt.h
mutt_ssl.c
muttlib.c

index f046ecdb6935ba6f430d4bae4f4f1c7db02e62bb..00cfea5aa6735638ae41767eca24a76cbc42ccaf 100644 (file)
--- 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 e8fe0989b4bfcb52897737f3fa5a276122a915b4..ec2a4fa63b7050f6798304bf78363b4d7f0a82a1 100644 (file)
--- 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 *);
 
index bc9a523dc800a3e946acf1a983c462a5b2213091..52b02065f3c11cfbcb52eabafc3319281dc82f79 100644 (file)
@@ -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;
     }
   }
index 2a87349c11e660d8b32f740a51c23760ddade505..2f28dd7863b5651ea213a4d53579c7ccc84583a0 100644 (file)
--- 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;
 }