|
|
|
@ -80,12 +80,7 @@ static int my_SSL_set_fd(PGconn *conn, int fd);
|
|
|
|
|
static bool pq_init_ssl_lib = true;
|
|
|
|
|
static bool pq_init_crypto_lib = true;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* SSL_context is currently shared between threads and therefore we need to be
|
|
|
|
|
* careful to lock around any usage of it when providing thread safety.
|
|
|
|
|
* ssl_config_mutex is the mutex that we use to protect it.
|
|
|
|
|
*/
|
|
|
|
|
static SSL_CTX *SSL_context = NULL;
|
|
|
|
|
static bool ssl_lib_initialized = false;
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
|
|
|
|
static long ssl_open_connections = 0;
|
|
|
|
@ -133,44 +128,9 @@ pgtls_open_client(PGconn *conn)
|
|
|
|
|
/* First time through? */
|
|
|
|
|
if (conn->ssl == NULL)
|
|
|
|
|
{
|
|
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
|
|
|
|
int rc;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
|
|
|
|
if ((rc = pthread_mutex_lock(&ssl_config_mutex)))
|
|
|
|
|
{
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("could not acquire mutex: %s\n"), strerror(rc));
|
|
|
|
|
return PGRES_POLLING_FAILED;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
/* Create a connection-specific SSL object */
|
|
|
|
|
if (!(conn->ssl = SSL_new(SSL_context)) ||
|
|
|
|
|
!SSL_set_app_data(conn->ssl, conn) ||
|
|
|
|
|
!my_SSL_set_fd(conn, conn->sock))
|
|
|
|
|
{
|
|
|
|
|
char *err = SSLerrmessage(ERR_get_error());
|
|
|
|
|
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("could not establish SSL connection: %s\n"),
|
|
|
|
|
err);
|
|
|
|
|
SSLerrfree(err);
|
|
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
|
|
|
|
pthread_mutex_unlock(&ssl_config_mutex);
|
|
|
|
|
#endif
|
|
|
|
|
pgtls_close(conn);
|
|
|
|
|
|
|
|
|
|
return PGRES_POLLING_FAILED;
|
|
|
|
|
}
|
|
|
|
|
conn->ssl_in_use = true;
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
|
|
|
|
pthread_mutex_unlock(&ssl_config_mutex);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Load client certificate, private key, and trusted CA certs.
|
|
|
|
|
* Create a connection-specific SSL object, and load client certificate,
|
|
|
|
|
* private key, and trusted CA certs.
|
|
|
|
|
*/
|
|
|
|
|
if (initialize_SSL(conn) != 0)
|
|
|
|
|
{
|
|
|
|
@ -771,8 +731,7 @@ pq_lockingcallback(int mode, int n, const char *file, int line)
|
|
|
|
|
#endif /* ENABLE_THREAD_SAFETY && HAVE_CRYPTO_LOCK */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Initialize SSL system, in particular creating the SSL_context object
|
|
|
|
|
* that will be shared by all SSL-using connections in this process.
|
|
|
|
|
* Initialize SSL library.
|
|
|
|
|
*
|
|
|
|
|
* In threadsafe mode, this includes setting up libcrypto callback functions
|
|
|
|
|
* to do thread locking.
|
|
|
|
@ -851,7 +810,7 @@ pgtls_init(PGconn *conn)
|
|
|
|
|
#endif /* HAVE_CRYPTO_LOCK */
|
|
|
|
|
#endif /* ENABLE_THREAD_SAFETY */
|
|
|
|
|
|
|
|
|
|
if (!SSL_context)
|
|
|
|
|
if (!ssl_lib_initialized)
|
|
|
|
|
{
|
|
|
|
|
if (pq_init_ssl_lib)
|
|
|
|
|
{
|
|
|
|
@ -863,36 +822,7 @@ pgtls_init(PGconn *conn)
|
|
|
|
|
SSL_load_error_strings();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We use SSLv23_method() because it can negotiate use of the highest
|
|
|
|
|
* mutually supported protocol version, while alternatives like
|
|
|
|
|
* TLSv1_2_method() permit only one specific version. Note that we
|
|
|
|
|
* don't actually allow SSL v2 or v3, only TLS protocols (see below).
|
|
|
|
|
*/
|
|
|
|
|
SSL_context = SSL_CTX_new(SSLv23_method());
|
|
|
|
|
if (!SSL_context)
|
|
|
|
|
{
|
|
|
|
|
char *err = SSLerrmessage(ERR_get_error());
|
|
|
|
|
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("could not create SSL context: %s\n"),
|
|
|
|
|
err);
|
|
|
|
|
SSLerrfree(err);
|
|
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
|
|
|
|
pthread_mutex_unlock(&ssl_config_mutex);
|
|
|
|
|
#endif
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Disable old protocol versions */
|
|
|
|
|
SSL_CTX_set_options(SSL_context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Disable OpenSSL's moving-write-buffer sanity check, because it
|
|
|
|
|
* causes unnecessary failures in nonblocking send cases.
|
|
|
|
|
*/
|
|
|
|
|
SSL_CTX_set_mode(SSL_context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
|
|
|
|
ssl_lib_initialized = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
|
|
|
@ -936,9 +866,8 @@ destroy_ssl_system(void)
|
|
|
|
|
CRYPTO_set_id_callback(NULL);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We don't free the lock array or the SSL_context. If we get another
|
|
|
|
|
* connection in this process, we will just re-use them with the
|
|
|
|
|
* existing mutexes.
|
|
|
|
|
* We don't free the lock array. If we get another connection in
|
|
|
|
|
* this process, we will just re-use them with the existing mutexes.
|
|
|
|
|
*
|
|
|
|
|
* This means we leak a little memory on repeated load/unload of the
|
|
|
|
|
* library.
|
|
|
|
@ -950,26 +879,22 @@ destroy_ssl_system(void)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Initialize (potentially) per-connection SSL data, namely the
|
|
|
|
|
* client certificate, private key, and trusted CA certs.
|
|
|
|
|
*
|
|
|
|
|
* conn->ssl must already be created. It receives the connection's client
|
|
|
|
|
* certificate and private key. Note however that certificates also get
|
|
|
|
|
* loaded into the SSL_context object, and are therefore accessible to all
|
|
|
|
|
* connections in this process. This should be OK as long as there aren't
|
|
|
|
|
* any hash collisions among the certs.
|
|
|
|
|
* Create per-connection SSL object, and load the client certificate,
|
|
|
|
|
* private key, and trusted CA certs.
|
|
|
|
|
*
|
|
|
|
|
* Returns 0 if OK, -1 on failure (with a message in conn->errorMessage).
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
initialize_SSL(PGconn *conn)
|
|
|
|
|
{
|
|
|
|
|
SSL_CTX *SSL_context;
|
|
|
|
|
struct stat buf;
|
|
|
|
|
char homedir[MAXPGPATH];
|
|
|
|
|
char fnbuf[MAXPGPATH];
|
|
|
|
|
char sebuf[256];
|
|
|
|
|
bool have_homedir;
|
|
|
|
|
bool have_cert;
|
|
|
|
|
bool have_rootcert;
|
|
|
|
|
EVP_PKEY *pkey = NULL;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -985,6 +910,123 @@ initialize_SSL(PGconn *conn)
|
|
|
|
|
else /* won't need it */
|
|
|
|
|
have_homedir = false;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Create a new SSL_CTX object.
|
|
|
|
|
*
|
|
|
|
|
* We used to share a single SSL_CTX between all connections, but it was
|
|
|
|
|
* complicated if connections used different certificates. So now we create
|
|
|
|
|
* a separate context for each connection, and accept the overhead.
|
|
|
|
|
*/
|
|
|
|
|
SSL_context = SSL_CTX_new(SSLv23_method());
|
|
|
|
|
if (!SSL_context)
|
|
|
|
|
{
|
|
|
|
|
char *err = SSLerrmessage(ERR_get_error());
|
|
|
|
|
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("could not create SSL context: %s\n"),
|
|
|
|
|
err);
|
|
|
|
|
SSLerrfree(err);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Disable old protocol versions */
|
|
|
|
|
SSL_CTX_set_options(SSL_context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Disable OpenSSL's moving-write-buffer sanity check, because it
|
|
|
|
|
* causes unnecessary failures in nonblocking send cases.
|
|
|
|
|
*/
|
|
|
|
|
SSL_CTX_set_mode(SSL_context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the root cert file exists, load it so we can perform certificate
|
|
|
|
|
* verification. If sslmode is "verify-full" we will also do further
|
|
|
|
|
* verification after the connection has been completed.
|
|
|
|
|
*/
|
|
|
|
|
if (conn->sslrootcert && strlen(conn->sslrootcert) > 0)
|
|
|
|
|
strlcpy(fnbuf, conn->sslrootcert, sizeof(fnbuf));
|
|
|
|
|
else if (have_homedir)
|
|
|
|
|
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CERT_FILE);
|
|
|
|
|
else
|
|
|
|
|
fnbuf[0] = '\0';
|
|
|
|
|
|
|
|
|
|
if (fnbuf[0] != '\0' &&
|
|
|
|
|
stat(fnbuf, &buf) == 0)
|
|
|
|
|
{
|
|
|
|
|
X509_STORE *cvstore;
|
|
|
|
|
|
|
|
|
|
if (SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL) != 1)
|
|
|
|
|
{
|
|
|
|
|
char *err = SSLerrmessage(ERR_get_error());
|
|
|
|
|
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("could not read root certificate file \"%s\": %s\n"),
|
|
|
|
|
fnbuf, err);
|
|
|
|
|
SSLerrfree(err);
|
|
|
|
|
SSL_CTX_free(SSL_context);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((cvstore = SSL_CTX_get_cert_store(SSL_context)) != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (conn->sslcrl && strlen(conn->sslcrl) > 0)
|
|
|
|
|
strlcpy(fnbuf, conn->sslcrl, sizeof(fnbuf));
|
|
|
|
|
else if (have_homedir)
|
|
|
|
|
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CRL_FILE);
|
|
|
|
|
else
|
|
|
|
|
fnbuf[0] = '\0';
|
|
|
|
|
|
|
|
|
|
/* Set the flags to check against the complete CRL chain */
|
|
|
|
|
if (fnbuf[0] != '\0' &&
|
|
|
|
|
X509_STORE_load_locations(cvstore, fnbuf, NULL) == 1)
|
|
|
|
|
{
|
|
|
|
|
/* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */
|
|
|
|
|
#ifdef X509_V_FLAG_CRL_CHECK
|
|
|
|
|
X509_STORE_set_flags(cvstore,
|
|
|
|
|
X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
|
|
|
|
|
#else
|
|
|
|
|
char *err = SSLerrmessage(ERR_get_error());
|
|
|
|
|
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("SSL library does not support CRL certificates (file \"%s\")\n"),
|
|
|
|
|
fnbuf);
|
|
|
|
|
SSLerrfree(err);
|
|
|
|
|
SSL_CTX_free(SSL_context);
|
|
|
|
|
return -1;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
/* if not found, silently ignore; we do not require CRL */
|
|
|
|
|
}
|
|
|
|
|
have_rootcert = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* stat() failed; assume root file doesn't exist. If sslmode is
|
|
|
|
|
* verify-ca or verify-full, this is an error. Otherwise, continue
|
|
|
|
|
* without performing any server cert verification.
|
|
|
|
|
*/
|
|
|
|
|
if (conn->sslmode[0] == 'v') /* "verify-ca" or "verify-full" */
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* The only way to reach here with an empty filename is if
|
|
|
|
|
* pqGetHomeDirectory failed. That's a sufficiently unusual case
|
|
|
|
|
* that it seems worth having a specialized error message for it.
|
|
|
|
|
*/
|
|
|
|
|
if (fnbuf[0] == '\0')
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("could not get home directory to locate root certificate file\n"
|
|
|
|
|
"Either provide the file or change sslmode to disable server certificate verification.\n"));
|
|
|
|
|
else
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("root certificate file \"%s\" does not exist\n"
|
|
|
|
|
"Either provide the file or change sslmode to disable server certificate verification.\n"), fnbuf);
|
|
|
|
|
SSL_CTX_free(SSL_context);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
have_rootcert = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read the client certificate file */
|
|
|
|
|
if (conn->sslcert && strlen(conn->sslcert) > 0)
|
|
|
|
|
strlcpy(fnbuf, conn->sslcert, sizeof(fnbuf));
|
|
|
|
@ -1010,6 +1052,7 @@ initialize_SSL(PGconn *conn)
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("could not open certificate file \"%s\": %s\n"),
|
|
|
|
|
fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));
|
|
|
|
|
SSL_CTX_free(SSL_context);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
have_cert = false;
|
|
|
|
@ -1018,30 +1061,9 @@ initialize_SSL(PGconn *conn)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Cert file exists, so load it. Since OpenSSL doesn't provide the
|
|
|
|
|
* equivalent of "SSL_use_certificate_chain_file", we actually have to
|
|
|
|
|
* load the file twice. The first call loads any extra certs after
|
|
|
|
|
* the first one into chain-cert storage associated with the
|
|
|
|
|
* SSL_context. The second call loads the first cert (only) into the
|
|
|
|
|
* SSL object, where it will be correctly paired with the private key
|
|
|
|
|
* we load below. We do it this way so that each connection
|
|
|
|
|
* understands which subject cert to present, in case different
|
|
|
|
|
* sslcert settings are used for different connections in the same
|
|
|
|
|
* process.
|
|
|
|
|
*
|
|
|
|
|
* NOTE: This function may also modify our SSL_context and therefore
|
|
|
|
|
* we have to lock around this call and any places where we use the
|
|
|
|
|
* SSL_context struct.
|
|
|
|
|
* equivalent of "SSL_use_certificate_chain_file", we have to load
|
|
|
|
|
* it into the SSL context, rather than the SSL object.
|
|
|
|
|
*/
|
|
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
if ((rc = pthread_mutex_lock(&ssl_config_mutex)))
|
|
|
|
|
{
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("could not acquire mutex: %s\n"), strerror(rc));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
if (SSL_CTX_use_certificate_chain_file(SSL_context, fnbuf) != 1)
|
|
|
|
|
{
|
|
|
|
|
char *err = SSLerrmessage(ERR_get_error());
|
|
|
|
@ -1050,35 +1072,43 @@ initialize_SSL(PGconn *conn)
|
|
|
|
|
libpq_gettext("could not read certificate file \"%s\": %s\n"),
|
|
|
|
|
fnbuf, err);
|
|
|
|
|
SSLerrfree(err);
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
|
|
|
|
pthread_mutex_unlock(&ssl_config_mutex);
|
|
|
|
|
#endif
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SSL_use_certificate_file(conn->ssl, fnbuf, SSL_FILETYPE_PEM) != 1)
|
|
|
|
|
{
|
|
|
|
|
char *err = SSLerrmessage(ERR_get_error());
|
|
|
|
|
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("could not read certificate file \"%s\": %s\n"),
|
|
|
|
|
fnbuf, err);
|
|
|
|
|
SSLerrfree(err);
|
|
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
|
|
|
|
pthread_mutex_unlock(&ssl_config_mutex);
|
|
|
|
|
#endif
|
|
|
|
|
SSL_CTX_free(SSL_context);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* need to load the associated private key, too */
|
|
|
|
|
have_cert = true;
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
|
|
|
|
pthread_mutex_unlock(&ssl_config_mutex);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The SSL context is now loaded with the correct root and client certificates.
|
|
|
|
|
* Create a connection-specific SSL object. The private key is loaded directly
|
|
|
|
|
* into the SSL object. (We could load the private key into the context, too, but
|
|
|
|
|
* we have done it this way historically, and it doesn't really matter.)
|
|
|
|
|
*/
|
|
|
|
|
if (!(conn->ssl = SSL_new(SSL_context)) ||
|
|
|
|
|
!SSL_set_app_data(conn->ssl, conn) ||
|
|
|
|
|
!my_SSL_set_fd(conn, conn->sock))
|
|
|
|
|
{
|
|
|
|
|
char *err = SSLerrmessage(ERR_get_error());
|
|
|
|
|
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("could not establish SSL connection: %s\n"),
|
|
|
|
|
err);
|
|
|
|
|
SSLerrfree(err);
|
|
|
|
|
SSL_CTX_free(SSL_context);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
conn->ssl_in_use = true;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* SSL contexts are reference counted by OpenSSL. We can free it as soon as we
|
|
|
|
|
* have created the SSL object, and it will stick around for as long as it's
|
|
|
|
|
* actually needed.
|
|
|
|
|
*/
|
|
|
|
|
SSL_CTX_free(SSL_context);
|
|
|
|
|
SSL_context = NULL;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Read the SSL key. If a key is specified, treat it as an engine:key
|
|
|
|
|
* combination if there is colon present - we don't support files with
|
|
|
|
@ -1236,109 +1266,10 @@ initialize_SSL(PGconn *conn)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the root cert file exists, load it so we can perform certificate
|
|
|
|
|
* verification. If sslmode is "verify-full" we will also do further
|
|
|
|
|
* verification after the connection has been completed.
|
|
|
|
|
* If a root cert was loaded, also set our certificate verification callback.
|
|
|
|
|
*/
|
|
|
|
|
if (conn->sslrootcert && strlen(conn->sslrootcert) > 0)
|
|
|
|
|
strlcpy(fnbuf, conn->sslrootcert, sizeof(fnbuf));
|
|
|
|
|
else if (have_homedir)
|
|
|
|
|
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CERT_FILE);
|
|
|
|
|
else
|
|
|
|
|
fnbuf[0] = '\0';
|
|
|
|
|
|
|
|
|
|
if (fnbuf[0] != '\0' &&
|
|
|
|
|
stat(fnbuf, &buf) == 0)
|
|
|
|
|
{
|
|
|
|
|
X509_STORE *cvstore;
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
if ((rc = pthread_mutex_lock(&ssl_config_mutex)))
|
|
|
|
|
{
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("could not acquire mutex: %s\n"), strerror(rc));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
if (SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL) != 1)
|
|
|
|
|
{
|
|
|
|
|
char *err = SSLerrmessage(ERR_get_error());
|
|
|
|
|
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("could not read root certificate file \"%s\": %s\n"),
|
|
|
|
|
fnbuf, err);
|
|
|
|
|
SSLerrfree(err);
|
|
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
|
|
|
|
pthread_mutex_unlock(&ssl_config_mutex);
|
|
|
|
|
#endif
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((cvstore = SSL_CTX_get_cert_store(SSL_context)) != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (conn->sslcrl && strlen(conn->sslcrl) > 0)
|
|
|
|
|
strlcpy(fnbuf, conn->sslcrl, sizeof(fnbuf));
|
|
|
|
|
else if (have_homedir)
|
|
|
|
|
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CRL_FILE);
|
|
|
|
|
else
|
|
|
|
|
fnbuf[0] = '\0';
|
|
|
|
|
|
|
|
|
|
/* Set the flags to check against the complete CRL chain */
|
|
|
|
|
if (fnbuf[0] != '\0' &&
|
|
|
|
|
X509_STORE_load_locations(cvstore, fnbuf, NULL) == 1)
|
|
|
|
|
{
|
|
|
|
|
/* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */
|
|
|
|
|
#ifdef X509_V_FLAG_CRL_CHECK
|
|
|
|
|
X509_STORE_set_flags(cvstore,
|
|
|
|
|
X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
|
|
|
|
|
#else
|
|
|
|
|
char *err = SSLerrmessage(ERR_get_error());
|
|
|
|
|
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("SSL library does not support CRL certificates (file \"%s\")\n"),
|
|
|
|
|
fnbuf);
|
|
|
|
|
SSLerrfree(err);
|
|
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
|
|
|
|
pthread_mutex_unlock(&ssl_config_mutex);
|
|
|
|
|
#endif
|
|
|
|
|
return -1;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
/* if not found, silently ignore; we do not require CRL */
|
|
|
|
|
}
|
|
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
|
|
|
|
pthread_mutex_unlock(&ssl_config_mutex);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (have_rootcert)
|
|
|
|
|
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, verify_cb);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* stat() failed; assume root file doesn't exist. If sslmode is
|
|
|
|
|
* verify-ca or verify-full, this is an error. Otherwise, continue
|
|
|
|
|
* without performing any server cert verification.
|
|
|
|
|
*/
|
|
|
|
|
if (conn->sslmode[0] == 'v') /* "verify-ca" or "verify-full" */
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* The only way to reach here with an empty filename is if
|
|
|
|
|
* pqGetHomeDirectory failed. That's a sufficiently unusual case
|
|
|
|
|
* that it seems worth having a specialized error message for it.
|
|
|
|
|
*/
|
|
|
|
|
if (fnbuf[0] == '\0')
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("could not get home directory to locate root certificate file\n"
|
|
|
|
|
"Either provide the file or change sslmode to disable server certificate verification.\n"));
|
|
|
|
|
else
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
|
libpq_gettext("root certificate file \"%s\" does not exist\n"
|
|
|
|
|
"Either provide the file or change sslmode to disable server certificate verification.\n"), fnbuf);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the OpenSSL version used supports it (from 1.0.0 on) and the user
|
|
|
|
|