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:
parent
0a1b251c1a
commit
9797a7718c
|
@ -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
|
||||
|
|
|
@ -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 },
|
||||
|
|
Loading…
Reference in New Issue