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:
parent
5054867632
commit
3c486fbd1c
|
@ -1,4 +1,4 @@
|
||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.420 2008/11/13 09:45:24 mha Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.421 2008/11/20 09:29:35 mha Exp $ -->
|
||||||
|
|
||||||
<chapter Id="runtime">
|
<chapter Id="runtime">
|
||||||
<title>Operating System Environment</title>
|
<title>Operating System Environment</title>
|
||||||
|
@ -1646,13 +1646,17 @@ $ <userinput>kill -INT `head -1 /usr/local/pgsql/data/postmaster.pid`</userinput
|
||||||
been entered.
|
been entered.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<sect2 id="ssl-client-certificates">
|
||||||
|
<title>Using client certificates</title>
|
||||||
|
<para>
|
||||||
To require the client to supply a trusted certificate, place
|
To require the client to supply a trusted certificate, place
|
||||||
certificates of the certificate authorities (<acronym>CA</acronym>)
|
certificates of the certificate authorities (<acronym>CA</acronym>)
|
||||||
you trust in the file <filename>root.crt</filename> in the data
|
you trust in the file <filename>root.crt</filename> in the data
|
||||||
directory. A certificate will then be requested from the client during
|
directory, and set the <literal>clientcert</literal> parameter
|
||||||
|
to <literal>1</literal> on the appropriate line(s) in pg_hba.conf.
|
||||||
|
A certificate will then be requested from the client during
|
||||||
SSL connection startup. (See <xref linkend="libpq-ssl"> for a
|
SSL connection startup. (See <xref linkend="libpq-ssl"> for a
|
||||||
description of how to set up client certificates.) The server will
|
description of how to set up certificates on the client.) The server will
|
||||||
verify that the client's certificate is signed by one of the trusted
|
verify that the client's certificate is signed by one of the trusted
|
||||||
certificate authorities. Certificate Revocation List (CRL) entries
|
certificate authorities. Certificate Revocation List (CRL) entries
|
||||||
are also checked if the file <filename>root.crl</filename> exists.
|
are also checked if the file <filename>root.crl</filename> exists.
|
||||||
|
@ -1663,11 +1667,23 @@ $ <userinput>kill -INT `head -1 /usr/local/pgsql/data/postmaster.pid`</userinput
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If the <filename>root.crt</filename> file is not present, client
|
The <literal>clientcert</literal> option in <filename>pg_hba.conf</>
|
||||||
certificates will not be requested or checked. In this mode, SSL
|
is available for all authentication methods, but only for rows
|
||||||
provides encrypted communication but not authentication.
|
specified as <literal>hostssl</>. Unless specified, the default is
|
||||||
|
not to verify the client certificate.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<productname>PostgreSQL</> currently does not support authentication
|
||||||
|
using client certificates, since it cannot differentiate between
|
||||||
|
different users. As long as the user holds any certificate issued
|
||||||
|
by a trusted CA it will be accepted, regardless of what account the
|
||||||
|
user is trying to connect with.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="ssl-server-files">
|
||||||
|
<title>SSL Server File Usage</title>
|
||||||
<para>
|
<para>
|
||||||
The files <filename>server.key</>, <filename>server.crt</>,
|
The files <filename>server.key</>, <filename>server.crt</>,
|
||||||
<filename>root.crt</filename>, and <filename>root.crl</filename>
|
<filename>root.crt</filename>, and <filename>root.crl</filename>
|
||||||
|
@ -1704,7 +1720,7 @@ $ <userinput>kill -INT `head -1 /usr/local/pgsql/data/postmaster.pid`</userinput
|
||||||
<row>
|
<row>
|
||||||
<entry><filename>root.crt</></entry>
|
<entry><filename>root.crt</></entry>
|
||||||
<entry>trusted certificate authorities</entry>
|
<entry>trusted certificate authorities</entry>
|
||||||
<entry>requests client certificate; checks certificate is
|
<entry>checks that client certificate is
|
||||||
signed by a trusted certificate authority</entry>
|
signed by a trusted certificate authority</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
@ -1717,6 +1733,7 @@ $ <userinput>kill -INT `head -1 /usr/local/pgsql/data/postmaster.pid`</userinput
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</table>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="ssl-certificate-creation">
|
<sect2 id="ssl-certificate-creation">
|
||||||
<title>Creating a Self-Signed Certificate</title>
|
<title>Creating a Self-Signed Certificate</title>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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"),
|
errmsg("missing or erroneous pg_hba.conf file"),
|
||||||
errhint("See server log for details.")));
|
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)
|
switch (port->hba->auth_method)
|
||||||
{
|
{
|
||||||
case uaReject:
|
case uaReject:
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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)
|
* Since the server static private key ($DataDir/server.key)
|
||||||
* will normally be stored unencrypted so that the database
|
* will normally be stored unencrypted so that the database
|
||||||
|
@ -102,6 +102,7 @@ static const char *SSLerrmessage(void);
|
||||||
#define RENEGOTIATION_LIMIT (512 * 1024 * 1024)
|
#define RENEGOTIATION_LIMIT (512 * 1024 * 1024)
|
||||||
|
|
||||||
static SSL_CTX *SSL_context = NULL;
|
static SSL_CTX *SSL_context = NULL;
|
||||||
|
static bool ssl_loaded_verify_locations = false;
|
||||||
|
|
||||||
/* GUC variable controlling SSL cipher list */
|
/* GUC variable controlling SSL cipher list */
|
||||||
char *SSLCipherSuites = NULL;
|
char *SSLCipherSuites = NULL;
|
||||||
|
@ -202,6 +203,19 @@ secure_destroy(void)
|
||||||
#endif
|
#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.
|
* Attempt to negotiate secure session.
|
||||||
*/
|
*/
|
||||||
|
@ -754,15 +768,34 @@ initialize_SSL(void)
|
||||||
elog(FATAL, "could not set the cipher list (no valid ciphers available)");
|
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 */
|
ssl_loaded_verify_locations = false;
|
||||||
ereport(LOG,
|
|
||||||
|
/*
|
||||||
|
* 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",
|
(errmsg("could not load root certificate file \"%s\": %s",
|
||||||
ROOT_CERT_FILE, SSLerrmessage()),
|
ROOT_CERT_FILE, SSLerrmessage())));
|
||||||
errdetail("Will not verify client certificates.")));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -795,13 +828,18 @@ initialize_SSL(void)
|
||||||
ROOT_CRL_FILE, SSLerrmessage()),
|
ROOT_CRL_FILE, SSLerrmessage()),
|
||||||
errdetail("Certificates will not be checked against revocation list.")));
|
errdetail("Certificates will not be checked against revocation list.")));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
SSL_CTX_set_verify(SSL_context,
|
/*
|
||||||
(SSL_VERIFY_PEER |
|
* Always ask for SSL client cert, but don't fail if it's not presented. We'll fail later in this case,
|
||||||
SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
|
* based on what we find in pg_hba.conf.
|
||||||
SSL_VERIFY_CLIENT_ONCE),
|
*/
|
||||||
verify_cb);
|
SSL_CTX_set_verify(SSL_context,
|
||||||
|
(SSL_VERIFY_PEER |
|
||||||
|
SSL_VERIFY_CLIENT_ONCE),
|
||||||
|
verify_cb);
|
||||||
|
|
||||||
|
ssl_loaded_verify_locations = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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");
|
INVALID_AUTH_OPTION("map", "ident, krb5, gssapi and sspi");
|
||||||
parsedline->usermap = pstrdup(c);
|
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)
|
else if (strcmp(token, "pamservice") == 0)
|
||||||
{
|
{
|
||||||
REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
|
REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* Interface to hba.c
|
* 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;
|
int ldapport;
|
||||||
char *ldapprefix;
|
char *ldapprefix;
|
||||||
char *ldapsuffix;
|
char *ldapsuffix;
|
||||||
|
bool clientcert;
|
||||||
} HbaLine;
|
} HbaLine;
|
||||||
|
|
||||||
typedef struct Port hbaPort;
|
typedef struct Port hbaPort;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
* prototypes for functions in be-secure.c
|
||||||
*/
|
*/
|
||||||
extern int secure_initialize(void);
|
extern int secure_initialize(void);
|
||||||
|
extern bool secure_loaded_verify_locations(void);
|
||||||
extern void secure_destroy(void);
|
extern void secure_destroy(void);
|
||||||
extern int secure_open_server(Port *port);
|
extern int secure_open_server(Port *port);
|
||||||
extern void secure_close(Port *port);
|
extern void secure_close(Port *port);
|
||||||
|
|
Loading…
Reference in New Issue