1:  8d93ca3792 ! 1:  ad71dc8b72 Add sslcertmode option for client certificates
    @@ configure: else
        fi
     -  # Function introduced in OpenSSL 1.0.2.
     -  for ac_func in X509_get_signature_nid
    -+  # Functions introduced in OpenSSL 1.0.2. LibreSSL doesn't have all of these.
    ++  # Functions introduced in OpenSSL 1.0.2. Note that LibreSSL doesn't have
    ++  # SSL_CTX_set_cert_cb().
     +  for ac_func in X509_get_signature_nid SSL_CTX_set_cert_cb
      do :
     -  ac_fn_c_check_func "$LINENO" "X509_get_signature_nid" "ac_cv_func_X509_get_signature_nid"
    @@ configure.ac: if test "$with_ssl" = openssl ; then
        fi
     -  # Function introduced in OpenSSL 1.0.2.
     -  AC_CHECK_FUNCS([X509_get_signature_nid])
    -+  # Functions introduced in OpenSSL 1.0.2. LibreSSL doesn't have all of these.
    ++  # Functions introduced in OpenSSL 1.0.2. Note that LibreSSL doesn't have
    ++  # SSL_CTX_set_cert_cb().
     +  AC_CHECK_FUNCS([X509_get_signature_nid SSL_CTX_set_cert_cb])
        # Functions introduced in OpenSSL 1.1.0. We used to check for
        # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
    @@ doc/src/sgml/libpq.sgml: postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
     +          <term><literal>allow</literal> (default)</term>
     +          <listitem>
     +           <para>
    -+            a certificate may be sent, if the server requests one and it has
    -+            been provided via <literal>sslcert</literal>
    ++            a certificate may be sent, if the server requests one and the client
    ++            has one to send
     +           </para>
     +          </listitem>
     +         </varlistentry>
    @@ meson.build: if sslopt in ['auto', 'openssl']
            ['SSL_new', {'required': true}],
      
     -      # Function introduced in OpenSSL 1.0.2.
    -+      # Functions introduced in OpenSSL 1.0.2. LibreSSL doesn't have all of these.
    ++      # Functions introduced in OpenSSL 1.0.2.
            ['X509_get_signature_nid'],
    -+      ['SSL_CTX_set_cert_cb'],
    ++      ['SSL_CTX_set_cert_cb'], # not in LibreSSL
      
            # Functions introduced in OpenSSL 1.1.0. We used to check for
            # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
    @@ src/interfaces/libpq/fe-auth.c: check_expected_areq(AuthRequest areq, PGconn *co
     +		 */
     +		if (!conn->ssl_cert_requested)
     +		{
    -+			libpq_append_conn_error(conn, "server did not request a certificate");
    ++			libpq_append_conn_error(conn, "server did not request an SSL certificate");
     +			return false;
     +		}
     +		else if (!conn->ssl_cert_sent)
     +		{
    -+			libpq_append_conn_error(conn, "server accepted connection without a valid certificate");
    ++			libpq_append_conn_error(conn, "server accepted connection without a valid SSL certificate");
     +			return false;
     +		}
     +	}
    @@ src/interfaces/libpq/fe-connect.c: static const internalPQconninfoOption PQconni
      	{"sslpassword", NULL, NULL, NULL,
      		"SSL-Client-Key-Password", "*", 20,
      	offsetof(struct pg_conn, sslpassword)},
    +@@ src/interfaces/libpq/fe-connect.c: connectOptions2(PGconn *conn)
    + 			case 'r':			/* "require" */
    + 			case 'v':			/* "verify-ca" or "verify-full" */
    + 				conn->status = CONNECTION_BAD;
    +-				libpq_append_conn_error(conn, "sslmode value \"%s\" invalid when SSL support is not compiled in",
    +-										conn->sslmode);
    ++				libpq_append_conn_error(conn, "%s value \"%s\" invalid when SSL support is not compiled in",
    ++										"sslmode", conn->sslmode);
    + 				return false;
    + 		}
    + #endif
     @@ src/interfaces/libpq/fe-connect.c: connectOptions2(PGconn *conn)
      		return false;
      	}
    @@ src/interfaces/libpq/fe-connect.c: connectOptions2(PGconn *conn)
     +		if (strcmp(conn->sslcertmode, "require") == 0)
     +		{
     +			conn->status = CONNECTION_BAD;
    -+			libpq_append_conn_error(conn, "sslcertmode value \"%s\" invalid when SSL support is not compiled in",
    -+									conn->sslcertmode);
    ++			libpq_append_conn_error(conn, "%s value \"%s\" invalid when SSL support is not compiled in",
    ++									"sslcertmode", conn->sslcertmode);
     +			return false;
     +		}
     +#endif
     +#ifndef HAVE_SSL_CTX_SET_CERT_CB
     +		/*
     +		 * Without a certificate callback, the current implementation can't
    -+		 * figure out if a certficate was actually requested, so "require" is
    ++		 * figure out if a certificate was actually requested, so "require" is
     +		 * useless.
     +		 */
     +		if (strcmp(conn->sslcertmode, "require") == 0)
    @@ src/interfaces/libpq/fe-connect.c: connectOptions2(PGconn *conn)
      	/*
      	 * validate gssencmode option
      	 */
    +@@ src/interfaces/libpq/fe-connect.c: freePGconn(PGconn *conn)
    + 		explicit_bzero(conn->sslpassword, strlen(conn->sslpassword));
    + 		free(conn->sslpassword);
    + 	}
    ++	free(conn->sslcertmode);
    + 	free(conn->sslrootcert);
    + 	free(conn->sslcrl);
    + 	free(conn->sslcrldir);
     
      ## src/interfaces/libpq/fe-secure-openssl.c ##
     @@ src/interfaces/libpq/fe-secure-openssl.c: verify_cb(int ok, X509_STORE_CTX *ctx)
    @@ src/test/ssl/t/001_ssltests.pl: $node->connect_ok(
     +	"$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require sslcertmode=require",
     +	"connect with sslcertmode=require fails without a client certificate",
     +	expected_stderr => $supports_sslcertmode_require
    -+		? qr/server accepted connection without a valid certificate/
    ++		? qr/server accepted connection without a valid SSL certificate/
     +		: qr/sslcertmode value "require" is not supported/);
     +
      # CRL tests
    @@ src/test/ssl/t/001_ssltests.pl: $node->connect_ok(
      $node->connect_fails(
      	"$common_connstr user=ssltestuser sslcert=ssl/client.crt "
     
    + ## src/test/ssl/t/003_sslinfo.pl ##
    +@@ src/test/ssl/t/003_sslinfo.pl: my $SERVERHOSTADDR = '127.0.0.1';
    + # This is the pattern to use in pg_hba.conf to match incoming connections.
    + my $SERVERHOSTCIDR = '127.0.0.1/32';
    + 
    ++# Determine whether build supports sslcertmode=require.
    ++my $supports_sslcertmode_require =
    ++  check_pg_config("#define HAVE_SSL_CTX_SET_CERT_CB 1");
    ++
    + # Allocation of base connection string shared among multiple tests.
    + my $common_connstr;
    + 
    +@@ src/test/ssl/t/003_sslinfo.pl: $result = $node->safe_psql(
    + 	connstr => $common_connstr);
    + is($result, 'CA:FALSE|t', 'extract extension from cert');
    + 
    ++# Sanity tests for sslcertmode, using ssl_client_cert_present()
    ++my @cases = (
    ++	{ opts => "sslcertmode=allow",					present => 't' },
    ++	{ opts => "sslcertmode=allow sslcert=invalid",	present => 'f' },
    ++	{ opts => "sslcertmode=disable",				present => 'f' },
    ++);
    ++if ($supports_sslcertmode_require)
    ++{
    ++	push(@cases, { opts => "sslcertmode=require",	present => 't' });
    ++}
    ++
    ++foreach my $c (@cases) {
    ++	$result = $node->safe_psql(
    ++		"trustdb",
    ++		"SELECT ssl_client_cert_present();",
    ++		connstr => "$common_connstr dbname=trustdb $c->{'opts'}"
    ++	);
    ++	is($result, $c->{'present'}, "ssl_client_cert_present() for $c->{'opts'}");
    ++}
    ++
    + done_testing();
    +
      ## src/tools/msvc/Solution.pm ##
     @@ src/tools/msvc/Solution.pm: sub GenerateFiles
      		HAVE_SETPROCTITLE_FAST                   => undef,
2:  e2343c0089 ! 2:  c9ecdd54ea require_auth: decouple SASL and SCRAM
    @@ src/interfaces/libpq/fe-connect.c: connectOptions2(PGconn *conn)
     +				free(part);
     +				continue; /* avoid the bitmask manipulation below */
      			}
    - 			else if (strcmp(method, "creds") == 0)
    + 			else if (strcmp(method, "none") == 0)
      			{
     
      ## src/interfaces/libpq/libpq-int.h ##
