Commit 91fa7b47 authored by Heikki Linnakangas's avatar Heikki Linnakangas

Add API functions to libpq to interrogate SSL related stuff.

This makes it possible to query for things like the SSL version and cipher
used, without depending on OpenSSL functions or macros. That is a good
thing if we ever get another SSL implementation.

PQgetssl() still works, but it should be considered as deprecated as it
only works with OpenSSL. In particular, PQgetSslInUse() should be used to
check if a connection uses SSL, because as soon as we have another
implementation, PQgetssl() will return NULL even if SSL is in use.
parent 809d9a26
......@@ -1848,33 +1848,127 @@ int PQconnectionUsedPassword(const PGconn *conn);
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<varlistentry id="libpq-pqgetssl">
<term><function>PQgetssl</function><indexterm><primary>PQgetssl</></></term>
<para>
The following functions return information related to SSL. This information
usually doesn't change after a connection is established.
<variablelist>
<varlistentry id="libpq-pqsslinuse">
<term><function>PQsslInUse</function><indexterm><primary>PQsslInUse</></></term>
<listitem>
<para>
<indexterm><primary>SSL</><secondary sortas="libpq">in libpq</secondary></indexterm>
Returns the SSL structure used in the connection, or null
if SSL is not in use.
Returns true (1) if the connection uses SSL, false (0) if not.
<synopsis>
void *PQgetssl(const PGconn *conn);
int PQsslInUse(const PGconn *conn);
</synopsis>
</para>
</listitem>
</varlistentry>
<varlistentry id="libpq-pqsslAttribute">
<term><function>PQsslAttribute</function><indexterm><primary>PQsslAttribute</></></term>
<listitem>
<para>
This structure can be used to verify encryption levels, check server
certificates, and more. Refer to the <productname>OpenSSL</>
documentation for information about this structure.
Returns SSL-related information about the connection.
<synopsis>
const char *PQsslAttribute(const PGconn *conn, const char *attribute_name);
</synopsis>
</para>
<para>
The list of available attributes varies depending on the SSL library
being used, and the type of connection. If an attribute is not
available, returns NULL.
</para>
<para>
The following attributes are commonly available:
<variablelist>
<varlistentry>
<term><literal>library</literal></term>
<listitem>
<para>
Name of the SSL implementation in use. (Currently, only
<literal>"OpenSSL"</literal> is implemented)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>protocol</literal></term>
<listitem>
<para>
SSL/TLS version in use. Common values are "SSLv2", "SSLv3",
"TLSv1", "TLSv1.1" and "TLSv1.2", but an implementation may
return other strings if some other protocol is used.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>key_bits</literal></term>
<listitem>
<para>
Number of key bits used by the encryption algorithm.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>cipher</literal></term>
<listitem>
<para>
A short name of the ciphersuite used, e.g.
<literal>"DHE-RSA-DES-CBC3-SHA"</literal>. The names are specific
to each SSL implementation.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>compression</literal></term>
<listitem>
<para>
If SSL compression is in use, returns the name of the compression
algorithm, or "on" if compression is used but the algorithm is
not known. If compression is not in use, returns "off".
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</listitem>
</varlistentry>
<varlistentry id="libpq-pqsslattributes">
<term><function>PQsslAttributes</function><indexterm><primary>PQsslAttributes</></></term>
<listitem>
<para>
Return an array of SSL attribute names available. The array is terminated by a NULL pointer.
<synopsis>
const char **PQsslAttributes(const PGconn *conn);
</synopsis>
</para>
</listitem>
</varlistentry>
<varlistentry id="libpq-pqsslstruct">
<term><function>PQsslStruct</function><indexterm><primary>PQsslStruct</></></term>
<listitem>
<para>
Return a pointer to an SSL-implementation specific object describing
the connection.
<synopsis>
void *PQsslStruct(const PGconn *conn, const char *struct_name);
</synopsis>
</para>
<para>
The actual return value is of type <type>SSL *</type>,
where <type>SSL</type> is a type defined by
the <productname>OpenSSL</productname> library, but it is not declared
this way to avoid requiring the <productname>OpenSSL</productname>
header files. To use this function, code along the following lines
could be used:
The structs available depends on the SSL implementation in use.
For OpenSSL, there is one struct, under the name "OpenSSL",
and it returns a pointer to the OpenSSL <literal>SSL</literal> struct.
To use this function, code along the following lines could be used:
<programlisting><![CDATA[
#include <libpq-fe.h>
#include <openssl/ssl.h>
......@@ -1886,13 +1980,42 @@ void *PQgetssl(const PGconn *conn);
dbconn = PQconnectdb(...);
...
ssl = PQgetssl(dbconn);
ssl = PQsslStruct(dbconn, "OpenSSL");
if (ssl)
{
/* use OpenSSL functions to access ssl */
}
]]></programlisting>
</para>
<para>
This structure can be used to verify encryption levels, check server
certificates, and more. Refer to the <productname>OpenSSL</>
documentation for information about this structure.
</para>
</listitem>
</varlistentry>
<varlistentry id="libpq-pqgetssl">
<term><function>PQgetssl</function><indexterm><primary>PQgetssl</></></term>
<listitem>
<para>
<indexterm><primary>SSL</><secondary sortas="libpq">in libpq</secondary></indexterm>
Returns the SSL structure used in the connection, or null
if SSL is not in use.
<synopsis>
void *PQgetssl(const PGconn *conn);
</synopsis>
</para>
<para>
This function is equivalent to PQsslStruct(conn, "OpenSSL"). It should
not be used in new applications, because the returned struct is
specific to OpenSSL and will not be available if another SSL
implementation is used. To check if a connection uses SSL, call
<function>PQsslInUse</> instead, and for more details about the
connection, use <function>PQsslAttribute</>.
</para>
</listitem>
</varlistentry>
......
......@@ -30,9 +30,6 @@
#include <sys/types.h> /* for umask() */
#include <sys/stat.h> /* for stat() */
#endif
#ifdef USE_OPENSSL
#include <openssl/ssl.h>
#endif
#include "portability/instr_time.h"
......@@ -1815,28 +1812,24 @@ connection_warnings(bool in_startup)
static void
printSSLInfo(void)
{
#ifdef USE_OPENSSL
int sslbits = -1;
SSL *ssl;
const char *protocol;
const char *cipher;
const char *bits;
const char *compression;
ssl = PQgetssl(pset.db);
if (!ssl)
if (!PQsslInUse(pset.db))
return; /* no SSL */
SSL_get_cipher_bits(ssl, &sslbits);
printf(_("SSL connection (protocol: %s, cipher: %s, bits: %d, compression: %s)\n"),
SSL_get_version(ssl), SSL_get_cipher(ssl), sslbits,
SSL_get_current_compression(ssl) ? _("on") : _("off"));
#else
protocol = PQsslAttribute(pset.db, "protocol");
cipher = PQsslAttribute(pset.db, "cipher");
bits = PQsslAttribute(pset.db, "key_bits");
compression = PQsslAttribute(pset.db, "compression");
/*
* If psql is compiled without SSL but is using a libpq with SSL, we
* cannot figure out the specifics about the connection. But we know it's
* SSL secured.
*/
if (PQgetssl(pset.db))
printf(_("SSL connection (unknown cipher)\n"));
#endif
printf(_("SSL connection (protocol: %s, cipher: %s, bits: %s, compression: %s)\n"),
protocol ? protocol : _("unknown"),
cipher ? cipher : _("unknown"),
bits ? bits : _("unknown"),
(compression && strcmp(compression, "off") != 0) ? _("on") : _("off"));
}
......
......@@ -165,3 +165,7 @@ lo_lseek64 162
lo_tell64 163
lo_truncate64 164
PQconninfo 165
PQsslInUse 166
PQsslStruct 167
PQsslAttributes 168
PQsslAttribute 169
......@@ -1488,6 +1488,18 @@ SSLerrfree(char *buf)
free(buf);
}
/* ------------------------------------------------------------ */
/* SSL information functions */
/* ------------------------------------------------------------ */
int
PQsslInUse(PGconn *conn)
{
if (!conn)
return 0;
return conn->ssl_in_use;
}
/*
* Return pointer to OpenSSL object.
*/
......@@ -1499,6 +1511,62 @@ PQgetssl(PGconn *conn)
return conn->ssl;
}
void *
PQsslStruct(PGconn *conn, const char *struct_name)
{
if (!conn)
return NULL;
if (strcmp(struct_name, "OpenSSL") == 0)
return conn->ssl;
return NULL;
}
const char **
PQsslAttributes(PGconn *conn)
{
static const char *result[] = {
"library",
"key_bits",
"cipher",
"compression",
"protocol",
NULL
};
return result;
}
const char *
PQsslAttribute(PGconn *conn, const char *attribute_name)
{
if (!conn)
return NULL;
if (conn->ssl == NULL)
return NULL;
if (strcmp(attribute_name, "library") == 0)
return "OpenSSL";
if (strcmp(attribute_name, "key_bits") == 0)
{
static char sslbits_str[10];
int sslbits;
SSL_get_cipher_bits(conn->ssl, &sslbits);
snprintf(sslbits_str, sizeof(sslbits_str), "%d", sslbits);
return sslbits_str;
}
if (strcmp(attribute_name, "cipher") == 0)
return SSL_get_cipher(conn->ssl);
if (strcmp(attribute_name, "compression") == 0)
return SSL_get_current_compression(conn->ssl) ? "on" : "off";
if (strcmp(attribute_name, "protocol") == 0)
return SSL_get_version(conn->ssl);
return NULL; /* unknown attribute */
}
/*
* Private substitute BIO: this does the sending and receiving using send() and
......
......@@ -381,12 +381,32 @@ retry_masked:
return n;
}
/* Dummy versions of SSL info functions, when built without SSL support */
#ifndef USE_SSL
int
PQsslInUse(PGconn *conn)
{
return 0;
}
void *
PQgetssl(PGconn *conn)
{
return NULL;
}
void *
PQsslStruct(PGconn *conn, const char *struct_name)
{
return NULL;
}
const char *
PQsslAttribute(PGconn *conn, const char *attribute_name)
{
return NULL;
}
#endif /* USE_SSL */
......
......@@ -318,6 +318,12 @@ extern int PQconnectionUsedPassword(const PGconn *conn);
extern int PQclientEncoding(const PGconn *conn);
extern int PQsetClientEncoding(PGconn *conn, const char *encoding);
/* SSL information functions */
extern int PQsslInUse(PGconn *conn);
extern void *PQsslStruct(PGconn *conn, const char *struct_name);
extern const char *PQsslAttribute(PGconn *conn, const char *attribute_name);
extern const char **PQsslAttributes(PGconn *conn);
/* Get the OpenSSL structure associated with a connection. Returns NULL for
* unencrypted connections or if any other TLS library is in use. */
extern void *PQgetssl(PGconn *conn);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment