On 14/05/2024 01:29, Jacob Champion wrote:
Definitely not a major problem, but I think
select_next_encryption_method() has gone stale, since it originally
provided generality and lines of fallback that no longer exist. In
other words, I think the following code is now misleading:

if (conn->sslmode[0] == 'a')
     SELECT_NEXT_METHOD(ENC_PLAINTEXT);

SELECT_NEXT_METHOD(ENC_NEGOTIATED_SSL);
SELECT_NEXT_METHOD(ENC_DIRECT_SSL);

if (conn->sslmode[0] != 'a')
     SELECT_NEXT_METHOD(ENC_PLAINTEXT);

To me, that implies that negotiated mode takes precedence over direct,
but the point of the patch is that it's not possible to have both. And
if direct SSL is in use, then sslmode can't be "allow" anyway, and we
definitely don't want ENC_PLAINTEXT.

So if someone proposes a change to select_next_encryption_method(),
you'll have to remember to stare at init_allowed_encryption_methods()
as well, and think really hard about what's going on. And vice-versa.
That worries me.

Ok, yeah, I can see that now. Here's a new version to address that. I merged ENC_SSL_NEGOTIATED_SSL and ENC_SSL_DIRECT_SSL to a single method, ENC_SSL. The places that need to distinguish between them now check conn-sslnegotiation. That seems more clear now that there is no fallback.

--
Heikki Linnakangas
Neon (https://neon.tech)
From 7a2bc2ede5ba7bef147e509ce3c4d5472c8e0247 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakan...@iki.fi>
Date: Wed, 15 May 2024 16:27:51 +0300
Subject: [PATCH v2 1/1] Remove option to fall back from direct to postgres SSL
 negotiation

There were three problems with the sslnegotiation options:

1. The sslmode=prefer and sslnegotiation=requiredirect combination was
somewhat dangerous, as you might unintentionally fall back to
plaintext authentication when connecting to a pre-v17 server.

2. There was an asymmetry between 'postgres' and 'direct'
options. 'postgres' meant "try only traditional negotiation", while
'direct' meant "try direct first, and fall back to traditional
negotiation if it fails". That was apparent only if you knew that the
'requiredirect' mode also exists.

3. The "require" word in 'requiredirect' suggests that it's somehow
more strict or more secure, similar to sslmode. However, I don't
consider direct SSL connections to be a security feature.

To address these problems:

- Only allow sslnegotiation='direct' if sslmode='require' or
stronger. And for the record, Jacob and Robert felt that we should do
that (or have sslnegotiation='direct' imply sslmode='require') anyway,
regardless of the first issue.

- Remove the 'direct' mode that falls back to traditional negotiation,
and rename what was called 'requiredirect' to 'direct' instead. In
other words, there is no "try both methods" option anymore, 'postgres'
now means the traditional negotiation and 'direct' means a direct SSL
connection.

Reviewed-by: Jelte Fennema-Nio, Robert Haas, Jacob Champion
Discussion: https://www.postgresql.org/message-id/d3b1608a-a1b6-4eda-9ec5-ddb3e4375808%40iki.fi
---
 doc/src/sgml/libpq.sgml                       |  49 ++--
 src/interfaces/libpq/fe-connect.c             | 144 +++++-----
 src/interfaces/libpq/fe-secure-openssl.c      |   2 +-
 src/interfaces/libpq/libpq-int.h              |   6 +-
 .../libpq/t/005_negotiate_encryption.pl       | 254 ++++++++----------
 5 files changed, 202 insertions(+), 253 deletions(-)

diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 1d32c226d8..b32e497b1b 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1772,15 +1772,18 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
       <term><literal>sslnegotiation</literal></term>
       <listitem>
        <para>
-        This option controls whether <productname>PostgreSQL</productname>
-        will perform its protocol negotiation to request encryption from the
-        server or will just directly make a standard <acronym>SSL</acronym>
-        connection.  Traditional <productname>PostgreSQL</productname>
-        protocol negotiation is the default and the most flexible with
-        different server configurations. If the server is known to support
-        direct <acronym>SSL</acronym> connections then the latter requires one
-        fewer round trip reducing connection latency and also allows the use
-        of protocol agnostic SSL network tools.
+        This option controls how SSL encryption is negotiated with the server,
+        if SSL is used. In the default <literal>postgres</literal> mode, the
+        client first asks the server if SSL is supported. In
+        <literal>direct</literal> mode, the client starts the standard SSL
+        handshake directly after establishing the TCP/IP connection. Traditional
+        <productname>PostgreSQL</productname> protocol negotiation is the most
+        flexible with different server configurations. If the server is known
+        to support direct <acronym>SSL</acronym> connections then the latter
+        requires one fewer round trip reducing connection latency and also
+        allows the use of protocol agnostic SSL network tools. The direct SSL
+        option was introduced in <productname>PostgreSQL</productname> version
+        17.
        </para>
 
         <variablelist>
@@ -1798,32 +1801,14 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
           <term><literal>direct</literal></term>
           <listitem>
            <para>
-             first attempt to establish a standard SSL connection and if that
-             fails reconnect and perform the negotiation. This fallback
-             process adds significant latency if the initial SSL connection
-             fails.
-           </para>
-           <para>
-             An exception is if <literal>gssencmode</literal> is set
-             to <literal>prefer</literal>, but the server rejects GSS encryption.
-             In that case, SSL is negotiated over the same TCP connection using
-             <productname>PostgreSQL</productname> protocol negotiation. In
-             other words, the direct SSL handshake is not used, if a TCP
-             connection has already been established and can be used for the
+             start SSL handshake directly after establishing the TCP/IP
+             connection.  This is only allowed with sslmode=require or higher,
+             because the weaker settings could lead to unintended fallback to
+             plaintext authentication when the server does not support direct
              SSL handshake.
            </para>
           </listitem>
          </varlistentry>
-
-         <varlistentry>
-          <term><literal>requiredirect</literal></term>
-          <listitem>
-           <para>
-             attempt to establish a standard SSL connection and if that fails
-             return a connection failure immediately.
-           </para>
-          </listitem>
-         </varlistentry>
         </variablelist>
       </listitem>
      </varlistentry>
@@ -2064,7 +2049,7 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
         connections without having to decrypt the SSL stream.  (Note that
         unless the proxy is aware of the PostgreSQL protocol handshake this
         would require setting <literal>sslnegotiation</literal>
-        to <literal>direct</literal> or <literal>requiredirect</literal>.)
+        to <literal>direct</literal>.)
         However, <acronym>SNI</acronym> makes the destination host name appear
         in cleartext in the network traffic, so it might be undesirable in
         some cases.
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 81d278c395..85f55b14a9 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -274,7 +274,7 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
 	offsetof(struct pg_conn, sslmode)},
 
 	{"sslnegotiation", "PGSSLNEGOTIATION", DefaultSSLNegotiation, NULL,
-		"SSL-Negotiation", "", 14,	/* sizeof("requiredirect") == 14 */
+		"SSL-Negotiation", "", 9,	/* sizeof("postgres") == 9  */
 	offsetof(struct pg_conn, sslnegotiation)},
 
 	{"sslcompression", "PGSSLCOMPRESSION", "0", NULL,
@@ -1590,8 +1590,7 @@ pqConnectOptions2(PGconn *conn)
 	if (conn->sslnegotiation)
 	{
 		if (strcmp(conn->sslnegotiation, "postgres") != 0
-			&& strcmp(conn->sslnegotiation, "direct") != 0
-			&& strcmp(conn->sslnegotiation, "requiredirect") != 0)
+			&& strcmp(conn->sslnegotiation, "direct") != 0)
 		{
 			conn->status = CONNECTION_BAD;
 			libpq_append_conn_error(conn, "invalid %s value: \"%s\"",
@@ -1608,6 +1607,25 @@ pqConnectOptions2(PGconn *conn)
 			return false;
 		}
 #endif
+
+		/*
+		 * Don't allow direct SSL negotiation with sslmode='prefer', because
+		 * that poses a risk of unintentional fallback to plaintext connection
+		 * when connecting to a pre-v17 server that does not support direct
+		 * SSL connections. To keep things simple, don't allow it with
+		 * sslmode='allow' or sslmode='disable' either. If a user goes through
+		 * the trouble of setting sslnegotiation='direct', they probably
+		 * intend to use SSL, and sslmode=disable or allow is probably a user
+		 * user mistake anyway.
+		 */
+		if (conn->sslnegotiation[0] == 'd' &&
+			conn->sslmode[0] != 'r' && conn->sslmode[0] != 'v')
+		{
+			conn->status = CONNECTION_BAD;
+			libpq_append_conn_error(conn, "weak sslmode \"%s\" may not be used with sslnegotiation=direct (use \"require\", \"verify-ca\", or \"verify-full\")",
+									conn->sslmode);
+			return false;
+		}
 	}
 	else
 	{
@@ -3347,42 +3365,47 @@ keep_going:						/* We will come back to here until there is
 					goto error_return;
 
 				/*
-				 * If direct SSL is enabled, jump right into SSL handshake. We
-				 * will come back here after SSL encryption has been
-				 * established, with ssl_in_use set.
-				 */
-				if (conn->current_enc_method == ENC_DIRECT_SSL && !conn->ssl_in_use)
-				{
-					conn->status = CONNECTION_SSL_STARTUP;
-					return PGRES_POLLING_WRITING;
-				}
-
-				/*
-				 * If negotiated SSL is enabled, request SSL and proceed with
-				 * SSL handshake.  We will come back here after SSL encryption
-				 * has been established, with ssl_in_use set.
+				 * If SSL is enabled, start the SSL negotiation. We will come
+				 * back here after SSL encryption has been established, with
+				 * ssl_in_use set.
 				 */
-				if (conn->current_enc_method == ENC_NEGOTIATED_SSL && !conn->ssl_in_use)
+				if (conn->current_enc_method == ENC_SSL && !conn->ssl_in_use)
 				{
-					ProtocolVersion pv;
-
 					/*
-					 * Send the SSL request packet.
-					 *
-					 * Theoretically, this could block, but it really
-					 * shouldn't since we only got here if the socket is
-					 * write-ready.
+					 * If traditional postgres SSL negotiation is used, send
+					 * the SSL request.  In direct negotiation, jump straight
+					 * into the SSL handshake.
 					 */
-					pv = pg_hton32(NEGOTIATE_SSL_CODE);
-					if (pqPacketSend(conn, 0, &pv, sizeof(pv)) != STATUS_OK)
+					if (conn->sslnegotiation[0] == 'p')
 					{
-						libpq_append_conn_error(conn, "could not send SSL negotiation packet: %s",
-												SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
-						goto error_return;
+						ProtocolVersion pv;
+
+						Assert(conn->sslnegotiation[0] == 'p');
+
+						/*
+						 * Send the SSL request packet.
+						 *
+						 * Theoretically, this could block, but it really
+						 * shouldn't since we only got here if the socket is
+						 * write-ready.
+						 */
+						pv = pg_hton32(NEGOTIATE_SSL_CODE);
+						if (pqPacketSend(conn, 0, &pv, sizeof(pv)) != STATUS_OK)
+						{
+							libpq_append_conn_error(conn, "could not send SSL negotiation packet: %s",
+													SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
+							goto error_return;
+						}
+						/* Ok, wait for response */
+						conn->status = CONNECTION_SSL_STARTUP;
+						return PGRES_POLLING_READING;
+					}
+					else
+					{
+						Assert(conn->sslnegotiation[0] == 'd');
+						conn->status = CONNECTION_SSL_STARTUP;
+						return PGRES_POLLING_WRITING;
 					}
-					/* Ok, wait for response */
-					conn->status = CONNECTION_SSL_STARTUP;
-					return PGRES_POLLING_READING;
 				}
 #endif							/* USE_SSL */
 
@@ -3453,11 +3476,11 @@ keep_going:						/* We will come back to here until there is
 				PostgresPollingStatusType pollres;
 
 				/*
-				 * On first time through, get the postmaster's response to our
-				 * SSL negotiation packet. If we are trying a direct ssl
-				 * connection, go straight to initiating ssl.
+				 * On first time through with traditional SSL negotiation, get
+				 * the postmaster's response to our SSLRequest packet. With
+				 * sslnegotiation='direct', go straight to initiating SSL.
 				 */
-				if (!conn->ssl_in_use && conn->current_enc_method == ENC_NEGOTIATED_SSL)
+				if (!conn->ssl_in_use && conn->sslnegotiation[0] == 'p')
 				{
 					/*
 					 * We use pqReadData here since it has the logic to
@@ -4282,7 +4305,7 @@ init_allowed_encryption_methods(PGconn *conn)
 	if (conn->raddr.addr.ss_family == AF_UNIX)
 	{
 		/* Don't request SSL or GSSAPI over Unix sockets */
-		conn->allowed_enc_methods &= ~(ENC_DIRECT_SSL | ENC_NEGOTIATED_SSL | ENC_GSSAPI);
+		conn->allowed_enc_methods &= ~(ENC_SSL | ENC_GSSAPI);
 
 		/*
 		 * XXX: we probably should not do this. sslmode=require works
@@ -4309,12 +4332,7 @@ init_allowed_encryption_methods(PGconn *conn)
 	/* sslmode anything but 'disable', and GSSAPI not required */
 	if (conn->sslmode[0] != 'd' && conn->gssencmode[0] != 'r')
 	{
-		if (conn->sslnegotiation[0] == 'p')
-			conn->allowed_enc_methods |= ENC_NEGOTIATED_SSL;
-		else if (conn->sslnegotiation[0] == 'd')
-			conn->allowed_enc_methods |= ENC_DIRECT_SSL | ENC_NEGOTIATED_SSL;
-		else if (conn->sslnegotiation[0] == 'r')
-			conn->allowed_enc_methods |= ENC_DIRECT_SSL;
+		conn->allowed_enc_methods |= ENC_SSL;
 	}
 #endif
 
@@ -4354,7 +4372,8 @@ encryption_negotiation_failed(PGconn *conn)
 
 	if (select_next_encryption_method(conn, true))
 	{
-		if (conn->current_enc_method == ENC_DIRECT_SSL)
+		/* An existing connection cannot be reused for direct SSL */
+		if (conn->current_enc_method == ENC_SSL && conn->sslnegotiation[0] == 'd')
 			return 2;
 		else
 			return 1;
@@ -4376,18 +4395,6 @@ connection_failed(PGconn *conn)
 	Assert((conn->failed_enc_methods & conn->current_enc_method) == 0);
 	conn->failed_enc_methods |= conn->current_enc_method;
 
-	/*
-	 * If the server reported an error after the SSL handshake, no point in
-	 * retrying with negotiated vs direct SSL.
-	 */
-	if ((conn->current_enc_method & (ENC_DIRECT_SSL | ENC_NEGOTIATED_SSL)) != 0 &&
-		conn->ssl_handshake_started)
-	{
-		conn->failed_enc_methods |= (ENC_DIRECT_SSL | ENC_NEGOTIATED_SSL) & conn->allowed_enc_methods;
-	}
-	else
-		conn->failed_enc_methods |= conn->current_enc_method;
-
 	return select_next_encryption_method(conn, false);
 }
 
@@ -4445,24 +4452,17 @@ select_next_encryption_method(PGconn *conn, bool have_valid_connection)
 	SELECT_NEXT_METHOD(ENC_GSSAPI);
 #endif
 
-	/* With sslmode=allow, try plaintext connection before SSL. */
-	if (conn->sslmode[0] == 'a')
-		SELECT_NEXT_METHOD(ENC_PLAINTEXT);
-
 	/*
-	 * If enabled, try direct SSL. Unless we have a valid TCP connection that
-	 * failed negotiating GSSAPI encryption; in that case we prefer to reuse
-	 * the connection with negotiated SSL, instead of reconnecting to do
-	 * direct SSL. The point of sslnegotiation=direct is to avoid the
-	 * roundtrip from the negotiation, but reconnecting would also incur a
-	 * roundtrip. (In sslnegotiation=requiredirect mode, negotiated SSL is not
-	 * in the list of allowed methods and we will reconnect.)
+	 * The order between SSL encryption and plaintext depends on sslmode. With
+	 * sslmode=allow, try plaintext connection before SSL. With
+	 * sslmode=prefer, it's the other way round. With other modes, we only try
+	 * plaintext or SSL connections so the order they're listed here doesn't
+	 * matter.
 	 */
-	if (have_valid_connection)
-		SELECT_NEXT_METHOD(ENC_NEGOTIATED_SSL);
+	if (conn->sslmode[0] == 'a')
+		SELECT_NEXT_METHOD(ENC_PLAINTEXT);
 
-	SELECT_NEXT_METHOD(ENC_DIRECT_SSL);
-	SELECT_NEXT_METHOD(ENC_NEGOTIATED_SSL);
+	SELECT_NEXT_METHOD(ENC_SSL);
 
 	if (conn->sslmode[0] != 'a')
 		SELECT_NEXT_METHOD(ENC_PLAINTEXT);
diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c
index fb6bb911f5..bf9dfbf918 100644
--- a/src/interfaces/libpq/fe-secure-openssl.c
+++ b/src/interfaces/libpq/fe-secure-openssl.c
@@ -1586,7 +1586,7 @@ open_client_SSL(PGconn *conn)
 	}
 
 	/* ALPN is mandatory with direct SSL connections */
-	if (conn->current_enc_method == ENC_DIRECT_SSL)
+	if (conn->current_enc_method == ENC_SSL && conn->sslnegotiation[0] == 'd')
 	{
 		const unsigned char *selected;
 		unsigned int len;
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 3691e5ee96..3886204c70 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -235,8 +235,7 @@ typedef enum
 #define ENC_ERROR			0
 #define ENC_PLAINTEXT		0x01
 #define ENC_GSSAPI			0x02
-#define ENC_DIRECT_SSL		0x04
-#define ENC_NEGOTIATED_SSL	0x08
+#define ENC_SSL				0x04
 
 /* Target server type (decoded value of target_session_attrs) */
 typedef enum
@@ -395,8 +394,7 @@ struct pg_conn
 	char	   *keepalives_count;	/* maximum number of TCP keepalive
 									 * retransmits */
 	char	   *sslmode;		/* SSL mode (require,prefer,allow,disable) */
-	char	   *sslnegotiation; /* SSL initiation style
-								 * (postgres,direct,requiredirect) */
+	char	   *sslnegotiation; /* SSL initiation style (postgres,direct) */
 	char	   *sslcompression; /* SSL compression (0 or 1) */
 	char	   *sslkey;			/* client key filename */
 	char	   *sslcert;		/* client certificate filename */
diff --git a/src/interfaces/libpq/t/005_negotiate_encryption.pl b/src/interfaces/libpq/t/005_negotiate_encryption.pl
index bc19cd244b..c3f70d31bc 100644
--- a/src/interfaces/libpq/t/005_negotiate_encryption.pl
+++ b/src/interfaces/libpq/t/005_negotiate_encryption.pl
@@ -213,7 +213,7 @@ my @all_test_users =
   ('testuser', 'ssluser', 'nossluser', 'gssuser', 'nogssuser');
 my @all_gssencmodes = ('disable', 'prefer', 'require');
 my @all_sslmodes = ('disable', 'allow', 'prefer', 'require');
-my @all_sslnegotiations = ('postgres', 'direct', 'requiredirect');
+my @all_sslnegotiations = ('postgres', 'direct');
 
 my $server_config = {
 	server_ssl => 0,
@@ -228,23 +228,22 @@ if ($ssl_supported)
 {
 	$test_table = q{
 # USER      GSSENCMODE   SSLMODE      SSLNEGOTIATION EVENTS                      -> OUTCOME
-testuser    disable      disable      *              connect, authok             -> plain
-.           .            allow        *              connect, authok             -> plain
+testuser    disable      disable      postgres       connect, authok             -> plain
+.           .            allow        postgres       connect, authok             -> plain
 .           .            prefer       postgres       connect, sslreject, authok  -> plain
-.           .            .            direct         connect, directsslreject, reconnect, sslreject, authok  -> plain
-.           .            .            requiredirect  connect, directsslreject, reconnect, authok -> plain
 .           .            require      postgres       connect, sslreject          -> fail
-.           .            .            direct         connect, directsslreject, reconnect, sslreject -> fail
-.           .            .            requiredirect  connect, directsslreject    -> fail
-.           prefer       disable      *              connect, authok             -> plain
-.           .            allow        *              connect, authok             -> plain
+.           .            .            direct         connect, directsslreject    -> fail
+.           prefer       disable      postgres       connect, authok             -> plain
+.           .            allow        postgres       connect, authok             -> plain
 .           .            prefer       postgres       connect, sslreject, authok  -> plain
-.           .            .            direct         connect, directsslreject, reconnect, sslreject, authok  -> plain
-.           .            .            requiredirect  connect, directsslreject, reconnect, authok -> plain
 .           .            require      postgres       connect, sslreject          -> fail
-.           .            .            direct         connect, directsslreject, reconnect, sslreject -> fail
-.           .            .            requiredirect  connect, directsslreject    -> fail
-	};
+.           .            .            direct         connect, directsslreject    -> fail
+
+# sslnegotiation=direct is not acccepted unless sslmode=require or stronger
+*           *            disable      direct         -     -> fail
+*           *            allow        direct         -     -> fail
+*           *            prefer       direct         -     -> fail
+};
 }
 else
 {
@@ -258,11 +257,10 @@ testuser    disable      disable      postgres       connect, authok
 .           .            allow        postgres       connect, authok             -> plain
 .           .            prefer       postgres       connect, authok             -> plain
 
-# Without SSL support, sslmode=require and sslnegotiation=direct/requiredirect
-# are not accepted at all.
-.           *            require      *              -     -> fail
-.           *            *            direct         -     -> fail
-.           *            *            requiredirect  -     -> fail
+# Without SSL support, sslmode=require and sslnegotiation=direct are
+# not accepted at all
+*           *            require      *              -     -> fail
+*           *            *            direct         -     -> fail
 	};
 }
 
@@ -288,34 +286,26 @@ SKIP:
 
 	$test_table = q{
 # USER      GSSENCMODE   SSLMODE      SSLNEGOTIATION EVENTS                                          -> OUTCOME
-testuser    disable      disable      *              connect, authok                                 -> plain
-.           .            allow        *              connect, authok                                 -> plain
+testuser    disable      disable      postgres       connect, authok                                 -> plain
+.           .            allow        postgres       connect, authok                                 -> plain
 .           .            prefer       postgres       connect, sslaccept, authok                      -> ssl
-.           .            .            direct         connect, directsslaccept, authok                -> ssl
-.           .            .            requiredirect  connect, directsslaccept, authok                -> ssl
 .           .            require      postgres       connect, sslaccept, authok                      -> ssl
 .           .            .            direct         connect, directsslaccept, authok                -> ssl
-.           .            .            requiredirect  connect, directsslaccept, authok                -> ssl
-ssluser     .            disable      *              connect, authfail                               -> fail
+ssluser     .            disable      postgres       connect, authfail                               -> fail
 .           .            allow        postgres       connect, authfail, reconnect, sslaccept, authok -> ssl
-.           .            .            direct         connect, authfail, reconnect, directsslaccept, authok -> ssl
-.           .            .            requiredirect  connect, authfail, reconnect, directsslaccept, authok -> ssl
 .           .            prefer       postgres       connect, sslaccept, authok                      -> ssl
-.           .            .            direct         connect, directsslaccept, authok                -> ssl
-.           .            .            requiredirect  connect, directsslaccept, authok                -> ssl
 .           .            require      postgres       connect, sslaccept, authok                      -> ssl
 .           .            .            direct         connect, directsslaccept, authok                -> ssl
-.           .            .            requiredirect  connect, directsslaccept, authok                -> ssl
-nossluser   .            disable      *              connect, authok                                 -> plain
+nossluser   .            disable      postgres       connect, authok                                 -> plain
 .           .            allow        postgres       connect, authok                                 -> plain
-.           .            .            direct         connect, authok                                 -> plain
-.           .            .            requiredirect  connect, authok                                 -> plain
 .           .            prefer       postgres       connect, sslaccept, authfail, reconnect, authok -> plain
-.           .            .            direct         connect, directsslaccept, authfail, reconnect, authok -> plain
-.           .            .            requiredirect  connect, directsslaccept, authfail, reconnect, authok -> plain
 .           .            require      postgres       connect, sslaccept, authfail                    -> fail
 .           .            require      direct         connect, directsslaccept, authfail              -> fail
-.           .            require      requiredirect  connect, directsslaccept, authfail              -> fail
+
+# sslnegotiation=direct is not acccepted unless sslmode=require or stronger
+*           *            disable      direct         -     -> fail
+*           *            allow        direct         -     -> fail
+*           *            prefer       direct         -     -> fail
 };
 
 	# Enable SSL in the server
@@ -350,62 +340,54 @@ SKIP:
 
 	$test_table = q{
 # USER      GSSENCMODE   SSLMODE      SSLNEGOTIATION EVENTS                       -> OUTCOME
-testuser    disable      disable      *              connect, authok              -> plain
-.           .            allow        *              connect, authok              -> plain
+testuser    disable      disable      postgres       connect, authok              -> plain
+.           .            allow        postgres       connect, authok              -> plain
 .           .            prefer       postgres       connect, sslreject, authok   -> plain
-.           .            .            direct         connect, directsslreject, reconnect, sslreject, authok  -> plain
-.           .            .            requiredirect  connect, directsslreject, reconnect, authok             -> plain
 .           .            require      postgres       connect, sslreject                -> fail
-.           .            .            direct         connect, directsslreject, reconnect, sslreject -> fail
-.           .            .            requiredirect  connect, directsslreject          -> fail
-.           prefer       *            *              connect, gssaccept, authok        -> gss
-.           require      *            *              connect, gssaccept, authok        -> gss
+.           .            .            direct         connect, directsslreject          -> fail
+.           prefer       *            postgres       connect, gssaccept, authok        -> gss
+.           prefer       require      direct         connect, gssaccept, authok        -> gss
+.           require      *            postgres       connect, gssaccept, authok        -> gss
+.           .            require      direct         connect, gssaccept, authok        -> gss
 
-gssuser     disable      disable      *              connect, authfail                  -> fail
+gssuser     disable      disable      postgres       connect, authfail                  -> fail
 .           .            allow        postgres       connect, authfail, reconnect, sslreject -> fail
-.           .            .            direct         connect, authfail, reconnect, directsslreject, reconnect, sslreject -> fail
-.           .            .            requiredirect  connect, authfail, reconnect, directsslreject -> fail
 .           .            prefer       postgres       connect, sslreject, authfail       -> fail
-.           .            .            direct         connect, directsslreject, reconnect, sslreject, authfail -> fail
-.           .            .            requiredirect  connect, directsslreject, reconnect, authfail -> fail
 .           .            require      postgres       connect, sslreject                 -> fail
-.           .            .            direct         connect, directsslreject, reconnect, sslreject -> fail
-.           .            .            requiredirect  connect, directsslreject           -> fail
-.           prefer       *            *              connect, gssaccept, authok   -> gss
-.           require      *            *              connect, gssaccept, authok   -> gss
+.           .            .            direct         connect, directsslreject           -> fail
+.           prefer       *            postgres       connect, gssaccept, authok   -> gss
+.           prefer       require      direct         connect, gssaccept, authok   -> gss
+.           require      *            postgres       connect, gssaccept, authok   -> gss
+.           .            require      direct         connect, gssaccept, authok   -> gss
 
-nogssuser   disable      disable      *              connect, authok              -> plain
+nogssuser   disable      disable      postgres       connect, authok              -> plain
 .           .            allow        postgres       connect, authok              -> plain
-.           .            .            direct         connect, authok              -> plain
-.           .            .            requiredirect  connect, authok              -> plain
 .           .            prefer       postgres       connect, sslreject, authok   -> plain
-.           .            .            direct         connect, directsslreject, reconnect, sslreject, authok   -> plain
-.           .            .            requiredirect  connect, directsslreject, reconnect, authok              -> plain
 .           .            require      postgres       connect, sslreject                 -> fail
-.           .            .            direct         connect, directsslreject, reconnect, sslreject -> fail
-.           .            .            requiredirect  connect, directsslreject           -> fail
-.           prefer       disable      *              connect, gssaccept, authfail, reconnect, authok             -> plain
+.           .            .            direct         connect, directsslreject           -> fail
+.           prefer       disable      postgres       connect, gssaccept, authfail, reconnect, authok             -> plain
 .           .            allow        postgres       connect, gssaccept, authfail, reconnect, authok             -> plain
-.           .            .            direct         connect, gssaccept, authfail, reconnect, authok             -> plain
-.           .            .            requiredirect  connect, gssaccept, authfail, reconnect, authok             -> plain
 .           .            prefer       postgres       connect, gssaccept, authfail, reconnect, sslreject, authok  -> plain
-.           .            .            direct         connect, gssaccept, authfail, reconnect, directsslreject, reconnect, sslreject, authok  -> plain
-.           .            .            requiredirect  connect, gssaccept, authfail, reconnect, directsslreject, reconnect, authok  -> plain
 .           .            require      postgres       connect, gssaccept, authfail, reconnect, sslreject          -> fail
-.           .            .            direct         connect, gssaccept, authfail, reconnect, directsslreject, reconnect, sslreject          -> fail
-.           .            .            requiredirect  connect, gssaccept, authfail, reconnect, directsslreject          -> fail
-.           require      disable      *              connect, gssaccept, authfail -> fail
-.           .            allow        *              connect, gssaccept, authfail -> fail
-.           .            prefer       *              connect, gssaccept, authfail -> fail
-.           .            require      *              connect, gssaccept, authfail -> fail   # If both GSSAPI and sslmode are required, and GSS is not available -> fail
+.           .            .            direct         connect, gssaccept, authfail, reconnect, directsslreject          -> fail
+.           require      disable      postgres       connect, gssaccept, authfail -> fail
+.           .            allow        postgres       connect, gssaccept, authfail -> fail
+.           .            prefer       postgres       connect, gssaccept, authfail -> fail
+.           .            require      postgres       connect, gssaccept, authfail -> fail   # If both GSSAPI and sslmode are required, and GSS is not available -> fail
+.           .            .            direct         connect, gssaccept, authfail -> fail   # If both GSSAPI and sslmode are required, and GSS is not available -> fail
+
+# sslnegotiation=direct is not acccepted unless sslmode=require or stronger
+*           *            disable      direct         -     -> fail
+*           *            allow        direct         -     -> fail
+*           *            prefer       direct         -     -> fail
 	};
 
 	# The expected events and outcomes above assume that SSL support
 	# is enabled. When libpq is compiled without SSL support, all
 	# attempts to connect with sslmode=require or
-	# sslnegotiation=direct/requiredirect would fail immediately without
-	# even connecting to the server. Skip those, because we tested
-	# them earlier already.
+	# sslnegotiation=direct would fail immediately without even
+	# connecting to the server. Skip those, because we tested them
+	# earlier already.
 	my ($sslmodes, $sslnegotiations);
 	if ($ssl_supported != 0)
 	{
@@ -445,100 +427,84 @@ SKIP:
 
 	$test_table = q{
 # USER      GSSENCMODE   SSLMODE      SSLNEGOTIATION EVENTS                       -> OUTCOME
-testuser    disable      disable      *              connect, authok              -> plain
-.           .            allow        *              connect, authok              -> plain
-.           .            prefer       postgres       connect, sslaccept, authok         -> ssl
-.           .            .            direct         connect, directsslaccept, authok   -> ssl
-.           .            .            requiredirect  connect, directsslaccept, authok   -> ssl
-.           .            require      postgres       connect, sslaccept, authok         -> ssl
+testuser    disable      disable      postgres       connect, authok              -> plain
+.           .            allow        postgres       connect, authok              -> plain
+.           .            prefer       postgres       connect, sslaccept, authok   -> ssl
+.           .            require      postgres       connect, sslaccept, authok   -> ssl
 .           .            .            direct         connect, directsslaccept, authok   -> ssl
-.           .            .            requiredirect  connect, directsslaccept, authok   -> ssl
-.           prefer       disable      *              connect, gssaccept, authok   -> gss
-.           .            allow        *              connect, gssaccept, authok   -> gss
-.           .            prefer       *              connect, gssaccept, authok   -> gss
-.           .            require      *              connect, gssaccept, authok   -> gss     # If both GSS and SSL is possible, GSS is chosen over SSL, even if sslmode=require
-.           require      disable      *              connect, gssaccept, authok   -> gss
-.           .            allow        *              connect, gssaccept, authok   -> gss
-.           .            prefer       *              connect, gssaccept, authok   -> gss
-.           .            require      *              connect, gssaccept, authok   -> gss     # If both GSS and SSL is possible, GSS is chosen over SSL, even if sslmode=require
-
-gssuser     disable      disable      *              connect, authfail            -> fail
+.           prefer       disable      postgres       connect, gssaccept, authok   -> gss
+.           .            allow        postgres       connect, gssaccept, authok   -> gss
+.           .            prefer       postgres       connect, gssaccept, authok   -> gss
+.           .            require      postgres       connect, gssaccept, authok   -> gss     # If both GSS and SSL is possible, GSS is chosen over SSL, even if sslmode=require
+.           .            .            direct         connect, gssaccept, authok   -> gss
+.           require      disable      postgres       connect, gssaccept, authok   -> gss
+.           .            allow        postgres       connect, gssaccept, authok   -> gss
+.           .            prefer       postgres       connect, gssaccept, authok   -> gss
+.           .            require      postgres       connect, gssaccept, authok   -> gss     # If both GSS and SSL is possible, GSS is chosen over SSL, even if sslmode=require
+.           .            .            direct         connect, gssaccept, authok   -> gss
+
+gssuser     disable      disable      postgres       connect, authfail            -> fail
 .           .            allow        postgres       connect, authfail, reconnect, sslaccept, authfail -> fail
-.           .            .            direct         connect, authfail, reconnect, directsslaccept, authfail -> fail
-.           .            .            requiredirect  connect, authfail, reconnect, directsslaccept, authfail -> fail
 .           .            prefer       postgres       connect, sslaccept, authfail, reconnect, authfail -> fail
-.           .            .            direct         connect, directsslaccept, authfail, reconnect, authfail -> fail
-.           .            .            requiredirect  connect, directsslaccept, authfail, reconnect, authfail -> fail
 .           .            require      postgres       connect, sslaccept, authfail       -> fail
 .           .            .            direct         connect, directsslaccept, authfail -> fail
-.           .            .            requiredirect  connect, directsslaccept, authfail -> fail
-.           prefer       disable      *              connect, gssaccept, authok   -> gss
-.           .            allow        *              connect, gssaccept, authok   -> gss
-.           .            prefer       *              connect, gssaccept, authok   -> gss
-.           .            require      *              connect, gssaccept, authok   -> gss   # GSS is chosen over SSL, even though sslmode=require
-.           require      disable      *              connect, gssaccept, authok   -> gss
-.           .            allow        *              connect, gssaccept, authok   -> gss
-.           .            prefer       *              connect, gssaccept, authok   -> gss
-.           .            require      *              connect, gssaccept, authok   -> gss     # If both GSS and SSL is possible, GSS is chosen over SSL, even if sslmode=require
-
-ssluser     disable      disable      *              connect, authfail            -> fail
+.           prefer       disable      postgres       connect, gssaccept, authok   -> gss
+.           .            allow        postgres       connect, gssaccept, authok   -> gss
+.           .            prefer       postgres       connect, gssaccept, authok   -> gss
+.           .            require      postgres       connect, gssaccept, authok   -> gss   # GSS is chosen over SSL, even though sslmode=require
+.           .            .            direct         connect, gssaccept, authok   -> gss
+.           require      disable      postgres       connect, gssaccept, authok   -> gss
+.           .            allow        postgres       connect, gssaccept, authok   -> gss
+.           .            prefer       postgres       connect, gssaccept, authok   -> gss
+.           .            require      postgres       connect, gssaccept, authok   -> gss     # If both GSS and SSL is possible, GSS is chosen over SSL, even if sslmode=require
+.           .            .            direct         connect, gssaccept, authok   -> gss
+
+ssluser     disable      disable      postgres       connect, authfail            -> fail
 .           .            allow        postgres       connect, authfail, reconnect, sslaccept, authok       -> ssl
-.           .            .            direct         connect, authfail, reconnect, directsslaccept, authok -> ssl
-.           .            .            requiredirect  connect, authfail, reconnect, directsslaccept, authok -> ssl
 .           .            prefer       postgres       connect, sslaccept, authok         -> ssl
-.           .            .            direct         connect, directsslaccept, authok   -> ssl
-.           .            .            requiredirect  connect, directsslaccept, authok   -> ssl
 .           .            require      postgres       connect, sslaccept, authok         -> ssl
 .           .            .            direct         connect, directsslaccept, authok   -> ssl
-.           .            .            requiredirect  connect, directsslaccept, authok   -> ssl
-.           prefer       disable      *              connect, gssaccept, authfail, reconnect, authfail -> fail
+.           prefer       disable      postgres       connect, gssaccept, authfail, reconnect, authfail -> fail
 .           .            allow        postgres       connect, gssaccept, authfail, reconnect, authfail, reconnect, sslaccept, authok       -> ssl
-.           .            .            direct         connect, gssaccept, authfail, reconnect, authfail, reconnect, directsslaccept, authok -> ssl
-.           .            .            requiredirect  connect, gssaccept, authfail, reconnect, authfail, reconnect, directsslaccept, authok -> ssl
 .           .            prefer       postgres       connect, gssaccept, authfail, reconnect, sslaccept, authok       -> ssl
-.           .            .            direct         connect, gssaccept, authfail, reconnect, directsslaccept, authok -> ssl
-.           .            .            requiredirect  connect, gssaccept, authfail, reconnect, directsslaccept, authok -> ssl
 .           .            require      postgres       connect, gssaccept, authfail, reconnect, sslaccept, authok       -> ssl
 .           .            .            direct         connect, gssaccept, authfail, reconnect, directsslaccept, authok -> ssl
-.           .            .            requiredirect  connect, gssaccept, authfail, reconnect, directsslaccept, authok -> ssl
-.           require      disable      *              connect, gssaccept, authfail -> fail
-.           .            allow        *              connect, gssaccept, authfail -> fail
-.           .            prefer       *              connect, gssaccept, authfail -> fail
-.           .            require      *              connect, gssaccept, authfail -> fail         # If both GSS and SSL are required, the sslmode=require is effectively ignored and GSS is required
+.           require      disable      postgres       connect, gssaccept, authfail -> fail
+.           .            allow        postgres       connect, gssaccept, authfail -> fail
+.           .            prefer       postgres       connect, gssaccept, authfail -> fail
+.           .            require      postgres       connect, gssaccept, authfail -> fail         # If both GSS and SSL are required, the sslmode=require is effectively ignored and GSS is required
+.           .            .            direct         connect, gssaccept, authfail -> fail
 
-nogssuser   disable      disable      *              connect, authok              -> plain
+nogssuser   disable      disable      postgres       connect, authok              -> plain
 .           .            allow        postgres       connect, authok              -> plain
-.           .            .            direct         connect, authok              -> plain
-.           .            .            requiredirect  connect, authok              -> plain
 .           .            prefer       postgres       connect, sslaccept, authok   -> ssl
-.           .            .            direct         connect, directsslaccept, authok   -> ssl
-.           .            .            requiredirect  connect, directsslaccept, authok   -> ssl
 .           .            require      postgres       connect, sslaccept, authok   -> ssl
 .           .            .            direct         connect, directsslaccept, authok   -> ssl
-.           .            .            requiredirect  connect, directsslaccept, authok   -> ssl
-.           prefer       disable      *              connect, gssaccept, authfail, reconnect, authok              -> plain
-.           .            allow        *              connect, gssaccept, authfail, reconnect, authok              -> plain
+.           prefer       disable      postgres       connect, gssaccept, authfail, reconnect, authok              -> plain
+.           .            allow        postgres       connect, gssaccept, authfail, reconnect, authok              -> plain
 .           .            prefer       postgres       connect, gssaccept, authfail, reconnect, sslaccept, authok         -> ssl
-.           .            .            direct         connect, gssaccept, authfail, reconnect, directsslaccept, authok   -> ssl
-.           .            .            requiredirect  connect, gssaccept, authfail, reconnect, directsslaccept, authok   -> ssl
 .           .            require      postgres       connect, gssaccept, authfail, reconnect, sslaccept, authok         -> ssl
 .           .            .            direct         connect, gssaccept, authfail, reconnect, directsslaccept, authok   -> ssl
-.           .            .            requiredirect  connect, gssaccept, authfail, reconnect, directsslaccept, authok   -> ssl
-.           require      disable      *              connect, gssaccept, authfail -> fail
-.           .            allow        *              connect, gssaccept, authfail -> fail
-.           .            prefer       *              connect, gssaccept, authfail -> fail
-.           .            require      *              connect, gssaccept, authfail -> fail   # If both GSS and SSL are required, the sslmode=require is effectively ignored and GSS is required
-
-nossluser   disable      disable      *              connect, authok              -> plain
-.           .            allow        *              connect, authok              -> plain
+.           require      disable      postgres       connect, gssaccept, authfail -> fail
+.           .            allow        postgres       connect, gssaccept, authfail -> fail
+.           .            prefer       postgres       connect, gssaccept, authfail -> fail
+.           .            require      postgres       connect, gssaccept, authfail -> fail   # If both GSS and SSL are required, the sslmode=require is effectively ignored and GSS is required
+.           .            .            direct         connect, gssaccept, authfail -> fail
+
+nossluser   disable      disable      postgres       connect, authok              -> plain
+.           .            allow        postgres       connect, authok              -> plain
 .           .            prefer       postgres       connect, sslaccept, authfail, reconnect, authok       -> plain
-.           .            .            direct         connect, directsslaccept, authfail, reconnect, authok -> plain
-.           .            .            requiredirect  connect, directsslaccept, authfail, reconnect, authok -> plain
 .           .            require      postgres       connect, sslaccept, authfail       -> fail
 .           .            .            direct         connect, directsslaccept, authfail -> fail
-.           .            .            requiredirect  connect, directsslaccept, authfail -> fail
-.           prefer       *            *              connect, gssaccept, authok   -> gss
-.           require      *            *              connect, gssaccept, authok   -> gss
+.           prefer       *            postgres       connect, gssaccept, authok   -> gss
+.           .            require      direct         connect, gssaccept, authok   -> gss
+.           require      *            postgres       connect, gssaccept, authok   -> gss
+.           .            require      direct         connect, gssaccept, authok   -> gss
+
+# sslnegotiation=direct is not acccepted unless sslmode=require or stronger
+*           *            disable      direct         -     -> fail
+*           *            allow        direct         -     -> fail
+*           *            prefer       direct         -     -> fail
 	};
 
 	note("Running tests with both GSS and SSL enabled in server");
-- 
2.39.2

Reply via email to