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
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
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.
{ "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 },