aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/libpq/auth.c36
-rw-r--r--src/backend/libpq/be-secure.c64
-rw-r--r--src/backend/libpq/hba.c34
-rw-r--r--src/include/libpq/hba.h3
-rw-r--r--src/include/libpq/libpq.h3
5 files changed, 123 insertions, 17 deletions
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index bccb0a516f2..dfa3ff2e9a9 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.171 2008/11/18 13:10:20 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.172 2008/11/20 09:29:36 mha Exp $
*
*-------------------------------------------------------------------------
*/
@@ -275,6 +275,40 @@ ClientAuthentication(Port *port)
errmsg("missing or erroneous pg_hba.conf file"),
errhint("See server log for details.")));
+ /*
+ * This is the first point where we have access to the hba record for
+ * the current connection, so perform any verifications based on the
+ * hba options field that should be done *before* the authentication
+ * here.
+ */
+ if (port->hba->clientcert)
+ {
+ /*
+ * When we parse pg_hba.conf, we have already made sure that we have
+ * been able to load a certificate store. Thus, if a certificate is
+ * present on the client, it has been verified against our root
+ * certificate store, and the connection would have been aborted
+ * already if it didn't verify ok.
+ */
+#ifdef USE_SSL
+ if (!port->peer)
+ {
+ ereport(FATAL,
+ (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
+ errmsg("connection requires a valid client certificate")));
+ }
+#else
+ /*
+ * hba.c makes sure hba->clientcert can't be set unless OpenSSL
+ * is present.
+ */
+ Assert(false);
+#endif
+ }
+
+ /*
+ * Now proceed to do the actual authentication check
+ */
switch (port->hba->auth_method)
{
case uaReject:
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index bae9fe8464f..fd7e703c526 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.85 2008/10/24 12:24:35 mha Exp $
+ * $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.86 2008/11/20 09:29:36 mha Exp $
*
* Since the server static private key ($DataDir/server.key)
* will normally be stored unencrypted so that the database
@@ -102,6 +102,7 @@ static const char *SSLerrmessage(void);
#define RENEGOTIATION_LIMIT (512 * 1024 * 1024)
static SSL_CTX *SSL_context = NULL;
+static bool ssl_loaded_verify_locations = false;
/* GUC variable controlling SSL cipher list */
char *SSLCipherSuites = NULL;
@@ -203,6 +204,19 @@ secure_destroy(void)
}
/*
+ * Indicate if we have loaded the root CA store to verify certificates
+ */
+bool
+secure_loaded_verify_locations(void)
+{
+#ifdef USE_SSL
+ return ssl_loaded_verify_locations;
+#endif
+
+ return false;
+}
+
+/*
* Attempt to negotiate secure session.
*/
int
@@ -754,15 +768,34 @@ initialize_SSL(void)
elog(FATAL, "could not set the cipher list (no valid ciphers available)");
/*
- * Require and check client certificates only if we have a root.crt file.
+ * Attempt to load CA store, so we can verify client certificates if needed.
*/
- if (!SSL_CTX_load_verify_locations(SSL_context, ROOT_CERT_FILE, NULL))
+ if (access(ROOT_CERT_FILE, R_OK))
{
- /* Not fatal - we do not require client certificates */
- ereport(LOG,
+ ssl_loaded_verify_locations = false;
+
+ /*
+ * If root certificate file simply not found. Don't log an error here, because
+ * it's quite likely the user isn't planning on using client certificates.
+ * If we can't access it for other reasons, it is an error.
+ */
+ if (errno != ENOENT)
+ {
+ ereport(FATAL,
+ (errmsg("could not access root certificate file \"%s\": %m",
+ ROOT_CERT_FILE)));
+ }
+ }
+ else if (!SSL_CTX_load_verify_locations(SSL_context, ROOT_CERT_FILE, NULL))
+ {
+ /*
+ * File was there, but we could not load it. This means the file is somehow
+ * broken, and we cannot do verification at all - so abort here.
+ */
+ ssl_loaded_verify_locations = false;
+ ereport(FATAL,
(errmsg("could not load root certificate file \"%s\": %s",
- ROOT_CERT_FILE, SSLerrmessage()),
- errdetail("Will not verify client certificates.")));
+ ROOT_CERT_FILE, SSLerrmessage())));
}
else
{
@@ -795,13 +828,18 @@ initialize_SSL(void)
ROOT_CRL_FILE, SSLerrmessage()),
errdetail("Certificates will not be checked against revocation list.")));
}
- }
- SSL_CTX_set_verify(SSL_context,
- (SSL_VERIFY_PEER |
- SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
- SSL_VERIFY_CLIENT_ONCE),
- verify_cb);
+ /*
+ * Always ask for SSL client cert, but don't fail if it's not presented. We'll fail later in this case,
+ * based on what we find in pg_hba.conf.
+ */
+ SSL_CTX_set_verify(SSL_context,
+ (SSL_VERIFY_PEER |
+ SSL_VERIFY_CLIENT_ONCE),
+ verify_cb);
+
+ ssl_loaded_verify_locations = true;
+ }
}
}
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index d5e56bda453..64f67818c93 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.172 2008/10/28 12:10:43 mha Exp $
+ * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.173 2008/11/20 09:29:36 mha Exp $
*
*-------------------------------------------------------------------------
*/
@@ -927,6 +927,38 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
INVALID_AUTH_OPTION("map", "ident, krb5, gssapi and sspi");
parsedline->usermap = pstrdup(c);
}
+ else if (strcmp(token, "clientcert") == 0)
+ {
+ /*
+ * Since we require ctHostSSL, this really can never happen on non-SSL-enabled
+ * builds, so don't bother checking for USE_SSL.
+ */
+ if (parsedline->conntype != ctHostSSL)
+ {
+ ereport(LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("clientcert can only be configured for \"hostssl\" rows"),
+ errcontext("line %d of configuration file \"%s\"",
+ line_num, HbaFileName)));
+ return false;
+ }
+ if (strcmp(c, "1") == 0)
+ {
+ if (!secure_loaded_verify_locations())
+ {
+ ereport(LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("client certificates can only be checked if a root certificate store is available"),
+ errdetail("make sure the root certificate store is present and readable"),
+ errcontext("line %d of configuration file \"%s\"",
+ line_num, HbaFileName)));
+ return false;
+ }
+ parsedline->clientcert = true;
+ }
+ else
+ parsedline->clientcert = false;
+ }
else if (strcmp(token, "pamservice") == 0)
{
REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index 79b5a51c6d0..cf5942a2668 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -4,7 +4,7 @@
* Interface to hba.c
*
*
- * $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.51 2008/10/28 12:10:44 mha Exp $
+ * $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.52 2008/11/20 09:29:36 mha Exp $
*
*-------------------------------------------------------------------------
*/
@@ -54,6 +54,7 @@ typedef struct
int ldapport;
char *ldapprefix;
char *ldapsuffix;
+ bool clientcert;
} HbaLine;
typedef struct Port hbaPort;
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
index 53c6437cea1..cc4d1bbd7da 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/libpq/libpq.h,v 1.69 2008/01/01 19:45:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/libpq/libpq.h,v 1.70 2008/11/20 09:29:36 mha Exp $
*
*-------------------------------------------------------------------------
*/
@@ -67,6 +67,7 @@ extern void pq_endcopyout(bool errorAbort);
* prototypes for functions in be-secure.c
*/
extern int secure_initialize(void);
+extern bool secure_loaded_verify_locations(void);
extern void secure_destroy(void);
extern int secure_open_server(Port *port);
extern void secure_close(Port *port);