Hello,
I make an a patch, which adds 4 functions to sslinfo extension module:
1) ssl_extension_names() --- get short names of X509v3 extensions from client certificate and it's values; 2) ssl_extension_value(text) --- get value of extension from certificate (argument --- short name of extension); 3) ssl_extension_is_critical(text) --- returns true, if extension is critical and false, if is not (argument --- short name of extension).
You can view some information of certificate's extensions via those functions. What do you think about it?
--
Best regards, Dmitry Voronin
*** 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);
+ int 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 0, if we have found extension in certificate and 1, if we not.
+ */
+ int 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 1;
+
+ 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 0;
+ }
+
+
+ /* 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';
+ int error = 0;
+
+ /* 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;
+ int error = 0;
+
+ /* 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 name \"%s\"", ext_name)));
+
+ /* 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/contrib/sslinfo/sslinfo.control
--- b/contrib/sslinfo/sslinfo.control
***************
*** 1,5 ****
# sslinfo extension
comment = 'information about SSL certificates'
! default_version = '1.0'
module_pathname = '$libdir/sslinfo'
relocatable = true
--- 1,5 ----
# sslinfo extension
comment = 'information about SSL certificates'
! default_version = '1.1'
module_pathname = '$libdir/sslinfo'
relocatable = true
*** 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
