]> granicus.if.org Git - neomutt/commitdiff
Prevent skipped certs from showing a second time. (see #3916)
authorKevin McCarthy <kevin@8t8.us>
Thu, 9 Mar 2017 18:56:21 +0000 (10:56 -0800)
committerKevin McCarthy <kevin@8t8.us>
Thu, 9 Mar 2017 18:56:21 +0000 (10:56 -0800)
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

index 2ca21dda36b05f93658c3ab561760e814c4129b8..bf7c9eb396f4afa95100ffb3344a0188832009d1 100644 (file)
@@ -1029,6 +1029,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 ())))
   {
@@ -1058,6 +1064,31 @@ 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))
+      {
+        dprint (2, (debugfile,
+                    "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))
   {