Hello, Michael.
Please, attach new version of my patch to commitfest page.
--
Best regards, Dmitry Voronin
*** /dev/null
--- b/contrib/sslinfo/sslinfo--1.0--1.1.sql
***************
*** 0 ****
--- 1,21 ----
+ /* contrib/sslinfo/sslinfo--1.0--1.1.sql */
+
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "ALTER EXTENSION sslinfo UPDATE TO '1.1'" to load this file. \quit
+
+ CREATE OR REPLACE FUNCTION ssl_extension_value(text) RETURNS text
+ AS 'MODULE_PATHNAME', 'ssl_extension_value'
+ LANGUAGE C STRICT;
+
+ CREATE OR REPLACE FUNCTION ssl_extension_is_critical(text) RETURNS boolean
+ AS 'MODULE_PATHNAME', 'ssl_extension_is_critical'
+ LANGUAGE C STRICT;
+
+ CREATE TYPE extension AS (
+ name text,
+ value text
+ );
+
+ CREATE OR REPLACE FUNCTION ssl_extension_names() RETURNS SETOF extension
+ AS 'MODULE_PATHNAME', 'ssl_extension_names'
+ LANGUAGE C STRICT;
*** /dev/null
--- b/contrib/sslinfo/sslinfo--1.1.sql
***************
*** 0 ****
--- 1,58 ----
+ /* contrib/sslinfo/sslinfo--1.1.sql */
+
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "CREATE EXTENSION sslinfo" to load this file. \quit
+
+ CREATE FUNCTION ssl_client_serial() RETURNS numeric
+ AS 'MODULE_PATHNAME', 'ssl_client_serial'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION ssl_is_used() RETURNS boolean
+ AS 'MODULE_PATHNAME', 'ssl_is_used'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION ssl_version() RETURNS text
+ AS 'MODULE_PATHNAME', 'ssl_version'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION ssl_cipher() RETURNS text
+ AS 'MODULE_PATHNAME', 'ssl_cipher'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION ssl_client_cert_present() RETURNS boolean
+ AS 'MODULE_PATHNAME', 'ssl_client_cert_present'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION ssl_client_dn_field(text) RETURNS text
+ AS 'MODULE_PATHNAME', 'ssl_client_dn_field'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION ssl_issuer_field(text) RETURNS text
+ AS 'MODULE_PATHNAME', 'ssl_issuer_field'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION ssl_client_dn() RETURNS text
+ AS 'MODULE_PATHNAME', 'ssl_client_dn'
+ LANGUAGE C STRICT;
+
+ CREATE FUNCTION ssl_issuer_dn() RETURNS text
+ AS 'MODULE_PATHNAME', 'ssl_issuer_dn'
+ LANGUAGE C STRICT;
+
+ /* new in 1.1 */
+ CREATE OR REPLACE FUNCTION ssl_extension_value(text) RETURNS text
+ AS 'MODULE_PATHNAME', 'ssl_extension_value'
+ LANGUAGE C STRICT;
+
+ CREATE OR REPLACE FUNCTION ssl_extension_is_critical(text) RETURNS boolean
+ AS 'MODULE_PATHNAME', 'ssl_extension_is_critical'
+ LANGUAGE C STRICT;
+
+ CREATE TYPE extension AS (
+ name text,
+ value text
+ );
+
+ CREATE OR REPLACE FUNCTION ssl_extension_names() RETURNS SETOF extension
+ AS 'MODULE_PATHNAME', 'ssl_extension_names'
+ LANGUAGE C STRICT;
*** a/contrib/sslinfo/sslinfo.c
--- b/contrib/sslinfo/sslinfo.c
***************
*** 14,21 ****
--- 14,23 ----
#include "miscadmin.h"
#include "utils/builtins.h"
#include "mb/pg_wchar.h"
+ #include "funcapi.h"
#include <openssl/x509.h>
+ #include <openssl/x509v3.h>
#include <openssl/asn1.h>
PG_MODULE_MAGIC;
***************
*** 23,28 **** PG_MODULE_MAGIC;
--- 25,31 ----
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);
+ static bool get_extension(X509 *cert, const char *ext_name, X509_EXTENSION **extension);
/*
***************
*** 354,356 **** ssl_issuer_dn(PG_FUNCTION_ARGS)
--- 357,581 ----
PG_RETURN_NULL();
return X509_NAME_to_text(X509_get_issuer_name(MyProcPort->peer));
}
+
+
+ /*
+ * Returns extension object by given certificate and extension's name.
+ *
+ * Try to get extension from certificate by extension's name.
+ * We returns at extension param pointer to X509_EXTENSION.
+ *
+ * Returns true, if we have found extension in certificate and false, if we not.
+ */
+ static bool get_extension(X509* cert, const char *ext_name, X509_EXTENSION **extension)
+ {
+ int nid = 0;
+ int loc = 0;
+
+ /* try to convert extension name to ObjectID */
+ nid = OBJ_txt2nid(ext_name);
+ /* Not success ? */
+ if (nid == NID_undef)
+ return false;
+
+ loc = X509_get_ext_by_NID(cert, nid, -1);
+
+ /* palloc memory for extension and copy it */
+ *extension = (X509_EXTENSION *) palloc(sizeof(X509_EXTENSION *));
+ memcpy(*extension, X509_get_ext(cert, loc), sizeof(X509_EXTENSION));
+
+ return true;
+ }
+
+
+ /* Returns value of extension
+ *
+ * This function returns value of extension by given name in client certificate.
+ *
+ * Returns text datum.
+ */
+ PG_FUNCTION_INFO_V1(ssl_extension_value);
+ Datum
+ ssl_extension_value(PG_FUNCTION_ARGS)
+ {
+ X509 *cert = MyProcPort->peer;
+ X509_EXTENSION *ext = NULL;
+ char *ext_name = text_to_cstring(PG_GETARG_TEXT_P(0));
+ BIO *membuf = NULL;
+ char *val = NULL;
+ char nullterm = '\0';
+ bool error = false;
+
+ /* If we have no ssl security */
+ if (cert == NULL)
+ PG_RETURN_NULL();
+
+ /* If extension's converting from text name to extension's OID failed (return NID_undef) */
+ if (OBJ_txt2nid(ext_name) == NID_undef)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Unknown extension name \"%s\"", ext_name)));
+
+ /* Extension's name is correct, try to get extension object from certificate */
+ error = get_extension(cert, ext_name, &ext);
+
+ /* Not found? */
+ if (!error)
+ PG_RETURN_NULL();
+
+ /* Print extension to BIO */
+ membuf = BIO_new(BIO_s_mem());
+ X509V3_EXT_print(membuf, ext, 0, 0);
+ BIO_write(membuf, &nullterm, 1);
+ BIO_get_mem_data(membuf, &val);
+
+ /* Copy value */
+ val = pstrdup(val);
+
+ /* Clear BIO */
+ BIO_free(membuf);
+
+ /* free extension */
+ if (ext)
+ pfree(ext);
+
+ PG_RETURN_TEXT_P(cstring_to_text(val));
+ }
+
+
+ /* Returns status of extension
+ *
+ * Returns true, if extension is critical and false, if it is not.
+ *
+ * Returns bool datum.
+ */
+ PG_FUNCTION_INFO_V1(ssl_extension_is_critical);
+ Datum
+ ssl_extension_is_critical(PG_FUNCTION_ARGS)
+ {
+ X509 *cert = MyProcPort->peer;
+ X509_EXTENSION *ext = NULL;
+ char *ext_name = text_to_cstring(PG_GETARG_TEXT_P(0));
+ int critical;
+ bool error = false;
+
+ /* If we have no ssl security */
+ if (cert == NULL)
+ PG_RETURN_NULL();
+
+ /* If extension's converting from text name to extension's OID failed (return NID_undef) */
+ if (OBJ_txt2nid(ext_name) == NID_undef)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Unknown extension name \"%s\"", ext_name)));
+
+ /* Extension's name is correct, try to get extension object from certificate */
+ error = get_extension(cert, ext_name, &ext);
+
+ /* Not found? */
+ if (!error)
+ PG_RETURN_NULL();
+
+ critical = X509_EXTENSION_get_critical(ext);
+
+ /* free extension */
+ if (ext)
+ pfree(ext);
+
+ PG_RETURN_BOOL(critical);
+ }
+
+
+ /* Returns key-value pairs of extension name and it's value
+ *
+ * This function print extensions of client certificate at table form (extension's name and it's value).
+ *
+ * Returns setof text datum.
+ */
+ PG_FUNCTION_INFO_V1(ssl_extension_names);
+ Datum
+ ssl_extension_names(PG_FUNCTION_ARGS)
+ {
+ X509 *cert = MyProcPort->peer;
+ FuncCallContext *funcctx;
+ STACK_OF(X509_EXTENSION) *ext_stack = NULL;
+ int call;
+ int max_calls;
+ TupleDesc tupdesc;
+ AttInMetadata *attinmeta;
+ MemoryContext oldcontext;
+ char **values;
+ HeapTuple tuple;
+ int nid;
+ X509_EXTENSION *ext = NULL;
+ ASN1_OBJECT *obj = NULL;
+ BIO *membuf = NULL;
+ char nullterm = '\0';
+
+ /* If we have no ssl security */
+ if (cert == NULL)
+ PG_RETURN_NULL();
+
+ /* Get all extensions of certificate */
+ ext_stack = cert->cert_info->extensions;
+
+ /* Certificate does not have extensions? */
+ if (ext_stack == NULL)
+ PG_RETURN_NULL();
+
+ if (SRF_IS_FIRSTCALL())
+ {
+ funcctx = SRF_FIRSTCALL_INIT();
+ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+ /* Set mac_calls as a count of extensions in certificate */
+ funcctx->max_calls = X509_get_ext_count(cert);
+
+ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("function returning record called in context "
+ "that cannot accept type record")));
+
+ attinmeta = TupleDescGetAttInMetadata(tupdesc);
+ funcctx->attinmeta = attinmeta;
+
+ MemoryContextSwitchTo(oldcontext);
+ }
+
+ funcctx = SRF_PERCALL_SETUP();
+ call = funcctx->call_cntr;
+ max_calls = funcctx->max_calls;
+ attinmeta = funcctx->attinmeta;
+
+ if (call < max_calls)
+ {
+ values = (char **) palloc(2 * sizeof(char *));
+
+ /* Get extension from certificate */
+ ext = sk_X509_EXTENSION_value(ext_stack, call);
+ obj = X509_EXTENSION_get_object(ext);
+ nid = OBJ_obj2nid(obj);
+
+ if (nid == NID_undef)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Unknown extension at position %d", call)));
+
+ /* Set extension name as first value in array */
+ values[0] = (char *) OBJ_nid2sn(nid);
+
+ /* Print extension's value and set as second value in array */
+ membuf = BIO_new(BIO_s_mem());
+ X509V3_EXT_print(membuf, ext, 0, 0);
+ BIO_write(membuf, &nullterm, 1);
+ BIO_get_mem_data(membuf, &values[1]);
+
+ /* Build tuple */
+ tuple = BuildTupleFromCStrings(attinmeta, values);
+
+ BIO_free(membuf);
+
+ SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+ }
+ SRF_RETURN_DONE(funcctx);
+ }
*** a/doc/src/sgml/sslinfo.sgml
--- b/doc/src/sgml/sslinfo.sgml
***************
*** 219,224 **** emailAddress
--- 219,266 ----
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_extension_value(extension_name text) returns text</function>
+ <indexterm>
+ <primary>ssl_extension_value</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Returns value of extension by given name in client certificate.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_extension_is_critical(extension_name text) returns boolean</function>
+ <indexterm>
+ <primary>ssl_extension_is_critical</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Returns TRUE if extension is critical and FALSE if not.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_extension_names() returns SETOF text </function>
+ <indexterm>
+ <primary>ssl_extension_names</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Print extensions of client certificate at table form (extension's name and it's value).
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</sect2>
***************
*** 228,233 **** emailAddress
--- 270,279 ----
<para>
Victor Wagner <email>[email protected]</email>, Cryptocom LTD
</para>
+
+ <para>
+ Extension's functions: Dmitry Voronin <email>[email protected]</email>
+ </para>
<para>
E-Mail of Cryptocom OpenSSL development group:
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers