MINOR: ssl: Add support for returning the dn samples from ssl_(c|f)_(i|s)_dn in LDAP v3 (RFC2253) format.

Modifies the existing sample extraction methods (smp_fetch_ssl_x_i_dn,
smp_fetch_ssl_x_s_dn) to accommodate a third argument that indicates the
DN should be returned in LDAP v3 format. When the third argument is
present, the new function (ssl_sock_get_dn_formatted) is called with
three parameters including the X509_NAME, a buffer containing the format
argument, and a buffer for the output.  If the supplied format matches
the supported format string (currently only "rfc2253" is supported), the
formatted value is extracted into the supplied output buffer using
OpenSSL's X509_NAME_print_ex and BIO_s_mem. 1 is returned when a dn
value is retrieved.  0 is returned when a value is not retrieved.

Argument validation is added to each of the related sample
configurations to ensure the third argument passed is either blank or
"rfc2253" using strcmp.  An error is returned if the third argument is
present with any other value.

Documentation was updated in configuration.txt and it was noted during
preliminary reviews that a CLEANUP patch should follow that adjusts the
documentation.  Currently, this patch and the existing documentation are
copied with some minor revisions for each sample configuration.  It
might be better to have one entry for all of the samples or entries for
each that reference back to a primary entry that explains the sample in
detail.

Special thanks to Chris, Willy, Tim and Aleks for the feedback.

Author: Elliot Otchet <degroens@yahoo.com>
Reviewed-by: Tim Duesterhus <tim@bastelstu.be>
This commit is contained in:
Elliot Otchet 2020-01-15 08:12:14 -05:00 committed by Willy Tarreau
parent ee1a6fc943
commit 71f829767d
2 changed files with 86 additions and 10 deletions

View File

@ -15246,7 +15246,7 @@ ssl_c_err : integer
to your SSL library's documentation to find the exhaustive list of error to your SSL library's documentation to find the exhaustive list of error
codes. 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, When the incoming connection was made over an SSL/TLS transport layer,
returns the full distinguished name of the issuer of the certificate 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 presented by the client when no <entry> is specified, or the value of the
@ -15255,6 +15255,11 @@ ssl_c_i_dn([<entry>[,<occ>]]) : string
the value of the nth given entry value from the beginning/end of the DN. 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 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(CN)" retrieves the common name.
The <format> parameter allows you to receive the DN suitable for
consumption by different protocols. Currently supported is rfc2253 for
LDAP v3.
If you'd like to modify the format only you can specify an empty string
and zero for the first two parameters. Example: ssl_c_i_dn(,0,rfc2253)
ssl_c_key_alg : string ssl_c_key_alg : string
Returns the name of the algorithm used to generate the key of the certificate Returns the name of the algorithm used to generate the key of the certificate
@ -15271,7 +15276,7 @@ ssl_c_notbefore : string
YYMMDDhhmmss[Z] when the incoming connection was made over an SSL/TLS YYMMDDhhmmss[Z] when the incoming connection was made over an SSL/TLS
transport layer. 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, When the incoming connection was made over an SSL/TLS transport layer,
returns the full distinguished name of the subject of the certificate 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 presented by the client when no <entry> is specified, or the value of the
@ -15280,6 +15285,11 @@ ssl_c_s_dn([<entry>[,<occ>]]) : string
the value of the nth given entry value from the beginning/end of the DN. 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 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(CN)" retrieves the common name.
The <format> parameter allows you to receive the DN suitable for
consumption by different protocols. Currently supported is rfc2253 for
LDAP v3.
If you'd like to modify the format only you can specify an empty string
and zero for the first two parameters. Example: ssl_c_s_dn(,0,rfc2253)
ssl_c_serial : binary ssl_c_serial : binary
Returns the serial of the certificate presented by the client when the Returns the serial of the certificate presented by the client when the
@ -15320,7 +15330,7 @@ ssl_f_der : binary
incoming connection was made over an SSL/TLS transport layer. When used for 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. 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, When the incoming connection was made over an SSL/TLS transport layer,
returns the full distinguished name of the issuer of the certificate 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 presented by the frontend when no <entry> is specified, or the value of the
@ -15329,6 +15339,11 @@ ssl_f_i_dn([<entry>[,<occ>]]) : string
the value of the nth given entry value from the beginning/end of the DN. 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 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(CN)" retrieves the common name.
The <format> parameter allows you to receive the DN suitable for
consumption by different protocols. Currently supported is rfc2253 for
LDAP v3.
If you'd like to modify the format only you can specify an empty string
and zero for the first two parameters. Example: ssl_f_i_dn(,0,rfc2253)
ssl_f_key_alg : string ssl_f_key_alg : string
Returns the name of the algorithm used to generate the key of the certificate Returns the name of the algorithm used to generate the key of the certificate
@ -15345,7 +15360,7 @@ ssl_f_notbefore : string
YYMMDDhhmmss[Z] when the incoming connection was made over an SSL/TLS YYMMDDhhmmss[Z] when the incoming connection was made over an SSL/TLS
transport layer. 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, When the incoming connection was made over an SSL/TLS transport layer,
returns the full distinguished name of the subject of the certificate 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 presented by the frontend when no <entry> is specified, or the value of the
@ -15354,6 +15369,11 @@ ssl_f_s_dn([<entry>[,<occ>]]) : string
the value of the nth given entry value from the beginning/end of the DN. 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 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(CN)" retrieves the common name.
The <format> parameter allows you to receive the DN suitable for
consumption by different protocols. Currently supported is rfc2253 for
LDAP v3.
If you'd like to modify the format only you can specify an empty string
and zero for the first two parameters. Example: ssl_f_s_dn(,0,rfc2253)
ssl_f_serial : binary ssl_f_serial : binary
Returns the serial of the certificate presented by the frontend when the Returns the serial of the certificate presented by the frontend when the

View File

@ -7117,6 +7117,39 @@ static int ssl_sock_get_san_oneline(X509 *cert, struct buffer *out)
} }
#endif #endif
/*
* Extract the DN in the specified format from the X509_NAME and copy result to a chunk.
* Currently supports rfc2253 for returning LDAP V3 DNs.
* Returns 1 if dn entries exist, 0 if no dn entry was found.
*/
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_strcmp(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 /* 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. * Returns 1 if dn entries exits, 0 if no dn entry found or -1 if output is not large enough.
*/ */
@ -7596,7 +7629,7 @@ smp_fetch_ssl_x_i_dn(const struct arg *args, struct sample *smp, const char *kw,
goto out; goto out;
smp_trash = get_trash_chunk(); 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; int pos = 1;
if (args[1].type == ARGT_SINT) if (args[1].type == ARGT_SINT)
@ -7605,6 +7638,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) if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
goto out; goto out;
} }
else if (args && args[2].type == ARGT_STR && args[2].data.str.data > 0) {
if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
goto out;
}
else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0) else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
goto out; goto out;
@ -7700,7 +7737,7 @@ smp_fetch_ssl_x_s_dn(const struct arg *args, struct sample *smp, const char *kw,
goto out; goto out;
smp_trash = get_trash_chunk(); 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; int pos = 1;
if (args[1].type == ARGT_SINT) if (args[1].type == ARGT_SINT)
@ -7709,6 +7746,10 @@ smp_fetch_ssl_x_s_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) if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
goto out; goto out;
} }
else if (args && args[2].type == ARGT_STR && args[2].data.str.data > 0) {
if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
goto out;
}
else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0) else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
goto out; goto out;
@ -11076,6 +11117,21 @@ err:
} }
# endif # endif
/* Argument validation functions */
/* This function is used to validate the arguments passed to any "x_dn" ssl
* keywords. These keywords support specifying a third parameter that must be
* either empty or the value "rfc2253". Returns 0 on error, non-zero if OK.
*/
int val_dnfmt(struct arg *arg, char **err_msg)
{
if (arg && arg[2].type == ARGT_STR && arg[2].data.str.data > 0 && (strcmp(arg[2].data.str.area, "rfc2253") != 0)) {
memprintf(err_msg, "only rfc2253 or a blank value are currently supported as the format argument.");
return 0;
}
return 1;
}
/* register cli keywords */ /* register cli keywords */
static struct cli_kw_list cli_kws = {{ },{ static struct cli_kw_list cli_kws = {{ },{
#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0) #if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
@ -11121,24 +11177,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_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_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_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),val_dnfmt, 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_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_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_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_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),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
{ "ssl_c_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, 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_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_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_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_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_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),val_dnfmt, 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_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_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_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_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),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
{ "ssl_f_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, 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_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 }, { "ssl_f_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },