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.
Best regards,
On Thursday, January 2, 2020, 1:17:23 PM EST, Aleksandar Lazic
<[email protected]> wrote:
Hi Chris.
I can't verify the c code. I just ask to add a documentation to the patch. Can
the sample be tested with vtest?
It would be nice to mention that rfc2253 is LDAP v3. :-)
Regards
Aleks.
Jan 2, 2020 3:41:35 PM Chris Software <[email protected]>:
> Hello haproxy,
> My team member has completed a patch which allows someone to configure the
> format of the proxied certificate's DN and Issuer DN.
> I have attached the patch here. How can we submit this for inclusion to
> haproxy?
> Chris
>
>
> On Fri, Dec 20, 2019 at 12:53 PM Chris Software < [email protected]
> [mailto:[email protected]] > wrote:
>
> > Hello,
> >
> > This is an update on the offchance that some diligent team member is
> > spinning their wheels on this.
> >
> > Some team members of mine are modifying the haproxy ssl.c file to make the
> > format of the ssl_c_s_dn variable configurable, and editing for simplicity
> > to use standard openssl function calls.
> >
> > There is discussion about submitting this change back as a patch.
> >
> > Chris
> >
> >
> >
> >
> >
>
From 430d5b181fda66798b2edd4b8bd69a2c1e89810d Mon Sep 17 00:00:00 2001
From: degroens <[email protected]>
Date: Wed, 1 Jan 2020 18:42:08 -0500
Subject: [PATCH 3/3] Adds support for generating RFC2253 DNs using
configuration variables by invoking OpenSSL library features.
---
doc/configuration.txt | 22 ++++++++
src/ssl_sock.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 160 insertions(+)
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 9bc7d71..2876b56 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -4605,8 +4605,10 @@ http-request set-header <name> <fmt> [ { if | unless } <condition> ]
http-request set-header X-SSL-Session_ID %[ssl_fc_session_id,hex]
http-request set-header X-SSL-Client-Verify %[ssl_c_verify]
http-request set-header X-SSL-Client-DN %{+Q}[ssl_c_s_dn]
+ http-request set-header X-SSL-Client-DN-2253 %{+Q}[ssl_c_s_dn_rfc2253]
http-request set-header X-SSL-Client-CN %{+Q}[ssl_c_s_dn(cn)]
http-request set-header X-SSL-Issuer %{+Q}[ssl_c_i_dn]
+ http-request set-header X-SSL-Issuer-DN-2253 %{+Q}[ssl_c_i_dn_rfc2253]
http-request set-header X-SSL-Client-NotBefore %{+Q}[ssl_c_notbefore]
http-request set-header X-SSL-Client-NotAfter %{+Q}[ssl_c_notafter]
@@ -15253,6 +15255,11 @@ ssl_c_i_dn([<entry>[,<occ>]]) : string
For instance, "ssl_c_i_dn(OU,2)" the second organization unit, and
"ssl_c_i_dn(CN)" retrieves the common name.
+ssl_c_i_dn_rfc2253 : string
+ When the incoming connection was made over an SSL/TLS transport layer,
+ returns the full distinguished name of the issuer of the certifcate
+ presented by the client in RFC 2253 (LDAP v3) format.
+
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
@@ -15278,6 +15285,11 @@ ssl_c_s_dn([<entry>[,<occ>]]) : string
For instance, "ssl_c_s_dn(OU,2)" the second organization unit, and
"ssl_c_s_dn(CN)" retrieves the common name.
+ssl_c_s_dn_rfc2253 : string
+ When the incoming connection was made over an SSL/TLS transport layer,
+ returns the full distinguished name of the subject of the certifcate
+ presented by the client in RFC 2253 (LDAP v3) format.
+
ssl_c_serial : binary
Returns the serial of the certificate presented by the client when the
incoming connection was made over an SSL/TLS transport layer. When used for
@@ -15327,6 +15339,11 @@ ssl_f_i_dn([<entry>[,<occ>]]) : string
For instance, "ssl_f_i_dn(OU,2)" the second organization unit, and
"ssl_f_i_dn(CN)" retrieves the common name.
+ssl_f_i_dn_rfc2253 : string
+ When the incoming connection was made over an SSL/TLS transport layer,
+ returns the full distinguished name of the issuer of the certifcate
+ presented by the frontend in RFC 2253 (LDAP v3) format.
+
ssl_f_key_alg : string
Returns the name of the algorithm used to generate the key of the certificate
presented by the frontend when the incoming connection was made over an
@@ -15352,6 +15369,11 @@ ssl_f_s_dn([<entry>[,<occ>]]) : string
For instance, "ssl_f_s_dn(OU,2)" the second organization unit, and
"ssl_f_s_dn(CN)" retrieves the common name.
+ssl_f_s_dn_rfc2253 : string
+ When the incoming connection was made over an SSL/TLS transport layer,
+ returns the full distinguished name of the subject of the certifcate
+ presented by the frontend in RFC 2253 (LDAP v3) format.
+
ssl_f_serial : binary
Returns the serial of the certificate presented by the frontend when the
incoming connection was made over an SSL/TLS transport layer. When used for
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index e4dd913..d01b778 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -7696,6 +7696,140 @@ out:
return ret;
}
+/*
+* string, returns a string of a formatted full dn in rfc 2253 format of certificate's issuer
+* The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
+ * should be use.
+*/
+static int
+smp_fetch_ssl_x_i_dn_rfc2253(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+ int cert_peer = (kw[4] == 'c') ? 1 : 0;
+ X509 *crt = NULL;
+ X509_NAME *name;
+ BIO *bio = NULL;
+ int ret = 0;
+ int dataLen = -1;
+ struct connection *conn;
+ struct ssl_sock_ctx *ctx;
+ struct buffer *smp_trash;
+
+ conn = objt_conn(smp->sess->origin);
+ if (!conn || conn->xprt != &ssl_sock)
+ return 0;
+ ctx = conn->xprt_ctx;
+
+ if (!(conn->flags & CO_FL_CONNECTED)) {
+ smp->flags |= SMP_F_MAY_CHANGE;
+ return 0;
+ }
+
+ if (cert_peer)
+ crt = SSL_get_peer_certificate(ctx->ssl);
+ else
+ crt = SSL_get_certificate(ctx->ssl);
+ if (!crt)
+ goto out;
+
+ name = X509_get_issuer_name(crt);
+ if (!name)
+ goto out;
+
+ bio = BIO_new(BIO_s_mem());
+ if (bio == NULL)
+ goto out;
+
+ if (X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253) < 0)
+ goto out;
+
+ smp_trash = get_trash_chunk();
+
+ if ((dataLen = BIO_read(bio, smp_trash->area, smp_trash->size - 1)) <= 0)
+ goto out;
+
+ smp_trash->area[dataLen] = '\0';
+ smp->data.type = SMP_T_STR;
+ smp_trash->data = dataLen;
+ smp->data.u.str = *smp_trash;
+
+ ret = 1;
+
+ out:
+ /* SSL_get_peer_certificate, it increase X509 * ref count */
+ if (cert_peer && crt)
+ X509_free(crt);
+ if (bio)
+ BIO_free(bio);
+ return ret;
+}
+
+/*
+* string, returns a string of a formatted full dn in rfc 2253 format of certificate's subject
+* The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
+ * should be use.
+*/
+static int
+smp_fetch_ssl_x_s_dn_rfc2253(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+ int cert_peer = (kw[4] == 'c') ? 1 : 0;
+ X509 *crt = NULL;
+ X509_NAME *name;
+ BIO *bio = NULL;
+ int ret = 0;
+ int dataLen = -1;
+ struct connection *conn;
+ struct ssl_sock_ctx *ctx;
+ struct buffer *smp_trash;
+
+ conn = objt_conn(smp->sess->origin);
+ if (!conn || conn->xprt != &ssl_sock)
+ return 0;
+ ctx = conn->xprt_ctx;
+
+ if (!(conn->flags & CO_FL_CONNECTED)) {
+ smp->flags |= SMP_F_MAY_CHANGE;
+ return 0;
+ }
+
+ if (cert_peer)
+ crt = SSL_get_peer_certificate(ctx->ssl);
+ else
+ crt = SSL_get_certificate(ctx->ssl);
+ if (!crt)
+ goto out;
+
+ name = X509_get_subject_name(crt);
+ if (!name)
+ goto out;
+
+ bio = BIO_new(BIO_s_mem());
+ if (bio == NULL)
+ goto out;
+
+ if (X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253) < 0)
+ goto out;
+
+ smp_trash = get_trash_chunk();
+
+ if ((dataLen = BIO_read(bio, smp_trash->area, smp_trash->size - 1)) <= 0)
+ goto out;
+
+ smp_trash->area[dataLen] = '\0';
+ smp->data.type = SMP_T_STR;
+ smp_trash->data = dataLen;
+ smp->data.u.str = *smp_trash;
+
+ ret = 1;
+
+ out:
+ /* SSL_get_peer_certificate, it increase X509 * ref count */
+ if (cert_peer && crt)
+ X509_free(crt);
+ if (bio)
+ BIO_free(bio);
+ return ret;
+}
+
/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's subject
* The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
* should be use.
@@ -11155,11 +11289,13 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
{ "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_rfc2253", smp_fetch_ssl_x_i_dn_rfc2253, 0, 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_rfc2253", smp_fetch_ssl_x_s_dn_rfc2253, 0, 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 },
@@ -11167,11 +11303,13 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
{ "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_rfc2253", smp_fetch_ssl_x_i_dn_rfc2253, 0, 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_rfc2253", smp_fetch_ssl_x_s_dn_rfc2253, 0, 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