*
* Written by Victor B. Wagner <vitus@cryptocom.ru>, Cryptocom LTD
* This file is distributed under BSD-style license.
+ *
+ * contrib/sslinfo/sslinfo.c
*/
#include "postgres.h"
#include <openssl/x509.h>
#include <openssl/asn1.h>
-
PG_MODULE_MAGIC;
+static Datum X509_NAME_field_to_text(X509_NAME *name, text *fieldName);
+static Datum X509_NAME_to_text(X509_NAME *name);
+static Datum ASN1_STRING_to_text(ASN1_STRING *str);
-Datum ssl_is_used(PG_FUNCTION_ARGS);
-Datum ssl_client_cert_present(PG_FUNCTION_ARGS);
-Datum ssl_client_serial(PG_FUNCTION_ARGS);
-Datum ssl_client_dn_field(PG_FUNCTION_ARGS);
-Datum ssl_issuer_field(PG_FUNCTION_ARGS);
-Datum ssl_client_dn(PG_FUNCTION_ARGS);
-Datum ssl_issuer_dn(PG_FUNCTION_ARGS);
-Datum X509_NAME_field_to_text(X509_NAME *name, text *fieldName);
-Datum X509_NAME_to_text(X509_NAME *name);
-Datum ASN1_STRING_to_text(ASN1_STRING *str);
-
-/*
+/*
* Indicates whether current session uses SSL
*
* Function has no arguments. Returns bool. True if current session
* is SSL session and false if it is local or non-ssl session.
*/
PG_FUNCTION_INFO_V1(ssl_is_used);
-Datum ssl_is_used(PG_FUNCTION_ARGS)
+Datum
+ssl_is_used(PG_FUNCTION_ARGS)
{
- PG_RETURN_BOOL(MyProcPort->ssl !=NULL);
+ PG_RETURN_BOOL(MyProcPort->ssl != NULL);
}
/*
- * Indicates whether current client have provided a certificate
+ * Returns SSL version currently in use.
+ */
+PG_FUNCTION_INFO_V1(ssl_version);
+Datum
+ssl_version(PG_FUNCTION_ARGS)
+{
+ if (MyProcPort->ssl == NULL)
+ PG_RETURN_NULL();
+ PG_RETURN_TEXT_P(cstring_to_text(SSL_get_version(MyProcPort->ssl)));
+}
+
+
+/*
+ * Returns SSL cipher currently in use.
+ */
+PG_FUNCTION_INFO_V1(ssl_cipher);
+Datum
+ssl_cipher(PG_FUNCTION_ARGS)
+{
+ if (MyProcPort->ssl == NULL)
+ PG_RETURN_NULL();
+ PG_RETURN_TEXT_P(cstring_to_text(SSL_get_cipher(MyProcPort->ssl)));
+}
+
+
+/*
+ * Indicates whether current client provided a certificate
*
* Function has no arguments. Returns bool. True if current session
* is SSL session and client certificate is verified, otherwise false.
*/
PG_FUNCTION_INFO_V1(ssl_client_cert_present);
-Datum ssl_client_cert_present(PG_FUNCTION_ARGS)
+Datum
+ssl_client_cert_present(PG_FUNCTION_ARGS)
{
PG_RETURN_BOOL(MyProcPort->peer != NULL);
}
* SSL connection is established without sending client certificate.
*/
PG_FUNCTION_INFO_V1(ssl_client_serial);
-Datum ssl_client_serial(PG_FUNCTION_ARGS)
+Datum
+ssl_client_serial(PG_FUNCTION_ARGS)
{
- Datum result;
- Port *port = MyProcPort;
- X509 *peer = port->peer;
+ Datum result;
+ Port *port = MyProcPort;
+ X509 *peer = port->peer;
ASN1_INTEGER *serial = NULL;
- BIGNUM *b;
- char *decimal;
+ BIGNUM *b;
+ char *decimal;
if (!peer)
PG_RETURN_NULL();
serial = X509_get_serialNumber(peer);
b = ASN1_INTEGER_to_BN(serial, NULL);
decimal = BN_bn2dec(b);
+
BN_free(b);
result = DirectFunctionCall3(numeric_in,
CStringGetDatum(decimal),
* current database encoding if possible. Any invalid characters are
* replaced by question marks.
*
- * Parameter: str - OpenSSL ASN1_STRING structure. Memory managment
+ * Parameter: str - OpenSSL ASN1_STRING structure. Memory management
* of this structure is responsibility of caller.
*
* Returns Datum, which can be directly returned from a C language SQL
* function.
*/
-Datum ASN1_STRING_to_text(ASN1_STRING *str)
+static Datum
+ASN1_STRING_to_text(ASN1_STRING *str)
{
- BIO *membuf = NULL;
- size_t size, outlen;
- char *sp;
- char *dp;
- text *result;
+ BIO *membuf;
+ size_t size;
+ char nullterm;
+ char *sp;
+ char *dp;
+ text *result;
membuf = BIO_new(BIO_s_mem());
- BIO_set_close(membuf, BIO_CLOSE);
- ASN1_STRING_print_ex(membuf,str,
+ (void) BIO_set_close(membuf, BIO_CLOSE);
+ ASN1_STRING_print_ex(membuf, str,
((ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB)
| ASN1_STRFLGS_UTF8_CONVERT));
-
- outlen = 0;
- BIO_write(membuf, &outlen, 1);
+ /* ensure null termination of the BIO's content */
+ nullterm = '\0';
+ BIO_write(membuf, &nullterm, 1);
size = BIO_get_mem_data(membuf, &sp);
- dp = (char *) pg_do_encoding_conversion((unsigned char *) sp,
- size-1,
- PG_UTF8,
- GetDatabaseEncoding());
- outlen = strlen(dp);
- result = palloc(VARHDRSZ + outlen);
- memcpy(VARDATA(result), dp, outlen);
+ dp = pg_any_to_server(sp, size - 1, PG_UTF8);
+ result = cstring_to_text(dp);
if (dp != sp)
pfree(dp);
-
BIO_free(membuf);
- VARATT_SIZEP(result) = outlen + VARHDRSZ;
+
PG_RETURN_TEXT_P(result);
}
*
* Parameter: X509_NAME *name - either subject or issuer of certificate
* Parameter: text fieldName - field name string like 'CN' or commonName
- * to be looked up in the OpenSSL ASN1 OID database
+ * to be looked up in the OpenSSL ASN1 OID database
*
* Returns result of ASN1_STRING_to_text applied to appropriate
* part of name
*/
-Datum X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
+static Datum
+X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
{
- char *sp;
- char *string_fieldname;
- char *dp;
- size_t name_len = VARSIZE(fieldName) - VARHDRSZ;
- int nid, index, i;
+ char *string_fieldname;
+ int nid,
+ index;
ASN1_STRING *data;
- string_fieldname = palloc(name_len + 1);
- sp = VARDATA(fieldName);
- dp = string_fieldname;
- for (i = 0; i < name_len; i++)
- *dp++ = *sp++;
- *dp = '\0';
+ string_fieldname = text_to_cstring(fieldName);
nid = OBJ_txt2nid(string_fieldname);
if (nid == NID_undef)
ereport(ERROR,
pfree(string_fieldname);
index = X509_NAME_get_index_by_NID(name, nid, -1);
if (index < 0)
- return (Datum)0;
+ return (Datum) 0;
data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, index));
return ASN1_STRING_to_text(data);
}
* there is no field with such name in the certificate.
*/
PG_FUNCTION_INFO_V1(ssl_client_dn_field);
-Datum ssl_client_dn_field(PG_FUNCTION_ARGS)
+Datum
+ssl_client_dn_field(PG_FUNCTION_ARGS)
{
- text *fieldname = PG_GETARG_TEXT_P(0);
- Datum result;
+ text *fieldname = PG_GETARG_TEXT_P(0);
+ Datum result;
if (!(MyProcPort->peer))
PG_RETURN_NULL();
* there is no field with such name in the certificate.
*/
PG_FUNCTION_INFO_V1(ssl_issuer_field);
-Datum ssl_issuer_field(PG_FUNCTION_ARGS)
+Datum
+ssl_issuer_field(PG_FUNCTION_ARGS)
{
- text *fieldname = PG_GETARG_TEXT_P(0);
- Datum result;
+ text *fieldname = PG_GETARG_TEXT_P(0);
+ Datum result;
if (!(MyProcPort->peer))
PG_RETURN_NULL();
* Returns: text datum which contains string representation of
* X509_NAME
*/
-Datum X509_NAME_to_text(X509_NAME *name)
+static Datum
+X509_NAME_to_text(X509_NAME *name)
{
- BIO *membuf = BIO_new(BIO_s_mem());
- int i,nid,count = X509_NAME_entry_count(name);
+ BIO *membuf = BIO_new(BIO_s_mem());
+ int i,
+ nid,
+ count = X509_NAME_entry_count(name);
X509_NAME_ENTRY *e;
ASN1_STRING *v;
-
const char *field_name;
- size_t size,outlen;
- char *sp;
- char *dp;
- text *result;
-
- BIO_set_close(membuf, BIO_CLOSE);
- for (i=0; i<count; i++)
+ size_t size;
+ char nullterm;
+ char *sp;
+ char *dp;
+ text *result;
+
+ (void) BIO_set_close(membuf, BIO_CLOSE);
+ for (i = 0; i < count; i++)
{
e = X509_NAME_get_entry(name, i);
nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(e));
if (!field_name)
field_name = OBJ_nid2ln(nid);
BIO_printf(membuf, "/%s=", field_name);
- ASN1_STRING_print_ex(membuf,v,
+ ASN1_STRING_print_ex(membuf, v,
((ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB)
| ASN1_STRFLGS_UTF8_CONVERT));
}
- i=0;
- BIO_write(membuf, &i, 1);
+ /* ensure null termination of the BIO's content */
+ nullterm = '\0';
+ BIO_write(membuf, &nullterm, 1);
size = BIO_get_mem_data(membuf, &sp);
-
- dp = (char *) pg_do_encoding_conversion((unsigned char *) sp,
- size-1,
- PG_UTF8,
- GetDatabaseEncoding());
- BIO_free(membuf);
- outlen = strlen(dp);
- result = palloc(VARHDRSZ + outlen);
- memcpy(VARDATA(result), dp, outlen);
-
- /* pg_do_encoding_conversion has annoying habit of returning
- * source pointer */
+ dp = pg_any_to_server(sp, size - 1, PG_UTF8);
+ result = cstring_to_text(dp);
if (dp != sp)
pfree(dp);
- VARATT_SIZEP(result) = outlen + VARHDRSZ;
+ BIO_free(membuf);
+
PG_RETURN_TEXT_P(result);
}
* Returns text datum.
*/
PG_FUNCTION_INFO_V1(ssl_client_dn);
-Datum ssl_client_dn(PG_FUNCTION_ARGS)
+Datum
+ssl_client_dn(PG_FUNCTION_ARGS)
{
if (!(MyProcPort->peer))
PG_RETURN_NULL();
* Returns text datum.
*/
PG_FUNCTION_INFO_V1(ssl_issuer_dn);
-Datum ssl_issuer_dn(PG_FUNCTION_ARGS)
+Datum
+ssl_issuer_dn(PG_FUNCTION_ARGS)
{
if (!(MyProcPort->peer))
PG_RETURN_NULL();