Support configuring TLSv1.3 cipher suites
authorDaniel Gustafsson <[email protected]>
Thu, 24 Oct 2024 13:20:32 +0000 (15:20 +0200)
committerDaniel Gustafsson <[email protected]>
Thu, 24 Oct 2024 13:20:32 +0000 (15:20 +0200)
The ssl_ciphers GUC can only set cipher suites for TLSv1.2, and lower,
connections. For TLSv1.3 connections a different OpenSSL API must be
used.  This adds a new GUC, ssl_tls13_ciphers, which can be used to
configure a colon separated list of cipher suites to support when
performing a TLSv1.3 handshake.

Original  by Erica Zhang with additional hacking by me.

Author: Erica Zhang <[email protected]>
Author: Daniel Gustafsson <[email protected]>
Reviewed-by: Jacob Champion <[email protected]>
Reviewed-by: Andres Freund <[email protected]>
Reviewed-by: Peter Eisentraut <[email protected]>
Reviewed-by: Jelte Fennema-Nio <[email protected]>
Discussion: https://postgr.es/m/[email protected]

doc/src/sgml/config.sgml
src/backend/libpq/be-secure-openssl.c
src/backend/libpq/be-secure.c
src/backend/utils/misc/guc_tables.c
src/backend/utils/misc/postgresql.conf.sample
src/include/libpq/libpq.h
src/test/ssl/t/SSL/Server.pm

index f8d862a6ce405d58f1d2c2b568881504706e68fa..dc401087dc66e3f9562439cc5c8450252dce0c84 100644 (file)
@@ -1340,6 +1340,28 @@ include_dir 'conf.d'
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-ssl-tls13-ciphers" xreflabel="ssl_tls13_ciphers">
+      <term><varname>ssl_tls13_ciphers</varname> (<type>string</type>)
+      <indexterm>
+       <primary><varname>ssl_tls13_ciphers</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Specifies a list of cipher suites that are allowed by connections using
+        <acronym>TLS</acronym> version 1.3.  Multiple cipher suites can be
+        specified by using a colon separated list. If left blank, the default
+        set of cipher suites in <productname>OpenSSL</productname> will be used.
+       </para>
+
+       <para>
+        This parameter can only be set in the
+        <filename>postgresql.conf</filename> file or on the server command
+        line.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-ssl-ciphers" xreflabel="ssl_ciphers">
       <term><varname>ssl_ciphers</varname> (<type>string</type>)
       <indexterm>
@@ -1348,15 +1370,13 @@ include_dir 'conf.d'
       </term>
       <listitem>
        <para>
-        Specifies a list of <acronym>SSL</acronym> cipher suites that are
-        allowed to be used by SSL connections.  See the
-        <citerefentry><refentrytitle>ciphers</refentrytitle></citerefentry>
+        Specifies a list of <acronym>SSL</acronym> ciphers that are allowed by
+        connections using TLS version 1.2 and lower, see
+        <xref linkend="guc-ssl-tls13-ciphers"/> for TLS version 1.3 connections. See
+        the <citerefentry><refentrytitle>ciphers</refentrytitle></citerefentry>
         manual page in the <productname>OpenSSL</productname> package for the
-        syntax of this setting and a list of supported values.  Only
-        connections using TLS version 1.2 and lower are affected.  There is
-        currently no setting that controls the cipher choices used by TLS
-        version 1.3 connections.  The default value is
-        <literal>HIGH:MEDIUM:+3DES:!aNULL</literal>.  The default is usually a
+        syntax of this setting and a list of supported values.  The default value
+        is <literal>HIGH:MEDIUM:+3DES:!aNULL</literal>.  The default is usually a
         reasonable choice unless you have specific security requirements.
        </para>
 
index c8cd81d8537be0fef1e36803d911376c6857afe4..469be36e76413dc6cb1b6f5e9b7152cbe83bd741 100644 (file)
@@ -288,15 +288,31 @@ be_tls_init(bool isServerStart)
        if (!initialize_ecdh(context, isServerStart))
                goto error;
 
-       /* set up the allowed cipher list */
-       if (SSL_CTX_set_cipher_list(context, SSLCipherSuites) != 1)
+       /* set up the allowed cipher list for TLSv1.2 and below */
+       if (SSL_CTX_set_cipher_list(context, SSLCipherList) != 1)
        {
                ereport(isServerStart ? FATAL : LOG,
                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                errmsg("could not set the cipher list (no valid ciphers available)")));
+                                errmsg("could not set the TLSv1.2 cipher list (no valid ciphers available)")));
                goto error;
        }
 
+       /*
+        * Set up the allowed cipher suites for TLSv1.3. If the GUC is an empty
+        * string we leave the allowed suites to be the OpenSSL default value.
+        */
+       if (SSLCipherSuites[0])
+       {
+               /* set up the allowed cipher suites */
+               if (SSL_CTX_set_ciphersuites(context, SSLCipherSuites) != 1)
+               {
+                       ereport(isServerStart ? FATAL : LOG,
+                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                                        errmsg("could not set the TLSv1.3 cipher suites (no valid ciphers available)")));
+                       goto error;
+               }
+       }
+
        /* Let server choose order */
        if (SSLPreferServerCiphers)
                SSL_CTX_set_options(context, SSL_OP_CIPHER_SERVER_PREFERENCE);
index ef20ea755b70bdb898a403b408c287d176f8c91d..2139f81f2414e5ab7810715eb72bf4e5eb917659 100644 (file)
@@ -49,6 +49,7 @@ bool          ssl_loaded_verify_locations = false;
 
 /* GUC variable controlling SSL cipher list */
 char      *SSLCipherSuites = NULL;
+char      *SSLCipherList = NULL;
 
 /* GUC variable for default ECHD curve. */
 char      *SSLECDHCurve;
index 859e6658e779edaf6befaa7d641d7403fd209a15..8a67f01200cad1d2dadf1c34714538ffe7bc462e 100644 (file)
@@ -4641,12 +4641,23 @@ struct config_string ConfigureNamesString[] =
        },
 
        {
-               {"ssl_ciphers", PGC_SIGHUP, CONN_AUTH_SSL,
-                       gettext_noop("Sets the list of allowed SSL ciphers."),
+               {"ssl_tls13_ciphers", PGC_SIGHUP, CONN_AUTH_SSL,
+                       gettext_noop("Sets the list of allowed TLSv1.3 cipher suites (leave blank for default)."),
                        NULL,
                        GUC_SUPERUSER_ONLY
                },
                &SSLCipherSuites,
+               "",
+               NULL, NULL, NULL
+       },
+
+       {
+               {"ssl_ciphers", PGC_SIGHUP, CONN_AUTH_SSL,
+                       gettext_noop("Sets the list of allowed TLSv1.2 (and lower) ciphers."),
+                       NULL,
+                       GUC_SUPERUSER_ONLY
+               },
+               &SSLCipherList,
 #ifdef USE_OPENSSL
                "HIGH:MEDIUM:+3DES:!aNULL",
 #else
index 204eab5f1a722bddc683b64befdbf25f3c814059..39a3ac231274bbe24e3fa063a25707903fe51827 100644 (file)
 #ssl_crl_file = ''
 #ssl_crl_dir = ''
 #ssl_key_file = 'server.key'
-#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL'      # allowed SSL ciphers
+#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL'      # allowed TLSv1.2 ciphers
+#ssl_tls13_ciphers = ''        # allowed TLSv1.3 cipher suites, blank for default
 #ssl_prefer_server_ciphers = on
 #ssl_groups = 'prime256v1'
 #ssl_min_protocol_version = 'TLSv1.2'
index 142c98462ed66914c7eb5195002a8a69dbf440f6..d825b4c7b6c7aa00e01dd5485f0bfe56a4338038 100644 (file)
@@ -118,6 +118,7 @@ extern ssize_t secure_open_gssapi(Port *port);
 
 /* GUCs */
 extern PGDLLIMPORT char *SSLCipherSuites;
+extern PGDLLIMPORT char *SSLCipherList;
 extern PGDLLIMPORT char *SSLECDHCurve;
 extern PGDLLIMPORT bool SSLPreferServerCiphers;
 extern PGDLLIMPORT int ssl_min_protocol_version;
index c1b25a4ebf6f4f3067e6bf4ecd92f45142c41087..b8d268e616ce7720535b728e11736c7ab6cc2810 100644 (file)
@@ -300,8 +300,9 @@ sub switch_server_cert
        ok(unlink($node->data_dir . '/sslconfig.conf'));
        $node->append_conf('sslconfig.conf', "ssl=on");
        $node->append_conf('sslconfig.conf', $backend->set_server_cert(\%params));
-       # use lists of ECDH curves for syntax testing
+       # use lists of ECDH curves and cipher suites for syntax testing
        $node->append_conf('sslconfig.conf', 'ssl_groups=prime256v1:secp521r1');
+       $node->append_conf('sslconfig.conf', 'ssl_tls13_ciphers=TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256');
 
        $node->append_conf('sslconfig.conf',
                "ssl_passphrase_command='" . $params{passphrase_cmd} . "'")