@@ -274,7 +274,7 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
274274 offsetof(struct pg_conn , sslmode )},
275275
276276 {"sslnegotiation" , "PGSSLNEGOTIATION" , DefaultSSLNegotiation , NULL ,
277- "SSL-Negotiation" , "" , 14 , /* sizeof("requiredirect ") == 14 */
277+ "SSL-Negotiation" , "" , 9 , /* sizeof("postgres ") == 9 */
278278 offsetof(struct pg_conn , sslnegotiation )},
279279
280280 {"sslcompression" , "PGSSLCOMPRESSION" , "0" , NULL ,
@@ -1590,8 +1590,7 @@ pqConnectOptions2(PGconn *conn)
15901590 if (conn -> sslnegotiation )
15911591 {
15921592 if (strcmp (conn -> sslnegotiation , "postgres" ) != 0
1593- && strcmp (conn -> sslnegotiation , "direct" ) != 0
1594- && strcmp (conn -> sslnegotiation , "requiredirect" ) != 0 )
1593+ && strcmp (conn -> sslnegotiation , "direct" ) != 0 )
15951594 {
15961595 conn -> status = CONNECTION_BAD ;
15971596 libpq_append_conn_error (conn , "invalid %s value: \"%s\"" ,
@@ -1608,6 +1607,25 @@ pqConnectOptions2(PGconn *conn)
16081607 return false;
16091608 }
16101609#endif
1610+
1611+ /*
1612+ * Don't allow direct SSL negotiation with sslmode='prefer', because
1613+ * that poses a risk of unintentional fallback to plaintext connection
1614+ * when connecting to a pre-v17 server that does not support direct
1615+ * SSL connections. To keep things simple, don't allow it with
1616+ * sslmode='allow' or sslmode='disable' either. If a user goes through
1617+ * the trouble of setting sslnegotiation='direct', they probably
1618+ * intend to use SSL, and sslmode=disable or allow is probably a user
1619+ * user mistake anyway.
1620+ */
1621+ if (conn -> sslnegotiation [0 ] == 'd' &&
1622+ conn -> sslmode [0 ] != 'r' && conn -> sslmode [0 ] != 'v' )
1623+ {
1624+ conn -> status = CONNECTION_BAD ;
1625+ libpq_append_conn_error (conn , "weak sslmode \"%s\" may not be used with sslnegotiation=direct (use \"require\", \"verify-ca\", or \"verify-full\")" ,
1626+ conn -> sslmode );
1627+ return false;
1628+ }
16111629 }
16121630 else
16131631 {
@@ -3347,42 +3365,45 @@ PQconnectPoll(PGconn *conn)
33473365 goto error_return ;
33483366
33493367 /*
3350- * If direct SSL is enabled, jump right into SSL handshake . We
3351- * will come back here after SSL encryption has been
3352- * established, with ssl_in_use set.
3368+ * If SSL is enabled, start the SSL negotiation . We will come
3369+ * back here after SSL encryption has been established, with
3370+ * ssl_in_use set.
33533371 */
3354- if (conn -> current_enc_method == ENC_DIRECT_SSL && !conn -> ssl_in_use )
3372+ if (conn -> current_enc_method == ENC_SSL && !conn -> ssl_in_use )
33553373 {
3356- conn -> status = CONNECTION_SSL_STARTUP ;
3357- return PGRES_POLLING_WRITING ;
3358- }
3359-
3360- /*
3361- * If negotiated SSL is enabled, request SSL and proceed with
3362- * SSL handshake. We will come back here after SSL encryption
3363- * has been established, with ssl_in_use set.
3364- */
3365- if (conn -> current_enc_method == ENC_NEGOTIATED_SSL && !conn -> ssl_in_use )
3366- {
3367- ProtocolVersion pv ;
3368-
33693374 /*
3370- * Send the SSL request packet.
3371- *
3372- * Theoretically, this could block, but it really
3373- * shouldn't since we only got here if the socket is
3374- * write-ready.
3375+ * If traditional postgres SSL negotiation is used, send
3376+ * the SSL request. In direct negotiation, jump straight
3377+ * into the SSL handshake.
33753378 */
3376- pv = pg_hton32 (NEGOTIATE_SSL_CODE );
3377- if (pqPacketSend (conn , 0 , & pv , sizeof (pv )) != STATUS_OK )
3379+ if (conn -> sslnegotiation [0 ] == 'p' )
33783380 {
3379- libpq_append_conn_error (conn , "could not send SSL negotiation packet: %s" ,
3380- SOCK_STRERROR (SOCK_ERRNO , sebuf , sizeof (sebuf )));
3381- goto error_return ;
3381+ ProtocolVersion pv ;
3382+
3383+ /*
3384+ * Send the SSL request packet.
3385+ *
3386+ * Theoretically, this could block, but it really
3387+ * shouldn't since we only got here if the socket is
3388+ * write-ready.
3389+ */
3390+ pv = pg_hton32 (NEGOTIATE_SSL_CODE );
3391+ if (pqPacketSend (conn , 0 , & pv , sizeof (pv )) != STATUS_OK )
3392+ {
3393+ libpq_append_conn_error (conn , "could not send SSL negotiation packet: %s" ,
3394+ SOCK_STRERROR (SOCK_ERRNO , sebuf , sizeof (sebuf )));
3395+ goto error_return ;
3396+ }
3397+ /* Ok, wait for response */
3398+ conn -> status = CONNECTION_SSL_STARTUP ;
3399+ return PGRES_POLLING_READING ;
3400+ }
3401+ else
3402+ {
3403+ Assert (conn -> sslnegotiation [0 ] == 'd' );
3404+ conn -> status = CONNECTION_SSL_STARTUP ;
3405+ return PGRES_POLLING_WRITING ;
33823406 }
3383- /* Ok, wait for response */
3384- conn -> status = CONNECTION_SSL_STARTUP ;
3385- return PGRES_POLLING_READING ;
33863407 }
33873408#endif /* USE_SSL */
33883409
@@ -3453,11 +3474,11 @@ PQconnectPoll(PGconn *conn)
34533474 PostgresPollingStatusType pollres ;
34543475
34553476 /*
3456- * On first time through, get the postmaster's response to our
3457- * SSL negotiation packet. If we are trying a direct ssl
3458- * connection , go straight to initiating ssl .
3477+ * On first time through with traditional SSL negotiation, get
3478+ * the postmaster's response to our SSLRequest packet. With
3479+ * sslnegotiation='direct' , go straight to initiating SSL .
34593480 */
3460- if (!conn -> ssl_in_use && conn -> current_enc_method == ENC_NEGOTIATED_SSL )
3481+ if (!conn -> ssl_in_use && conn -> sslnegotiation [ 0 ] == 'p' )
34613482 {
34623483 /*
34633484 * We use pqReadData here since it has the logic to
@@ -4282,7 +4303,7 @@ init_allowed_encryption_methods(PGconn *conn)
42824303 if (conn -> raddr .addr .ss_family == AF_UNIX )
42834304 {
42844305 /* Don't request SSL or GSSAPI over Unix sockets */
4285- conn -> allowed_enc_methods &= ~(ENC_DIRECT_SSL | ENC_NEGOTIATED_SSL | ENC_GSSAPI );
4306+ conn -> allowed_enc_methods &= ~(ENC_SSL | ENC_GSSAPI );
42864307
42874308 /*
42884309 * XXX: we probably should not do this. sslmode=require works
@@ -4309,12 +4330,7 @@ init_allowed_encryption_methods(PGconn *conn)
43094330 /* sslmode anything but 'disable', and GSSAPI not required */
43104331 if (conn -> sslmode [0 ] != 'd' && conn -> gssencmode [0 ] != 'r' )
43114332 {
4312- if (conn -> sslnegotiation [0 ] == 'p' )
4313- conn -> allowed_enc_methods |= ENC_NEGOTIATED_SSL ;
4314- else if (conn -> sslnegotiation [0 ] == 'd' )
4315- conn -> allowed_enc_methods |= ENC_DIRECT_SSL | ENC_NEGOTIATED_SSL ;
4316- else if (conn -> sslnegotiation [0 ] == 'r' )
4317- conn -> allowed_enc_methods |= ENC_DIRECT_SSL ;
4333+ conn -> allowed_enc_methods |= ENC_SSL ;
43184334 }
43194335#endif
43204336
@@ -4354,7 +4370,8 @@ encryption_negotiation_failed(PGconn *conn)
43544370
43554371 if (select_next_encryption_method (conn , true))
43564372 {
4357- if (conn -> current_enc_method == ENC_DIRECT_SSL )
4373+ /* An existing connection cannot be reused for direct SSL */
4374+ if (conn -> current_enc_method == ENC_SSL && conn -> sslnegotiation [0 ] == 'd' )
43584375 return 2 ;
43594376 else
43604377 return 1 ;
@@ -4376,18 +4393,6 @@ connection_failed(PGconn *conn)
43764393 Assert ((conn -> failed_enc_methods & conn -> current_enc_method ) == 0 );
43774394 conn -> failed_enc_methods |= conn -> current_enc_method ;
43784395
4379- /*
4380- * If the server reported an error after the SSL handshake, no point in
4381- * retrying with negotiated vs direct SSL.
4382- */
4383- if ((conn -> current_enc_method & (ENC_DIRECT_SSL | ENC_NEGOTIATED_SSL )) != 0 &&
4384- conn -> ssl_handshake_started )
4385- {
4386- conn -> failed_enc_methods |= (ENC_DIRECT_SSL | ENC_NEGOTIATED_SSL ) & conn -> allowed_enc_methods ;
4387- }
4388- else
4389- conn -> failed_enc_methods |= conn -> current_enc_method ;
4390-
43914396 return select_next_encryption_method (conn , false);
43924397}
43934398
@@ -4445,24 +4450,17 @@ select_next_encryption_method(PGconn *conn, bool have_valid_connection)
44454450 SELECT_NEXT_METHOD (ENC_GSSAPI );
44464451#endif
44474452
4448- /* With sslmode=allow, try plaintext connection before SSL. */
4449- if (conn -> sslmode [0 ] == 'a' )
4450- SELECT_NEXT_METHOD (ENC_PLAINTEXT );
4451-
44524453 /*
4453- * If enabled, try direct SSL. Unless we have a valid TCP connection that
4454- * failed negotiating GSSAPI encryption; in that case we prefer to reuse
4455- * the connection with negotiated SSL, instead of reconnecting to do
4456- * direct SSL. The point of sslnegotiation=direct is to avoid the
4457- * roundtrip from the negotiation, but reconnecting would also incur a
4458- * roundtrip. (In sslnegotiation=requiredirect mode, negotiated SSL is not
4459- * in the list of allowed methods and we will reconnect.)
4454+ * The order between SSL encryption and plaintext depends on sslmode. With
4455+ * sslmode=allow, try plaintext connection before SSL. With
4456+ * sslmode=prefer, it's the other way round. With other modes, we only try
4457+ * plaintext or SSL connections so the order they're listed here doesn't
4458+ * matter.
44604459 */
4461- if (have_valid_connection )
4462- SELECT_NEXT_METHOD (ENC_NEGOTIATED_SSL );
4460+ if (conn -> sslmode [ 0 ] == 'a' )
4461+ SELECT_NEXT_METHOD (ENC_PLAINTEXT );
44634462
4464- SELECT_NEXT_METHOD (ENC_DIRECT_SSL );
4465- SELECT_NEXT_METHOD (ENC_NEGOTIATED_SSL );
4463+ SELECT_NEXT_METHOD (ENC_SSL );
44664464
44674465 if (conn -> sslmode [0 ] != 'a' )
44684466 SELECT_NEXT_METHOD (ENC_PLAINTEXT );
0 commit comments