*** a/contrib/sslinfo/sslinfo--1.0.sql
--- b/contrib/sslinfo/sslinfo--1.0.sql
***************
*** 38,40 **** LANGUAGE C STRICT;
--- 38,56 ----
  CREATE FUNCTION ssl_issuer_dn() RETURNS text
  AS 'MODULE_PATHNAME', 'ssl_issuer_dn'
  LANGUAGE C STRICT;
+ 
+ CREATE OR REPLACE FUNCTION ssl_get_extension_value(text) RETURNS text
+ AS 'MODULE_PATHNAME', 'ssl_get_extension_value'
+ LANGUAGE C STRICT;
+ 
+ CREATE OR REPLACE FUNCTION ssl_is_critical_extension(text) RETURNS boolean
+ AS 'MODULE_PATHNAME', 'ssl_is_critical_extension'
+ LANGUAGE C STRICT;
+ 
+ CREATE OR REPLACE FUNCTION ssl_get_count_of_extensions() RETURNS integer
+ AS 'MODULE_PATHNAME', 'ssl_get_count_of_extensions'
+ LANGUAGE C STRICT;
+ 
+ CREATE OR REPLACE FUNCTION ssl_get_extension_names() RETURNS SETOF text 
+ AS 'MODULE_PATHNAME', 'ssl_get_extension_names'
+ LANGUAGE C STRICT;
\ No newline at end of file
\ No newline at end of file
*** a/contrib/sslinfo/sslinfo--unpackaged--1.0.sql
--- b/contrib/sslinfo/sslinfo--unpackaged--1.0.sql
***************
*** 11,16 **** ALTER EXTENSION sslinfo ADD function ssl_issuer_field(text);
--- 11,21 ----
  ALTER EXTENSION sslinfo ADD function ssl_client_dn();
  ALTER EXTENSION sslinfo ADD function ssl_issuer_dn();
  
+ ALTER EXTENSION sslinfo ADD function ssl_get_extension_value();
+ ALTER EXTENSION sslinfo ADD function ssl_is_critical_extension();
+ ALTER EXTENSION sslinfo ADD function ssl_count_of_extensions();
+ ALTER EXTENSION sslinfo ADD function ssl_get_extension_names();
+ 
  -- These functions were not in 9.0:
  
  CREATE FUNCTION ssl_version() RETURNS text
*** a/contrib/sslinfo/sslinfo.c
--- b/contrib/sslinfo/sslinfo.c
***************
*** 5,10 ****
--- 5,12 ----
   * This file is distributed under BSD-style license.
   *
   * contrib/sslinfo/sslinfo.c
+  * 
+  * Extension functions written by Dmitry Voronin carriingfate92@yandex.ru, CNIIEISU.
   */
  
  #include "postgres.h"
***************
*** 14,31 ****
  #include "miscadmin.h"
  #include "utils/builtins.h"
  #include "mb/pg_wchar.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);
  
  
  /*
   * Indicates whether current session uses SSL
--- 16,49 ----
  #include "miscadmin.h"
  #include "utils/builtins.h"
  #include "mb/pg_wchar.h"
+ #include "funcapi.h"
  
  #include <openssl/x509.h>
  #include <openssl/asn1.h>
+ #include <openssl/x509v3.h>
  
  
  PG_MODULE_MAGIC;
  
  
! Datum		ssl_is_used(PG_FUNCTION_ARGS);
! Datum		ssl_version(PG_FUNCTION_ARGS);
! Datum		ssl_cipher(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);
  
+ X509_EXTENSION	*get_extension(X509* certificate, char *name);
+ Datum 		ssl_get_extension_value(PG_FUNCTION_ARGS);
+ Datum		ssl_is_critical_extension(PG_FUNCTION_ARGS);
+ Datum 		ssl_get_count_of_extensions(PG_FUNCTION_ARGS);
+ Datum		ssl_get_extension_names(PG_FUNCTION_ARGS);
  
  /*
   * Indicates whether current session uses SSL
***************
*** 42,48 **** ssl_is_used(PG_FUNCTION_ARGS)
  
  
  /*
!  * Returns SSL version currently in use.
   */
  PG_FUNCTION_INFO_V1(ssl_version);
  Datum
--- 60,66 ----
  
  
  /*
!  * Returns SSL cipher currently in use.
   */
  PG_FUNCTION_INFO_V1(ssl_version);
  Datum
***************
*** 68,74 **** ssl_cipher(PG_FUNCTION_ARGS)
  
  
  /*
!  * 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.
--- 86,92 ----
  
  
  /*
!  * Indicates whether current client have provided a certificate
   *
   * Function has no arguments.  Returns bool.  True if current session
   * is SSL session and client certificate is verified, otherwise false.
***************
*** 129,135 **** ssl_client_serial(PG_FUNCTION_ARGS)
   * Returns Datum, which can be directly returned from a C language SQL
   * function.
   */
! static Datum
  ASN1_STRING_to_text(ASN1_STRING *str)
  {
  	BIO		   *membuf;
--- 147,153 ----
   * Returns Datum, which can be directly returned from a C language SQL
   * function.
   */
! Datum
  ASN1_STRING_to_text(ASN1_STRING *str)
  {
  	BIO		   *membuf;
***************
*** 148,154 **** ASN1_STRING_to_text(ASN1_STRING *str)
  	nullterm = '\0';
  	BIO_write(membuf, &nullterm, 1);
  	size = BIO_get_mem_data(membuf, &sp);
! 	dp = pg_any_to_server(sp, size - 1, PG_UTF8);
  	result = cstring_to_text(dp);
  	if (dp != sp)
  		pfree(dp);
--- 166,175 ----
  	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());
  	result = cstring_to_text(dp);
  	if (dp != sp)
  		pfree(dp);
***************
*** 170,176 **** ASN1_STRING_to_text(ASN1_STRING *str)
   * Returns result of ASN1_STRING_to_text applied to appropriate
   * part of name
   */
! static Datum
  X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
  {
  	char	   *string_fieldname;
--- 191,197 ----
   * Returns result of ASN1_STRING_to_text applied to appropriate
   * part of name
   */
! Datum
  X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
  {
  	char	   *string_fieldname;
***************
*** 275,281 **** ssl_issuer_field(PG_FUNCTION_ARGS)
   * Returns: text datum which contains string representation of
   * X509_NAME
   */
! static Datum
  X509_NAME_to_text(X509_NAME *name)
  {
  	BIO		   *membuf = BIO_new(BIO_s_mem());
--- 296,302 ----
   * Returns: text datum which contains string representation of
   * X509_NAME
   */
! Datum
  X509_NAME_to_text(X509_NAME *name)
  {
  	BIO		   *membuf = BIO_new(BIO_s_mem());
***************
*** 310,316 **** X509_NAME_to_text(X509_NAME *name)
  	nullterm = '\0';
  	BIO_write(membuf, &nullterm, 1);
  	size = BIO_get_mem_data(membuf, &sp);
! 	dp = pg_any_to_server(sp, size - 1, PG_UTF8);
  	result = cstring_to_text(dp);
  	if (dp != sp)
  		pfree(dp);
--- 331,340 ----
  	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());
  	result = cstring_to_text(dp);
  	if (dp != sp)
  		pfree(dp);
***************
*** 356,358 **** ssl_issuer_dn(PG_FUNCTION_ARGS)
--- 380,525 ----
  		PG_RETURN_NULL();
  	return X509_NAME_to_text(X509_get_issuer_name(MyProcPort->peer));
  }
+ 
+ 
+ X509_EXTENSION *get_extension(X509* certificate, char *name) {
+ 	int 			extension_nid = 0;
+ 	int 			locate = 0;
+ 	
+ 	extension_nid = OBJ_sn2nid(name);
+ 	if (extension_nid == NID_undef) {
+ 		extension_nid = OBJ_ln2nid(name);
+ 		if (extension_nid == NID_undef) 
+ 			return NULL;
+ 	}
+ 	locate = X509_get_ext_by_NID(certificate, extension_nid,  -1);
+ 	return X509_get_ext(certificate, locate);
+ }
+ 
+ /* Returns value of extension. 
+  * 
+  * This function returns value of extension by short name in client certificate. 
+  * 
+  * Returns text datum. 
+  */
+ 
+ PG_FUNCTION_INFO_V1(ssl_get_extension_value);
+ Datum
+ ssl_get_extension_value(PG_FUNCTION_ARGS) {	
+ 	X509 			*certificate = MyProcPort -> peer;
+ 	X509_EXTENSION 		*extension = NULL;
+ 	char 			*extension_name = text_to_cstring(PG_GETARG_TEXT_P(0));
+ 	BIO 			*bio = NULL;
+ 	char 			*value = NULL;
+ 	char 			nullterm = '\0';
+ 	text 			*result = NULL;
+ 
+ 	if (certificate == NULL)
+ 		PG_RETURN_NULL();
+ 
+ 	extension = get_extension(certificate, extension_name);
+ 	if (extension == NULL)
+ 		elog(ERROR, "Extension by name \"%s\" is not found in certificate", extension_name);
+ 
+ 	bio = BIO_new(BIO_s_mem());
+ 	X509V3_EXT_print(bio, extension, -1, -1);
+ 	BIO_write(bio, &nullterm, 1);
+ 	BIO_get_mem_data(bio, &value);
+ 
+ 	result = cstring_to_text(value);
+ 	BIO_free(bio);
+ 
+ 	PG_RETURN_TEXT_P(result);
+ }
+ 
+ /* Returns status of extension 
+  * 
+  * Returns true, if extension is critical and false, if it is not.
+  * 
+  * Returns bool datum
+  */
+ PG_FUNCTION_INFO_V1(ssl_is_critical_extension);
+ Datum
+ ssl_is_critical_extension(PG_FUNCTION_ARGS) {
+ 	X509 			*certificate = MyProcPort -> peer;
+ 	X509_EXTENSION 		*extension = NULL;
+ 	char 			*extension_name = text_to_cstring(PG_GETARG_TEXT_P(0));
+ 	int 			critical = 0;
+ 	
+ 	if (certificate == NULL)
+ 		PG_RETURN_NULL();
+ 	
+ 	extension = get_extension(certificate, extension_name);
+ 	if (extension == NULL) 
+ 		elog(ERROR, "Extension name \"%s\" is not found in certificate", extension_name);
+ 	
+ 	critical = X509_EXTENSION_get_critical(extension);
+ 	PG_RETURN_BOOL(critical);
+ }
+ 
+ /* Returns count of extensions in client certificate
+  * 
+  * Returns int datum
+  */
+ PG_FUNCTION_INFO_V1(ssl_get_count_of_extensions);
+ Datum
+ ssl_get_count_of_extensions(PG_FUNCTION_ARGS) {
+ 	X509 			*certificate = MyProcPort -> peer;
+ 	
+ 	if (certificate == NULL)
+ 		PG_RETURN_NULL();
+ 	
+ 	PG_RETURN_INT32(X509_get_ext_count(certificate));
+ }
+ 
+ /* Returns short names of extensions in client certificate
+  * 
+  * Returns setof text datum
+  */
+ PG_FUNCTION_INFO_V1(ssl_get_extension_names);
+ Datum
+ ssl_get_extension_names(PG_FUNCTION_ARGS) {
+ 	X509				*certificate = MyProcPort -> peer;
+ 	FuncCallContext 		*funcctx;
+ 	STACK_OF(X509_EXTENSION) 	*extension_stack = NULL;
+ 	MemoryContext 			oldcontext;
+ 	int 				call = 0;
+ 	int 				max_calls = 0;
+ 	X509_EXTENSION			*extension = NULL;
+ 	ASN1_OBJECT			*object = NULL;
+ 	int 				extension_nid = 0;
+ 	text*				result = NULL;
+ 	
+ 	if (certificate == NULL)
+ 		PG_RETURN_NULL();
+ 	
+ 	extension_stack = certificate -> cert_info -> extensions;
+ 	if (extension_stack == NULL) 
+ 		PG_RETURN_NULL();
+ 	
+ 	if (SRF_IS_FIRSTCALL()) {
+ 		funcctx = SRF_FIRSTCALL_INIT();
+ 		oldcontext = MemoryContextSwitchTo(funcctx -> multi_call_memory_ctx);
+ 		funcctx -> max_calls = X509_get_ext_count(certificate);
+ 		MemoryContextSwitchTo(oldcontext);
+ 	}
+ 	funcctx = SRF_PERCALL_SETUP();
+ 	
+ 	call = funcctx -> call_cntr;
+ 	max_calls = funcctx -> max_calls;
+ 	
+ 	if (call < max_calls) {
+ 		extension = sk_X509_EXTENSION_value(extension_stack, call);
+ 		object = X509_EXTENSION_get_object(extension);
+ 		extension_nid = OBJ_obj2nid(object);
+ 	    
+ 		if (extension_nid == NID_undef)
+ 			elog(ERROR, "Unknown extension in certificate");
+ 	    
+ 		result = cstring_to_text(OBJ_nid2sn(extension_nid));
+ 	    
+  		SRF_RETURN_NEXT(funcctx, (Datum) result);
+ 	}
+ 	SRF_RETURN_DONE(funcctx);
+ }
+ 
