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
+ allow (default)
+
+
-+ a certificate may be sent, if the server requests one and it has
-+ been provided via sslcert
++ a certificate may be sent, if the server requests one and the client
++ has one to send
+
+
+
@@ 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 ##