MINOR: ssl/sample: ssl_c_san returns a comma separated list of SAN

The ssl_c_san sample fetch returns a list of Subject Alt Name which was
presented by the client certificate.

The format is the same as the "openssl x509 -text" command, it's a
Description: Value list separated by commas.
The format is directly generated by the GENERAL_NAME_print() openssl
function.

https://github.com/openssl/openssl/blob/openssl-3.0/crypto/x509/v3_san.c#L207

Example:
    IP Address:127.0.0.1, IP Address:127.0.0.2, IP Address:127.0.0.3, URI:http://docs.haproxy.org/2.7/, DNS:ca.tests.haproxy.com
This commit is contained in:
William Lallemand 2023-02-27 22:16:06 +01:00 committed by William Lallemand
parent 0a1b251c1a
commit 9797a7718c
2 changed files with 95 additions and 0 deletions

View File

@ -22920,6 +22920,7 @@ ssl_c_notafter string
ssl_c_notbefore string
ssl_c_r_dn([<entry>[,<occ>[,<format>]]]) string
ssl_c_s_dn([<entry>[,<occ>[,<format>]]]) string
ssl_c_san string
ssl_c_serial binary
ssl_c_sha1 binary
ssl_c_sig_alg string
@ -23264,6 +23265,23 @@ ssl_c_s_dn([<entry>[,<occ>[,<format>]]]) : string
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_san : string
When the incoming connection was made over an SSL/TLS transport layer, and was
provided with a client certificate. Returns a string of comma separated
Subject Alt Name fields contained into the provided certificate.
This can be used to inspect the client certificate.
Example:
acl is_valid_client_cert ssl_c_used && ! ssl_c_verify
http-request set-header X-SSL-Client-SAN %[ssl_c_san] if is_valid_client_cert
will results in:
X-SSL-Client-SAN: IP Address:127.0.0.1, IP Address:127.0.0.2, IP Address:127.0.0.3, URI:http://docs.haproxy.org/2.7/, DNS:ca.tests.haproxy.com
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

View File

@ -997,6 +997,82 @@ smp_fetch_ssl_x_i_dn(const struct arg *args, struct sample *smp, const char *kw,
return ret;
}
/*
* returns a string of comma separated SAN in a client certificate, Use "GENERAL_NAME_print"
* Example: "IP Address:127.0.0.1, IP Address:127.0.0.2, IP Address:127.0.0.3, URI:http://docs.haproxy.org/2.7/, DNS:ca.tests.haproxy.com"
*/
static int
smp_fetch_ssl_x_san(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
int conn_server = (kw[4] == 's') ? 1 : 0;
STACK_OF(GENERAL_NAME) *names;
X509 *crt = NULL;
int ret = 0;
struct buffer *smp_trash;
struct connection *conn;
SSL *ssl;
int i, read;
BIO *bio = NULL;
if (conn_server)
conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
else
conn = objt_conn(smp->sess->origin);
ssl = ssl_sock_get_ssl_object(conn);
if (!ssl)
return 0;
if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
smp->flags |= SMP_F_MAY_CHANGE;
return 0;
}
if (cert_peer)
crt = ssl_sock_get_peer_certificate(ssl);
else
crt = SSL_get_certificate(ssl);
if (!crt)
goto out;
names = X509_get_ext_d2i(crt, NID_subject_alt_name, NULL, NULL);
if (!names)
goto out;
smp_trash = get_trash_chunk();
bio = BIO_new(BIO_s_mem());
if (!bio)
goto out;
for (i = 0; i < sk_GENERAL_NAME_num(names); i++) {
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
if (i != 0)
BIO_puts(bio, ", ");
GENERAL_NAME_print(bio, name);
}
sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
read = BIO_read(bio, smp_trash->area, smp_trash->size-1);
if (read <= 0) /* nothing to read, prevent negative array index */
goto out;
smp_trash->area[read] = '\0';
smp_trash->data = read;
smp->flags = SMP_F_VOL_SESS;
smp->data.type = SMP_T_STR;
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);
BIO_free(bio);
return ret;
}
/* string, returns notbefore date in ASN1_UTCTIME format.
* The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
* should be use.
@ -2343,6 +2419,7 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
{ "ssl_c_r_dn", smp_fetch_ssl_r_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
#endif
{ "ssl_c_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
{ "ssl_c_san", smp_fetch_ssl_x_san, 0, 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_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },