MINOR: ssl: add the ssl_s_* sample fetches for server side certificate
This commit adds some sample fetches that were lacking on the server
side:
ssl_s_key_alg, ssl_s_notafter, ssl_s_notbefore, ssl_s_sig_alg,
ssl_s_i_dn, ssl_s_s_dn, ssl_s_serial, ssl_s_sha1, ssl_s_der,
ssl_s_version
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 780d27f..6612d3d 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -17077,6 +17077,74 @@
Returns the symmetric cipher key size used in bits when the incoming
connection was made over an SSL/TLS transport layer.
+ssl_s_der : binary
+ Returns the DER formatted certificate presented by the server when the
+ outgoing 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.
+
+ssl_s_key_alg : string
+ Returns the name of the algorithm used to generate the key of the certificate
+ presented by the server when the outgoing connection was made over an
+ SSL/TLS transport layer.
+
+ssl_s_notafter : string
+ Returns the end date presented by the server as a formatted string
+ YYMMDDhhmmss[Z] when the outgoing connection was made over an SSL/TLS
+ transport layer.
+
+ssl_s_notbefore : string
+ Returns the start date presented by the server as a formatted string
+ YYMMDDhhmmss[Z] when the outgoing connection was made over an SSL/TLS
+ transport layer.
+
+ssl_s_i_dn([<entry>[,<occ>[,<format>]]]) : string
+ When the outgoing connection was made over an SSL/TLS transport layer,
+ returns the full distinguished name of the issuer of the certificate
+ presented by the server when no <entry> is specified, or the value of the
+ first given entry found from the beginning of the DN. If a positive/negative
+ occurrence number is specified as the optional second argument, it returns
+ 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
+ "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_s_i_dn(,0,rfc2253)
+
+ssl_s_s_dn([<entry>[,<occ>[,<format>]]]) : string
+ When the outgoing connection was made over an SSL/TLS transport layer,
+ returns the full distinguished name of the subject of the certificate
+ presented by the server when no <entry> is specified, or the value of the
+ first given entry found from the beginning of the DN. If a positive/negative
+ occurrence number is specified as the optional second argument, it returns
+ 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
+ "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_s_s_dn(,0,rfc2253)
+
+ssl_s_serial : binary
+ Returns the serial of the certificate presented by the server when the
+ outgoing 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.
+
+ssl_s_sha1 : binary
+ Returns the SHA-1 fingerprint of the certificate presented by the server
+ when the outgoing connection was made over an SSL/TLS transport layer. This
+ can be used to know which certificate was chosen using SNI.
+
+ssl_s_sig_alg : string
+ Returns the name of the algorithm used to sign the certificate presented by
+ the server when the outgoing connection was made over an SSL/TLS transport
+ layer.
+
+ssl_s_version : integer
+ Returns the version of the certificate presented by the server when the
+ outgoing connection was made over an SSL/TLS transport layer.
7.3.5. Fetching samples from buffer contents (Layer 6)
------------------------------------------------------
diff --git a/reg-tests/ssl/ssl_server_samples.vtc b/reg-tests/ssl/ssl_server_samples.vtc
new file mode 100644
index 0000000..0ee2998
--- /dev/null
+++ b/reg-tests/ssl/ssl_server_samples.vtc
@@ -0,0 +1,73 @@
+#REGTEST_TYPE=devel
+
+varnishtest "Test the ssl_s_* sample fetches"
+#REQUIRE_VERSION=2.2
+#REQUIRE_OPTIONS=OPENSSL
+feature ignore_unknown_macro
+
+server s1 -repeat 3 {
+ rxreq
+ txresp
+} -start
+
+haproxy h1 -conf {
+ global
+ tune.ssl.default-dh-param 2048
+ tune.ssl.capture-cipherlist-size 1
+ crt-base ${testdir}
+ stats socket "${tmpdir}/h1/stats" level admin
+
+ defaults
+ mode http
+ option httplog
+ ${no-htx} option http-use-htx
+ log stderr local0 debug err
+ option logasap
+ timeout connect 1s
+ timeout client 1s
+ timeout server 1s
+
+
+ listen clear-lst
+ bind "fd@${clearlst}"
+ balance roundrobin
+ http-response add-header x-ssl-sha1 %[ssl_s_sha1,hex]
+ http-response add-header x-ssl-notafter %[ssl_s_notafter]
+ http-response add-header x-ssl-notbefore %[ssl_s_notbefore]
+ http-response add-header x-ssl-sig_alg %[ssl_s_sig_alg]
+ http-response add-header x-ssl-i_dn %[ssl_s_i_dn]
+ http-response add-header x-ssl-s_dn %[ssl_s_s_dn]
+ http-response add-header x-ssl-s_serial %[ssl_s_serial,hex]
+ http-response add-header x-ssl-key_alg %[ssl_s_key_alg]
+ http-response add-header x-ssl-der %[ssl_s_der,hex]
+ http-response add-header x-ssl-version %[ssl_s_version]
+
+ server s1 "${tmpdir}/ssl.sock" ssl verify none sni str(www.test1.com)
+
+ listen ssl-lst
+ mode http
+ ${no-htx} option http-use-htx
+
+ bind "${tmpdir}/ssl.sock" ssl strict-sni crt-list ${testdir}/localhost.crt-list
+
+ server s1 ${s1_addr}:${s1_port}
+} -start
+
+
+client c1 -connect ${h1_clearlst_sock} {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-ssl-sha1 == "2195C9F0FD58470313013FC27C1B9CF9864BD1C6"
+ expect resp.http.x-ssl-notafter == "180116230238Z"
+ expect resp.http.x-ssl-notbefore == "160117230238Z"
+ expect resp.http.x-ssl-sig_alg == "RSA-SHA256"
+ expect resp.http.x-ssl-i_dn == "/C=FR/ST=Ile-de-France/L=Paris/O=ozon.io/CN=Ozon Test CA/emailAddress=support@ozon.io"
+ expect resp.http.x-ssl-s_dn == "/C=FR/ST=Ile-de-France/L=Neuilly-sur-Seine/O=TOAD Consulting/OU=eParapher Team/CN=www.test1.com/emailAddress=arnault.michel@toad-consulting.fr"
+ expect resp.http.x-ssl-s_serial == "02"
+ expect resp.http.x-ssl-key_alg == "rsaEncryption"
+ expect resp.http.x-ssl-version == "3"
+ expect resp.http.x-ssl-der ~ 3082067930820461A0030201020201.*
+} -run
+
+
diff --git a/src/ssl_sample.c b/src/ssl_sample.c
index cc6f537..4c7eccc 100644
--- a/src/ssl_sample.c
+++ b/src/ssl_sample.c
@@ -91,14 +91,20 @@
static int
smp_fetch_ssl_x_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
- int cert_peer = (kw[4] == 'c') ? 1 : 0;
+ int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
+ int conn_server = (kw[4] == 's') ? 1 : 0;
+
X509 *crt = NULL;
int ret = 0;
struct buffer *smp_trash;
struct connection *conn;
SSL *ssl;
- conn = objt_conn(smp->sess->origin);
+ if (conn_server)
+ conn = cs_conn(objt_cs(smp->strm->si[1].end));
+ else
+ conn = objt_conn(smp->sess->origin);
+
ssl = ssl_sock_get_ssl_object(conn);
if (!ssl)
return 0;
@@ -137,14 +143,18 @@
static int
smp_fetch_ssl_x_serial(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
- int cert_peer = (kw[4] == 'c') ? 1 : 0;
+ int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
+ int conn_server = (kw[4] == 's') ? 1 : 0;
X509 *crt = NULL;
int ret = 0;
struct buffer *smp_trash;
struct connection *conn;
SSL *ssl;
- conn = objt_conn(smp->sess->origin);
+ if (conn_server)
+ conn = cs_conn(objt_cs(smp->strm->si[1].end));
+ else
+ conn = objt_conn(smp->sess->origin);
ssl = ssl_sock_get_ssl_object(conn);
if (!ssl)
return 0;
@@ -183,7 +193,8 @@
static int
smp_fetch_ssl_x_sha1(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
- int cert_peer = (kw[4] == 'c') ? 1 : 0;
+ int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
+ int conn_server = (kw[4] == 's') ? 1 : 0;
X509 *crt = NULL;
const EVP_MD *digest;
int ret = 0;
@@ -192,7 +203,11 @@
struct connection *conn;
SSL *ssl;
- conn = objt_conn(smp->sess->origin);
+ if (conn_server)
+ conn = cs_conn(objt_cs(smp->strm->si[1].end));
+ else
+ conn = objt_conn(smp->sess->origin);
+
ssl = ssl_sock_get_ssl_object(conn);
if (!ssl)
return 0;
@@ -230,14 +245,19 @@
static int
smp_fetch_ssl_x_notafter(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
- int cert_peer = (kw[4] == 'c') ? 1 : 0;
+ int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
+ int conn_server = (kw[4] == 's') ? 1 : 0;
X509 *crt = NULL;
int ret = 0;
struct buffer *smp_trash;
struct connection *conn;
SSL *ssl;
- conn = objt_conn(smp->sess->origin);
+ if (conn_server)
+ conn = cs_conn(objt_cs(smp->strm->si[1].end));
+ else
+ conn = objt_conn(smp->sess->origin);
+
ssl = ssl_sock_get_ssl_object(conn);
if (!ssl)
return 0;
@@ -275,7 +295,8 @@
static int
smp_fetch_ssl_x_i_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
- int cert_peer = (kw[4] == 'c') ? 1 : 0;
+ int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
+ int conn_server = (kw[4] == 's') ? 1 : 0;
X509 *crt = NULL;
X509_NAME *name;
int ret = 0;
@@ -283,7 +304,11 @@
struct connection *conn;
SSL *ssl;
- conn = objt_conn(smp->sess->origin);
+ if (conn_server)
+ conn = cs_conn(objt_cs(smp->strm->si[1].end));
+ else
+ conn = objt_conn(smp->sess->origin);
+
ssl = ssl_sock_get_ssl_object(conn);
if (!ssl)
return 0;
@@ -338,14 +363,19 @@
static int
smp_fetch_ssl_x_notbefore(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
- int cert_peer = (kw[4] == 'c') ? 1 : 0;
+ int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
+ int conn_server = (kw[4] == 's') ? 1 : 0;
X509 *crt = NULL;
int ret = 0;
struct buffer *smp_trash;
struct connection *conn;
SSL *ssl;
- conn = objt_conn(smp->sess->origin);
+ if (conn_server)
+ conn = cs_conn(objt_cs(smp->strm->si[1].end));
+ else
+ conn = objt_conn(smp->sess->origin);
+
ssl = ssl_sock_get_ssl_object(conn);
if (!ssl)
return 0;
@@ -383,7 +413,8 @@
static int
smp_fetch_ssl_x_s_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
- int cert_peer = (kw[4] == 'c') ? 1 : 0;
+ int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
+ int conn_server = (kw[4] == 's') ? 1 : 0;
X509 *crt = NULL;
X509_NAME *name;
int ret = 0;
@@ -391,7 +422,11 @@
struct connection *conn;
SSL *ssl;
- conn = objt_conn(smp->sess->origin);
+ if (conn_server)
+ conn = cs_conn(objt_cs(smp->strm->si[1].end));
+ else
+ conn = objt_conn(smp->sess->origin);
+
ssl = ssl_sock_get_ssl_object(conn);
if (!ssl)
return 0;
@@ -475,12 +510,17 @@
static int
smp_fetch_ssl_x_version(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
- int cert_peer = (kw[4] == 'c') ? 1 : 0;
+ int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
+ int conn_server = (kw[4] == 's') ? 1 : 0;
+
X509 *crt;
struct connection *conn;
SSL *ssl;
- conn = objt_conn(smp->sess->origin);
+ if (conn_server)
+ conn = cs_conn(objt_cs(smp->strm->si[1].end));
+ else
+ conn = objt_conn(smp->sess->origin);
ssl = ssl_sock_get_ssl_object(conn);
if (!ssl)
return 0;
@@ -513,14 +553,19 @@
static int
smp_fetch_ssl_x_sig_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
- int cert_peer = (kw[4] == 'c') ? 1 : 0;
+ int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
+ int conn_server = (kw[4] == 's') ? 1 : 0;
X509 *crt;
__OPENSSL_110_CONST__ ASN1_OBJECT *algorithm;
int nid;
struct connection *conn;
SSL *ssl;
- conn = objt_conn(smp->sess->origin);
+ if (conn_server)
+ conn = cs_conn(objt_cs(smp->strm->si[1].end));
+ else
+ conn = objt_conn(smp->sess->origin);
+
ssl = ssl_sock_get_ssl_object(conn);
if (!ssl)
return 0;
@@ -565,14 +610,18 @@
static int
smp_fetch_ssl_x_key_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
- int cert_peer = (kw[4] == 'c') ? 1 : 0;
+ int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
+ int conn_server = (kw[4] == 's') ? 1 : 0;
X509 *crt;
ASN1_OBJECT *algorithm;
int nid;
struct connection *conn;
SSL *ssl;
- conn = objt_conn(smp->sess->origin);
+ if (conn_server)
+ conn = cs_conn(objt_cs(smp->strm->si[1].end));
+ else
+ conn = objt_conn(smp->sess->origin);
ssl = ssl_sock_get_ssl_object(conn);
if (!ssl)
return 0;
@@ -1337,6 +1386,18 @@
{ "ssl_fc_cipherlist_hex", smp_fetch_ssl_fc_cl_hex, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
{ "ssl_fc_cipherlist_str", smp_fetch_ssl_fc_cl_str, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
{ "ssl_fc_cipherlist_xxh", smp_fetch_ssl_fc_cl_xxh64, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
+
+/* SSL server certificate fetches */
+ { "ssl_s_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
+ { "ssl_s_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
+ { "ssl_s_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
+ { "ssl_s_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
+ { "ssl_s_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
+ { "ssl_s_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
+ { "ssl_s_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
+ { "ssl_s_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
+ { "ssl_s_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
+ { "ssl_s_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
{ NULL, NULL, 0, 0, 0 },
}};