Willy,
The patch attached implements as close to your intent as I could get without 
making changes outside of ssl_sock.c.
If you remember, you had asked for a patch that implemented extending the 
current methods with a third option to indicate the DN output should be in RFC 
2253  e.g. "ssl_c_i_dn(,,rfc2253)".
This patch comes close to that.  It extends the existing methods, but the 
options have to be passed as "ssl_c_i_dn(,0,rfc2253)"  This is because the 
second argument is an integer and the arg parser doesn't like missing integers. 

The patch includes examples in the configuration documentation that 
demonstrated how to configure it for the needed output.
As always, feedback is greatly appreciated.  If acceptable, what are the next 
steps to get this accepted?

Best,
-Elliot

    On Sunday, January 12, 2020, 1:41:19 PM EST, Elliot Otchet 
<[email protected]> wrote:  
 
  Willy,
Thanks for the note back.  Your suggestion seems like a good approach.  I'll 
submit a new patch when I have this worked up and tested for a bit.

Regards,
Elliot

    On Thursday, January 9, 2020, 12:42:36 AM EST, Willy Tarreau <[email protected]> 
wrote:  
 
 Hi Elliot & Chris,

On Sun, Jan 05, 2020 at 09:09:18PM +0000, Elliot Otchet wrote:
>  Hi,
> An updated patch is attached for the implementation that adds documentation
> to the doc/configuration.txt and fixes an issue identified during testing.
> I couldn't locate tests for the preexisting ssl_c_s_dn and related
> parameters.  I'd be happy to add tests for the new ones if someone could
> point me in the right direction of the existing ones.

Sorry for the late response, it seems your previous messages were sent
in the unlucky period where everyone's busy doing everything but looking 
at the mailing list :-)

I understand the problem you're facing and I agree that it's easier to have
fresh new code to handle this. However instead of having a separate set of
sample fetches for this, it would be much better to add an optional argument
to the existing one which would change the output format. This would even
allow to factor some existing code I guess. Look for example at the UUID
sample fetch which is a good illustration of this:

  uuid([<version>]) : string
    Returns a UUID following the RFC4122 standard. If the version is not
    specified, a UUID version 4 (fully random) is returned.

I'm seeing that ssl_c_i_dn() and ssl_c_s_dn() already take up to two
optional args. But that doesn't prevent one from adding a third one with
the output format specification. If you just want to get it emitted with
no specific field filtering you could just use "ssl_c_i_dn(,,rfc2253)" for
example (or any other arg value you choose).

Just my two cents,
Willy

    
From 56cb18cd01346d11980ad3e5ba8e99148e60e863 Mon Sep 17 00:00:00 2001
From: degroens <[email protected]>
Date: Wed, 15 Jan 2020 08:12:14 -0500
Subject: [PATCH] Extends _s_dn and i_dn options with the ability to output
 RFC2253 (LDAP v3) DNs

---
 doc/configuration.txt | 18 ++++++++++----
 src/ssl_sock.c        | 69 +++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 66 insertions(+), 21 deletions(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index 9ac8985..ba562f3 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -15246,7 +15246,7 @@ ssl_c_err : integer
   to your SSL library's documentation to find the exhaustive list of error
   codes.
 
-ssl_c_i_dn([<entry>[,<occ>]]) : string
+ssl_c_i_dn([<entry>[,<occ>],<format>]) : string
   When the incoming connection was made over an SSL/TLS transport layer,
   returns the full distinguished name of the issuer of the certificate
   presented by the client when no <entry> is specified, or the value of the
@@ -15255,8 +15255,10 @@ ssl_c_i_dn([<entry>[,<occ>]]) : string
   the value of the nth given entry value from the beginning/end of the DN.
   For instance, "ssl_c_i_dn(OU,2)" the second organization unit, and
   "ssl_c_i_dn(CN)" retrieves the common name.
+  To obtain a DN formatted according to RFC 2253 for LDAP v3, specify
+  "ssl_c_i_dn(,0,rfc2253)" in the configuration.
 
-ssl_c_key_alg : string
+ssl_c_key_alg : string]
   Returns the name of the algorithm used to generate the key of the certificate
   presented by the client when the incoming connection was made over an SSL/TLS
   transport layer.
@@ -15271,7 +15273,7 @@ ssl_c_notbefore : string
   YYMMDDhhmmss[Z] when the incoming connection was made over an SSL/TLS
   transport layer.
 
-ssl_c_s_dn([<entry>[,<occ>]]) : string
+ssl_c_s_dn([<entry>[,<occ>],<format>]) : string
   When the incoming connection was made over an SSL/TLS transport layer,
   returns the full distinguished name of the subject of the certificate
   presented by the client when no <entry> is specified, or the value of the
@@ -15280,6 +15282,8 @@ ssl_c_s_dn([<entry>[,<occ>]]) : string
   the value of the nth given entry value from the beginning/end of the DN.
   For instance, "ssl_c_s_dn(OU,2)" the second organization unit, and
   "ssl_c_s_dn(CN)" retrieves the common name.
+  To obtain a DN formatted according to RFC 2253 for LDAP v3, specify
+  "ssl_c_s_dn(,0,rfc2253)" in the configuration.
 
 ssl_c_serial : binary
   Returns the serial of the certificate presented by the client when the
@@ -15320,7 +15324,7 @@ ssl_f_der : binary
   incoming connection was made over an SSL/TLS transport layer. When used for
   an ACL, the value(s) to match against can be passed in hexadecimal form.
 
-ssl_f_i_dn([<entry>[,<occ>]]) : string
+ssl_f_i_dn([<entry>[,<occ>],<format>]) : string
   When the incoming connection was made over an SSL/TLS transport layer,
   returns the full distinguished name of the issuer of the certificate
   presented by the frontend when no <entry> is specified, or the value of the
@@ -15329,6 +15333,8 @@ ssl_f_i_dn([<entry>[,<occ>]]) : string
   the value of the nth given entry value from the beginning/end of the DN.
   For instance, "ssl_f_i_dn(OU,2)" the second organization unit, and
   "ssl_f_i_dn(CN)" retrieves the common name.
+  To obtain a DN formatted according to RFC 2253 for LDAP v3, specify
+  "ssl_f_i_dn(,0,rfc2253)" in the configuration.
 
 ssl_f_key_alg : string
   Returns the name of the algorithm used to generate the key of the certificate
@@ -15345,7 +15351,7 @@ ssl_f_notbefore : string
   YYMMDDhhmmss[Z] when the incoming connection was made over an SSL/TLS
   transport layer.
 
-ssl_f_s_dn([<entry>[,<occ>]]) : string
+ssl_f_s_dn([<entry>[,<occ>],<format>]) : string
   When the incoming connection was made over an SSL/TLS transport layer,
   returns the full distinguished name of the subject of the certificate
   presented by the frontend when no <entry> is specified, or the value of the
@@ -15354,6 +15360,8 @@ ssl_f_s_dn([<entry>[,<occ>]]) : string
   the value of the nth given entry value from the beginning/end of the DN.
   For instance, "ssl_f_s_dn(OU,2)" the second organization unit, and
   "ssl_f_s_dn(CN)" retrieves the common name.
+  To obtain a DN formatted according to RFC 2253 for LDAP v3, specify
+  "ssl_f_s_dn(,0,rfc2253)" in the configuration.
 
 ssl_f_serial : binary
   Returns the serial of the certificate presented by the frontend when the
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index ff8af23..a6ace26 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -7144,6 +7144,35 @@ static int ssl_sock_get_san_oneline(X509 *cert, struct buffer *out)
 }
 #endif
 
+static int
+ssl_sock_get_dn_formatted(X509_NAME *a, const struct buffer *format, struct buffer *out)
+{
+	BIO *bio = NULL;
+	int ret = 0;
+	int data_len = 0;
+
+	if (chunk_strcasecmp(format, "rfc2253") == 0) {
+		bio = BIO_new(BIO_s_mem());
+		if (bio == NULL)
+			goto out;
+
+		if (X509_NAME_print_ex(bio, a, 0, XN_FLAG_RFC2253) < 0)
+			goto out;
+
+		if ((data_len = BIO_read(bio, out->area, out->size)) <= 0)
+			goto out;
+
+		out->data = data_len;
+
+		ret = 1;
+	}
+out:
+	if (bio)
+		BIO_free(bio);
+	return ret;
+}
+
+
 /* Extract and format full DN from a X509_NAME and copy result into a chunk
  * Returns 1 if dn entries exits, 0 if no dn entry found or -1 if output is not large enough.
  */
@@ -7623,7 +7652,7 @@ smp_fetch_ssl_x_i_dn(const struct arg *args, struct sample *smp, const char *kw,
 		goto out;
 
 	smp_trash = get_trash_chunk();
-	if (args && args[0].type == ARGT_STR) {
+	if (args && args[0].type == ARGT_STR && args[0].data.str.data > 0) {
 		int pos = 1;
 
 		if (args[1].type == ARGT_SINT)
@@ -7632,6 +7661,10 @@ smp_fetch_ssl_x_i_dn(const struct arg *args, struct sample *smp, const char *kw,
 		if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
 			goto out;
 	}
+	else if (args && args[2].type == ARGT_STR && args[2].data.str.data > 0) {
+		if (ssl_sock_get_dn_formatted(name, &args[0].data.str, smp_trash) <= 0)
+			goto out;
+	}
 	else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
 		goto out;
 
@@ -7727,17 +7760,21 @@ smp_fetch_ssl_x_s_dn(const struct arg *args, struct sample *smp, const char *kw,
 		goto out;
 
 	smp_trash = get_trash_chunk();
-	if (args && args[0].type == ARGT_STR) {
-		int pos = 1;
-
-		if (args[1].type == ARGT_SINT)
-			pos = args[1].data.sint;
-
-		if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
-			goto out;
-	}
-	else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
-		goto out;
+        if (args && args[0].type == ARGT_STR && args[0].data.str.data > 0) {
+                int pos = 1;
+
+                if (args[1].type == ARGT_SINT)
+                        pos = args[1].data.sint;
+
+                if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
+                        goto out;
+        }
+        else if (args && args[2].type == ARGT_STR && args[2].data.str.data > 0) {
+                if (ssl_sock_get_dn_formatted(name, &args[0].data.str, smp_trash) <= 0)
+                        goto out;
+        }
+        else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
+                goto out;
 
 	smp->data.type = SMP_T_STR;
 	smp->data.u.str = *smp_trash;
@@ -11148,24 +11185,24 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
 	{ "ssl_c_ca_err_depth",     smp_fetch_ssl_c_ca_err_depth, 0,                   NULL,    SMP_T_SINT, SMP_USE_L5CLI },
 	{ "ssl_c_der",              smp_fetch_ssl_x_der,          0,                   NULL,    SMP_T_BIN,  SMP_USE_L5CLI },
 	{ "ssl_c_err",              smp_fetch_ssl_c_err,          0,                   NULL,    SMP_T_SINT, SMP_USE_L5CLI },
-	{ "ssl_c_i_dn",             smp_fetch_ssl_x_i_dn,         ARG2(0,STR,SINT),    NULL,    SMP_T_STR,  SMP_USE_L5CLI },
+	{ "ssl_c_i_dn",             smp_fetch_ssl_x_i_dn,         ARG3(0,STR,SINT,STR),NULL,    SMP_T_STR,  SMP_USE_L5CLI },
 	{ "ssl_c_key_alg",          smp_fetch_ssl_x_key_alg,      0,                   NULL,    SMP_T_STR,  SMP_USE_L5CLI },
 	{ "ssl_c_notafter",         smp_fetch_ssl_x_notafter,     0,                   NULL,    SMP_T_STR,  SMP_USE_L5CLI },
 	{ "ssl_c_notbefore",        smp_fetch_ssl_x_notbefore,    0,                   NULL,    SMP_T_STR,  SMP_USE_L5CLI },
 	{ "ssl_c_sig_alg",          smp_fetch_ssl_x_sig_alg,      0,                   NULL,    SMP_T_STR,  SMP_USE_L5CLI },
-	{ "ssl_c_s_dn",             smp_fetch_ssl_x_s_dn,         ARG2(0,STR,SINT),    NULL,    SMP_T_STR,  SMP_USE_L5CLI },
+	{ "ssl_c_s_dn",             smp_fetch_ssl_x_s_dn,         ARG3(0,STR,SINT,STR),NULL,    SMP_T_STR,  SMP_USE_L5CLI },
 	{ "ssl_c_serial",           smp_fetch_ssl_x_serial,       0,                   NULL,    SMP_T_BIN,  SMP_USE_L5CLI },
 	{ "ssl_c_sha1",             smp_fetch_ssl_x_sha1,         0,                   NULL,    SMP_T_BIN,  SMP_USE_L5CLI },
 	{ "ssl_c_used",             smp_fetch_ssl_c_used,         0,                   NULL,    SMP_T_BOOL, SMP_USE_L5CLI },
 	{ "ssl_c_verify",           smp_fetch_ssl_c_verify,       0,                   NULL,    SMP_T_SINT, SMP_USE_L5CLI },
 	{ "ssl_c_version",          smp_fetch_ssl_x_version,      0,                   NULL,    SMP_T_SINT, SMP_USE_L5CLI },
 	{ "ssl_f_der",              smp_fetch_ssl_x_der,          0,                   NULL,    SMP_T_BIN,  SMP_USE_L5CLI },
-	{ "ssl_f_i_dn",             smp_fetch_ssl_x_i_dn,         ARG2(0,STR,SINT),    NULL,    SMP_T_STR,  SMP_USE_L5CLI },
+	{ "ssl_f_i_dn",             smp_fetch_ssl_x_i_dn,         ARG3(0,STR,SINT,STR),NULL,    SMP_T_STR,  SMP_USE_L5CLI },
 	{ "ssl_f_key_alg",          smp_fetch_ssl_x_key_alg,      0,                   NULL,    SMP_T_STR,  SMP_USE_L5CLI },
 	{ "ssl_f_notafter",         smp_fetch_ssl_x_notafter,     0,                   NULL,    SMP_T_STR,  SMP_USE_L5CLI },
 	{ "ssl_f_notbefore",        smp_fetch_ssl_x_notbefore,    0,                   NULL,    SMP_T_STR,  SMP_USE_L5CLI },
 	{ "ssl_f_sig_alg",          smp_fetch_ssl_x_sig_alg,      0,                   NULL,    SMP_T_STR,  SMP_USE_L5CLI },
-	{ "ssl_f_s_dn",             smp_fetch_ssl_x_s_dn,         ARG2(0,STR,SINT),    NULL,    SMP_T_STR,  SMP_USE_L5CLI },
+	{ "ssl_f_s_dn",             smp_fetch_ssl_x_s_dn,         ARG3(0,STR,SINT,STR),NULL,    SMP_T_STR,  SMP_USE_L5CLI },
 	{ "ssl_f_serial",           smp_fetch_ssl_x_serial,       0,                   NULL,    SMP_T_BIN,  SMP_USE_L5CLI },
 	{ "ssl_f_sha1",             smp_fetch_ssl_x_sha1,         0,                   NULL,    SMP_T_BIN,  SMP_USE_L5CLI },
 	{ "ssl_f_version",          smp_fetch_ssl_x_version,      0,                   NULL,    SMP_T_SINT, SMP_USE_L5CLI },
-- 
1.8.3.1

Reply via email to