1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Control client certificate requesting with the pg_hba option "clientcert"

instead of just relying on the root certificate file to be present.
This commit is contained in:
Magnus Hagander
2008-11-20 09:29:36 +00:00
parent 5054867632
commit 3c486fbd1c
6 changed files with 148 additions and 25 deletions

View File

@ -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:

View File

@ -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;
@ -202,6 +203,19 @@ secure_destroy(void)
#endif
}
/*
* 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.
*/
@ -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;
}
}
}

View File

@ -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");

View File

@ -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;

View File

@ -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);