mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-11-21 03:13:05 +08:00
contrib/sslinfo: add ssl_extension_info SRF
This new function provides information about SSL extensions present in the X509 certificate used for the current connection. Extension version updated to version 1.1. Author: Дмитрий Воронин (Dmitry Voronin) Reviewed by: Michael Paquier, Heikki Linnakangas, Álvaro Herrera
This commit is contained in:
parent
582fbffb0c
commit
49124613f1
@ -4,7 +4,8 @@ MODULE_big = sslinfo
|
||||
OBJS = sslinfo.o $(WIN32RES)
|
||||
|
||||
EXTENSION = sslinfo
|
||||
DATA = sslinfo--1.0.sql sslinfo--unpackaged--1.0.sql
|
||||
DATA = sslinfo--1.0--1.1.sql sslinfo--1.1.sql \
|
||||
sslinfo--unpackaged--1.0.sql
|
||||
PGFILEDESC = "sslinfo - information about client SSL certificate"
|
||||
|
||||
ifdef USE_PGXS
|
||||
|
12
contrib/sslinfo/sslinfo--1.0--1.1.sql
Normal file
12
contrib/sslinfo/sslinfo--1.0--1.1.sql
Normal file
@ -0,0 +1,12 @@
|
||||
/* 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_info(OUT name text,
|
||||
OUT value text,
|
||||
OUT critical boolean
|
||||
) RETURNS SETOF record
|
||||
AS 'MODULE_PATHNAME', 'ssl_extension_info'
|
||||
LANGUAGE C STRICT;
|
@ -1,4 +1,4 @@
|
||||
/* contrib/sslinfo/sslinfo--1.0.sql */
|
||||
/* 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
|
||||
@ -38,3 +38,11 @@ LANGUAGE C STRICT;
|
||||
CREATE FUNCTION ssl_issuer_dn() RETURNS text
|
||||
AS 'MODULE_PATHNAME', 'ssl_issuer_dn'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION
|
||||
ssl_extension_info(OUT name text,
|
||||
OUT value text,
|
||||
OUT critical boolean
|
||||
) RETURNS SETOF record
|
||||
AS 'MODULE_PATHNAME', 'ssl_extension_info'
|
||||
LANGUAGE C STRICT;
|
@ -8,15 +8,16 @@
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
#include "fmgr.h"
|
||||
#include "utils/numeric.h"
|
||||
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include "access/htup_details.h"
|
||||
#include "funcapi.h"
|
||||
#include "libpq/libpq-be.h"
|
||||
#include "miscadmin.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "mb/pg_wchar.h"
|
||||
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
PG_MODULE_MAGIC;
|
||||
|
||||
@ -24,6 +25,13 @@ 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);
|
||||
|
||||
/*
|
||||
* Function context for data persisting over repeated calls.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
TupleDesc tupdesc;
|
||||
} SSLExtensionInfoContext;
|
||||
|
||||
/*
|
||||
* Indicates whether current session uses SSL
|
||||
@ -373,3 +381,148 @@ ssl_issuer_dn(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_NULL();
|
||||
return X509_NAME_to_text(X509_get_issuer_name(MyProcPort->peer));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns information about available SSL extensions.
|
||||
*
|
||||
* Returns setof record made of the following values:
|
||||
* - name of the extension.
|
||||
* - value of the extension.
|
||||
* - critical status of the extension.
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(ssl_extension_info);
|
||||
Datum
|
||||
ssl_extension_info(PG_FUNCTION_ARGS)
|
||||
{
|
||||
X509 *cert = MyProcPort->peer;
|
||||
FuncCallContext *funcctx;
|
||||
int call_cntr;
|
||||
int max_calls;
|
||||
MemoryContext oldcontext;
|
||||
SSLExtensionInfoContext *fctx;
|
||||
|
||||
STACK_OF(X509_EXTENSION) *ext_stack = NULL;
|
||||
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
|
||||
TupleDesc tupdesc;
|
||||
|
||||
/* create a function context for cross-call persistence */
|
||||
funcctx = SRF_FIRSTCALL_INIT();
|
||||
|
||||
/*
|
||||
* Switch to memory context appropriate for multiple function calls
|
||||
*/
|
||||
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
||||
|
||||
/* Create a user function context for cross-call persistence */
|
||||
fctx = (SSLExtensionInfoContext *) palloc(sizeof(SSLExtensionInfoContext));
|
||||
|
||||
/* Construct tuple descriptor */
|
||||
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")));
|
||||
fctx->tupdesc = BlessTupleDesc(tupdesc);
|
||||
|
||||
/* Get all extensions of certificate */
|
||||
if (cert && cert->cert_info)
|
||||
ext_stack = cert->cert_info->extensions;
|
||||
|
||||
/* Set max_calls as a count of extensions in certificate */
|
||||
max_calls = cert != NULL ? X509_get_ext_count(cert) : 0;
|
||||
|
||||
if (cert != NULL &&
|
||||
ext_stack != NULL &&
|
||||
max_calls > 0)
|
||||
{
|
||||
/* got results, keep track of them */
|
||||
funcctx->max_calls = max_calls;
|
||||
funcctx->user_fctx = fctx;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* fast track when no results */
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
SRF_RETURN_DONE(funcctx);
|
||||
}
|
||||
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
}
|
||||
|
||||
/* stuff done on every call of the function */
|
||||
funcctx = SRF_PERCALL_SETUP();
|
||||
|
||||
/*
|
||||
* Initialize per-call variables.
|
||||
*/
|
||||
call_cntr = funcctx->call_cntr;
|
||||
max_calls = funcctx->max_calls;
|
||||
fctx = funcctx->user_fctx;
|
||||
|
||||
ext_stack = cert->cert_info->extensions;
|
||||
|
||||
/* do while there are more left to send */
|
||||
if (call_cntr < max_calls)
|
||||
{
|
||||
Datum values[3];
|
||||
bool nulls[3];
|
||||
char *buf;
|
||||
HeapTuple tuple;
|
||||
Datum result;
|
||||
BIO *membuf;
|
||||
X509_EXTENSION *ext;
|
||||
ASN1_OBJECT *obj;
|
||||
int nid;
|
||||
int len;
|
||||
|
||||
/* need a BIO for this */
|
||||
membuf = BIO_new(BIO_s_mem());
|
||||
if (membuf == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("could not create OpenSSL BIO structure")));
|
||||
|
||||
/* Get the extension from the certificate */
|
||||
ext = sk_X509_EXTENSION_value(ext_stack, call_cntr);
|
||||
obj = X509_EXTENSION_get_object(ext);
|
||||
|
||||
/* Get the extension name */
|
||||
nid = OBJ_obj2nid(obj);
|
||||
if (nid == NID_undef)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("unknown OpenSSL extension in certificate at position %d",
|
||||
call_cntr)));
|
||||
values[0] = CStringGetTextDatum(OBJ_nid2sn(nid));
|
||||
nulls[0] = false;
|
||||
|
||||
/* Get the extension value */
|
||||
if (X509V3_EXT_print(membuf, ext, 0, 0) <= 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("could not print extension value in certificate at position %d",
|
||||
call_cntr)));
|
||||
len = BIO_get_mem_data(membuf, &buf);
|
||||
values[1] = PointerGetDatum(cstring_to_text_with_len(buf, len));
|
||||
nulls[1] = false;
|
||||
|
||||
/* Get critical status */
|
||||
values[2] = BoolGetDatum(X509_EXTENSION_get_critical(ext));
|
||||
nulls[2] = false;
|
||||
|
||||
/* Build tuple */
|
||||
tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
|
||||
result = HeapTupleGetDatum(tuple);
|
||||
|
||||
if (BIO_free(membuf) != 1)
|
||||
elog(ERROR, "could not free OpenSSL BIO structure");
|
||||
|
||||
SRF_RETURN_NEXT(funcctx, result);
|
||||
}
|
||||
|
||||
/* Do when there is no more left */
|
||||
SRF_RETURN_DONE(funcctx);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
# sslinfo extension
|
||||
comment = 'information about SSL certificates'
|
||||
default_version = '1.0'
|
||||
default_version = '1.1'
|
||||
module_pathname = '$libdir/sslinfo'
|
||||
relocatable = true
|
||||
|
@ -219,6 +219,21 @@ emailAddress
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>ssl_extension_info() returns setof record</function>
|
||||
<indexterm>
|
||||
<primary>ssl_extension_info</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Provide information about extensions of client certificate: extension name,
|
||||
extension value, and if it is a critical extension.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</sect2>
|
||||
|
||||
@ -229,6 +244,10 @@ emailAddress
|
||||
Victor Wagner <email>vitus@cryptocom.ru</email>, Cryptocom LTD
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Dmitry Voronin <email>carriingfate92@yandex.ru</email>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
E-Mail of Cryptocom OpenSSL development group:
|
||||
<email>openssl@cryptocom.ru</email>
|
||||
|
Loading…
Reference in New Issue
Block a user