blob: f93ae0a8f1a05a183a73be0f55f0ff8933605002 [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
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001215 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
1216 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
1217 else
1218 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1219 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1220
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001221 if (!conn || conn->xprt != &ssl_sock)
1222 return 0;
1223 ctx = conn->xprt_ctx;
1224
1225 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1226 smp->flags = SMP_F_MAY_CHANGE;
1227 return 0;
1228 }
1229
1230 if (!ctx)
1231 return 0;
1232
1233 smp->flags = SMP_F_VOL_SESS;
1234 smp->data.type = SMP_T_SINT;
1235 smp->data.u.sint = ctx->hsk_error_code;
1236 return 1;
1237}
1238
1239static int
Marcin Deranek959a48c2021-07-13 15:14:21 +02001240smp_fetch_ssl_fc_protocol_hello_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1241{
1242 struct connection *conn;
1243 struct ssl_capture *capture;
1244 SSL *ssl;
1245
1246 conn = objt_conn(smp->sess->origin);
1247 ssl = ssl_sock_get_ssl_object(conn);
1248 if (!ssl)
1249 return 0;
1250
1251 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1252 if (!capture)
1253 return 0;
1254
1255 smp->flags = SMP_F_VOL_SESS;
1256 smp->data.type = SMP_T_SINT;
1257 smp->data.u.sint = capture->protocol_version;
1258 return 1;
1259}
1260
1261static int
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001262smp_fetch_ssl_fc_hsk_err_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
1263{
1264 struct connection *conn;
1265 struct ssl_sock_ctx *ctx;
1266 const char *err_code_str;
1267
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001268 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
1269 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
1270 else
1271 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1272 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1273
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001274 if (!conn || conn->xprt != &ssl_sock)
1275 return 0;
1276 ctx = conn->xprt_ctx;
1277
1278 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1279 smp->flags = SMP_F_MAY_CHANGE;
1280 return 0;
1281 }
1282
1283 if (!ctx || !ctx->hsk_error_code)
1284 return 0;
1285
1286 err_code_str = ERR_error_string(ctx->hsk_error_code, NULL);
1287
1288 smp->flags = SMP_F_VOL_SESS;
1289 smp->data.type = SMP_T_STR;
1290 smp->data.u.str.area = (char*)err_code_str;
1291 smp->data.u.str.data = strlen(err_code_str);
1292
Marcin Deranek959a48c2021-07-13 15:14:21 +02001293 return 1;
1294}
1295
1296/* binary, returns tls client hello extensions list.
1297 * Arguments: filter_option (0,1)
1298 */
1299static int
1300smp_fetch_ssl_fc_ext_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1301{
1302 struct buffer *smp_trash;
1303 struct connection *conn;
1304 struct ssl_capture *capture;
1305 SSL *ssl;
1306
1307 conn = objt_conn(smp->sess->origin);
1308 ssl = ssl_sock_get_ssl_object(conn);
1309 if (!ssl)
1310 return 0;
1311
1312 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1313 if (!capture)
1314 return 0;
1315
1316 if (args[0].data.sint) {
1317 smp_trash = get_trash_chunk();
1318 exclude_tls_grease(capture->data + capture->extensions_offset, capture->extensions_len, smp_trash);
1319 smp->data.u.str.area = smp_trash->area;
1320 smp->data.u.str.data = smp_trash->data;
1321 smp->flags = SMP_F_VOL_SESS;
1322 }
1323 else {
1324 smp->data.u.str.area = capture->data + capture->extensions_offset;
1325 smp->data.u.str.data = capture->extensions_len;
1326 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1327 }
1328
1329 smp->data.type = SMP_T_BIN;
1330 return 1;
1331}
1332
1333/* binary, returns tls client hello supported elliptic curves.
1334 * Arguments: filter_option (0,1)
1335 */
1336static int
1337smp_fetch_ssl_fc_ecl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1338{
1339 struct buffer *smp_trash;
1340 struct connection *conn;
1341 struct ssl_capture *capture;
1342 SSL *ssl;
1343
1344 conn = objt_conn(smp->sess->origin);
1345 ssl = ssl_sock_get_ssl_object(conn);
1346 if (!ssl)
1347 return 0;
1348
1349 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1350 if (!capture)
1351 return 0;
1352
1353 if (args[0].data.sint) {
1354 smp_trash = get_trash_chunk();
1355 exclude_tls_grease(capture->data + capture->ec_offset, capture->ec_len, smp_trash);
1356 smp->data.u.str.area = smp_trash->area;
1357 smp->data.u.str.data = smp_trash->data;
1358 smp->flags = SMP_F_VOL_SESS;
1359 }
1360 else {
1361 smp->data.u.str.area = capture->data + capture->ec_offset;
1362 smp->data.u.str.data = capture->ec_len;
1363 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1364 }
1365
1366 smp->data.type = SMP_T_BIN;
1367 return 1;
1368}
1369
1370/* binary, returns tls client hello supported elliptic curve point formats */
1371static int
1372smp_fetch_ssl_fc_ecf_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1373{
1374 struct connection *conn;
1375 struct ssl_capture *capture;
1376 SSL *ssl;
1377
1378 conn = objt_conn(smp->sess->origin);
1379 ssl = ssl_sock_get_ssl_object(conn);
1380 if (!ssl)
1381 return 0;
1382
1383 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1384 if (!capture)
1385 return 0;
1386
1387 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1388 smp->data.type = SMP_T_BIN;
1389 smp->data.u.str.area = capture->data + capture->ec_formats_offset;
1390 smp->data.u.str.data = capture->ec_formats_len;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001391 return 1;
1392}
1393
William Lallemand7d42ef52020-07-06 11:41:30 +02001394/* Dump the SSL keylog, it only works with "tune.ssl.keylog 1" */
William Lallemand722180a2021-06-09 16:46:12 +02001395#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02001396static int smp_fetch_ssl_x_keylog(const struct arg *args, struct sample *smp, const char *kw, void *private)
1397{
1398 struct connection *conn;
1399 struct ssl_keylog *keylog;
1400 SSL *ssl;
1401 char *src = NULL;
1402 const char *sfx;
1403
1404 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1405 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1406
William Lallemandeec1d452020-07-07 10:48:13 +02001407 if (!conn)
1408 return 0;
1409
William Lallemand7d42ef52020-07-06 11:41:30 +02001410 if (conn->flags & CO_FL_WAIT_XPRT) {
1411 smp->flags |= SMP_F_MAY_CHANGE;
1412 return 0;
1413 }
1414
1415 ssl = ssl_sock_get_ssl_object(conn);
1416 if (!ssl)
1417 return 0;
1418
1419 keylog = SSL_get_ex_data(ssl, ssl_keylog_index);
1420 if (!keylog)
1421 return 0;
1422
1423 sfx = kw + strlen("ssl_xx_");
1424
1425 if (strcmp(sfx, "client_early_traffic_secret") == 0) {
1426 src = keylog->client_early_traffic_secret;
1427 } else if (strcmp(sfx, "client_handshake_traffic_secret") == 0) {
1428 src = keylog->client_handshake_traffic_secret;
1429 } else if (strcmp(sfx, "server_handshake_traffic_secret") == 0) {
1430 src = keylog->server_handshake_traffic_secret;
1431 } else if (strcmp(sfx, "client_traffic_secret_0") == 0) {
1432 src = keylog->client_traffic_secret_0;
1433 } else if (strcmp(sfx, "server_traffic_secret_0") == 0) {
1434 src = keylog->server_traffic_secret_0;
1435 } else if (strcmp(sfx, "exporter_secret") == 0) {
1436 src = keylog->exporter_secret;
1437 } else if (strcmp(sfx, "early_exporter_secret") == 0) {
1438 src = keylog->early_exporter_secret;
1439 }
1440
1441 if (!src || !*src)
1442 return 0;
1443
1444 smp->data.u.str.area = src;
1445 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001446 smp->flags |= SMP_F_VOL_TEST | SMP_F_CONST;
William Lallemand7d42ef52020-07-06 11:41:30 +02001447 smp->data.u.str.data = strlen(smp->data.u.str.area);
1448 return 1;
William Lallemand7d42ef52020-07-06 11:41:30 +02001449}
1450#endif
1451
William Lallemand15e16942020-05-15 00:25:08 +02001452static int
1453smp_fetch_ssl_fc_cl_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
1454{
Ilya Shipitsinc9dfee42020-10-31 02:10:02 +05001455#if defined(OPENSSL_IS_BORINGSSL) || defined(SSL_CTRL_GET_RAW_CIPHERLIST)
William Lallemand15e16942020-05-15 00:25:08 +02001456 struct buffer *data;
1457 int i;
1458
1459 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1460 return 0;
1461
1462 data = get_trash_chunk();
1463 for (i = 0; i + 1 < smp->data.u.str.data; i += 2) {
1464 const char *str;
1465 const SSL_CIPHER *cipher;
1466 const unsigned char *bin = (const unsigned char *) smp->data.u.str.area + i;
1467 uint16_t id = (bin[0] << 8) | bin[1];
1468#if defined(OPENSSL_IS_BORINGSSL)
1469 cipher = SSL_get_cipher_by_value(id);
1470#else
1471 struct connection *conn = __objt_conn(smp->sess->origin);
1472 SSL *ssl = ssl_sock_get_ssl_object(conn);
1473 cipher = SSL_CIPHER_find(ssl, bin);
1474#endif
1475 str = SSL_CIPHER_get_name(cipher);
1476 if (!str || strcmp(str, "(NONE)") == 0)
1477 chunk_appendf(data, "%sUNKNOWN(%04x)", i == 0 ? "" : ",", id);
1478 else
1479 chunk_appendf(data, "%s%s", i == 0 ? "" : ",", str);
1480 }
1481 smp->data.type = SMP_T_STR;
1482 smp->data.u.str = *data;
1483 return 1;
1484#else
1485 return smp_fetch_ssl_fc_cl_xxh64(args, smp, kw, private);
1486#endif
1487}
1488
1489#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1490static int
1491smp_fetch_ssl_fc_unique_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1492{
1493 struct connection *conn;
1494 int finished_len;
1495 struct buffer *finished_trash;
1496 SSL *ssl;
1497
1498 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001499 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001500 else
1501 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1502 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1503
1504 smp->flags = 0;
1505 ssl = ssl_sock_get_ssl_object(conn);
1506 if (!ssl)
1507 return 0;
1508
1509 if (conn->flags & CO_FL_WAIT_XPRT) {
1510 smp->flags |= SMP_F_MAY_CHANGE;
1511 return 0;
1512 }
1513
1514 finished_trash = get_trash_chunk();
1515 if (!SSL_session_reused(ssl))
1516 finished_len = SSL_get_peer_finished(ssl,
1517 finished_trash->area,
1518 finished_trash->size);
1519 else
1520 finished_len = SSL_get_finished(ssl,
1521 finished_trash->area,
1522 finished_trash->size);
1523
1524 if (!finished_len)
1525 return 0;
1526
1527 finished_trash->data = finished_len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001528 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001529 smp->data.u.str = *finished_trash;
1530 smp->data.type = SMP_T_BIN;
1531
1532 return 1;
1533}
1534#endif
1535
1536/* integer, returns the first verify error in CA chain of client certificate chain. */
1537static int
1538smp_fetch_ssl_c_ca_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
1539{
1540 struct connection *conn;
1541 struct ssl_sock_ctx *ctx;
1542
1543 conn = objt_conn(smp->sess->origin);
1544 if (!conn || conn->xprt != &ssl_sock)
1545 return 0;
1546 ctx = conn->xprt_ctx;
1547
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001548 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001549 smp->flags = SMP_F_MAY_CHANGE;
1550 return 0;
1551 }
1552
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001553 if (!ctx)
1554 return 0;
1555
William Lallemand15e16942020-05-15 00:25:08 +02001556 smp->data.type = SMP_T_SINT;
1557 smp->data.u.sint = (unsigned long long int)SSL_SOCK_ST_TO_CA_ERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001558 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001559
1560 return 1;
1561}
1562
1563/* integer, returns the depth of the first verify error in CA chain of client certificate chain. */
1564static int
1565smp_fetch_ssl_c_ca_err_depth(const struct arg *args, struct sample *smp, const char *kw, void *private)
1566{
1567 struct connection *conn;
1568 struct ssl_sock_ctx *ctx;
1569
1570 conn = objt_conn(smp->sess->origin);
1571 if (!conn || conn->xprt != &ssl_sock)
1572 return 0;
1573
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001574 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001575 smp->flags = SMP_F_MAY_CHANGE;
1576 return 0;
1577 }
1578 ctx = conn->xprt_ctx;
1579
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001580 if (!ctx)
1581 return 0;
1582
William Lallemand15e16942020-05-15 00:25:08 +02001583 smp->data.type = SMP_T_SINT;
1584 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CAEDEPTH(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001585 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001586
1587 return 1;
1588}
1589
1590/* integer, returns the first verify error on client certificate */
1591static int
1592smp_fetch_ssl_c_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
1593{
1594 struct connection *conn;
1595 struct ssl_sock_ctx *ctx;
1596
1597 conn = objt_conn(smp->sess->origin);
1598 if (!conn || conn->xprt != &ssl_sock)
1599 return 0;
1600
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001601 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001602 smp->flags = SMP_F_MAY_CHANGE;
1603 return 0;
1604 }
1605
1606 ctx = conn->xprt_ctx;
1607
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001608 if (!ctx)
1609 return 0;
1610
William Lallemand15e16942020-05-15 00:25:08 +02001611 smp->data.type = SMP_T_SINT;
1612 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CRTERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001613 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001614
1615 return 1;
1616}
1617
1618/* integer, returns the verify result on client cert */
1619static int
1620smp_fetch_ssl_c_verify(const struct arg *args, struct sample *smp, const char *kw, void *private)
1621{
1622 struct connection *conn;
1623 SSL *ssl;
1624
1625 conn = objt_conn(smp->sess->origin);
1626 ssl = ssl_sock_get_ssl_object(conn);
1627 if (!ssl)
1628 return 0;
1629
1630 if (conn->flags & CO_FL_WAIT_XPRT) {
1631 smp->flags = SMP_F_MAY_CHANGE;
1632 return 0;
1633 }
1634
1635 smp->data.type = SMP_T_SINT;
1636 smp->data.u.sint = (long long int)SSL_get_verify_result(ssl);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001637 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001638
1639 return 1;
1640}
1641
1642/* Argument validation functions */
1643
1644/* This function is used to validate the arguments passed to any "x_dn" ssl
1645 * keywords. These keywords support specifying a third parameter that must be
1646 * either empty or the value "rfc2253". Returns 0 on error, non-zero if OK.
1647 */
1648int val_dnfmt(struct arg *arg, char **err_msg)
1649{
1650 if (arg && arg[2].type == ARGT_STR && arg[2].data.str.data > 0 && (strcmp(arg[2].data.str.area, "rfc2253") != 0)) {
1651 memprintf(err_msg, "only rfc2253 or a blank value are currently supported as the format argument.");
1652 return 0;
1653 }
1654 return 1;
1655}
1656
1657/* Note: must not be declared <const> as its list will be overwritten.
1658 * Please take care of keeping this list alphabetically sorted.
1659 */
1660static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
1661 { "ssl_bc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
1662 { "ssl_bc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
1663#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1664 { "ssl_bc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
1665#endif
1666 { "ssl_bc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
1667#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
1668 { "ssl_bc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
1669#endif
1670 { "ssl_bc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
1671 { "ssl_bc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
1672 { "ssl_bc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
1673 { "ssl_bc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
1674#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1675 { "ssl_bc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
1676#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05001677#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02001678 { "ssl_bc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
1679 { "ssl_bc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
1680 { "ssl_bc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
1681#endif
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001682 { "ssl_bc_hsk_err", smp_fetch_ssl_fc_hsk_err, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
1683 { "ssl_bc_hsk_err_str", smp_fetch_ssl_fc_hsk_err_str, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
William Lallemand15e16942020-05-15 00:25:08 +02001684 { "ssl_c_ca_err", smp_fetch_ssl_c_ca_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1685 { "ssl_c_ca_err_depth", smp_fetch_ssl_c_ca_err_depth, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1686 { "ssl_c_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02001687 { "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 +02001688 { "ssl_c_err", smp_fetch_ssl_c_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1689 { "ssl_c_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
1690 { "ssl_c_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1691 { "ssl_c_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1692 { "ssl_c_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1693 { "ssl_c_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1694 { "ssl_c_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
1695 { "ssl_c_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1696 { "ssl_c_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1697 { "ssl_c_used", smp_fetch_ssl_c_used, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
1698 { "ssl_c_verify", smp_fetch_ssl_c_verify, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1699 { "ssl_c_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1700 { "ssl_f_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1701 { "ssl_f_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
1702 { "ssl_f_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1703 { "ssl_f_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1704 { "ssl_f_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1705 { "ssl_f_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1706 { "ssl_f_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
1707 { "ssl_f_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1708 { "ssl_f_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1709 { "ssl_f_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1710 { "ssl_fc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
1711 { "ssl_fc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1712 { "ssl_fc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1713 { "ssl_fc_has_crt", smp_fetch_ssl_fc_has_crt, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
1714 { "ssl_fc_has_early", smp_fetch_ssl_fc_has_early, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
1715 { "ssl_fc_has_sni", smp_fetch_ssl_fc_has_sni, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
1716 { "ssl_fc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
1717#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
1718 { "ssl_fc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1719#endif
1720#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1721 { "ssl_fc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1722#endif
1723 { "ssl_fc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1724#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1725 { "ssl_fc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1726#endif
1727 { "ssl_fc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1728#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1729 { "ssl_fc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1730#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05001731#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02001732 { "ssl_fc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1733 { "ssl_fc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1734 { "ssl_fc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1735#endif
William Lallemand7d42ef52020-07-06 11:41:30 +02001736
William Lallemand722180a2021-06-09 16:46:12 +02001737#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02001738 { "ssl_fc_client_early_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1739 { "ssl_fc_client_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1740 { "ssl_fc_server_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1741 { "ssl_fc_client_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1742 { "ssl_fc_server_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1743 { "ssl_fc_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1744 { "ssl_fc_early_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1745#endif
1746
William Lallemand15e16942020-05-15 00:25:08 +02001747#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1748 { "ssl_fc_sni", smp_fetch_ssl_fc_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1749#endif
Marcin Deranek959a48c2021-07-13 15:14:21 +02001750 { "ssl_fc_cipherlist_bin", smp_fetch_ssl_fc_cl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
1751 { "ssl_fc_cipherlist_hex", smp_fetch_ssl_fc_cl_hex, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_USE_L5CLI },
1752 { "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 +02001753 { "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 +02001754 { "ssl_fc_hsk_err", smp_fetch_ssl_fc_hsk_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1755 { "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 +02001756 { "ssl_fc_protocol_hello_id",smp_fetch_ssl_fc_protocol_hello_id,0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
1757 { "ssl_fc_extlist_bin", smp_fetch_ssl_fc_ext_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
1758 { "ssl_fc_eclist_bin", smp_fetch_ssl_fc_ecl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
1759 { "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 +02001760
1761/* SSL server certificate fetches */
1762 { "ssl_s_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02001763 { "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 +02001764 { "ssl_s_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1765 { "ssl_s_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1766 { "ssl_s_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1767 { "ssl_s_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
1768 { "ssl_s_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
1769 { "ssl_s_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
1770 { "ssl_s_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1771 { "ssl_s_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
1772 { "ssl_s_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
William Lallemand15e16942020-05-15 00:25:08 +02001773 { NULL, NULL, 0, 0, 0 },
1774}};
1775
1776INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
1777
1778/* Note: must not be declared <const> as its list will be overwritten.
1779 * Please take care of keeping this list alphabetically sorted.
1780 */
1781static struct acl_kw_list acl_kws = {ILH, {
1782 { "ssl_fc_sni_end", "ssl_fc_sni", PAT_MATCH_END },
1783 { "ssl_fc_sni_reg", "ssl_fc_sni", PAT_MATCH_REG },
1784 { /* END */ },
1785}};
1786
1787INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);