<!--
-$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.163 2004/09/23 13:31:09 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.164 2004/09/26 22:51:49 tgl Exp $
-->
<chapter id="libpq">
<para>
If <productname>PostgreSQL</> is compiled without SSL support,
- using option <literal>require</> will cause an error, and
+ using option <literal>require</> will cause an error, while
options <literal>allow</> and <literal>prefer</> will be
tolerated but <application>libpq</> will be unable to negotiate
an <acronym>SSL</>
connection.<indexterm><primary>SSL</><secondary
sortas="libpq">with libpq</></indexterm>
</para>
-
- <para>
- Please note that <acronym>SSL</> support in libpq covers
- encryption only. It will not verify the validity of the
- certificate presented by the server that you are connecting to,
- nor verify that the hostname matches that of the server's
- certificate. Additionally, there is no support for client
- certificates.
- </para>
</listitem>
</varlistentry>
</para>
</sect1>
+
+<sect1 id="libpq-ssl">
+<title>SSL Support</title>
+
+<indexterm zone="libpq-ssl">
+ <primary>SSL</primary>
+</indexterm>
+
+ <para>
+ <productname>PostgreSQL</> has native support for using
+ <acronym>SSL</> connections to encrypt client/server communications
+ for increased security. See <xref linkend="ssl-tcp"> for details
+ about the server-side <acronym>SSL</> functionality.
+ </para>
+
+ <para>
+ If the server demands a client certificate,
+ <application>libpq</application>
+ will send the certificate stored in file
+ <filename>.postgresql/postgresql.crt</> within the user's home directory.
+ A matching private key file <filename>.postgresql/postgresql.key</>
+ must also be present, and must not be world-readable.
+ </para>
+
+ <para>
+ If the file <filename>.postgresql/root.crt</> is present in the user's
+ home directory,
+ <application>libpq</application> will use the certificate list stored
+ therein to verify the server's certificate. The SSL connection will
+ fail if the server does not present a certificate; therefore, to
+ use this feature the server must also have a <filename>root.crt</> file.
+ </para>
+</sect1>
+
+
<sect1 id="libpq-threading">
<title>Behavior in Threaded Programs</title>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.283 2004/09/23 13:15:57 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.284 2004/09/26 22:51:49 tgl Exp $
-->
<Chapter Id="runtime">
<para>
Enables <acronym>SSL</> connections. Please read
<xref linkend="ssl-tcp"> before using this. The default
- is off.
+ is off. This parameter can only be set at server start.
</para>
</listitem>
</varlistentry>
The server will listen for both standard and <acronym>SSL</>
connections on the same TCP port, and will negotiate with any
connecting client on whether to use <acronym>SSL</>. See <xref
- linkend="auth-pg-hba-conf"> about how to force the server to
- require use of <acronym>SSL</> for certain connections.
+ linkend="auth-pg-hba-conf"> about how to set up the server to
+ require use of <acronym>SSL</> for some or all connections.
</para>
<para>
<para>
If verification of client certificates is required, place the
- certificates of the <acronym>CA</acronym> you wish to check for in
+ certificates of the <acronym>CA</acronym>(s) you wish to check for in
the file <filename>root.crt</filename> in the data directory. When
present, a client certificate will be requested from the client
- making the connection and it must have been signed by one of the
- certificates present in <filename>root.crt</filename>. If no
- certificate is presented, the connection will be allowed to proceed
- anway.
+ during SSL connection startup, and it must have been signed by one of the
+ certificates present in <filename>root.crt</filename>.
</para>
<para>
- The <filename>root.crt</filename> file is always checked for, and
- its absence will be noted through a message in the log. This is
- merely an informative message that client certificates will not be
- requested.
+ When the <filename>root.crt</filename> file is not present, client
+ certificates will not be requested or checked. In this mode, SSL
+ provides communication security but not authentication.
+ </para>
+
+ <para>
+ The files <filename>server.key</>, <filename>server.crt</>,
+ and <filename>root.crt</filename> are only examined during server
+ start; so you must restart the server to make changes in them take
+ effect.
</para>
</sect1>
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.50 2004/09/23 20:27:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.51 2004/09/26 22:51:49 tgl Exp $
*
* Since the server static private key ($DataDir/server.key)
* will normally be stored unencrypted so that the database
* (total in both directions) before we require renegotiation.
*/
#define RENEGOTIATION_LIMIT (512 * 1024 * 1024)
-#define CA_PATH NULL
static SSL_CTX *SSL_context = NULL;
#endif
load_dh_file(int keylength)
{
FILE *fp;
- char fnbuf[2048];
+ char fnbuf[MAXPGPATH];
DH *dh = NULL;
int codes;
/* attempt to open file. It's not an error if it doesn't exist. */
- snprintf(fnbuf, sizeof fnbuf, "%s/dh%d.pem", DataDir, keylength);
+ snprintf(fnbuf, sizeof(fnbuf), "%s/dh%d.pem", DataDir, keylength);
if ((fp = fopen(fnbuf, "r")) == NULL)
return NULL;
if (SSL_CTX_set_cipher_list(SSL_context, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH") != 1)
elog(FATAL, "could not set the cipher list (no valid ciphers available)");
- /* accept client certificates, but don't require them. */
+ /*
+ * Require and check client certificates only if we have a root.crt file.
+ */
snprintf(fnbuf, sizeof(fnbuf), "%s/root.crt", DataDir);
- if (!SSL_CTX_load_verify_locations(SSL_context, fnbuf, CA_PATH))
+ if (!SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL))
{
/* Not fatal - we do not require client certificates */
ereport(LOG,
(errmsg("could not load root certificate file \"%s\": %s",
fnbuf, SSLerrmessage()),
errdetail("Will not verify client certificates.")));
- return 0;
}
- SSL_CTX_set_verify(SSL_context,
- SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE,
- verify_cb);
+ else
+ {
+ SSL_CTX_set_verify(SSL_context,
+ (SSL_VERIFY_PEER |
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
+ SSL_VERIFY_CLIENT_ONCE),
+ verify_cb);
+ }
return 0;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.51 2004/09/23 20:27:43 tgl Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.52 2004/09/26 22:51:49 tgl Exp $
*
* NOTES
+ * [ Most of these notes are wrong/obsolete, but perhaps not all ]
+ *
* The client *requires* a valid server certificate. Since
* SSH tunnels provide anonymous confidentiality, the presumption
* is that sites that want endpoint authentication will use the
if (h == NULL)
{
printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("could not get information about host (%s): %s\n"),
+ libpq_gettext("could not get information about host \"%s\": %s\n"),
conn->peer_cn, hstrerror(h_errno));
return -1;
}
struct passwd pwdstr;
struct passwd *pwd = NULL;
FILE *fp;
- char fnbuf[2048];
+ char fnbuf[MAXPGPATH];
DH *dh = NULL;
int codes;
- if (pqGetpwuid(getuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) == 0)
+ if (pqGetpwuid(getuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) != 0)
return NULL;
/* attempt to open file. It's not an error if it doesn't exist. */
- snprintf(fnbuf, sizeof fnbuf, "%s/.postgresql/dh%d.pem",
+ snprintf(fnbuf, sizeof(fnbuf), "%s/.postgresql/dh%d.pem",
pwd->pw_dir, keylength);
if ((fp = fopen(fnbuf, "r")) == NULL)
* This callback is only called when the server wants a
* client cert.
*
- * Returns 1 on success, 0 on no data, -1 on error.
+ * Must return 1 on success, 0 on no data or error.
*/
static int
client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
struct passwd *pwd = NULL;
struct stat buf,
buf2;
- char fnbuf[2048];
+ char fnbuf[MAXPGPATH];
FILE *fp;
PGconn *conn = (PGconn *) SSL_get_app_data(ssl);
int (*cb) () = NULL; /* how to read user password */
char sebuf[256];
- if (pqGetpwuid(getuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) == 0)
+ if (pqGetpwuid(getuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) != 0)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not get user information\n"));
- return -1;
+ return 0;
}
/* read the user certificate */
- snprintf(fnbuf, sizeof fnbuf, "%s/.postgresql/postgresql.crt",
+ snprintf(fnbuf, sizeof(fnbuf), "%s/.postgresql/postgresql.crt",
pwd->pw_dir);
if (stat(fnbuf, &buf) == -1)
return 0;
if ((fp = fopen(fnbuf, "r")) == NULL)
{
printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("could not open certificate (%s): %s\n"),
+ libpq_gettext("could not open certificate file \"%s\": %s\n"),
fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));
- return -1;
+ return 0;
}
if (PEM_read_X509(fp, x509, NULL, NULL) == NULL)
{
char *err = SSLerrmessage();
printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("could not read certificate (%s): %s\n"),
+ libpq_gettext("could not read certificate file \"%s\": %s\n"),
fnbuf, err);
SSLerrfree(err);
fclose(fp);
- return -1;
+ return 0;
}
fclose(fp);
/* read the user key */
- snprintf(fnbuf, sizeof fnbuf, "%s/.postgresql/postgresql.key",
+ snprintf(fnbuf, sizeof(fnbuf), "%s/.postgresql/postgresql.key",
pwd->pw_dir);
if (stat(fnbuf, &buf) == -1)
{
printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("certificate present, but not private key (%s)\n"),
+ libpq_gettext("certificate present, but not private key file \"%s\"\n"),
fnbuf);
X509_free(*x509);
return 0;
buf.st_uid != getuid())
{
printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("private key (%s) has wrong permissions\n"), fnbuf);
+ libpq_gettext("private key file \"%s\" has wrong permissions\n"),
+ fnbuf);
X509_free(*x509);
- return -1;
+ return 0;
}
if ((fp = fopen(fnbuf, "r")) == NULL)
{
printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("could not open private key file (%s): %s\n"),
+ libpq_gettext("could not open private key file \"%s\": %s\n"),
fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));
X509_free(*x509);
- return -1;
+ return 0;
}
if (fstat(fileno(fp), &buf2) == -1 ||
buf.st_dev != buf2.st_dev || buf.st_ino != buf2.st_ino)
{
printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("private key (%s) changed during execution\n"), fnbuf);
+ libpq_gettext("private key file \"%s\" changed during execution\n"), fnbuf);
X509_free(*x509);
- return -1;
+ return 0;
}
if (PEM_read_PrivateKey(fp, pkey, cb, NULL) == NULL)
{
char *err = SSLerrmessage();
printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("could not read private key (%s): %s\n"),
+ libpq_gettext("could not read private key file \"%s\": %s\n"),
fnbuf, err);
SSLerrfree(err);
X509_free(*x509);
fclose(fp);
- return -1;
+ return 0;
}
fclose(fp);
char *err = SSLerrmessage();
printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("certificate/private key mismatch (%s): %s\n"),
+ libpq_gettext("certificate does not match private key file \"%s\": %s\n"),
fnbuf, err);
SSLerrfree(err);
X509_free(*x509);
EVP_PKEY_free(*pkey);
- return -1;
+ return 0;
}
return 1;
char pwdbuf[BUFSIZ];
struct passwd pwdstr;
struct passwd *pwd = NULL;
- char fnbuf[2048];
+ char fnbuf[MAXPGPATH];
#endif
if (init_ssl_system(conn))
return -1;
#ifndef WIN32
+ /* Set up to verify server cert, if root.crt is present */
if (pqGetpwuid(getuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) == 0)
{
- snprintf(fnbuf, sizeof fnbuf, "%s/.postgresql/root.crt",
+ snprintf(fnbuf, sizeof(fnbuf), "%s/.postgresql/root.crt",
pwd->pw_dir);
- if (stat(fnbuf, &buf) == -1)
+ if (stat(fnbuf, &buf) == 0)
{
- return 0;
-#ifdef NOT_USED
- char sebuf[256];
+ if (!SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL))
+ {
+ char *err = SSLerrmessage();
- /* CLIENT CERTIFICATES NOT REQUIRED bjm 2002-09-26 */
- printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("could not read root certificate list (%s): %s\n"),
- fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));
- return -1;
-#endif
- }
- if (!SSL_CTX_load_verify_locations(SSL_context, fnbuf, 0))
- {
- char *err = SSLerrmessage();
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("could not read root certificate file \"%s\": %s\n"),
+ fnbuf, err);
+ SSLerrfree(err);
+ return -1;
+ }
- printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("could not read root certificate list (%s): %s\n"),
- fnbuf, err);
- SSLerrfree(err);
- return -1;
+ SSL_CTX_set_verify(SSL_context, SSL_VERIFY_PEER, verify_cb);
}
}
- SSL_CTX_set_verify(SSL_context,
- SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb);
- SSL_CTX_set_verify_depth(SSL_context, 1);
-
/* set up empheral DH keys */
SSL_CTX_set_tmp_dh_callback(SSL_context, tmp_dh_cb);
SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_DH_USE);