blob: aa9a547e44bcb429443476460d9bec3c6447f37b [file] [log] [blame]
William Lallemand15e16942020-05-15 00:25:08 +02001/*
2 * This file contains the sample fetches related to the SSL
3 *
4 * Copyright (C) 2012 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
5 * Copyright (C) 2020 HAProxy Technologies, William Lallemand <wlallemand@haproxy.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 */
12
13#define _GNU_SOURCE
14#include <ctype.h>
15#include <dirent.h>
16#include <errno.h>
17#include <fcntl.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <unistd.h>
22
Willy Tarreaudcc048a2020-06-04 19:11:43 +020023#include <haproxy/acl.h>
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020024#include <haproxy/api.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020025#include <haproxy/arg.h>
Willy Tarreau2741c8c2020-06-02 11:28:02 +020026#include <haproxy/buf-t.h>
Willy Tarreau8efbdfb2020-06-04 11:29:21 +020027#include <haproxy/obj_type.h>
Willy Tarreau6019fab2020-05-27 16:26:00 +020028#include <haproxy/openssl-compat.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020029#include <haproxy/sample.h>
Willy Tarreau209108d2020-06-04 20:30:20 +020030#include <haproxy/ssl_sock.h>
Willy Tarreaub2bd8652020-06-04 14:21:22 +020031#include <haproxy/ssl_utils.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020032#include <haproxy/tools.h>
William Lallemand15e16942020-05-15 00:25:08 +020033
William Lallemand15e16942020-05-15 00:25:08 +020034
35/***** Below are some sample fetching functions for ACL/patterns *****/
36
37static int
38smp_fetch_ssl_fc_has_early(const struct arg *args, struct sample *smp, const char *kw, void *private)
39{
40 SSL *ssl;
41 struct connection *conn;
42
43 conn = objt_conn(smp->sess->origin);
44 ssl = ssl_sock_get_ssl_object(conn);
45 if (!ssl)
46 return 0;
47
48 smp->flags = 0;
49 smp->data.type = SMP_T_BOOL;
50#ifdef OPENSSL_IS_BORINGSSL
51 {
52 smp->data.u.sint = (SSL_in_early_data(ssl) &&
53 SSL_early_data_accepted(ssl));
54 }
55#else
56 smp->data.u.sint = ((conn->flags & CO_FL_EARLY_DATA) &&
57 (conn->flags & (CO_FL_EARLY_SSL_HS | CO_FL_SSL_WAIT_HS))) ? 1 : 0;
58#endif
59 return 1;
60}
61
62/* boolean, returns true if client cert was present */
63static int
64smp_fetch_ssl_fc_has_crt(const struct arg *args, struct sample *smp, const char *kw, void *private)
65{
66 struct connection *conn;
67 struct ssl_sock_ctx *ctx;
68
69 conn = objt_conn(smp->sess->origin);
70 if (!conn || conn->xprt != &ssl_sock)
71 return 0;
72
73 ctx = conn->xprt_ctx;
74
75 if (conn->flags & CO_FL_WAIT_XPRT) {
76 smp->flags |= SMP_F_MAY_CHANGE;
77 return 0;
78 }
79
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +020080 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +020081 smp->data.type = SMP_T_BOOL;
82 smp->data.u.sint = SSL_SOCK_ST_FL_VERIFY_DONE & ctx->xprt_st ? 1 : 0;
83
84 return 1;
85}
86
87/* binary, returns a certificate in a binary chunk (der/raw).
88 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
89 * should be use.
90 */
91static int
92smp_fetch_ssl_x_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
93{
William Lallemandbfa3e812020-06-25 20:07:18 +020094 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
95 int conn_server = (kw[4] == 's') ? 1 : 0;
96
William Lallemand15e16942020-05-15 00:25:08 +020097 X509 *crt = NULL;
98 int ret = 0;
99 struct buffer *smp_trash;
100 struct connection *conn;
101 SSL *ssl;
102
William Lallemandbfa3e812020-06-25 20:07:18 +0200103 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200104 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200105 else
106 conn = objt_conn(smp->sess->origin);
107
William Lallemand15e16942020-05-15 00:25:08 +0200108 ssl = ssl_sock_get_ssl_object(conn);
109 if (!ssl)
110 return 0;
111
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200112 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200113 smp->flags |= SMP_F_MAY_CHANGE;
114 return 0;
115 }
116
117 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200118 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200119 else
120 crt = SSL_get_certificate(ssl);
121
122 if (!crt)
123 goto out;
124
125 smp_trash = get_trash_chunk();
126 if (ssl_sock_crt2der(crt, smp_trash) <= 0)
127 goto out;
128
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200129 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200130 smp->data.u.str = *smp_trash;
131 smp->data.type = SMP_T_BIN;
132 ret = 1;
133out:
134 /* SSL_get_peer_certificate, it increase X509 * ref count */
135 if (cert_peer && crt)
136 X509_free(crt);
137 return ret;
138}
139
William Dauchya598b502020-08-06 18:11:38 +0200140/* binary, returns a chain certificate in a binary chunk (der/raw).
141 * The 5th keyword char is used to support only peer cert
142 */
143static int
144smp_fetch_ssl_x_chain_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
145{
146 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
147 int conn_server = (kw[4] == 's') ? 1 : 0;
148 struct buffer *smp_trash;
149 struct buffer *tmp_trash = NULL;
150 struct connection *conn;
151 STACK_OF(X509) *certs = NULL;
152 X509 *crt = NULL;
153 SSL *ssl;
154 int ret = 0;
155 int num_certs;
156 int i;
157
158 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200159 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Dauchya598b502020-08-06 18:11:38 +0200160 else
161 conn = objt_conn(smp->sess->origin);
162
163 if (!conn)
164 return 0;
165
166 ssl = ssl_sock_get_ssl_object(conn);
167 if (!ssl)
168 return 0;
169
170 if (conn->flags & CO_FL_WAIT_XPRT) {
171 smp->flags |= SMP_F_MAY_CHANGE;
172 return 0;
173 }
174
175 if (!cert_peer)
176 return 0;
177
178 certs = SSL_get_peer_cert_chain(ssl);
179 if (!certs)
180 return 0;
181
182 num_certs = sk_X509_num(certs);
183 if (!num_certs)
184 goto out;
185 smp_trash = get_trash_chunk();
186 tmp_trash = alloc_trash_chunk();
187 if (!tmp_trash)
188 goto out;
189 for (i = 0; i < num_certs; i++) {
190 crt = sk_X509_value(certs, i);
191 if (ssl_sock_crt2der(crt, tmp_trash) <= 0)
192 goto out;
193 chunk_cat(smp_trash, tmp_trash);
194 }
195
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200196 smp->flags = SMP_F_VOL_SESS;
William Dauchya598b502020-08-06 18:11:38 +0200197 smp->data.u.str = *smp_trash;
198 smp->data.type = SMP_T_BIN;
199 ret = 1;
200out:
201 if (tmp_trash)
202 free_trash_chunk(tmp_trash);
William Dauchya598b502020-08-06 18:11:38 +0200203 return ret;
204}
205
William Lallemand15e16942020-05-15 00:25:08 +0200206/* binary, returns serial of certificate in a binary chunk.
207 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
208 * should be use.
209 */
210static int
211smp_fetch_ssl_x_serial(const struct arg *args, struct sample *smp, const char *kw, void *private)
212{
William Lallemandbfa3e812020-06-25 20:07:18 +0200213 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
214 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200215 X509 *crt = NULL;
216 int ret = 0;
217 struct buffer *smp_trash;
218 struct connection *conn;
219 SSL *ssl;
220
William Lallemandbfa3e812020-06-25 20:07:18 +0200221 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200222 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200223 else
224 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +0200225 ssl = ssl_sock_get_ssl_object(conn);
226 if (!ssl)
227 return 0;
228
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200229 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200230 smp->flags |= SMP_F_MAY_CHANGE;
231 return 0;
232 }
233
234 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200235 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200236 else
237 crt = SSL_get_certificate(ssl);
238
239 if (!crt)
240 goto out;
241
242 smp_trash = get_trash_chunk();
243 if (ssl_sock_get_serial(crt, smp_trash) <= 0)
244 goto out;
245
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200246 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200247 smp->data.u.str = *smp_trash;
248 smp->data.type = SMP_T_BIN;
249 ret = 1;
250out:
251 /* SSL_get_peer_certificate, it increase X509 * ref count */
252 if (cert_peer && crt)
253 X509_free(crt);
254 return ret;
255}
256
257/* binary, returns the client certificate's SHA-1 fingerprint (SHA-1 hash of DER-encoded certificate) in a binary chunk.
258 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
259 * should be use.
260 */
261static int
262smp_fetch_ssl_x_sha1(const struct arg *args, struct sample *smp, const char *kw, void *private)
263{
William Lallemandbfa3e812020-06-25 20:07:18 +0200264 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
265 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200266 X509 *crt = NULL;
267 const EVP_MD *digest;
268 int ret = 0;
269 unsigned int len = 0;
270 struct buffer *smp_trash;
271 struct connection *conn;
272 SSL *ssl;
273
William Lallemandbfa3e812020-06-25 20:07:18 +0200274 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200275 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200276 else
277 conn = objt_conn(smp->sess->origin);
278
William Lallemand15e16942020-05-15 00:25:08 +0200279 ssl = ssl_sock_get_ssl_object(conn);
280 if (!ssl)
281 return 0;
282
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200283 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200284 smp->flags |= SMP_F_MAY_CHANGE;
285 return 0;
286 }
287
288 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200289 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200290 else
291 crt = SSL_get_certificate(ssl);
292 if (!crt)
293 goto out;
294
295 smp_trash = get_trash_chunk();
296 digest = EVP_sha1();
297 X509_digest(crt, digest, (unsigned char *) smp_trash->area, &len);
298 smp_trash->data = len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200299 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200300 smp->data.u.str = *smp_trash;
301 smp->data.type = SMP_T_BIN;
302 ret = 1;
303out:
304 /* SSL_get_peer_certificate, it increase X509 * ref count */
305 if (cert_peer && crt)
306 X509_free(crt);
307 return ret;
308}
309
310/* string, returns certificate's notafter date in ASN1_UTCTIME format.
311 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
312 * should be use.
313 */
314static int
315smp_fetch_ssl_x_notafter(const struct arg *args, struct sample *smp, const char *kw, void *private)
316{
William Lallemandbfa3e812020-06-25 20:07:18 +0200317 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
318 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200319 X509 *crt = NULL;
320 int ret = 0;
321 struct buffer *smp_trash;
322 struct connection *conn;
323 SSL *ssl;
324
William Lallemandbfa3e812020-06-25 20:07:18 +0200325 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200326 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200327 else
328 conn = objt_conn(smp->sess->origin);
329
William Lallemand15e16942020-05-15 00:25:08 +0200330 ssl = ssl_sock_get_ssl_object(conn);
331 if (!ssl)
332 return 0;
333
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200334 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200335 smp->flags |= SMP_F_MAY_CHANGE;
336 return 0;
337 }
338
339 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200340 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200341 else
342 crt = SSL_get_certificate(ssl);
343 if (!crt)
344 goto out;
345
346 smp_trash = get_trash_chunk();
347 if (ssl_sock_get_time(X509_getm_notAfter(crt), smp_trash) <= 0)
348 goto out;
349
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200350 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200351 smp->data.u.str = *smp_trash;
352 smp->data.type = SMP_T_STR;
353 ret = 1;
354out:
355 /* SSL_get_peer_certificate, it increase X509 * ref count */
356 if (cert_peer && crt)
357 X509_free(crt);
358 return ret;
359}
360
361/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's issuer
362 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
363 * should be use.
364 */
365static int
366smp_fetch_ssl_x_i_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
367{
William Lallemandbfa3e812020-06-25 20:07:18 +0200368 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
369 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200370 X509 *crt = NULL;
371 X509_NAME *name;
372 int ret = 0;
373 struct buffer *smp_trash;
374 struct connection *conn;
375 SSL *ssl;
376
William Lallemandbfa3e812020-06-25 20:07:18 +0200377 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200378 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200379 else
380 conn = objt_conn(smp->sess->origin);
381
William Lallemand15e16942020-05-15 00:25:08 +0200382 ssl = ssl_sock_get_ssl_object(conn);
383 if (!ssl)
384 return 0;
385
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200386 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200387 smp->flags |= SMP_F_MAY_CHANGE;
388 return 0;
389 }
390
391 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200392 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200393 else
394 crt = SSL_get_certificate(ssl);
395 if (!crt)
396 goto out;
397
398 name = X509_get_issuer_name(crt);
399 if (!name)
400 goto out;
401
402 smp_trash = get_trash_chunk();
Christopher Faulet3702f782021-01-29 11:30:37 +0100403 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200404 int pos = 1;
405
406 if (args[1].type == ARGT_SINT)
407 pos = args[1].data.sint;
408
409 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
410 goto out;
411 }
Christopher Faulet3702f782021-01-29 11:30:37 +0100412 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200413 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
414 goto out;
415 }
416 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
417 goto out;
418
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200419 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200420 smp->data.type = SMP_T_STR;
421 smp->data.u.str = *smp_trash;
422 ret = 1;
423out:
424 /* SSL_get_peer_certificate, it increase X509 * ref count */
425 if (cert_peer && crt)
426 X509_free(crt);
427 return ret;
428}
429
430/* string, returns notbefore date in ASN1_UTCTIME format.
431 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
432 * should be use.
433 */
434static int
435smp_fetch_ssl_x_notbefore(const struct arg *args, struct sample *smp, const char *kw, void *private)
436{
William Lallemandbfa3e812020-06-25 20:07:18 +0200437 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
438 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200439 X509 *crt = NULL;
440 int ret = 0;
441 struct buffer *smp_trash;
442 struct connection *conn;
443 SSL *ssl;
444
William Lallemandbfa3e812020-06-25 20:07:18 +0200445 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200446 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200447 else
448 conn = objt_conn(smp->sess->origin);
449
William Lallemand15e16942020-05-15 00:25:08 +0200450 ssl = ssl_sock_get_ssl_object(conn);
451 if (!ssl)
452 return 0;
453
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200454 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200455 smp->flags |= SMP_F_MAY_CHANGE;
456 return 0;
457 }
458
459 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200460 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200461 else
462 crt = SSL_get_certificate(ssl);
463 if (!crt)
464 goto out;
465
466 smp_trash = get_trash_chunk();
467 if (ssl_sock_get_time(X509_getm_notBefore(crt), smp_trash) <= 0)
468 goto out;
469
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200470 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200471 smp->data.u.str = *smp_trash;
472 smp->data.type = SMP_T_STR;
473 ret = 1;
474out:
475 /* SSL_get_peer_certificate, it increase X509 * ref count */
476 if (cert_peer && crt)
477 X509_free(crt);
478 return ret;
479}
480
481/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's subject
482 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
483 * should be use.
484 */
485static int
486smp_fetch_ssl_x_s_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
487{
William Lallemandbfa3e812020-06-25 20:07:18 +0200488 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
489 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200490 X509 *crt = NULL;
491 X509_NAME *name;
492 int ret = 0;
493 struct buffer *smp_trash;
494 struct connection *conn;
495 SSL *ssl;
496
William Lallemandbfa3e812020-06-25 20:07:18 +0200497 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200498 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200499 else
500 conn = objt_conn(smp->sess->origin);
501
William Lallemand15e16942020-05-15 00:25:08 +0200502 ssl = ssl_sock_get_ssl_object(conn);
503 if (!ssl)
504 return 0;
505
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200506 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200507 smp->flags |= SMP_F_MAY_CHANGE;
508 return 0;
509 }
510
511 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200512 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200513 else
514 crt = SSL_get_certificate(ssl);
515 if (!crt)
516 goto out;
517
518 name = X509_get_subject_name(crt);
519 if (!name)
520 goto out;
521
522 smp_trash = get_trash_chunk();
Christopher Faulet3702f782021-01-29 11:30:37 +0100523 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200524 int pos = 1;
525
526 if (args[1].type == ARGT_SINT)
527 pos = args[1].data.sint;
528
529 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
530 goto out;
531 }
Christopher Faulet3702f782021-01-29 11:30:37 +0100532 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200533 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
534 goto out;
535 }
536 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
537 goto out;
538
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200539 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200540 smp->data.type = SMP_T_STR;
541 smp->data.u.str = *smp_trash;
542 ret = 1;
543out:
544 /* SSL_get_peer_certificate, it increase X509 * ref count */
545 if (cert_peer && crt)
546 X509_free(crt);
547 return ret;
548}
549
550/* integer, returns true if current session use a client certificate */
551static int
552smp_fetch_ssl_c_used(const struct arg *args, struct sample *smp, const char *kw, void *private)
553{
554 X509 *crt;
555 struct connection *conn;
556 SSL *ssl;
557
558 conn = objt_conn(smp->sess->origin);
559 ssl = ssl_sock_get_ssl_object(conn);
560 if (!ssl)
561 return 0;
562
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200563 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200564 smp->flags |= SMP_F_MAY_CHANGE;
565 return 0;
566 }
567
568 /* SSL_get_peer_certificate returns a ptr on allocated X509 struct */
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200569 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200570 if (crt) {
571 X509_free(crt);
572 }
573
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200574 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200575 smp->data.type = SMP_T_BOOL;
576 smp->data.u.sint = (crt != NULL);
577 return 1;
578}
579
580/* integer, returns the certificate version
581 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
582 * should be use.
583 */
584static int
585smp_fetch_ssl_x_version(const struct arg *args, struct sample *smp, const char *kw, void *private)
586{
William Lallemandbfa3e812020-06-25 20:07:18 +0200587 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
588 int conn_server = (kw[4] == 's') ? 1 : 0;
589
William Lallemand15e16942020-05-15 00:25:08 +0200590 X509 *crt;
591 struct connection *conn;
592 SSL *ssl;
593
William Lallemandbfa3e812020-06-25 20:07:18 +0200594 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200595 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200596 else
597 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +0200598 ssl = ssl_sock_get_ssl_object(conn);
599 if (!ssl)
600 return 0;
601
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200602 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200603 smp->flags |= SMP_F_MAY_CHANGE;
604 return 0;
605 }
606
607 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200608 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200609 else
610 crt = SSL_get_certificate(ssl);
611 if (!crt)
612 return 0;
613
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200614 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200615 smp->data.u.sint = (unsigned int)(1 + X509_get_version(crt));
616 /* SSL_get_peer_certificate increase X509 * ref count */
617 if (cert_peer)
618 X509_free(crt);
619 smp->data.type = SMP_T_SINT;
620
621 return 1;
622}
623
624/* string, returns the certificate's signature algorithm.
625 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
626 * should be use.
627 */
628static int
629smp_fetch_ssl_x_sig_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
630{
William Lallemandbfa3e812020-06-25 20:07:18 +0200631 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
632 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200633 X509 *crt;
634 __OPENSSL_110_CONST__ ASN1_OBJECT *algorithm;
635 int nid;
636 struct connection *conn;
637 SSL *ssl;
638
William Lallemandbfa3e812020-06-25 20:07:18 +0200639 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200640 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200641 else
642 conn = objt_conn(smp->sess->origin);
643
William Lallemand15e16942020-05-15 00:25:08 +0200644 ssl = ssl_sock_get_ssl_object(conn);
645 if (!ssl)
646 return 0;
647
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200648 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200649 smp->flags |= SMP_F_MAY_CHANGE;
650 return 0;
651 }
652
653 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200654 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200655 else
656 crt = SSL_get_certificate(ssl);
657 if (!crt)
658 return 0;
659
660 X509_ALGOR_get0(&algorithm, NULL, NULL, X509_get0_tbs_sigalg(crt));
661 nid = OBJ_obj2nid(algorithm);
662
663 smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
664 if (!smp->data.u.str.area) {
665 /* SSL_get_peer_certificate increase X509 * ref count */
666 if (cert_peer)
667 X509_free(crt);
668 return 0;
669 }
670
671 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200672 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +0200673 smp->data.u.str.data = strlen(smp->data.u.str.area);
674 /* SSL_get_peer_certificate increase X509 * ref count */
675 if (cert_peer)
676 X509_free(crt);
677
678 return 1;
679}
680
681/* string, returns the certificate's key algorithm.
682 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
683 * should be use.
684 */
685static int
686smp_fetch_ssl_x_key_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
687{
William Lallemandbfa3e812020-06-25 20:07:18 +0200688 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
689 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200690 X509 *crt;
691 ASN1_OBJECT *algorithm;
692 int nid;
693 struct connection *conn;
694 SSL *ssl;
695
William Lallemandbfa3e812020-06-25 20:07:18 +0200696 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200697 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200698 else
699 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +0200700 ssl = ssl_sock_get_ssl_object(conn);
701 if (!ssl)
702 return 0;
703
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200704 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200705 smp->flags |= SMP_F_MAY_CHANGE;
706 return 0;
707 }
708
709 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200710 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200711 else
712 crt = SSL_get_certificate(ssl);
713 if (!crt)
714 return 0;
715
716 X509_PUBKEY_get0_param(&algorithm, NULL, NULL, NULL, X509_get_X509_PUBKEY(crt));
717 nid = OBJ_obj2nid(algorithm);
718
719 smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
720 if (!smp->data.u.str.area) {
721 /* SSL_get_peer_certificate increase X509 * ref count */
722 if (cert_peer)
723 X509_free(crt);
724 return 0;
725 }
726
727 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200728 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +0200729 smp->data.u.str.data = strlen(smp->data.u.str.area);
730 if (cert_peer)
731 X509_free(crt);
732
733 return 1;
734}
735
736/* boolean, returns true if front conn. transport layer is SSL.
737 * This function is also usable on backend conn if the fetch keyword 5th
738 * char is 'b'.
739 */
740static int
741smp_fetch_ssl_fc(const struct arg *args, struct sample *smp, const char *kw, void *private)
742{
743 struct connection *conn;
744
745 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +0200746 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +0200747 else
748 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
749 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
750
751 smp->data.type = SMP_T_BOOL;
752 smp->data.u.sint = (conn && conn->xprt == &ssl_sock);
753 return 1;
754}
755
756/* boolean, returns true if client present a SNI */
757static int
758smp_fetch_ssl_fc_has_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
759{
760#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
761 struct connection *conn = objt_conn(smp->sess->origin);
762 SSL *ssl = ssl_sock_get_ssl_object(conn);
763
764 smp->data.type = SMP_T_BOOL;
765 smp->data.u.sint = ssl && SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name) != NULL;
766 return 1;
767#else
768 return 0;
769#endif
770}
771
772/* boolean, returns true if client session has been resumed.
773 * This function is also usable on backend conn if the fetch keyword 5th
774 * char is 'b'.
775 */
776static int
777smp_fetch_ssl_fc_is_resumed(const struct arg *args, struct sample *smp, const char *kw, void *private)
778{
779 struct connection *conn;
780 SSL *ssl;
781
782 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +0200783 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +0200784 else
785 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
786 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
787
788 ssl = ssl_sock_get_ssl_object(conn);
789
790 smp->data.type = SMP_T_BOOL;
791 smp->data.u.sint = ssl && SSL_session_reused(ssl);
792 return 1;
793}
794
795/* string, returns the used cipher if front conn. transport layer is SSL.
796 * This function is also usable on backend conn if the fetch keyword 5th
797 * char is 'b'.
798 */
799static int
800smp_fetch_ssl_fc_cipher(const struct arg *args, struct sample *smp, const char *kw, void *private)
801{
802 struct connection *conn;
803 SSL *ssl;
804
805 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +0200806 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +0200807 else
808 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
809 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
810
811 smp->flags = 0;
812 ssl = ssl_sock_get_ssl_object(conn);
813 if (!ssl)
814 return 0;
815
816 smp->data.u.str.area = (char *)SSL_get_cipher_name(ssl);
817 if (!smp->data.u.str.area)
818 return 0;
819
820 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200821 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +0200822 smp->data.u.str.data = strlen(smp->data.u.str.area);
823
824 return 1;
825}
826
827/* integer, returns the algoritm's keysize if front conn. transport layer
828 * is SSL.
829 * This function is also usable on backend conn if the fetch keyword 5th
830 * char is 'b'.
831 */
832static int
833smp_fetch_ssl_fc_alg_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
834{
835 struct connection *conn;
836 SSL *ssl;
837 int sint;
838
839 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +0200840 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +0200841 else
842 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
843 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
844
845 smp->flags = 0;
846 ssl = ssl_sock_get_ssl_object(conn);
847 if (!ssl)
848 return 0;
849
850 if (!SSL_get_cipher_bits(ssl, &sint))
851 return 0;
852
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200853 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200854 smp->data.u.sint = sint;
855 smp->data.type = SMP_T_SINT;
856
857 return 1;
858}
859
860/* integer, returns the used keysize if front conn. transport layer is SSL.
861 * This function is also usable on backend conn if the fetch keyword 5th
862 * char is 'b'.
863 */
864static int
865smp_fetch_ssl_fc_use_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
866{
867 struct connection *conn;
868 SSL *ssl;
869
870 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +0200871 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +0200872 else
873 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
874 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
875
876 smp->flags = 0;
877 ssl = ssl_sock_get_ssl_object(conn);
878 if (!ssl)
879 return 0;
880
881 smp->data.u.sint = (unsigned int)SSL_get_cipher_bits(ssl, NULL);
882 if (!smp->data.u.sint)
883 return 0;
884
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200885 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200886 smp->data.type = SMP_T_SINT;
887
888 return 1;
889}
890
891#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
892static int
893smp_fetch_ssl_fc_npn(const struct arg *args, struct sample *smp, const char *kw, void *private)
894{
895 struct connection *conn;
896 SSL *ssl;
897 unsigned int len = 0;
898
899 smp->flags = SMP_F_CONST;
900 smp->data.type = SMP_T_STR;
901
902 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +0200903 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +0200904 else
905 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
906 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
907
908 ssl = ssl_sock_get_ssl_object(conn);
909 if (!ssl)
910 return 0;
911
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200912 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200913 smp->data.u.str.area = NULL;
914 SSL_get0_next_proto_negotiated(ssl,
915 (const unsigned char **)&smp->data.u.str.area,
916 &len);
917
918 if (!smp->data.u.str.area)
919 return 0;
920
921 smp->data.u.str.data = len;
922 return 1;
923}
924#endif
925
926#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
927static int
928smp_fetch_ssl_fc_alpn(const struct arg *args, struct sample *smp, const char *kw, void *private)
929{
930 struct connection *conn;
931 SSL *ssl;
932 unsigned int len = 0;
933
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200934 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +0200935 smp->data.type = SMP_T_STR;
936
937 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +0200938 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +0200939 else
940 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
941 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
942
943 ssl = ssl_sock_get_ssl_object(conn);
944 if (!ssl)
945 return 0;
946
947 smp->data.u.str.area = NULL;
948 SSL_get0_alpn_selected(ssl,
949 (const unsigned char **)&smp->data.u.str.area,
950 &len);
951
952 if (!smp->data.u.str.area)
953 return 0;
954
955 smp->data.u.str.data = len;
956 return 1;
957}
958#endif
959
960/* string, returns the used protocol if front conn. transport layer is SSL.
961 * This function is also usable on backend conn if the fetch keyword 5th
962 * char is 'b'.
963 */
964static int
965smp_fetch_ssl_fc_protocol(const struct arg *args, struct sample *smp, const char *kw, void *private)
966{
967 struct connection *conn;
968 SSL *ssl;
969
970 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +0200971 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +0200972 else
973 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
974 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
975
976 smp->flags = 0;
977 ssl = ssl_sock_get_ssl_object(conn);
978 if (!ssl)
979 return 0;
980
981 smp->data.u.str.area = (char *)SSL_get_version(ssl);
982 if (!smp->data.u.str.area)
983 return 0;
984
985 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200986 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +0200987 smp->data.u.str.data = strlen(smp->data.u.str.area);
988
989 return 1;
990}
991
992/* binary, returns the SSL stream id if front conn. transport layer is SSL.
993 * This function is also usable on backend conn if the fetch keyword 5th
994 * char is 'b'.
995 */
996#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
997static int
998smp_fetch_ssl_fc_session_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
999{
1000 struct connection *conn;
1001 SSL_SESSION *ssl_sess;
1002 SSL *ssl;
1003 unsigned int len = 0;
1004
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001005 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001006 smp->data.type = SMP_T_BIN;
1007
1008 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001009 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001010 else
1011 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1012 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1013
1014 ssl = ssl_sock_get_ssl_object(conn);
1015 if (!ssl)
1016 return 0;
1017
1018 ssl_sess = SSL_get_session(ssl);
1019 if (!ssl_sess)
1020 return 0;
1021
1022 smp->data.u.str.area = (char *)SSL_SESSION_get_id(ssl_sess, &len);
1023 if (!smp->data.u.str.area || !len)
1024 return 0;
1025
1026 smp->data.u.str.data = len;
1027 return 1;
1028}
1029#endif
1030
1031
Ilya Shipitsindf627942021-03-25 00:41:41 +05001032#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02001033static int
1034smp_fetch_ssl_fc_random(const struct arg *args, struct sample *smp, const char *kw, void *private)
1035{
1036 struct connection *conn;
1037 struct buffer *data;
1038 SSL *ssl;
1039
1040 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001041 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001042 else
1043 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1044 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1045
1046 ssl = ssl_sock_get_ssl_object(conn);
1047 if (!ssl)
1048 return 0;
1049
1050 data = get_trash_chunk();
1051 if (kw[7] == 'c')
1052 data->data = SSL_get_client_random(ssl,
1053 (unsigned char *) data->area,
1054 data->size);
1055 else
1056 data->data = SSL_get_server_random(ssl,
1057 (unsigned char *) data->area,
1058 data->size);
1059 if (!data->data)
1060 return 0;
1061
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001062 smp->flags = SMP_F_VOL_TEST;
William Lallemand15e16942020-05-15 00:25:08 +02001063 smp->data.type = SMP_T_BIN;
1064 smp->data.u.str = *data;
1065
1066 return 1;
1067}
1068
1069static int
1070smp_fetch_ssl_fc_session_key(const struct arg *args, struct sample *smp, const char *kw, void *private)
1071{
1072 struct connection *conn;
1073 SSL_SESSION *ssl_sess;
1074 struct buffer *data;
1075 SSL *ssl;
1076
1077 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001078 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001079 else
1080 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1081 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1082
1083 ssl = ssl_sock_get_ssl_object(conn);
1084 if (!ssl)
1085 return 0;
1086
1087 ssl_sess = SSL_get_session(ssl);
1088 if (!ssl_sess)
1089 return 0;
1090
1091 data = get_trash_chunk();
1092 data->data = SSL_SESSION_get_master_key(ssl_sess,
1093 (unsigned char *) data->area,
1094 data->size);
1095 if (!data->data)
1096 return 0;
1097
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001098 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001099 smp->data.type = SMP_T_BIN;
1100 smp->data.u.str = *data;
1101
1102 return 1;
1103}
1104#endif
1105
1106#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1107static int
1108smp_fetch_ssl_fc_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
1109{
1110 struct connection *conn;
1111 SSL *ssl;
1112
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001113 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001114 smp->data.type = SMP_T_STR;
1115
1116 conn = objt_conn(smp->sess->origin);
1117 ssl = ssl_sock_get_ssl_object(conn);
1118 if (!ssl)
1119 return 0;
1120
1121 smp->data.u.str.area = (char *)SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
1122 if (!smp->data.u.str.area)
1123 return 0;
1124
1125 smp->data.u.str.data = strlen(smp->data.u.str.area);
1126 return 1;
1127}
1128#endif
1129
Marcin Deranek959a48c2021-07-13 15:14:21 +02001130/* binary, returns tls client hello cipher list.
1131 * Arguments: filter_option (0,1)
1132 */
William Lallemand15e16942020-05-15 00:25:08 +02001133static int
1134smp_fetch_ssl_fc_cl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1135{
Marcin Deranek959a48c2021-07-13 15:14:21 +02001136 struct buffer *smp_trash;
William Lallemand15e16942020-05-15 00:25:08 +02001137 struct connection *conn;
1138 struct ssl_capture *capture;
1139 SSL *ssl;
1140
1141 conn = objt_conn(smp->sess->origin);
1142 ssl = ssl_sock_get_ssl_object(conn);
1143 if (!ssl)
1144 return 0;
1145
1146 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1147 if (!capture)
1148 return 0;
1149
Marcin Deranek959a48c2021-07-13 15:14:21 +02001150 if (args[0].data.sint) {
1151 smp_trash = get_trash_chunk();
1152 exclude_tls_grease(capture->data + capture->ciphersuite_offset, capture->ciphersuite_len, smp_trash);
1153 smp->data.u.str.area = smp_trash->area;
1154 smp->data.u.str.data = smp_trash->data;
1155 smp->flags = SMP_F_VOL_SESS;
1156 }
1157 else {
1158 smp->data.u.str.area = capture->data + capture->ciphersuite_offset;
1159 smp->data.u.str.data = capture->ciphersuite_len;
1160 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1161 }
1162
William Lallemand15e16942020-05-15 00:25:08 +02001163 smp->data.type = SMP_T_BIN;
William Lallemand15e16942020-05-15 00:25:08 +02001164 return 1;
1165}
1166
Marcin Deranek959a48c2021-07-13 15:14:21 +02001167/* binary, returns tls client hello cipher list as hexadecimal string.
1168 * Arguments: filter_option (0,1)
1169 */
William Lallemand15e16942020-05-15 00:25:08 +02001170static int
1171smp_fetch_ssl_fc_cl_hex(const struct arg *args, struct sample *smp, const char *kw, void *private)
1172{
1173 struct buffer *data;
1174
1175 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1176 return 0;
1177
1178 data = get_trash_chunk();
1179 dump_binary(data, smp->data.u.str.area, smp->data.u.str.data);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001180 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001181 smp->data.type = SMP_T_BIN;
1182 smp->data.u.str = *data;
1183 return 1;
1184}
1185
Marcin Deranek959a48c2021-07-13 15:14:21 +02001186/* integer, returns xxh64 hash of tls client hello cipher list. */
William Lallemand15e16942020-05-15 00:25:08 +02001187static int
1188smp_fetch_ssl_fc_cl_xxh64(const struct arg *args, struct sample *smp, const char *kw, void *private)
1189{
1190 struct connection *conn;
1191 struct ssl_capture *capture;
1192 SSL *ssl;
1193
1194 conn = objt_conn(smp->sess->origin);
1195 ssl = ssl_sock_get_ssl_object(conn);
1196 if (!ssl)
1197 return 0;
1198
1199 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1200 if (!capture)
1201 return 0;
1202
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001203 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001204 smp->data.type = SMP_T_SINT;
1205 smp->data.u.sint = capture->xxh64;
1206 return 1;
1207}
1208
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001209static int
1210smp_fetch_ssl_fc_hsk_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
1211{
1212 struct connection *conn;
1213 struct ssl_sock_ctx *ctx;
1214
1215 conn = objt_conn(smp->sess->origin);
1216 if (!conn || conn->xprt != &ssl_sock)
1217 return 0;
1218 ctx = conn->xprt_ctx;
1219
1220 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1221 smp->flags = SMP_F_MAY_CHANGE;
1222 return 0;
1223 }
1224
1225 if (!ctx)
1226 return 0;
1227
1228 smp->flags = SMP_F_VOL_SESS;
1229 smp->data.type = SMP_T_SINT;
1230 smp->data.u.sint = ctx->hsk_error_code;
1231 return 1;
1232}
1233
1234static int
Marcin Deranek959a48c2021-07-13 15:14:21 +02001235smp_fetch_ssl_fc_protocol_hello_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1236{
1237 struct connection *conn;
1238 struct ssl_capture *capture;
1239 SSL *ssl;
1240
1241 conn = objt_conn(smp->sess->origin);
1242 ssl = ssl_sock_get_ssl_object(conn);
1243 if (!ssl)
1244 return 0;
1245
1246 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1247 if (!capture)
1248 return 0;
1249
1250 smp->flags = SMP_F_VOL_SESS;
1251 smp->data.type = SMP_T_SINT;
1252 smp->data.u.sint = capture->protocol_version;
1253 return 1;
1254}
1255
1256static int
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001257smp_fetch_ssl_fc_hsk_err_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
1258{
1259 struct connection *conn;
1260 struct ssl_sock_ctx *ctx;
1261 const char *err_code_str;
1262
1263 conn = objt_conn(smp->sess->origin);
1264 if (!conn || conn->xprt != &ssl_sock)
1265 return 0;
1266 ctx = conn->xprt_ctx;
1267
1268 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1269 smp->flags = SMP_F_MAY_CHANGE;
1270 return 0;
1271 }
1272
1273 if (!ctx || !ctx->hsk_error_code)
1274 return 0;
1275
1276 err_code_str = ERR_error_string(ctx->hsk_error_code, NULL);
1277
1278 smp->flags = SMP_F_VOL_SESS;
1279 smp->data.type = SMP_T_STR;
1280 smp->data.u.str.area = (char*)err_code_str;
1281 smp->data.u.str.data = strlen(err_code_str);
1282
Marcin Deranek959a48c2021-07-13 15:14:21 +02001283 return 1;
1284}
1285
1286/* binary, returns tls client hello extensions list.
1287 * Arguments: filter_option (0,1)
1288 */
1289static int
1290smp_fetch_ssl_fc_ext_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1291{
1292 struct buffer *smp_trash;
1293 struct connection *conn;
1294 struct ssl_capture *capture;
1295 SSL *ssl;
1296
1297 conn = objt_conn(smp->sess->origin);
1298 ssl = ssl_sock_get_ssl_object(conn);
1299 if (!ssl)
1300 return 0;
1301
1302 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1303 if (!capture)
1304 return 0;
1305
1306 if (args[0].data.sint) {
1307 smp_trash = get_trash_chunk();
1308 exclude_tls_grease(capture->data + capture->extensions_offset, capture->extensions_len, smp_trash);
1309 smp->data.u.str.area = smp_trash->area;
1310 smp->data.u.str.data = smp_trash->data;
1311 smp->flags = SMP_F_VOL_SESS;
1312 }
1313 else {
1314 smp->data.u.str.area = capture->data + capture->extensions_offset;
1315 smp->data.u.str.data = capture->extensions_len;
1316 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1317 }
1318
1319 smp->data.type = SMP_T_BIN;
1320 return 1;
1321}
1322
1323/* binary, returns tls client hello supported elliptic curves.
1324 * Arguments: filter_option (0,1)
1325 */
1326static int
1327smp_fetch_ssl_fc_ecl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1328{
1329 struct buffer *smp_trash;
1330 struct connection *conn;
1331 struct ssl_capture *capture;
1332 SSL *ssl;
1333
1334 conn = objt_conn(smp->sess->origin);
1335 ssl = ssl_sock_get_ssl_object(conn);
1336 if (!ssl)
1337 return 0;
1338
1339 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1340 if (!capture)
1341 return 0;
1342
1343 if (args[0].data.sint) {
1344 smp_trash = get_trash_chunk();
1345 exclude_tls_grease(capture->data + capture->ec_offset, capture->ec_len, smp_trash);
1346 smp->data.u.str.area = smp_trash->area;
1347 smp->data.u.str.data = smp_trash->data;
1348 smp->flags = SMP_F_VOL_SESS;
1349 }
1350 else {
1351 smp->data.u.str.area = capture->data + capture->ec_offset;
1352 smp->data.u.str.data = capture->ec_len;
1353 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1354 }
1355
1356 smp->data.type = SMP_T_BIN;
1357 return 1;
1358}
1359
1360/* binary, returns tls client hello supported elliptic curve point formats */
1361static int
1362smp_fetch_ssl_fc_ecf_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1363{
1364 struct connection *conn;
1365 struct ssl_capture *capture;
1366 SSL *ssl;
1367
1368 conn = objt_conn(smp->sess->origin);
1369 ssl = ssl_sock_get_ssl_object(conn);
1370 if (!ssl)
1371 return 0;
1372
1373 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1374 if (!capture)
1375 return 0;
1376
1377 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1378 smp->data.type = SMP_T_BIN;
1379 smp->data.u.str.area = capture->data + capture->ec_formats_offset;
1380 smp->data.u.str.data = capture->ec_formats_len;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001381 return 1;
1382}
1383
William Lallemand7d42ef52020-07-06 11:41:30 +02001384/* Dump the SSL keylog, it only works with "tune.ssl.keylog 1" */
William Lallemand722180a2021-06-09 16:46:12 +02001385#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02001386static int smp_fetch_ssl_x_keylog(const struct arg *args, struct sample *smp, const char *kw, void *private)
1387{
1388 struct connection *conn;
1389 struct ssl_keylog *keylog;
1390 SSL *ssl;
1391 char *src = NULL;
1392 const char *sfx;
1393
1394 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1395 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1396
William Lallemandeec1d452020-07-07 10:48:13 +02001397 if (!conn)
1398 return 0;
1399
William Lallemand7d42ef52020-07-06 11:41:30 +02001400 if (conn->flags & CO_FL_WAIT_XPRT) {
1401 smp->flags |= SMP_F_MAY_CHANGE;
1402 return 0;
1403 }
1404
1405 ssl = ssl_sock_get_ssl_object(conn);
1406 if (!ssl)
1407 return 0;
1408
1409 keylog = SSL_get_ex_data(ssl, ssl_keylog_index);
1410 if (!keylog)
1411 return 0;
1412
1413 sfx = kw + strlen("ssl_xx_");
1414
1415 if (strcmp(sfx, "client_early_traffic_secret") == 0) {
1416 src = keylog->client_early_traffic_secret;
1417 } else if (strcmp(sfx, "client_handshake_traffic_secret") == 0) {
1418 src = keylog->client_handshake_traffic_secret;
1419 } else if (strcmp(sfx, "server_handshake_traffic_secret") == 0) {
1420 src = keylog->server_handshake_traffic_secret;
1421 } else if (strcmp(sfx, "client_traffic_secret_0") == 0) {
1422 src = keylog->client_traffic_secret_0;
1423 } else if (strcmp(sfx, "server_traffic_secret_0") == 0) {
1424 src = keylog->server_traffic_secret_0;
1425 } else if (strcmp(sfx, "exporter_secret") == 0) {
1426 src = keylog->exporter_secret;
1427 } else if (strcmp(sfx, "early_exporter_secret") == 0) {
1428 src = keylog->early_exporter_secret;
1429 }
1430
1431 if (!src || !*src)
1432 return 0;
1433
1434 smp->data.u.str.area = src;
1435 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001436 smp->flags |= SMP_F_VOL_TEST | SMP_F_CONST;
William Lallemand7d42ef52020-07-06 11:41:30 +02001437 smp->data.u.str.data = strlen(smp->data.u.str.area);
1438 return 1;
William Lallemand7d42ef52020-07-06 11:41:30 +02001439}
1440#endif
1441
William Lallemand15e16942020-05-15 00:25:08 +02001442static int
1443smp_fetch_ssl_fc_cl_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
1444{
Ilya Shipitsinc9dfee42020-10-31 02:10:02 +05001445#if defined(OPENSSL_IS_BORINGSSL) || defined(SSL_CTRL_GET_RAW_CIPHERLIST)
William Lallemand15e16942020-05-15 00:25:08 +02001446 struct buffer *data;
1447 int i;
1448
1449 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1450 return 0;
1451
1452 data = get_trash_chunk();
1453 for (i = 0; i + 1 < smp->data.u.str.data; i += 2) {
1454 const char *str;
1455 const SSL_CIPHER *cipher;
1456 const unsigned char *bin = (const unsigned char *) smp->data.u.str.area + i;
1457 uint16_t id = (bin[0] << 8) | bin[1];
1458#if defined(OPENSSL_IS_BORINGSSL)
1459 cipher = SSL_get_cipher_by_value(id);
1460#else
1461 struct connection *conn = __objt_conn(smp->sess->origin);
1462 SSL *ssl = ssl_sock_get_ssl_object(conn);
1463 cipher = SSL_CIPHER_find(ssl, bin);
1464#endif
1465 str = SSL_CIPHER_get_name(cipher);
1466 if (!str || strcmp(str, "(NONE)") == 0)
1467 chunk_appendf(data, "%sUNKNOWN(%04x)", i == 0 ? "" : ",", id);
1468 else
1469 chunk_appendf(data, "%s%s", i == 0 ? "" : ",", str);
1470 }
1471 smp->data.type = SMP_T_STR;
1472 smp->data.u.str = *data;
1473 return 1;
1474#else
1475 return smp_fetch_ssl_fc_cl_xxh64(args, smp, kw, private);
1476#endif
1477}
1478
1479#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1480static int
1481smp_fetch_ssl_fc_unique_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1482{
1483 struct connection *conn;
1484 int finished_len;
1485 struct buffer *finished_trash;
1486 SSL *ssl;
1487
1488 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001489 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001490 else
1491 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1492 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1493
1494 smp->flags = 0;
1495 ssl = ssl_sock_get_ssl_object(conn);
1496 if (!ssl)
1497 return 0;
1498
1499 if (conn->flags & CO_FL_WAIT_XPRT) {
1500 smp->flags |= SMP_F_MAY_CHANGE;
1501 return 0;
1502 }
1503
1504 finished_trash = get_trash_chunk();
1505 if (!SSL_session_reused(ssl))
1506 finished_len = SSL_get_peer_finished(ssl,
1507 finished_trash->area,
1508 finished_trash->size);
1509 else
1510 finished_len = SSL_get_finished(ssl,
1511 finished_trash->area,
1512 finished_trash->size);
1513
1514 if (!finished_len)
1515 return 0;
1516
1517 finished_trash->data = finished_len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001518 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001519 smp->data.u.str = *finished_trash;
1520 smp->data.type = SMP_T_BIN;
1521
1522 return 1;
1523}
1524#endif
1525
1526/* integer, returns the first verify error in CA chain of client certificate chain. */
1527static int
1528smp_fetch_ssl_c_ca_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
1529{
1530 struct connection *conn;
1531 struct ssl_sock_ctx *ctx;
1532
1533 conn = objt_conn(smp->sess->origin);
1534 if (!conn || conn->xprt != &ssl_sock)
1535 return 0;
1536 ctx = conn->xprt_ctx;
1537
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001538 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001539 smp->flags = SMP_F_MAY_CHANGE;
1540 return 0;
1541 }
1542
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001543 if (!ctx)
1544 return 0;
1545
William Lallemand15e16942020-05-15 00:25:08 +02001546 smp->data.type = SMP_T_SINT;
1547 smp->data.u.sint = (unsigned long long int)SSL_SOCK_ST_TO_CA_ERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001548 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001549
1550 return 1;
1551}
1552
1553/* integer, returns the depth of the first verify error in CA chain of client certificate chain. */
1554static int
1555smp_fetch_ssl_c_ca_err_depth(const struct arg *args, struct sample *smp, const char *kw, void *private)
1556{
1557 struct connection *conn;
1558 struct ssl_sock_ctx *ctx;
1559
1560 conn = objt_conn(smp->sess->origin);
1561 if (!conn || conn->xprt != &ssl_sock)
1562 return 0;
1563
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001564 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001565 smp->flags = SMP_F_MAY_CHANGE;
1566 return 0;
1567 }
1568 ctx = conn->xprt_ctx;
1569
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001570 if (!ctx)
1571 return 0;
1572
William Lallemand15e16942020-05-15 00:25:08 +02001573 smp->data.type = SMP_T_SINT;
1574 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CAEDEPTH(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001575 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001576
1577 return 1;
1578}
1579
1580/* integer, returns the first verify error on client certificate */
1581static int
1582smp_fetch_ssl_c_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
1583{
1584 struct connection *conn;
1585 struct ssl_sock_ctx *ctx;
1586
1587 conn = objt_conn(smp->sess->origin);
1588 if (!conn || conn->xprt != &ssl_sock)
1589 return 0;
1590
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001591 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001592 smp->flags = SMP_F_MAY_CHANGE;
1593 return 0;
1594 }
1595
1596 ctx = conn->xprt_ctx;
1597
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001598 if (!ctx)
1599 return 0;
1600
William Lallemand15e16942020-05-15 00:25:08 +02001601 smp->data.type = SMP_T_SINT;
1602 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CRTERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001603 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001604
1605 return 1;
1606}
1607
1608/* integer, returns the verify result on client cert */
1609static int
1610smp_fetch_ssl_c_verify(const struct arg *args, struct sample *smp, const char *kw, void *private)
1611{
1612 struct connection *conn;
1613 SSL *ssl;
1614
1615 conn = objt_conn(smp->sess->origin);
1616 ssl = ssl_sock_get_ssl_object(conn);
1617 if (!ssl)
1618 return 0;
1619
1620 if (conn->flags & CO_FL_WAIT_XPRT) {
1621 smp->flags = SMP_F_MAY_CHANGE;
1622 return 0;
1623 }
1624
1625 smp->data.type = SMP_T_SINT;
1626 smp->data.u.sint = (long long int)SSL_get_verify_result(ssl);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001627 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001628
1629 return 1;
1630}
1631
1632/* Argument validation functions */
1633
1634/* This function is used to validate the arguments passed to any "x_dn" ssl
1635 * keywords. These keywords support specifying a third parameter that must be
1636 * either empty or the value "rfc2253". Returns 0 on error, non-zero if OK.
1637 */
1638int val_dnfmt(struct arg *arg, char **err_msg)
1639{
1640 if (arg && arg[2].type == ARGT_STR && arg[2].data.str.data > 0 && (strcmp(arg[2].data.str.area, "rfc2253") != 0)) {
1641 memprintf(err_msg, "only rfc2253 or a blank value are currently supported as the format argument.");
1642 return 0;
1643 }
1644 return 1;
1645}
1646
1647/* Note: must not be declared <const> as its list will be overwritten.
1648 * Please take care of keeping this list alphabetically sorted.
1649 */
1650static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
1651 { "ssl_bc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
1652 { "ssl_bc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
1653#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1654 { "ssl_bc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
1655#endif
1656 { "ssl_bc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
1657#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
1658 { "ssl_bc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
1659#endif
1660 { "ssl_bc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
1661 { "ssl_bc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
1662 { "ssl_bc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
1663 { "ssl_bc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
1664#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1665 { "ssl_bc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
1666#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05001667#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02001668 { "ssl_bc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
1669 { "ssl_bc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
1670 { "ssl_bc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
1671#endif
1672 { "ssl_c_ca_err", smp_fetch_ssl_c_ca_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1673 { "ssl_c_ca_err_depth", smp_fetch_ssl_c_ca_err_depth, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1674 { "ssl_c_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02001675 { "ssl_c_chain_der", smp_fetch_ssl_x_chain_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Lallemand15e16942020-05-15 00:25:08 +02001676 { "ssl_c_err", smp_fetch_ssl_c_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1677 { "ssl_c_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
1678 { "ssl_c_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1679 { "ssl_c_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1680 { "ssl_c_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1681 { "ssl_c_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1682 { "ssl_c_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
1683 { "ssl_c_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1684 { "ssl_c_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1685 { "ssl_c_used", smp_fetch_ssl_c_used, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
1686 { "ssl_c_verify", smp_fetch_ssl_c_verify, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1687 { "ssl_c_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1688 { "ssl_f_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1689 { "ssl_f_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
1690 { "ssl_f_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1691 { "ssl_f_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1692 { "ssl_f_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1693 { "ssl_f_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1694 { "ssl_f_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
1695 { "ssl_f_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1696 { "ssl_f_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1697 { "ssl_f_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1698 { "ssl_fc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
1699 { "ssl_fc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1700 { "ssl_fc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1701 { "ssl_fc_has_crt", smp_fetch_ssl_fc_has_crt, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
1702 { "ssl_fc_has_early", smp_fetch_ssl_fc_has_early, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
1703 { "ssl_fc_has_sni", smp_fetch_ssl_fc_has_sni, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
1704 { "ssl_fc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
1705#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
1706 { "ssl_fc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1707#endif
1708#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1709 { "ssl_fc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1710#endif
1711 { "ssl_fc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1712#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1713 { "ssl_fc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1714#endif
1715 { "ssl_fc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1716#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1717 { "ssl_fc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1718#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05001719#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02001720 { "ssl_fc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1721 { "ssl_fc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1722 { "ssl_fc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1723#endif
William Lallemand7d42ef52020-07-06 11:41:30 +02001724
William Lallemand722180a2021-06-09 16:46:12 +02001725#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02001726 { "ssl_fc_client_early_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1727 { "ssl_fc_client_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1728 { "ssl_fc_server_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1729 { "ssl_fc_client_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1730 { "ssl_fc_server_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1731 { "ssl_fc_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1732 { "ssl_fc_early_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1733#endif
1734
William Lallemand15e16942020-05-15 00:25:08 +02001735#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1736 { "ssl_fc_sni", smp_fetch_ssl_fc_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1737#endif
Marcin Deranek959a48c2021-07-13 15:14:21 +02001738 { "ssl_fc_cipherlist_bin", smp_fetch_ssl_fc_cl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
1739 { "ssl_fc_cipherlist_hex", smp_fetch_ssl_fc_cl_hex, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_USE_L5CLI },
1740 { "ssl_fc_cipherlist_str", smp_fetch_ssl_fc_cl_str, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
William Lallemand15e16942020-05-15 00:25:08 +02001741 { "ssl_fc_cipherlist_xxh", smp_fetch_ssl_fc_cl_xxh64, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001742 { "ssl_fc_hsk_err", smp_fetch_ssl_fc_hsk_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1743 { "ssl_fc_hsk_err_str", smp_fetch_ssl_fc_hsk_err_str, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
Marcin Deranek959a48c2021-07-13 15:14:21 +02001744 { "ssl_fc_protocol_hello_id",smp_fetch_ssl_fc_protocol_hello_id,0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1745 { "ssl_fc_extlist_bin", smp_fetch_ssl_fc_ext_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
1746 { "ssl_fc_eclist_bin", smp_fetch_ssl_fc_ecl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
1747 { "ssl_fc_ecformats_bin", smp_fetch_ssl_fc_ecf_bin, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
William Lallemandbfa3e812020-06-25 20:07:18 +02001748
1749/* SSL server certificate fetches */
1750 { "ssl_s_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02001751 { "ssl_s_chain_der", smp_fetch_ssl_x_chain_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Lallemandbfa3e812020-06-25 20:07:18 +02001752 { "ssl_s_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1753 { "ssl_s_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1754 { "ssl_s_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1755 { "ssl_s_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1756 { "ssl_s_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
1757 { "ssl_s_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
1758 { "ssl_s_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1759 { "ssl_s_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1760 { "ssl_s_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
William Lallemand15e16942020-05-15 00:25:08 +02001761 { NULL, NULL, 0, 0, 0 },
1762}};
1763
1764INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
1765
1766/* Note: must not be declared <const> as its list will be overwritten.
1767 * Please take care of keeping this list alphabetically sorted.
1768 */
1769static struct acl_kw_list acl_kws = {ILH, {
1770 { "ssl_fc_sni_end", "ssl_fc_sni", PAT_MATCH_END },
1771 { "ssl_fc_sni_reg", "ssl_fc_sni", PAT_MATCH_REG },
1772 { /* END */ },
1773}};
1774
1775INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);