Blame SOURCES/emacs-0012-New-verify-error-GnuTLS-interface-for-certificate-va.patch

adfca8
From 59fd52bfdd7e4a763b5d950ee2213b3bb1e69916 Mon Sep 17 00:00:00 2001
adfca8
From: Jan Synacek <jsynacek@redhat.com>
adfca8
Date: Tue, 11 Sep 2018 13:03:56 +0200
adfca8
Subject: [PATCH 1/2] New verify-error GnuTLS interface for certificate
adfca8
 validation
adfca8
adfca8
* net/gnutls.el (gnutls-verify-error): New defcustom to control
adfca8
the behavior when a certificate fails validation.  Defaults to
adfca8
old behavior: never abort, just warn.
adfca8
(gnutls-negotiate): Use it.
adfca8
adfca8
* gnutls.c: Replace `:verify_hostname_error' with `:verify_error',
adfca8
now a list of certificate validation checks that will abort a
adfca8
connection with an error.
adfca8
(Fgnutls_boot): Document it and use it.
adfca8
adfca8
(cherry-picked from commit 31b4827ea9ba8d22deb17c0593f0f555a33e1fa4)
adfca8
adfca8
jsynacek: gnutls-verify-error defaults to t in RHEL-7.
adfca8
adfca8
Resolves: #1403643
adfca8
---
adfca8
 lisp/net/gnutls.el  |  67 ++++++++++++++++++++++++++++++++++++++++------------
adfca8
 src/bootstrap-emacs | Bin 25556936 -> 0 bytes
adfca8
 src/emacs           | Bin 25556936 -> 0 bytes
adfca8
 src/fns.c           |  22 ++++++++++++++++-
adfca8
 src/gnutls.c        |  48 +++++++++++++++++++++++--------------
adfca8
 src/temacs          | Bin 15992560 -> 0 bytes
adfca8
 6 files changed, 103 insertions(+), 34 deletions(-)
adfca8
 delete mode 100755 src/bootstrap-emacs
adfca8
 delete mode 100755 src/emacs
adfca8
 delete mode 100755 src/temacs
adfca8
adfca8
diff --git a/lisp/net/gnutls.el b/lisp/net/gnutls.el
adfca8
index 243c64e..2585f48 100644
adfca8
--- a/lisp/net/gnutls.el
adfca8
+++ b/lisp/net/gnutls.el
adfca8
@@ -51,6 +51,19 @@ set this variable to \"normal:-dhe-rsa\"."
adfca8
   :type '(choice (const nil)
adfca8
                  string))
adfca8
 
adfca8
+(defcustom gnutls-verify-error t
adfca8
+  "If non-nil, this should be a list of checks per hostname regex or t."
adfca8
+  :group 'gnutls
adfca8
+  :type '(choice
adfca8
+          (const t)
adfca8
+          (repeat :tag "List of hostname regexps with flags for each"
adfca8
+           (list
adfca8
+            (choice :tag "Hostname"
adfca8
+                    (const ".*" :tag "Any hostname")
adfca8
+                    regexp)
adfca8
+            (set (const :trustfiles)
adfca8
+                 (const :hostname))))))
adfca8
+
adfca8
 (defcustom gnutls-trustfiles
adfca8
   '(
adfca8
     "/etc/ssl/certs/ca-certificates.crt" ; Debian, Ubuntu, Gentoo and Arch Linux
adfca8
@@ -141,19 +154,25 @@ MIN-PRIME-BITS is the minimum acceptable size of Diffie-Hellman keys
adfca8
 \(see `gnutls-min-prime-bits' for more information).  Use nil for the
adfca8
 default.
adfca8
 
adfca8
-When VERIFY-HOSTNAME-ERROR is not nil, an error will be raised
adfca8
-when the hostname does not match the presented certificate's host
adfca8
-name.  The exact verification algorithm is a basic implementation
adfca8
-of the matching described in RFC2818 (HTTPS), which takes into
adfca8
-account wildcards, and the DNSName/IPAddress subject alternative
adfca8
-name PKIX extension.  See GnuTLS' gnutls_x509_crt_check_hostname
adfca8
-for details.  When VERIFY-HOSTNAME-ERROR is nil, only a warning
adfca8
-will be issued.
adfca8
+VERIFY-HOSTNAME-ERROR is a backwards compatibility option for
adfca8
+putting `:hostname' in VERIFY-ERROR.
adfca8
+
adfca8
+When VERIFY-ERROR is t or a list containing `:trustfiles', an
adfca8
+error will be raised when the peer certificate verification fails
adfca8
+as per GnuTLS' gnutls_certificate_verify_peers2.  Otherwise, only
adfca8
+warnings will be shown about the verification failure.
adfca8
 
adfca8
-When VERIFY-ERROR is not nil, an error will be raised when the
adfca8
-peer certificate verification fails as per GnuTLS'
adfca8
-gnutls_certificate_verify_peers2.  Otherwise, only warnings will
adfca8
-be shown about the verification failure.
adfca8
+When VERIFY-ERROR is t or a list containing `:hostname', an error
adfca8
+will be raised when the hostname does not match the presented
adfca8
+certificate's host name.  The exact verification algorithm is a
adfca8
+basic implementation of the matching described in
adfca8
+RFC2818 (HTTPS), which takes into account wildcards, and the
adfca8
+DNSName/IPAddress subject alternative name PKIX extension.  See
adfca8
+GnuTLS' gnutls_x509_crt_check_hostname for details.  Otherwise,
adfca8
+only a warning will be issued.
adfca8
+
adfca8
+Note that the list in `gnutls-verify-error', matched against the
adfca8
+HOSTNAME, is the default VERIFY-ERROR.
adfca8
 
adfca8
 VERIFY-FLAGS is a numeric OR of verification flags only for
adfca8
 `gnutls-x509pki' connections.  See GnuTLS' x509.h for details;
adfca8
@@ -186,8 +205,28 @@ defaults to GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT."
adfca8
                                 (if gnutls-algorithm-priority
adfca8
                                     (upcase gnutls-algorithm-priority)
adfca8
                                   "NORMAL")))))
adfca8
+         (verify-error (or verify-error
adfca8
+                           ;; this uses the value of `gnutls-verify-error'
adfca8
+                           (cond
adfca8
+                            ;; if t, pass it on
adfca8
+                            ((eq gnutls-verify-error t)
adfca8
+                             t)
adfca8
+                            ;; if a list, look for hostname matches
adfca8
+                            ((listp gnutls-verify-error)
adfca8
+                             (mapcan
adfca8
+                              (lambda (check)
adfca8
+                                (when (string-match (car check) hostname)
adfca8
+                                  (cdr check)))
adfca8
+                              gnutls-verify-error))
adfca8
+                            ;; else it's nil
adfca8
+                            (t nil))))
adfca8
          (min-prime-bits (or min-prime-bits gnutls-min-prime-bits))
adfca8
-         (params `(:priority ,priority-string
adfca8
+         params ret)
adfca8
+
adfca8
+    (when verify-hostname-error
adfca8
+      (push :hostname verify-error))
adfca8
+
adfca8
+    (setq params `(:priority ,priority-string
adfca8
                              :hostname ,hostname
adfca8
                              :loglevel ,gnutls-log-level
adfca8
                              :min-prime-bits ,min-prime-bits
adfca8
@@ -196,9 +235,7 @@ defaults to GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT."
adfca8
                              :keylist ,keylist
adfca8
                              :verify-flags ,verify-flags
adfca8
                              :verify-error ,verify-error
adfca8
-                             :verify-hostname-error ,verify-hostname-error
adfca8
                              :callbacks nil))
adfca8
-         ret)
adfca8
 
adfca8
     (gnutls-message-maybe
adfca8
      (setq ret (gnutls-boot process type params))
adfca8
diff --git a/src/fns.c b/src/fns.c
adfca8
index fbb3fb5..2a417ff 100644
adfca8
--- a/src/fns.c
adfca8
+++ b/src/fns.c
adfca8
@@ -2252,7 +2252,7 @@ usage: (nconc &rest LISTS)  */)
adfca8
  storing the results into elements of VALS, a C vector of Lisp_Objects.
adfca8
  LENI is the length of VALS, which should also be the length of SEQ.  */
adfca8
 
adfca8
-static void
adfca8
+static EMACS_INT
adfca8
 mapcar1 (EMACS_INT leni, Lisp_Object *vals, Lisp_Object fn, Lisp_Object seq)
adfca8
 {
adfca8
   register Lisp_Object tail;
adfca8
@@ -2326,6 +2326,7 @@ mapcar1 (EMACS_INT leni, Lisp_Object *vals, Lisp_Object fn, Lisp_Object seq)
adfca8
     }
adfca8
 
adfca8
   UNGCPRO;
adfca8
+  return leni;
adfca8
 }
adfca8
 
adfca8
 DEFUN ("mapconcat", Fmapconcat, Smapconcat, 3, 3, 0,
adfca8
@@ -2411,6 +2412,24 @@ SEQUENCE may be a list, a vector, a bool-vector, or a string.  */)
adfca8
 
adfca8
   return sequence;
adfca8
 }
adfca8
+
adfca8
+DEFUN ("mapcan", Fmapcan, Smapcan, 2, 2, 0,
adfca8
+       doc: /* Apply FUNCTION to each element of SEQUENCE, and concatenate
adfca8
+the results by altering them (using `nconc').
adfca8
+SEQUENCE may be a list, a vector, a bool-vector, or a string. */)
adfca8
+     (Lisp_Object function, Lisp_Object sequence)
adfca8
+{
adfca8
+  USE_SAFE_ALLOCA;
adfca8
+  EMACS_INT leni = XFASTINT (Flength (sequence));
adfca8
+  if (CHAR_TABLE_P (sequence))
adfca8
+    wrong_type_argument (Qlistp, sequence);
adfca8
+  Lisp_Object *args;
adfca8
+  SAFE_ALLOCA_LISP (args, leni);
adfca8
+  ptrdiff_t nmapped = mapcar1 (leni, args, function, sequence);
adfca8
+  Lisp_Object ret = Fnconc (nmapped, args);
adfca8
+  SAFE_FREE ();
adfca8
+  return ret;
adfca8
+}
adfca8
 
adfca8
 /* This is how C code calls `yes-or-no-p' and allows the user
adfca8
    to redefined it.
adfca8
@@ -4984,6 +5003,7 @@ this variable.  */);
adfca8
   defsubr (&Snconc);
adfca8
   defsubr (&Smapcar);
adfca8
   defsubr (&Smapc);
adfca8
+  defsubr (&Smapcan);
adfca8
   defsubr (&Smapconcat);
adfca8
   defsubr (&Syes_or_no_p);
adfca8
   defsubr (&Sload_average);
adfca8
diff --git a/src/gnutls.c b/src/gnutls.c
adfca8
index 57d9e17..0c4d10b 100644
adfca8
--- a/src/gnutls.c
adfca8
+++ b/src/gnutls.c
adfca8
@@ -49,7 +49,7 @@ static Lisp_Object QCgnutls_bootprop_loglevel;
adfca8
 static Lisp_Object QCgnutls_bootprop_hostname;
adfca8
 static Lisp_Object QCgnutls_bootprop_min_prime_bits;
adfca8
 static Lisp_Object QCgnutls_bootprop_verify_flags;
adfca8
-static Lisp_Object QCgnutls_bootprop_verify_hostname_error;
adfca8
+static Lisp_Object QCgnutls_bootprop_verify_error;
adfca8
 
adfca8
 /* Callback keys for `gnutls-boot'.  Unused currently.  */
adfca8
 static Lisp_Object QCgnutls_bootprop_callbacks_verify;
adfca8
@@ -729,8 +729,12 @@ certificates for `gnutls-x509pki'.
adfca8
 :verify-flags is a bitset as per GnuTLS'
adfca8
 gnutls_certificate_set_verify_flags.
adfca8
 
adfca8
-:verify-hostname-error, if non-nil, makes a hostname mismatch an
adfca8
-error.  Otherwise it will be just a warning.
adfca8
+:verify-hostname-error is ignored.  Pass :hostname in :verify-error
adfca8
+instead.
adfca8
+
adfca8
+:verify-error is a list of symbols to express verification checks or
adfca8
+`t' to do all checks.  Currently it can contain `:trustfiles' and
adfca8
+`:hostname' to verify the certificate or the hostname respectively.
adfca8
 
adfca8
 :min-prime-bits is the minimum accepted number of bits the client will
adfca8
 accept in Diffie-Hellman key exchange.
adfca8
@@ -774,8 +778,7 @@ one trustfile (usually a CA bundle).  */)
adfca8
   /* Lisp_Object callbacks; */
adfca8
   Lisp_Object loglevel;
adfca8
   Lisp_Object hostname;
adfca8
-  /* Lisp_Object verify_error; */
adfca8
-  Lisp_Object verify_hostname_error;
adfca8
+  Lisp_Object verify_error;
adfca8
   Lisp_Object prime_bits;
adfca8
 
adfca8
   CHECK_PROCESS (proc);
adfca8
@@ -800,11 +803,14 @@ one trustfile (usually a CA bundle).  */)
adfca8
   keylist               = Fplist_get (proplist, QCgnutls_bootprop_keylist);
adfca8
   crlfiles              = Fplist_get (proplist, QCgnutls_bootprop_crlfiles);
adfca8
   loglevel              = Fplist_get (proplist, QCgnutls_bootprop_loglevel);
adfca8
-  verify_hostname_error = Fplist_get (proplist, QCgnutls_bootprop_verify_hostname_error);
adfca8
+  verify_error          = Fplist_get (proplist, QCgnutls_bootprop_verify_error);
adfca8
   prime_bits            = Fplist_get (proplist, QCgnutls_bootprop_min_prime_bits);
adfca8
 
adfca8
+  if (!Flistp (verify_error))
adfca8
+    error ("gnutls-boot: invalid :verify_error parameter (not a list)");
adfca8
+
adfca8
   if (!STRINGP (hostname))
adfca8
-    error ("gnutls-boot: invalid :hostname parameter");
adfca8
+    error ("gnutls-boot: invalid :hostname parameter (not a string)");
adfca8
   c_hostname = SSDATA (hostname);
adfca8
 
adfca8
   state = XPROCESS (proc)->gnutls_state;
adfca8
@@ -1033,14 +1039,17 @@ one trustfile (usually a CA bundle).  */)
adfca8
 
adfca8
   if (peer_verification != 0)
adfca8
     {
adfca8
-      if (NILP (verify_hostname_error))
adfca8
-	GNUTLS_LOG2 (1, max_log_level, "certificate validation failed:",
adfca8
-		     c_hostname);
adfca8
-      else
adfca8
-	{
adfca8
+      if (EQ (verify_error, Qt)
adfca8
+          || !NILP (Fmember (QCgnutls_bootprop_trustfiles, verify_error)))
adfca8
+        {
adfca8
 	  emacs_gnutls_deinit (proc);
adfca8
 	  error ("Certificate validation failed %s, verification code %d",
adfca8
 		 c_hostname, peer_verification);
adfca8
+        }
adfca8
+      else
adfca8
+	{
adfca8
+          GNUTLS_LOG2 (1, max_log_level, "certificate validation failed:",
adfca8
+                       c_hostname);
adfca8
 	}
adfca8
     }
adfca8
 
adfca8
@@ -1080,14 +1089,17 @@ one trustfile (usually a CA bundle).  */)
adfca8
 
adfca8
       if (!fn_gnutls_x509_crt_check_hostname (gnutls_verify_cert, c_hostname))
adfca8
 	{
adfca8
-	  if (NILP (verify_hostname_error))
adfca8
-	    GNUTLS_LOG2 (1, max_log_level, "x509 certificate does not match:",
adfca8
-			 c_hostname);
adfca8
-	  else
adfca8
-	    {
adfca8
+          if (EQ (verify_error, Qt)
adfca8
+              || !NILP (Fmember (QCgnutls_bootprop_hostname, verify_error)))
adfca8
+            {
adfca8
 	      fn_gnutls_x509_crt_deinit (gnutls_verify_cert);
adfca8
 	      emacs_gnutls_deinit (proc);
adfca8
 	      error ("The x509 certificate does not match \"%s\"", c_hostname);
adfca8
+            }
adfca8
+	  else
adfca8
+	    {
adfca8
+              GNUTLS_LOG2 (1, max_log_level, "x509 certificate does not match:",
adfca8
+                           c_hostname);
adfca8
 	    }
adfca8
 	}
adfca8
       fn_gnutls_x509_crt_deinit (gnutls_verify_cert);
adfca8
@@ -1144,7 +1156,7 @@ syms_of_gnutls (void)
adfca8
   DEFSYM (QCgnutls_bootprop_min_prime_bits, ":min-prime-bits");
adfca8
   DEFSYM (QCgnutls_bootprop_loglevel, ":loglevel");
adfca8
   DEFSYM (QCgnutls_bootprop_verify_flags, ":verify-flags");
adfca8
-  DEFSYM (QCgnutls_bootprop_verify_hostname_error, ":verify-hostname-error");
adfca8
+  DEFSYM (QCgnutls_bootprop_verify_error, ":verify-error");
adfca8
 
adfca8
   DEFSYM (Qgnutls_e_interrupted, "gnutls-e-interrupted");
adfca8
   Fput (Qgnutls_e_interrupted, Qgnutls_code,
adfca8