Hello,
I make an a patch, which adds 4 functions to sslinfo extension module:
1) ssl_get_count_of_extensions() --- get count of X509v3 extensions from client certificate;
2) ssl_get_extension_names() --- get short names of X509v3 extensions from client certificate;
3) ssl_get_extension_value(text) --- get value of extension from certificate (argument --- short name of extension);
4) ssl_is_critical_extension(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.
I want, that my functions will be included in PostgreSQL release.
What do you think about it?
--
Best regards, Dmitry Voronin
Best regards, Dmitry Voronin
--- contrib/sslinfo/sslinfo.c 2014-03-17 23:35:47.000000000 +0400 +++ contrib/sslinfo/sslinfo.c 2014-04-18 11:09:49.567775647 +0400 @@ -5,6 +5,8 @@ * This file is distributed under BSD-style license. * * contrib/sslinfo/sslinfo.c + * + * Extension functions written by Dmitry Voronin carriingfat...@yandex.ru, CNIIEISU. */ #include "postgres.h" @@ -14,9 +16,11 @@ #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; @@ -35,6 +39,11 @@ 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 @@ -371,3 +380,146 @@ 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); +} + --- contrib/sslinfo/sslinfo--1.0.sql 2014-03-17 23:35:47.000000000 +0400 +++ contrib/sslinfo/sslinfo--1.0.sql 2014-04-18 11:12:03.768470905 +0400 @@ -38,3 +38,19 @@ 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; + --- contrib/sslinfo/sslinfo--unpackaged--1.0.sql 2014-04-18 11:17:44.937238072 +0400 +++ contrib/sslinfo/sslinfo--unpackaged--1.0.sql 2014-04-18 11:16:45.185110931 +0400 @@ -11,6 +11,11 @@ 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
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers