New functions for sslinfo extension

Started by Воронин Дмитрийover 11 years ago4 messages
#1Воронин Дмитрий
carriingfate92@yandex.ru
3 attachment(s)

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Attachments:

sslextensions.ctext/x-c; name=sslextensions.cDownload
sslextensions.controlapplication/octet-stream; name=sslextensions.controlDownload
sslextensions--1.0.sqlapplication/x-sql; name=sslextensions--1.0.sqlDownload
#2Michael Paquier
michael.paquier@gmail.com
In reply to: Воронин Дмитрий (#1)
Re: New functions for sslinfo extension

Hi,

On Thu, Apr 17, 2014 at 3:30 AM, Воронин Дмитрий
<carriingfate92@yandex.ru> wrote:

I want to present some 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).

I write those functions with libpq on C.

This looks interesting. This is unfortunately too late for 9.4, but
you can submit it for 9.5 in the next commit fest but registering a
new patch:
https://commitfest.postgresql.org/action/commitfest_view?id=22

Here are as well some guidelines that will help you submitting
nicely-formatted patches:
https://wiki.postgresql.org/wiki/Submitting_a_Patch
https://wiki.postgresql.org/wiki/Working_with_Git
https://wiki.postgresql.org/wiki/Creating_Clean_Patches

You should not send a patch in the shape of each file sent
individually, but something that is generated based on diffs on the
Postgres code. Also, I looked at your code, you should avoid the
following things, that are not conform to the code format of the
project:
- Some tabs of your code are made of 4 spaces, and are not tabs
- Postgres avoids conditions like (constant == variable) and it is
preferable to use (variable == constant).

Here is the documentation explaining the coding convention:
http://www.postgresql.org/docs/devel/static/source.html
Regards,
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#3Dmitry Voronin
carriingfate92@yandex.ru
In reply to: Michael Paquier (#2)
1 attachment(s)
Re: New functions for sslinfo extension

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Attachments:

postgresql-9.3.4-sslinfo-sslextensions.patchtext/x-diff; name=postgresql-9.3.4-sslinfo-sslextensions.patchDownload
--- 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 carriingfate92@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
#4Воронин Дмитрий
carriingfate92@yandex.ru
In reply to: Dmitry Voronin (#3)

<div><div>Hello,</div><div>О©╫</div><div>I make an a patch, which adds 4 functions to sslinfo extension module:</div><div><div>1) ssl_get_count_of_extensions() --- get count of X509v3 extensions from client certificate;</div><div>2) ssl_get_extension_names() --- get short names of X509v3 extensions from client certificate;</div><div>3) ssl_get_extension_value(text) --- get value of extension from certificate (argument --- short name of extension);</div><div>4) ssl_is_critical_extension(text) --- returns true, if extension is critical and false, if is not (argument --- short name of extension).</div><div>О©╫</div></div><div>You can view some information of certificate's extensions via those functions.</div><div>I want, that my functions will be included in PostgreSQL release.</div><div>О©╫</div><div>What do you think about it?</div><div>О©╫</div><div>-- <br />Best regards, Dmitry Voronin</div></div><div>О©╫</div>