Subject: bug#19404: 25.0.50; Gnus shows self-signed certificate warning when connecting to Gmane

From: Ted Zlatanov <[email-masked]>
Date: Wed, 24 Dec 2014 08:11:34 -0500

On Sat, 20 Dec 2014 22:44:54 +0100 Lars Ingebrigtsen <[email-masked]> wrote: 

LI> Ted Zlatanov <[email-masked]> writes:
>> If I understand correctly, it seems 1) the :self-signed message and
>> symbol need to be changed, and 2) we're waiting for the GnuTLS
>> developers to tell us the best way to detect a self-signed certificate.
>> 
>> For (1) I propose using :unknown-ca and "the certificate was signed by
>> an unknown and therefore untrusted authority"

LI> Sounds good.

On Sun, 21 Dec 2014 18:16:35 +0100 David Engster <[email-masked]> wrote: 

DE> Nick answered, and it's really simple: call gnutls_x509_crt_check_issuer
DE> on the certificate itself (meaning: provide the certificate in question
DE> for both arguments).

Please try the attached patch. I'm not able to test it myself because
I'm traveling, but it should be fairly trivial and addresses both
issues. Feel free to commit it with any changes you want, it's a tiny
change.

gnutls_x509_crt_check_issuer() has been in GnuTLS for all the versions
we support, so there was no need for a version check.

(there was a third issue, the expiration date was wrong, but that's not
as urgent)

Ted

diff --git a/src/gnutls.c b/src/gnutls.c
index bf9f132..500dbf3 100644
--- a/src/gnutls.c
+++ b/src/gnutls.c
@@ -154,6 +154,8 @@ enum extra_peer_verification
 	       (gnutls_session_t, gnutls_push_func));
 DEF_GNUTLS_FN (int, gnutls_x509_crt_check_hostname,
 	       (gnutls_x509_crt_t, const char *));
+DEF_GNUTLS_FN (int, gnutls_x509_crt_check_issuer,
+	       (gnutls_x509_crt_t, gnutls_x509_crt_t));
 DEF_GNUTLS_FN (void, gnutls_x509_crt_deinit, (gnutls_x509_crt_t));
 DEF_GNUTLS_FN (int, gnutls_x509_crt_import,
 	       (gnutls_x509_crt_t, const gnutls_datum_t *,
@@ -269,6 +271,7 @@ enum extra_peer_verification
   LOAD_GNUTLS_FN (library, gnutls_transport_set_pull_function);
   LOAD_GNUTLS_FN (library, gnutls_transport_set_push_function);
   LOAD_GNUTLS_FN (library, gnutls_x509_crt_check_hostname);
+  LOAD_GNUTLS_FN (library, gnutls_x509_crt_check_issuer);
   LOAD_GNUTLS_FN (library, gnutls_x509_crt_deinit);
   LOAD_GNUTLS_FN (library, gnutls_x509_crt_import);
   LOAD_GNUTLS_FN (library, gnutls_x509_crt_init);
@@ -365,6 +368,7 @@ enum extra_peer_verification
 #define fn_gnutls_strerror			gnutls_strerror
 #define fn_gnutls_transport_set_ptr2		gnutls_transport_set_ptr2
 #define fn_gnutls_x509_crt_check_hostname	gnutls_x509_crt_check_hostname
+#define fn_gnutls_x509_crt_check_issuer         gnutls_x509_crt_check_issuer
 #define fn_gnutls_x509_crt_deinit		gnutls_x509_crt_deinit
 #define fn_gnutls_x509_crt_get_activation_time  gnutls_x509_crt_get_activation_time
 #define fn_gnutls_x509_crt_get_dn               gnutls_x509_crt_get_dn
@@ -985,6 +989,10 @@ enum extra_peer_verification
   if (EQ (status_symbol, intern (":self-signed")))
     return build_string ("certificate signer was not found (self-signed)");
 
+  if (EQ (status_symbol, intern (":unknown-ca")))
+    return build_string ("the certificate was signed by an unknown "
+                         "and therefore untrusted authority");
+
   if (EQ (status_symbol, intern (":not-ca")))
     return build_string ("certificate signer is not a CA");
 
@@ -1029,7 +1037,7 @@ enum extra_peer_verification
     warnings = Fcons (intern (":revoked"), warnings);
 
   if (verification & GNUTLS_CERT_SIGNER_NOT_FOUND)
-    warnings = Fcons (intern (":self-signed"), warnings);
+    warnings = Fcons (intern (":unknown-ca"), warnings);
 
   if (verification & GNUTLS_CERT_SIGNER_NOT_CA)
     warnings = Fcons (intern (":not-ca"), warnings);
@@ -1047,6 +1055,13 @@ enum extra_peer_verification
       CERTIFICATE_NOT_MATCHING)
     warnings = Fcons (intern (":no-host-match"), warnings);
 
+  /* This could get called in the INIT stage, when the certificate is
+     not yet set. */
+  if (XPROCESS (proc)->gnutls_certificate != NULL &&
+      gnutls_x509_crt_check_issuer(XPROCESS (proc)->gnutls_certificate,
+                                   XPROCESS (proc)->gnutls_certificate))
+    warnings = Fcons (intern (":self-signed"), warnings);
+
   if (!NILP (warnings))
     result = list2 (intern (":warnings"), warnings);