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>vi...@cryptocom.ru</email>, Cryptocom LTD
    </para>
+   
+   <para>
+    Extension's functions: Dmitry Voronin <email>carriingfat...@yandex.ru</email>
+   </para>
  
    <para>
     E-Mail of Cryptocom OpenSSL development group:
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to