Skip to content

Commit 4912461

Browse files
committed
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
1 parent 582fbff commit 4912461

File tree

6 files changed

+202
-9
lines changed

6 files changed

+202
-9
lines changed

contrib/sslinfo/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ MODULE_big = sslinfo
44
OBJS = sslinfo.o $(WIN32RES)
55

66
EXTENSION = sslinfo
7-
DATA = sslinfo--1.0.sql sslinfo--unpackaged--1.0.sql
7+
DATA = sslinfo--1.0--1.1.sql sslinfo--1.1.sql \
8+
sslinfo--unpackaged--1.0.sql
89
PGFILEDESC = "sslinfo - information about client SSL certificate"
910

1011
ifdef USE_PGXS

contrib/sslinfo/sslinfo--1.0--1.1.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* contrib/sslinfo/sslinfo--1.0--1.1.sql */
2+
3+
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
4+
\echo Use "ALTER EXTENSION sslinfo UPDATE TO '1.1'" to load this file. \quit
5+
6+
CREATE OR REPLACE FUNCTION
7+
ssl_extension_info(OUT name text,
8+
OUT value text,
9+
OUT critical boolean
10+
) RETURNS SETOF record
11+
AS 'MODULE_PATHNAME', 'ssl_extension_info'
12+
LANGUAGE C STRICT;

contrib/sslinfo/sslinfo--1.0.sql renamed to contrib/sslinfo/sslinfo--1.1.sql

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* contrib/sslinfo/sslinfo--1.0.sql */
1+
/* contrib/sslinfo/sslinfo--1.1.sql */
22

33
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
44
\echo Use "CREATE EXTENSION sslinfo" to load this file. \quit
@@ -38,3 +38,11 @@ LANGUAGE C STRICT;
3838
CREATE FUNCTION ssl_issuer_dn() RETURNS text
3939
AS 'MODULE_PATHNAME', 'ssl_issuer_dn'
4040
LANGUAGE C STRICT;
41+
42+
CREATE FUNCTION
43+
ssl_extension_info(OUT name text,
44+
OUT value text,
45+
OUT critical boolean
46+
) RETURNS SETOF record
47+
AS 'MODULE_PATHNAME', 'ssl_extension_info'
48+
LANGUAGE C STRICT;

contrib/sslinfo/sslinfo.c

Lines changed: 159 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,30 @@
88
*/
99

1010
#include "postgres.h"
11-
#include "fmgr.h"
12-
#include "utils/numeric.h"
13-
#include "libpq/libpq-be.h"
14-
#include "miscadmin.h"
15-
#include "utils/builtins.h"
16-
#include "mb/pg_wchar.h"
1711

1812
#include <openssl/x509.h>
13+
#include <openssl/x509v3.h>
1914
#include <openssl/asn1.h>
2015

16+
#include "access/htup_details.h"
17+
#include "funcapi.h"
18+
#include "libpq/libpq-be.h"
19+
#include "miscadmin.h"
20+
#include "utils/builtins.h"
21+
2122
PG_MODULE_MAGIC;
2223

2324
static Datum X509_NAME_field_to_text(X509_NAME *name, text *fieldName);
2425
static Datum X509_NAME_to_text(X509_NAME *name);
2526
static Datum ASN1_STRING_to_text(ASN1_STRING *str);
2627

28+
/*
29+
* Function context for data persisting over repeated calls.
30+
*/
31+
typedef struct
32+
{
33+
TupleDesc tupdesc;
34+
} SSLExtensionInfoContext;
2735

2836
/*
2937
* Indicates whether current session uses SSL
@@ -373,3 +381,148 @@ ssl_issuer_dn(PG_FUNCTION_ARGS)
373381
PG_RETURN_NULL();
374382
return X509_NAME_to_text(X509_get_issuer_name(MyProcPort->peer));
375383
}
384+
385+
386+
/*
387+
* Returns information about available SSL extensions.
388+
*
389+
* Returns setof record made of the following values:
390+
* - name of the extension.
391+
* - value of the extension.
392+
* - critical status of the extension.
393+
*/
394+
PG_FUNCTION_INFO_V1(ssl_extension_info);
395+
Datum
396+
ssl_extension_info(PG_FUNCTION_ARGS)
397+
{
398+
X509 *cert = MyProcPort->peer;
399+
FuncCallContext *funcctx;
400+
int call_cntr;
401+
int max_calls;
402+
MemoryContext oldcontext;
403+
SSLExtensionInfoContext *fctx;
404+
405+
STACK_OF(X509_EXTENSION) *ext_stack = NULL;
406+
407+
if (SRF_IS_FIRSTCALL())
408+
{
409+
410+
TupleDesc tupdesc;
411+
412+
/* create a function context for cross-call persistence */
413+
funcctx = SRF_FIRSTCALL_INIT();
414+
415+
/*
416+
* Switch to memory context appropriate for multiple function calls
417+
*/
418+
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
419+
420+
/* Create a user function context for cross-call persistence */
421+
fctx = (SSLExtensionInfoContext *) palloc(sizeof(SSLExtensionInfoContext));
422+
423+
/* Construct tuple descriptor */
424+
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
425+
ereport(ERROR,
426+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
427+
errmsg("function returning record called in context that cannot accept type record")));
428+
fctx->tupdesc = BlessTupleDesc(tupdesc);
429+
430+
/* Get all extensions of certificate */
431+
if (cert && cert->cert_info)
432+
ext_stack = cert->cert_info->extensions;
433+
434+
/* Set max_calls as a count of extensions in certificate */
435+
max_calls = cert != NULL ? X509_get_ext_count(cert) : 0;
436+
437+
if (cert != NULL &&
438+
ext_stack != NULL &&
439+
max_calls > 0)
440+
{
441+
/* got results, keep track of them */
442+
funcctx->max_calls = max_calls;
443+
funcctx->user_fctx = fctx;
444+
}
445+
else
446+
{
447+
/* fast track when no results */
448+
MemoryContextSwitchTo(oldcontext);
449+
SRF_RETURN_DONE(funcctx);
450+
}
451+
452+
MemoryContextSwitchTo(oldcontext);
453+
}
454+
455+
/* stuff done on every call of the function */
456+
funcctx = SRF_PERCALL_SETUP();
457+
458+
/*
459+
* Initialize per-call variables.
460+
*/
461+
call_cntr = funcctx->call_cntr;
462+
max_calls = funcctx->max_calls;
463+
fctx = funcctx->user_fctx;
464+
465+
ext_stack = cert->cert_info->extensions;
466+
467+
/* do while there are more left to send */
468+
if (call_cntr < max_calls)
469+
{
470+
Datum values[3];
471+
bool nulls[3];
472+
char *buf;
473+
HeapTuple tuple;
474+
Datum result;
475+
BIO *membuf;
476+
X509_EXTENSION *ext;
477+
ASN1_OBJECT *obj;
478+
int nid;
479+
int len;
480+
481+
/* need a BIO for this */
482+
membuf = BIO_new(BIO_s_mem());
483+
if (membuf == NULL)
484+
ereport(ERROR,
485+
(errcode(ERRCODE_OUT_OF_MEMORY),
486+
errmsg("could not create OpenSSL BIO structure")));
487+
488+
/* Get the extension from the certificate */
489+
ext = sk_X509_EXTENSION_value(ext_stack, call_cntr);
490+
obj = X509_EXTENSION_get_object(ext);
491+
492+
/* Get the extension name */
493+
nid = OBJ_obj2nid(obj);
494+
if (nid == NID_undef)
495+
ereport(ERROR,
496+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
497+
errmsg("unknown OpenSSL extension in certificate at position %d",
498+
call_cntr)));
499+
values[0] = CStringGetTextDatum(OBJ_nid2sn(nid));
500+
nulls[0] = false;
501+
502+
/* Get the extension value */
503+
if (X509V3_EXT_print(membuf, ext, 0, 0) <= 0)
504+
ereport(ERROR,
505+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
506+
errmsg("could not print extension value in certificate at position %d",
507+
call_cntr)));
508+
len = BIO_get_mem_data(membuf, &buf);
509+
values[1] = PointerGetDatum(cstring_to_text_with_len(buf, len));
510+
nulls[1] = false;
511+
512+
/* Get critical status */
513+
values[2] = BoolGetDatum(X509_EXTENSION_get_critical(ext));
514+
nulls[2] = false;
515+
516+
/* Build tuple */
517+
tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
518+
result = HeapTupleGetDatum(tuple);
519+
520+
if (BIO_free(membuf) != 1)
521+
elog(ERROR, "could not free OpenSSL BIO structure");
522+
523+
SRF_RETURN_NEXT(funcctx, result);
524+
}
525+
526+
/* Do when there is no more left */
527+
SRF_RETURN_DONE(funcctx);
528+
}

contrib/sslinfo/sslinfo.control

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# sslinfo extension
22
comment = 'information about SSL certificates'
3-
default_version = '1.0'
3+
default_version = '1.1'
44
module_pathname = '$libdir/sslinfo'
55
relocatable = true

doc/src/sgml/sslinfo.sgml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,21 @@ emailAddress
219219
</para>
220220
</listitem>
221221
</varlistentry>
222+
223+
<varlistentry>
224+
<term>
225+
<function>ssl_extension_info() returns setof record</function>
226+
<indexterm>
227+
<primary>ssl_extension_info</primary>
228+
</indexterm>
229+
</term>
230+
<listitem>
231+
<para>
232+
Provide information about extensions of client certificate: extension name,
233+
extension value, and if it is a critical extension.
234+
</para>
235+
</listitem>
236+
</varlistentry>
222237
</variablelist>
223238
</sect2>
224239

@@ -229,6 +244,10 @@ emailAddress
229244
Victor Wagner <email>vitus@cryptocom.ru</email>, Cryptocom LTD
230245
</para>
231246

247+
<para>
248+
Dmitry Voronin <email>carriingfate92@yandex.ru</email>
249+
</para>
250+
232251
<para>
233252
E-Mail of Cryptocom OpenSSL development group:
234253
<email>openssl@cryptocom.ru</email>

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy