all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* ALPN support for GnuTLS connections
@ 2024-09-29  8:23 Eric Marsden
  2024-09-30  9:21 ` Robert Pluim
  0 siblings, 1 reply; 15+ messages in thread
From: Eric Marsden @ 2024-09-29  8:23 UTC (permalink / raw)
  To: emacs-devel

Hello,

The GnuTLS support in Emacs does not seem to support the TLS extension
Application Layer Protocol Negotiation (ALPN). ALPN is no longer just useful for
faster TLS handshakes (in HTTP/2, for example); it is mandatory in certain uses
of TLS.

The GnuTLS library does support ALPN (since 2013, it seems). My understanding is
that definitions for the two functions described here would need to be added to
gnutls.c:

   https://www.gnutls.org/manual/html_node/Application-Layer-Protocol-Negotiation-_0028ALPN_0029.html


Use case: the recent 17.0 release of PostgreSQL has added a "direct TLS"
connection mode which requires ALPN. Some hosted PostgreSQL providers only offer
direct TLS connections (I presume this allows them to use standard TLS
gateways). I would like to allow connections to these services using the pg-el
library (https://github.com/emarsden/pg-el), which implements the PostgreSQL
wire protocol.





^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: ALPN support for GnuTLS connections
  2024-09-29  8:23 ALPN support for GnuTLS connections Eric Marsden
@ 2024-09-30  9:21 ` Robert Pluim
  2024-09-30 10:21   ` Eric Marsden
  0 siblings, 1 reply; 15+ messages in thread
From: Robert Pluim @ 2024-09-30  9:21 UTC (permalink / raw)
  To: Eric Marsden; +Cc: emacs-devel

>>>>> On Sun, 29 Sep 2024 10:23:17 +0200, Eric Marsden <eric.marsden@risk-engineering.org> said:

    Eric> Hello,
    Eric> The GnuTLS support in Emacs does not seem to support the TLS extension
    Eric> Application Layer Protocol Negotiation (ALPN). ALPN is no longer just useful for
    Eric> faster TLS handshakes (in HTTP/2, for example); it is mandatory in certain uses
    Eric> of TLS.

    Eric> The GnuTLS library does support ALPN (since 2013, it seems). My understanding is
    Eric> that definitions for the two functions described here would need to be added to
    Eric> gnutls.c:

    Eric>   https://www.gnutls.org/manual/html_node/Application-Layer-Protocol-Negotiation-_0028ALPN_0029.html

Why would we need the 'get' API? Did you want to be able to set the
GNUTLS_ALPN_MANDATORY flag and fail the connection?

For the 'set' I guess we could add a keyword parameter to
`gnutls-negotiate' and its callers, and pass that down to
`gnutls-boot-parameters'.

Robert
-- 



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: ALPN support for GnuTLS connections
  2024-09-30  9:21 ` Robert Pluim
@ 2024-09-30 10:21   ` Eric Marsden
  2024-09-30 13:13     ` Robert Pluim
  0 siblings, 1 reply; 15+ messages in thread
From: Eric Marsden @ 2024-09-30 10:21 UTC (permalink / raw)
  To: Robert Pluim; +Cc: emacs-devel

On 30/09/2024 11:21, Robert Pluim wrote:
> Why would we need the 'get' API? Did you want to be able to set the
> GNUTLS_ALPN_MANDATORY flag and fail the connection?

I don't think this is a critical requirement, but I see that some
software using GnuTLS offers the possibility to fail the connection
if the selected application protocol is not in the requested list
(for example, the "--alpn-fatal" commandline argument to gnutls-serv).


> For the 'set' I guess we could add a keyword parameter to
> `gnutls-negotiate' and its callers, and pass that down to
> `gnutls-boot-parameters'.

That sounds good to me. Something like :alpn-protocols that
accepts a list of strings, or a comma-separated string.

(I should add that I am not volunteering to implement this; I have
no confidence in my ability to write the constrained type of C
needed for the Emacs core.)

Eric




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: ALPN support for GnuTLS connections
  2024-09-30 10:21   ` Eric Marsden
@ 2024-09-30 13:13     ` Robert Pluim
  2024-09-30 17:26       ` Eric Marsden
  0 siblings, 1 reply; 15+ messages in thread
From: Robert Pluim @ 2024-09-30 13:13 UTC (permalink / raw)
  To: Eric Marsden; +Cc: emacs-devel

>>>>> On Mon, 30 Sep 2024 12:21:30 +0200, Eric Marsden <eric.marsden@risk-engineering.org> said:

    Eric> On 30/09/2024 11:21, Robert Pluim wrote:
    >> Why would we need the 'get' API? Did you want to be able to set the
    >> GNUTLS_ALPN_MANDATORY flag and fail the connection?

    Eric> I don't think this is a critical requirement, but I see that some
    Eric> software using GnuTLS offers the possibility to fail the connection
    Eric> if the selected application protocol is not in the requested list
    Eric> (for example, the "--alpn-fatal" commandline argument to gnutls-serv).

OK, weʼll leave it aside for now.

    >> For the 'set' I guess we could add a keyword parameter to
    >> `gnutls-negotiate' and its callers, and pass that down to
    >> `gnutls-boot-parameters'.

    Eric> That sounds good to me. Something like :alpn-protocols that
    Eric> accepts a list of strings, or a comma-separated string.

    Eric> (I should add that I am not volunteering to implement this; I have
    Eric> no confidence in my ability to write the constrained type of C
    Eric> needed for the Emacs core.)

Think of it as a learning experience :-)

The existing code in `gnutls-boot' already does very similar things
for other parameters. If I propose a patch, could you test it? I
should be able to have something by the end of the week.

Robert
-- 



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: ALPN support for GnuTLS connections
  2024-09-30 13:13     ` Robert Pluim
@ 2024-09-30 17:26       ` Eric Marsden
  2024-10-07  8:22         ` Robert Pluim
  0 siblings, 1 reply; 15+ messages in thread
From: Eric Marsden @ 2024-09-30 17:26 UTC (permalink / raw)
  To: Robert Pluim; +Cc: emacs-devel

On 30/09/2024 15:13, Robert Pluim wrote:
> The existing code in `gnutls-boot' already does very similar things
> for other parameters. If I propose a patch, could you test it? I
> should be able to have something by the end of the week.

Sure, I would be glad to test a patch.

Eric




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: ALPN support for GnuTLS connections
  2024-09-30 17:26       ` Eric Marsden
@ 2024-10-07  8:22         ` Robert Pluim
  2024-10-10 13:54           ` Robert Pluim
  0 siblings, 1 reply; 15+ messages in thread
From: Robert Pluim @ 2024-10-07  8:22 UTC (permalink / raw)
  To: Eric Marsden; +Cc: emacs-devel

>>>>> On Mon, 30 Sep 2024 19:26:54 +0200, Eric Marsden <eric.marsden@risk-engineering.org> said:

    Eric> On 30/09/2024 15:13, Robert Pluim wrote:
    >> The existing code in `gnutls-boot' already does very similar things
    >> for other parameters. If I propose a patch, could you test it? I
    >> should be able to have something by the end of the week.

    Eric> Sure, I would be glad to test a patch.

The code is written but not tested fully, and since Iʼve been sick the
past few days I havenʼt been able to complete it. Hopefully Iʼll get
to it by the end of this week.

Thanks

Robert
-- 



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: ALPN support for GnuTLS connections
  2024-10-07  8:22         ` Robert Pluim
@ 2024-10-10 13:54           ` Robert Pluim
  2024-10-10 16:23             ` Eli Zaretskii
  2024-10-12  9:30             ` Eric Marsden
  0 siblings, 2 replies; 15+ messages in thread
From: Robert Pluim @ 2024-10-10 13:54 UTC (permalink / raw)
  To: Eric Marsden; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 764 bytes --]

>>>>> On Mon, 07 Oct 2024 10:22:25 +0200, Robert Pluim <rpluim@gmail.com> said:

>>>>> On Mon, 30 Sep 2024 19:26:54 +0200, Eric Marsden <eric.marsden@risk-engineering.org> said:
    Eric> On 30/09/2024 15:13, Robert Pluim wrote:
    >>> The existing code in `gnutls-boot' already does very similar things
    >>> for other parameters. If I propose a patch, could you test it? I
    >>> should be able to have something by the end of the week.

    Eric> Sure, I would be glad to test a patch.

    Robert> The code is written but not tested fully, and since Iʼve been sick the
    Robert> past few days I havenʼt been able to complete it. Hopefully Iʼll get
    Robert> to it by the end of this week.

Patch below. Works in my limited testing.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-support-for-GnuTLS-ALPN-negotiation.patch --]
[-- Type: text/x-diff, Size: 8447 bytes --]

From 9ec71754d4c7b593772fa336101e189b6a0ff962 Mon Sep 17 00:00:00 2001
From: Robert Pluim <rpluim@gmail.com>
Date: Thu, 10 Oct 2024 15:48:49 +0200
Subject: [PATCH] Add support for GnuTLS ALPN negotiation
To: emacs-devel@gnu.org

* lisp/net/gnutls.el (open-gnutls-stream): Pass unrecognized
parameters down to gnutls-boot.
(gnutls-negotiate): Add :alpn-protocols keyword.
(gnutls-boot-parameters): Add :alpn-protocols keyword.
* src/gnutls.c [GNUTLS_VERSION_NUMBER >= 0x030200] : Define
HAVE_GNUTLS_ALPN_SET_PROTOCOLS.
(Fgnutls_boot) [HAVE_GNUTLS_ALPN_SET_PROTOCOLS]: Add
:alpn-protocols keyword.  Pass any string values to
gnutls_alpn_set_protocols.
(syms_of_gnutls): Add QCalpn_protocols symbol.
---
 lisp/net/gnutls.el | 38 ++++++++++++++++++++++++++++----------
 src/gnutls.c       | 43 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+), 10 deletions(-)

diff --git a/lisp/net/gnutls.el b/lisp/net/gnutls.el
index b5fb4d47d57..dc9870136d6 100644
--- a/lisp/net/gnutls.el
+++ b/lisp/net/gnutls.el
@@ -168,7 +168,9 @@ open-gnutls-stream
 Fifth arg PARAMETERS is an optional list of keyword/value pairs.
 Only :client-certificate, :nowait, and :coding keywords are
 recognized, and have the same meaning as for
-`open-network-stream'.
+`open-network-stream'.  Any other keyword arguments are presumed to be
+TLS-specific parameters, and are passed down to `gnutls-boot'
+unmodified.
 For historical reasons PARAMETERS can also be a symbol, which is
 interpreted the same as passing a list containing :nowait and the
 value of that symbol.
@@ -197,23 +199,32 @@ open-gnutls-stream
          (cert (network-stream-certificate host service parameters))
          (keylist (and cert (list cert)))
          (nowait (plist-get parameters :nowait))
+         (tls-parameters (apply #'append
+                                (cl-remove-if
+                                 (lambda (elt)
+                                   (memq (car elt)
+                                         '(:client-certificate :nowait :coding)))
+                                 (seq-split parameters 2))))
          (process (open-network-stream
                    name buffer host service
                    :nowait nowait
                    :tls-parameters
                    (and nowait
                         (cons 'gnutls-x509pki
-                              (gnutls-boot-parameters
-                               :type 'gnutls-x509pki
-                               :keylist keylist
-                               :hostname (puny-encode-domain host))))
+                              (apply #'gnutls-boot-parameters
+                                     :type 'gnutls-x509pki
+                                     :keylist keylist
+                                     :hostname (puny-encode-domain host)
+                                     tls-parameters)))
                    :coding (plist-get parameters :coding))))
     (if nowait
         process
-      (gnutls-negotiate :process process
-                        :type 'gnutls-x509pki
-                        :keylist keylist
-                        :hostname (puny-encode-domain host)))))
+      (apply #'gnutls-negotiate
+             :process process
+             :type 'gnutls-x509pki
+             :keylist keylist
+             :hostname (puny-encode-domain host)
+             tls-parameters))))
 
 (define-error 'gnutls-error "GnuTLS error")
 
@@ -226,6 +237,7 @@ gnutls-negotiate
            &key process type hostname priority-string
            trustfiles crlfiles keylist min-prime-bits
            verify-flags verify-error verify-hostname-error
+           alpn-protocols
            &allow-other-keys)
   "Negotiate a SSL/TLS connection.  Return proc.  Signal gnutls-error.
 
@@ -241,6 +253,7 @@ gnutls-negotiate
                   :type type
                   :hostname hostname
                   :priority-string priority-string
+                  :alpn-protocols alpn-protocols
                   :trustfiles trustfiles
                   :crlfiles crlfiles
                   :keylist keylist
@@ -266,7 +279,7 @@ gnutls-boot-parameters
            &key type hostname priority-string
            trustfiles crlfiles keylist min-prime-bits
            verify-flags verify-error verify-hostname-error
-           pass flags
+           pass flags alpn-protocols
            &allow-other-keys)
   "Return a keyword list of parameters suitable for passing to `gnutls-boot'.
 
@@ -290,6 +303,10 @@ gnutls-boot-parameters
 bitflag of the gnutls_pkcs_encrypt_flags_t enum of GnuTLS.  The
 empty list corresponds to the bitflag with value 0.
 
+ALPN-PROTOCOLS is a list of strings to be offered as protocols in ALPN
+negotiation.  Note that failure to negotiate a protocol is not treated
+as a fatal error by Emacs.
+
 When VERIFY-ERROR is t or a list containing `:trustfiles', an
 error will be raised when the peer certificate verification fails
 as per GnuTLS' gnutls_certificate_verify_peers2.  Otherwise, only
@@ -359,6 +376,7 @@ gnutls-boot-parameters
          (push :hostname verify-error))
 
     `(:priority ,priority-string
+                :alpn-protocols ,alpn-protocols
                 :hostname ,hostname
                 :loglevel ,gnutls-log-level
                 :min-prime-bits ,min-prime-bits
diff --git a/src/gnutls.c b/src/gnutls.c
index 334d1d47eb6..0360d9cb740 100644
--- a/src/gnutls.c
+++ b/src/gnutls.c
@@ -36,6 +36,7 @@
 # if GNUTLS_VERSION_NUMBER >= 0x030200
 #  define HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2
 #  define HAVE_GNUTLS_CIPHER_GET_IV_SIZE
+#  define HAVE_GNUTLS_ALPN_SET_PROTOCOLS
 # endif
 
 # if GNUTLS_VERSION_NUMBER >= 0x030202
@@ -1900,6 +1901,10 @@ DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 3, 0,
 
 :priority is a GnuTLS priority string, defaults to "NORMAL".
 
+:alpn-protocols is a list of strings to use for ALPN negotiation.
+Failing to agree on an ALPN protocol is not treated as a fatal error by
+Emacs.
+
 :trustfiles is a list of PEM-encoded trust files for `gnutls-x509pki'.
 
 :crlfiles is a list of PEM-encoded CRL lists for `gnutls-x509pki'.
@@ -1979,6 +1984,7 @@ DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 3, 0,
 
   /* Placeholders for the property list elements.  */
   Lisp_Object priority_string;
+  Lisp_Object alpn_protocols;
   Lisp_Object trustfiles;
   Lisp_Object crlfiles;
   Lisp_Object keylist;
@@ -2011,6 +2017,7 @@ DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 3, 0,
 
   hostname              = plist_get (proplist, QChostname);
   priority_string       = plist_get (proplist, QCpriority);
+  alpn_protocols        = plist_get (proplist, QCalpn_protocols);
   trustfiles            = plist_get (proplist, QCtrustfiles);
   keylist               = plist_get (proplist, QCkeylist);
   crlfiles              = plist_get (proplist, QCcrlfiles);
@@ -2251,6 +2258,41 @@ DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 3, 0,
 
   GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_PRIORITY;
 
+#ifdef HAVE_GNUTLS_ALPN_SET_PROTOCOLS
+  if (!NILP (alpn_protocols))
+    {
+      Lisp_Object length = Fproper_list_p (alpn_protocols);
+      if (!NILP (length))
+	{
+	  int count = XFIXNAT (length);
+	  gnutls_datum_t *protocols = xzalloc (count * sizeof (gnutls_datum_t));
+	  count = 0;
+	  GNUTLS_LOG (1, max_log_level, "setting ALPN protocols");
+	  for (Lisp_Object tail = alpn_protocols; CONSP (tail); tail = XCDR (tail))
+	    {
+	      Lisp_Object proto = XCAR (tail);
+	      if (STRINGP (proto))
+		{
+		  protocols[count].data = SDATA (proto);
+		  protocols[count].size = strlen (SSDATA (proto));
+		  count++;
+		}
+	    }
+	  int ret = 0;
+	  if (count)
+	    ret = gnutls_alpn_set_protocols (state, protocols, count, 0);
+
+	  /* gnutls_alpn_set_protocols copies the protocol strings, so
+	     we can free it here.  */
+	  xfree (protocols);
+	  if (ret < GNUTLS_E_SUCCESS)
+	    return gnutls_make_error (ret);
+
+	  GNUTLS_LOG (1, max_log_level, "ALPN protocols set");
+	}
+    }
+#endif
+
   if (FIXNUMP (prime_bits))
     gnutls_dh_set_prime_bits (state, XUFIXNUM (prime_bits));
 
@@ -3020,6 +3062,7 @@ syms_of_gnutls (void)
   /* The following are for the property list of 'gnutls-boot'.  */
   DEFSYM (QChostname, ":hostname");
   DEFSYM (QCpriority, ":priority");
+  DEFSYM (QCalpn_protocols, ":alpn-protocols");
   DEFSYM (QCtrustfiles, ":trustfiles");
   DEFSYM (QCkeylist, ":keylist");
   DEFSYM (QCcrlfiles, ":crlfiles");
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: ALPN support for GnuTLS connections
  2024-10-10 13:54           ` Robert Pluim
@ 2024-10-10 16:23             ` Eli Zaretskii
  2024-10-11  7:32               ` Robert Pluim
  2024-10-12  9:30             ` Eric Marsden
  1 sibling, 1 reply; 15+ messages in thread
From: Eli Zaretskii @ 2024-10-10 16:23 UTC (permalink / raw)
  To: Robert Pluim; +Cc: eric.marsden, emacs-devel

> From: Robert Pluim <rpluim@gmail.com>
> Cc: emacs-devel@gnu.org
> Date: Thu, 10 Oct 2024 15:54:53 +0200
> 
> Patch below. Works in my limited testing.

Thanks, but I think it will fail to link on MS-Windows, because you
didn't say the magic words to load gnutls_alpn_set_protocols from the
library and call the function through a function pointer.

Also, what about calling this out in NEWS?



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: ALPN support for GnuTLS connections
  2024-10-10 16:23             ` Eli Zaretskii
@ 2024-10-11  7:32               ` Robert Pluim
  0 siblings, 0 replies; 15+ messages in thread
From: Robert Pluim @ 2024-10-11  7:32 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eric.marsden, emacs-devel

>>>>> On Thu, 10 Oct 2024 19:23:07 +0300, Eli Zaretskii <eliz@gnu.org> said:

    >> From: Robert Pluim <rpluim@gmail.com>
    >> Cc: emacs-devel@gnu.org
    >> Date: Thu, 10 Oct 2024 15:54:53 +0200
    >> 
    >> Patch below. Works in my limited testing.

    Eli> Thanks, but I think it will fail to link on MS-Windows, because you
    Eli> didn't say the magic words to load gnutls_alpn_set_protocols from the
    Eli> library and call the function through a function pointer.

Right. Iʼll copy the appropriate boiler-plate.

    Eli> Also, what about calling this out in NEWS?

Once it works, yes :-)

Robert
-- 



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: ALPN support for GnuTLS connections
  2024-10-10 13:54           ` Robert Pluim
  2024-10-10 16:23             ` Eli Zaretskii
@ 2024-10-12  9:30             ` Eric Marsden
  2024-10-14  9:22               ` Robert Pluim
  2024-10-15  3:02               ` Richard Stallman
  1 sibling, 2 replies; 15+ messages in thread
From: Eric Marsden @ 2024-10-12  9:30 UTC (permalink / raw)
  To: Robert Pluim; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 2056 bytes --]

On 10/10/2024 15:54, Robert Pluim wrote:
> Patch below. Works in my limited testing.

Excellent, I can confirm that this works with the PostgreSQL 17.0 use 
case that I mentioned upthread, as well as with test servers from 
OpenSSL and Rustls (see the attached test file).

Remaining questions in my mind:

(1) It would be useful for elisp code to be able to determine whether 
Emacs has ALPN support. The elisp code will generally know that the 
service it's connecting to requires ALPN, and it would be useful to be 
able to inform the user that they should upgrade Emacs, instead of 
getting a generic "connection failed" error. The C preprocessor test 
HAVE_GNUTLS_ALPN_SET_PROTOCOLS  isn't visible from elisp, nor is (I 
think?) the binding to gnutls_alpn_set_protocols. This might also be 
useful for other features such as the AEAD support. Perhaps a function 
such as gnutls-feature-available-p(:alpn) ?

(2) The current behaviour of connection failing only depending on the 
server's ALPN setting is I think less than ideal. If the server is not 
configured to request ALPN, sending ALPN does not lead to failure. If 
server is looking for ALPN and wants another protocol, the connection 
fails. I think the default behaviour should be for the connection to 
fail if one of the ALPN protocols requested by the client is not 
selected: this seems to be more consistent and avoids a security attack 
called ALPACA, https://alpaca-attack.com/. This just requires a change 
to use GNUTLS_ALPN_MANDATORY (as well as updates to the documentation)

         ret = gnutls_alpn_set_protocols (state, protocols, count, 
GNUTLS_ALPN_MANDATORY);

In fact I see reading the ALPACA web page that TLS clients are 
recommended to use the SNI extension to indicate the server name that 
they wish to connect to, which gnutls.c is not currently doing. One 
thing at a time!

(3) Perhaps you could add the attached tiny patch to the logging support 
for gnutls.c (which is very verbose), so that an EAGAIN doesn't pollute 
logs at level 1.


Thanks,

Eric



[-- Attachment #2: alpn.el --]
[-- Type: text/x-emacs-lisp, Size: 3660 bytes --]

;; ALPN testing for Emacs v31   -*- lexical-binding: t -*-
;;
;; Author: Eric Marsden <eric.marsden@risk-engineering.org>
;;
;; Perhaps a little inconsistent: if server is not configured to check ALPN, sending ALPN does not
;; lead to failure. If server is looking for ALPN and chooses another one, connection fails.

(require 'gnutls)

(defvar alpn-port 8881)
(defvar alpn-protocol "foobles")


(defun alpn-setup-certs ()
  (let* ((certdir (expand-file-name "certs" temporary-file-directory))
         (_ (make-directory certdir t))
         (default-directory certdir))
    (shell-command (concat "openssl req -new -nodes -text -out root.csr "
                               "-keyout root.key -subj '/CN=localhost'"))
    (set-file-modes "root.key" #o600)
    (shell-command (concat "openssl x509 -req -in root.csr -text -days 42 "
                               "-extfile /etc/ssl/openssl.cnf -extensions v3_ca "
                               "-signkey root.key -out root.crt"))
    (shell-command (concat "openssl req -new -nodes -text -out server.csr "
                               "-keyout server.key -subj '/CN=localhost'"))
    (set-file-modes "server.key" #o600)
    (shell-command (concat "openssl x509 -req -in server.csr -text -days 42 "
                               "-CA root.crt -CAkey root.key "
                               "-CAcreateserial -out server.crt"))
    (shell-command (concat "openssl req -new -nodes -out client.csr -keyout client.key "
                               "-subj '/CN=emacs'"))
    (shell-command (concat "openssl x509 -req -days 42 -in client.csr "
                               "-CA root.crt -CAkey root.key "
                               "-CAcreateserial -out client.crt"))
    certdir))

(defun alpn-setup/openssl (certdir)
  (let* ((cmd (format "openssl s_server -rev -port %d -cert %s -key %s -debug -alpn %s"
                      alpn-port
                      (expand-file-name "server.crt" certdir)
                      (expand-file-name "server.key" certdir)
                      alpn-protocol))
         (buf (get-buffer-create "*OpenSSL*")))
    (start-process-shell-command "openssl" buf cmd)))

(defun alpn-setup/rustls (certdir)
  (let* ((cargo (expand-file-name ".cargo/bin/cargo" (getenv "HOME")))
         (cmd (format "%s run --bin tlsserver-mio -- --port %d --certs %s --key %s --proto %s echo"
                      cargo
                      alpn-port
                      (expand-file-name "server.crt" certdir)
                      (expand-file-name "server.key" certdir)
                      alpn-protocol))
         (buf (get-buffer-create "*Rustls*"))
         ;; clone of https://github.com/rustls/rustls.git
         (default-directory "/tmp/rustls"))
    (start-process-shell-command "rustls" buf cmd)))

(defun alpn-fetch (certdir)
  (let* ((buf (generate-new-buffer " *ALPN*"))
         (process (open-network-stream "alpn" buf "localhost" alpn-port))
         (gnutls-log-level 2))
    (gnutls-negotiate :process process
                      :hostname "localhost"
                      :alpn-protocols (list alpn-protocol)
                      :trustfiles (list (expand-file-name "root.crt" certdir)))
    (process-send-string process "bizzles\n")
    (accept-process-output process 0.1)
    (with-current-buffer buf (buffer-string))))

(defun alpn-test-openssl ()
  (let ((certdir (alpn-setup-certs)))
    (alpn-setup/openssl certdir)
    (sleep-for 1)
    (message "ALPN> %s" (alpn-fetch certdir))))

(defun alpn-test-rustls ()
  (let ((certdir (alpn-setup-certs)))
    (alpn-setup/rustls certdir)
    (sleep-for 1)
    (message "ALPN> %s" (alpn-fetch certdir))))


[-- Attachment #3: log-retry.diff --]
[-- Type: text/x-patch, Size: 406 bytes --]

diff --git a/src/gnutls.c b/src/gnutls.c
index 334d1d4..edf6691 100644
--- a/src/gnutls.c
+++ b/src/gnutls.c
@@ -854,7 +854,7 @@ emacs_gnutls_handle_error (gnutls_session_t session, int err)
                        max_log_level,
                        "retry:",
                        str);
-	  FALLTHROUGH;
+	  break;
         default:
           GNUTLS_LOG2 (1,
                        max_log_level,

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: ALPN support for GnuTLS connections
  2024-10-12  9:30             ` Eric Marsden
@ 2024-10-14  9:22               ` Robert Pluim
  2024-10-15  7:06                 ` Eric Marsden
  2024-10-15  3:02               ` Richard Stallman
  1 sibling, 1 reply; 15+ messages in thread
From: Robert Pluim @ 2024-10-14  9:22 UTC (permalink / raw)
  To: Eric Marsden; +Cc: emacs-devel

>>>>> On Sat, 12 Oct 2024 11:30:41 +0200, Eric Marsden <eric.marsden@risk-engineering.org> said:

    Eric> On 10/10/2024 15:54, Robert Pluim wrote:
    >> Patch below. Works in my limited testing.

    Eric> Excellent, I can confirm that this works with the PostgreSQL 17.0 use
    Eric> case that I mentioned upthread, as well as with test servers from
    Eric> OpenSSL and Rustls (see the attached test file).

    Eric> Remaining questions in my mind:

    Eric> (1) It would be useful for elisp code to be able to determine whether
    Eric> Emacs has ALPN support. The elisp code will generally know that the
    Eric> service it's connecting to requires ALPN, and it would be useful to be
    Eric> able to inform the user that they should upgrade Emacs, instead of
    Eric> getting a generic "connection failed" error. The C preprocessor test
    Eric> HAVE_GNUTLS_ALPN_SET_PROTOCOLS  isn't visible from elisp, nor is (I
    Eric> think?) the binding to gnutls_alpn_set_protocols. This might also be
    Eric> useful for other features such as the AEAD support. Perhaps a function
    Eric> such as gnutls-feature-available-p(:alpn) ?

`gnutls-available-p' returns a list of available TLS features, we can put
"alpn" in there. AEAD is already there.

    Eric> (2) The current behaviour of connection failing only depending on the
    Eric> server's ALPN setting is I think less than ideal. If the server is not
    Eric> configured to request ALPN, sending ALPN does not lead to failure. If
    Eric> server is looking for ALPN and wants another protocol, the connection
    Eric> fails. I think the default behaviour should be for the connection to
    Eric> fail if one of the ALPN protocols requested by the client is not
    Eric> selected: this seems to be more consistent and avoids a security
    Eric> attack called ALPACA, https://alpaca-attack.com/. This just requires a
    Eric> change to use GNUTLS_ALPN_MANDATORY (as well as updates to the
    Eric> documentation)

    Eric>         ret = gnutls_alpn_set_protocols (state, protocols, count,
    Eric> GNUTLS_ALPN_MANDATORY);

Yes, in order to palliate servers not following the requirement to be
strict, the recommendation is for the client to be strict. I donʼt
mind that, although we should add a way to turn it off. Perhaps an
":alpn-flags" parameter with symbols for the two current flags, plus
one that means "zero".

    Eric> In fact I see reading the ALPACA web page that TLS clients are
    Eric> recommended to use the SNI extension to indicate the server name that
    Eric> they wish to connect to, which gnutls.c is not currently doing. One
    Eric> thing at a time!

gnutls.c has been sending SNI since 2014

    Eric> (3) Perhaps you could add the attached tiny patch to the logging
    Eric> support for gnutls.c (which is very verbose), so that an EAGAIN
    Eric> doesn't pollute logs at level 1.

Iʼm reluctant to make such a change: GnuTLS logging is really only for
when things go wrong, and Iʼd rather not handicap it. And this is what
`delete-matching-lines' is for 😺.

Robert
-- 



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: ALPN support for GnuTLS connections
  2024-10-12  9:30             ` Eric Marsden
  2024-10-14  9:22               ` Robert Pluim
@ 2024-10-15  3:02               ` Richard Stallman
  2024-10-15  7:33                 ` Eric Marsden
  1 sibling, 1 reply; 15+ messages in thread
From: Richard Stallman @ 2024-10-15  3:02 UTC (permalink / raw)
  To: Eric Marsden, rpluim; +Cc: emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

Could you describe some specific situations in which ALPN would be
useful in Emacs?  What Wikipedia says about ALPN is very abstract --
I'd like to get an idea of what concrete activities need ALPN
or would be improved by it.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: ALPN support for GnuTLS connections
  2024-10-14  9:22               ` Robert Pluim
@ 2024-10-15  7:06                 ` Eric Marsden
  2024-10-18 12:37                   ` Robert Pluim
  0 siblings, 1 reply; 15+ messages in thread
From: Eric Marsden @ 2024-10-15  7:06 UTC (permalink / raw)
  To: Robert Pluim; +Cc: emacs-devel

On 14/10/2024 11:22, Robert Pluim wrote:
>>>>>> On Sat, 12 Oct 2024 11:30:41 +0200, Eric Marsden <eric.marsden@risk-engineering.org> said:
>      Eric> (1) It would be useful for elisp code to be able to determine whether
>      Eric> Emacs has ALPN support. The elisp code will generally know that the
>      Eric> service it's connecting to requires ALPN, and it would be useful to be
>      Eric> able to inform the user that they should upgrade Emacs, instead of
>      Eric> getting a generic "connection failed" error. The C preprocessor test
>      Eric> HAVE_GNUTLS_ALPN_SET_PROTOCOLS  isn't visible from elisp, nor is (I
>      Eric> think?) the binding to gnutls_alpn_set_protocols. This might also be
>      Eric> useful for other features such as the AEAD support. Perhaps a function
>      Eric> such as gnutls-feature-available-p(:alpn) ?
>
> `gnutls-available-p' returns a list of available TLS features, we can put
> "alpn" in there. AEAD is already there.
OK, that sounds good to me, thanks.

> Yes, in order to palliate servers not following the requirement to be
> strict, the recommendation is for the client to be strict. I donʼt
> mind that, although we should add a way to turn it off. Perhaps an
> ":alpn-flags" parameter with symbols for the two current flags, plus
> one that means "zero".
Also sounds good.

>      Eric> In fact I see reading the ALPACA web page that TLS clients are
>      Eric> recommended to use the SNI extension to indicate the server name that
>      Eric> they wish to connect to, which gnutls.c is not currently doing. One
>      Eric> thing at a time!
>
> gnutls.c has been sending SNI since 2014
Thanks for the correction.

Eric




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: ALPN support for GnuTLS connections
  2024-10-15  3:02               ` Richard Stallman
@ 2024-10-15  7:33                 ` Eric Marsden
  0 siblings, 0 replies; 15+ messages in thread
From: Eric Marsden @ 2024-10-15  7:33 UTC (permalink / raw)
  To: rms; +Cc: emacs-devel

On 15/10/2024 05:02, Richard Stallman wrote:
> Could you describe some specific situations in which ALPN would be
> useful in Emacs?  What Wikipedia says about ALPN is very abstract --
> I'd like to get an idea of what concrete activities need ALPN
> or would be improved by it.

ALPN makes it possible to serve different application-level protocols (e.g.
HTTP/1.1, HTTP/2, HTTP/3) from the same network endpoint, with the choice of
application-level protocol made at the TLS protocol level. This means that the
choice of application-level protocol is secure; it happens at the same protocol
level as the checking of digital certificates. It also improves performance when
establishing a network connection, because the negociation of application
protocol is made during the initial handshake, without requiring multiple back
and forth network messages.

Alternative historic methods for selecting an application-level protocol include
the STARTTLS “connection upgrade” mechanism used for SMTP and IMAP for example,
and the “Upgrade” HTTP header used for protocol upgrade. These either have
security problems (e.g. “STARTTLS stripping” to block connection upgrade) or
performance problems. RFC 9325 “Recommendations for Secure Use of Transport
Layer Security (TLS) and Datagram Transport Layer Security (DTLS)” states that
“TLS implementations (both client- and server-side) MUST support” ALPN.

In the particular example that motivated my interest in ALPN for Emacs, version
17 of the PostgreSQL database includes a new ALPN-based “direct TLS” connection
mode, as an alternative to its historical STARTTLS-like connection upgrade
mechanism. For a service provider who makes it possible to access PostgreSQL
over the internet, there are many benefits to the new ALPN-based mechanism, such
as allowing the use of commercial “TLS gateways” (that do no application-level
processing) as entrypoints to their network. I expect that over time, an
increasing proportion of internet services will require ALPN.

Eric




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: ALPN support for GnuTLS connections
  2024-10-15  7:06                 ` Eric Marsden
@ 2024-10-18 12:37                   ` Robert Pluim
  0 siblings, 0 replies; 15+ messages in thread
From: Robert Pluim @ 2024-10-18 12:37 UTC (permalink / raw)
  To: Eric Marsden; +Cc: emacs-devel

>>>>> On Tue, 15 Oct 2024 09:06:49 +0200, Eric Marsden <eric.marsden@risk-engineering.org> said:

    Eric> On 14/10/2024 11:22, Robert Pluim wrote:
    >>>>>>> On Sat, 12 Oct 2024 11:30:41 +0200, Eric Marsden <eric.marsden@risk-engineering.org> said:
    Eric> (1) It would be useful for elisp code to be able to determine whether
    Eric> Emacs has ALPN support. The elisp code will generally know that the
    Eric> service it's connecting to requires ALPN, and it would be useful to be
    Eric> able to inform the user that they should upgrade Emacs, instead of
    Eric> getting a generic "connection failed" error. The C preprocessor test
    Eric> HAVE_GNUTLS_ALPN_SET_PROTOCOLS  isn't visible from elisp, nor is (I
    Eric> think?) the binding to gnutls_alpn_set_protocols. This might also be
    Eric> useful for other features such as the AEAD support. Perhaps a function
    Eric> such as gnutls-feature-available-p(:alpn) ?
    >> 
    >> `gnutls-available-p' returns a list of available TLS features, we can put
    >> "alpn" in there. AEAD is already there.
    Eric> OK, that sounds good to me, thanks.

    >> Yes, in order to palliate servers not following the requirement to be
    >> strict, the recommendation is for the client to be strict. I donʼt
    >> mind that, although we should add a way to turn it off. Perhaps an
    >> ":alpn-flags" parameter with symbols for the two current flags, plus
    >> one that means "zero".
    Eric> Also sounds good.

Except that itʼs not working. Either GNUTLS_ALPN_MANDATORY is a
server-only flag or Iʼm using it wrong. More debugging required.

Robert
-- 



^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2024-10-18 12:37 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-29  8:23 ALPN support for GnuTLS connections Eric Marsden
2024-09-30  9:21 ` Robert Pluim
2024-09-30 10:21   ` Eric Marsden
2024-09-30 13:13     ` Robert Pluim
2024-09-30 17:26       ` Eric Marsden
2024-10-07  8:22         ` Robert Pluim
2024-10-10 13:54           ` Robert Pluim
2024-10-10 16:23             ` Eli Zaretskii
2024-10-11  7:32               ` Robert Pluim
2024-10-12  9:30             ` Eric Marsden
2024-10-14  9:22               ` Robert Pluim
2024-10-15  7:06                 ` Eric Marsden
2024-10-18 12:37                   ` Robert Pluim
2024-10-15  3:02               ` Richard Stallman
2024-10-15  7:33                 ` Eric Marsden

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.