blob: a18d66c357a62acb51702bf63a2792b533b70df7 [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 Tarreau99ea1882021-10-06 15:37:17 +020026#include <haproxy/base64.h>
Willy Tarreau2741c8c2020-06-02 11:28:02 +020027#include <haproxy/buf-t.h>
Christopher Faulet1329f2a2021-12-16 17:32:56 +010028#include <haproxy/conn_stream.h>
Willy Tarreau8efbdfb2020-06-04 11:29:21 +020029#include <haproxy/obj_type.h>
Willy Tarreau6019fab2020-05-27 16:26:00 +020030#include <haproxy/openssl-compat.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020031#include <haproxy/sample.h>
Willy Tarreau209108d2020-06-04 20:30:20 +020032#include <haproxy/ssl_sock.h>
Willy Tarreaub2bd8652020-06-04 14:21:22 +020033#include <haproxy/ssl_utils.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020034#include <haproxy/tools.h>
Willy Tarreau99ea1882021-10-06 15:37:17 +020035#include <haproxy/vars.h>
William Lallemand15e16942020-05-15 00:25:08 +020036
William Lallemand15e16942020-05-15 00:25:08 +020037
38/***** Below are some sample fetching functions for ACL/patterns *****/
39
Willy Tarreau99ea1882021-10-06 15:37:17 +020040#if defined(HAVE_CRYPTO_memcmp)
41/* Compares bytestring with a variable containing a bytestring. Return value
42 * is `true` if both bytestrings are bytewise identical and `false` otherwise.
43 *
44 * Comparison will be performed in constant time if both bytestrings are of
45 * the same length. If the lengths differ execution time will not be constant.
46 */
47static int sample_conv_secure_memcmp(const struct arg *arg_p, struct sample *smp, void *private)
48{
49 struct sample tmp;
50 int result;
51
52 smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
53 if (arg_p[0].type != ARGT_VAR)
54 return 0;
55
56 if (!sample_conv_var2smp(&arg_p[0].data.var, &tmp, SMP_T_BIN))
57 return 0;
58
59 if (smp->data.u.str.data != tmp.data.u.str.data) {
60 smp->data.u.sint = 0;
61 smp->data.type = SMP_T_BOOL;
62 return 1;
63 }
64
65 /* The following comparison is performed in constant time. */
66 result = CRYPTO_memcmp(smp->data.u.str.area, tmp.data.u.str.area, smp->data.u.str.data);
67
68 smp->data.u.sint = result == 0;
69 smp->data.type = SMP_T_BOOL;
70 return 1;
71}
72
73/* This function checks the "secure_memcmp" converter's arguments and extracts the
74 * variable name and its scope.
75 */
76static int smp_check_secure_memcmp(struct arg *args, struct sample_conv *conv,
77 const char *file, int line, char **err)
78{
79 if (!args[0].data.str.data) {
80 memprintf(err, "missing variable name");
81 return 0;
82 }
83
84 /* Try to decode a variable. */
85 if (vars_check_arg(&args[0], NULL))
86 return 1;
87
88 memprintf(err, "failed to register variable name '%s'",
89 args[0].data.str.area);
90 return 0;
91}
92#endif // HAVE_secure_memcmp()
93
94static int smp_check_sha2(struct arg *args, struct sample_conv *conv,
95 const char *file, int line, char **err)
96{
97 if (args[0].type == ARGT_STOP)
98 return 1;
99 if (args[0].type != ARGT_SINT) {
100 memprintf(err, "Invalid type '%s'", arg_type_names[args[0].type]);
101 return 0;
102 }
103
104 switch (args[0].data.sint) {
105 case 224:
106 case 256:
107 case 384:
108 case 512:
109 /* this is okay */
110 return 1;
111 default:
112 memprintf(err, "Unsupported number of bits: '%lld'", args[0].data.sint);
113 return 0;
114 }
115}
116
117static int sample_conv_sha2(const struct arg *arg_p, struct sample *smp, void *private)
118{
119 struct buffer *trash = get_trash_chunk();
120 int bits = 256;
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100121 EVP_MD_CTX *mdctx;
122 const EVP_MD *evp = NULL;
123 unsigned int digest_length = 0;
Willy Tarreau99ea1882021-10-06 15:37:17 +0200124 if (arg_p->data.sint)
125 bits = arg_p->data.sint;
126
127 switch (bits) {
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100128 case 224:
129 evp = EVP_sha224();
Willy Tarreau99ea1882021-10-06 15:37:17 +0200130 break;
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100131 case 256:
132 evp = EVP_sha256();
Willy Tarreau99ea1882021-10-06 15:37:17 +0200133 break;
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100134 case 384:
135 evp = EVP_sha384();
Willy Tarreau99ea1882021-10-06 15:37:17 +0200136 break;
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100137 case 512:
138 evp = EVP_sha512();
Willy Tarreau99ea1882021-10-06 15:37:17 +0200139 break;
Willy Tarreau99ea1882021-10-06 15:37:17 +0200140 default:
141 return 0;
142 }
143
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100144 mdctx = EVP_MD_CTX_new();
145 if (!mdctx)
146 return 0;
147 EVP_DigestInit_ex(mdctx, evp, NULL);
148 EVP_DigestUpdate(mdctx, smp->data.u.str.area, smp->data.u.str.data);
149 EVP_DigestFinal_ex(mdctx, (unsigned char*)trash->area, &digest_length);
150 trash->data = digest_length;
151
152 EVP_MD_CTX_free(mdctx);
153
Willy Tarreau99ea1882021-10-06 15:37:17 +0200154 smp->data.u.str = *trash;
155 smp->data.type = SMP_T_BIN;
156 smp->flags &= ~SMP_F_CONST;
157 return 1;
158}
159
160/* This function checks an <arg> and fills it with a variable type if the
161 * <arg> string contains a valid variable name. If failed, the function
162 * tries to perform a base64 decode operation on the same string, and
163 * fills the <arg> with the decoded content.
164 *
165 * Validation is skipped if the <arg> string is empty.
166 *
167 * This function returns 0 if the variable lookup fails and the specified
168 * <arg> string is not a valid base64 encoded string, as well if
169 * unexpected argument type is specified or memory allocation error
170 * occurs. Otherwise it returns 1.
171 */
172static inline int sample_check_arg_base64(struct arg *arg, char **err)
173{
174 char *dec = NULL;
175 int dec_size;
176
177 if (arg->type != ARGT_STR) {
178 memprintf(err, "unexpected argument type");
179 return 0;
180 }
181
182 if (arg->data.str.data == 0) /* empty */
183 return 1;
184
185 if (vars_check_arg(arg, NULL))
186 return 1;
187
188 if (arg->data.str.data % 4) {
189 memprintf(err, "argument needs to be base64 encoded, and "
190 "can either be a string or a variable");
191 return 0;
192 }
193
194 dec_size = (arg->data.str.data / 4 * 3)
195 - (arg->data.str.area[arg->data.str.data-1] == '=' ? 1 : 0)
196 - (arg->data.str.area[arg->data.str.data-2] == '=' ? 1 : 0);
197
198 if ((dec = malloc(dec_size)) == NULL) {
199 memprintf(err, "memory allocation error");
200 return 0;
201 }
202
203 dec_size = base64dec(arg->data.str.area, arg->data.str.data, dec, dec_size);
204 if (dec_size < 0) {
205 memprintf(err, "argument needs to be base64 encoded, and "
206 "can either be a string or a variable");
207 free(dec);
208 return 0;
209 }
210
211 /* base64 decoded */
212 chunk_destroy(&arg->data.str);
213 arg->data.str.area = dec;
214 arg->data.str.data = dec_size;
215 return 1;
216}
217
218#ifdef EVP_CIPH_GCM_MODE
219static int check_aes_gcm(struct arg *args, struct sample_conv *conv,
220 const char *file, int line, char **err)
221{
222 switch(args[0].data.sint) {
223 case 128:
224 case 192:
225 case 256:
226 break;
227 default:
228 memprintf(err, "key size must be 128, 192 or 256 (bits).");
229 return 0;
230 }
231
232 /* Try to decode variables. */
233 if (!sample_check_arg_base64(&args[1], err)) {
234 memprintf(err, "failed to parse nonce : %s", *err);
235 return 0;
236 }
237 if (!sample_check_arg_base64(&args[2], err)) {
238 memprintf(err, "failed to parse key : %s", *err);
239 return 0;
240 }
241 if (!sample_check_arg_base64(&args[3], err)) {
242 memprintf(err, "failed to parse aead_tag : %s", *err);
243 return 0;
244 }
245
246 return 1;
247}
248
249/* Arguments: AES size in bits, nonce, key, tag. The last three arguments are base64 encoded */
250static int sample_conv_aes_gcm_dec(const struct arg *arg_p, struct sample *smp, void *private)
251{
252 struct sample nonce, key, aead_tag;
253 struct buffer *smp_trash = NULL, *smp_trash_alloc = NULL;
254 EVP_CIPHER_CTX *ctx;
255 int dec_size, ret;
256
257 smp_trash_alloc = alloc_trash_chunk();
258 if (!smp_trash_alloc)
259 return 0;
260
261 /* smp copy */
262 smp_trash_alloc->data = smp->data.u.str.data;
263 if (unlikely(smp_trash_alloc->data > smp_trash_alloc->size))
264 smp_trash_alloc->data = smp_trash_alloc->size;
265 memcpy(smp_trash_alloc->area, smp->data.u.str.area, smp_trash_alloc->data);
266
267 ctx = EVP_CIPHER_CTX_new();
268
269 if (!ctx)
270 goto err;
271
272 smp_trash = alloc_trash_chunk();
273 if (!smp_trash)
274 goto err;
275
276 smp_set_owner(&nonce, smp->px, smp->sess, smp->strm, smp->opt);
277 if (!sample_conv_var2smp_str(&arg_p[1], &nonce))
278 goto err;
279
280 if (arg_p[1].type == ARGT_VAR) {
281 dec_size = base64dec(nonce.data.u.str.area, nonce.data.u.str.data, smp_trash->area, smp_trash->size);
282 if (dec_size < 0)
283 goto err;
284 smp_trash->data = dec_size;
285 nonce.data.u.str = *smp_trash;
286 }
287
288 /* Set cipher type and mode */
289 switch(arg_p[0].data.sint) {
290 case 128:
291 EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);
292 break;
293 case 192:
294 EVP_DecryptInit_ex(ctx, EVP_aes_192_gcm(), NULL, NULL, NULL);
295 break;
296 case 256:
297 EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
298 break;
299 }
300
301 EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce.data.u.str.data, NULL);
302
303 /* Initialise IV */
304 if(!EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, (unsigned char *) nonce.data.u.str.area))
305 goto err;
306
307 smp_set_owner(&key, smp->px, smp->sess, smp->strm, smp->opt);
308 if (!sample_conv_var2smp_str(&arg_p[2], &key))
309 goto err;
310
311 if (arg_p[2].type == ARGT_VAR) {
312 dec_size = base64dec(key.data.u.str.area, key.data.u.str.data, smp_trash->area, smp_trash->size);
313 if (dec_size < 0)
314 goto err;
315 smp_trash->data = dec_size;
316 key.data.u.str = *smp_trash;
317 }
318
319 /* Initialise key */
320 if (!EVP_DecryptInit_ex(ctx, NULL, NULL, (unsigned char *) key.data.u.str.area, NULL))
321 goto err;
322
323 if (!EVP_DecryptUpdate(ctx, (unsigned char *) smp_trash->area, (int *) &smp_trash->data,
324 (unsigned char *) smp_trash_alloc->area, (int) smp_trash_alloc->data))
325 goto err;
326
327 smp_set_owner(&aead_tag, smp->px, smp->sess, smp->strm, smp->opt);
328 if (!sample_conv_var2smp_str(&arg_p[3], &aead_tag))
329 goto err;
330
331 if (arg_p[3].type == ARGT_VAR) {
332 dec_size = base64dec(aead_tag.data.u.str.area, aead_tag.data.u.str.data, smp_trash_alloc->area, smp_trash_alloc->size);
333 if (dec_size < 0)
334 goto err;
335 smp_trash_alloc->data = dec_size;
336 aead_tag.data.u.str = *smp_trash_alloc;
337 }
338
339 dec_size = smp_trash->data;
340
341 EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, aead_tag.data.u.str.data, (void *) aead_tag.data.u.str.area);
342 ret = EVP_DecryptFinal_ex(ctx, (unsigned char *) smp_trash->area + smp_trash->data, (int *) &smp_trash->data);
343
344 if (ret <= 0)
345 goto err;
346
347 smp->data.u.str.data = dec_size + smp_trash->data;
348 smp->data.u.str.area = smp_trash->area;
349 smp->data.type = SMP_T_BIN;
350 smp_dup(smp);
351 free_trash_chunk(smp_trash_alloc);
352 free_trash_chunk(smp_trash);
353 return 1;
354
355err:
356 free_trash_chunk(smp_trash_alloc);
357 free_trash_chunk(smp_trash);
358 return 0;
359}
360#endif
361
362static int check_crypto_digest(struct arg *args, struct sample_conv *conv,
363 const char *file, int line, char **err)
364{
365 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
366
367 if (evp)
368 return 1;
369
370 memprintf(err, "algorithm must be a valid OpenSSL message digest name.");
371 return 0;
372}
373
374static int sample_conv_crypto_digest(const struct arg *args, struct sample *smp, void *private)
375{
376 struct buffer *trash = get_trash_chunk();
377 unsigned char *md = (unsigned char*) trash->area;
378 unsigned int md_len = trash->size;
379 EVP_MD_CTX *ctx = EVP_MD_CTX_new();
380 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
381
382 if (!ctx)
383 return 0;
384
385 if (!EVP_DigestInit_ex(ctx, evp, NULL) ||
386 !EVP_DigestUpdate(ctx, smp->data.u.str.area, smp->data.u.str.data) ||
387 !EVP_DigestFinal_ex(ctx, md, &md_len)) {
388 EVP_MD_CTX_free(ctx);
389 return 0;
390 }
391
392 EVP_MD_CTX_free(ctx);
393
394 trash->data = md_len;
395 smp->data.u.str = *trash;
396 smp->data.type = SMP_T_BIN;
397 smp->flags &= ~SMP_F_CONST;
398 return 1;
399}
400
401static int check_crypto_hmac(struct arg *args, struct sample_conv *conv,
402 const char *file, int line, char **err)
403{
404 if (!check_crypto_digest(args, conv, file, line, err))
405 return 0;
406
407 if (!sample_check_arg_base64(&args[1], err)) {
408 memprintf(err, "failed to parse key : %s", *err);
409 return 0;
410 }
411
412 return 1;
413}
414
415static int sample_conv_crypto_hmac(const struct arg *args, struct sample *smp, void *private)
416{
417 struct sample key;
418 struct buffer *trash = NULL, *key_trash = NULL;
419 unsigned char *md;
420 unsigned int md_len;
421 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
422 int dec_size;
423
424 smp_set_owner(&key, smp->px, smp->sess, smp->strm, smp->opt);
425 if (!sample_conv_var2smp_str(&args[1], &key))
426 return 0;
427
428 if (args[1].type == ARGT_VAR) {
429 key_trash = alloc_trash_chunk();
430 if (!key_trash)
431 goto err;
432
433 dec_size = base64dec(key.data.u.str.area, key.data.u.str.data, key_trash->area, key_trash->size);
434 if (dec_size < 0)
435 goto err;
436 key_trash->data = dec_size;
437 key.data.u.str = *key_trash;
438 }
439
440 trash = alloc_trash_chunk();
441 if (!trash)
442 goto err;
443
444 md = (unsigned char*) trash->area;
445 md_len = trash->size;
446 if (!HMAC(evp, key.data.u.str.area, key.data.u.str.data, (const unsigned char*) smp->data.u.str.area,
447 smp->data.u.str.data, md, &md_len))
448 goto err;
449
450 free_trash_chunk(key_trash);
451
452 trash->data = md_len;
453 smp->data.u.str = *trash;
454 smp->data.type = SMP_T_BIN;
455 smp_dup(smp);
456 free_trash_chunk(trash);
457 return 1;
458
459err:
460 free_trash_chunk(key_trash);
461 free_trash_chunk(trash);
462 return 0;
463}
464
William Lallemand15e16942020-05-15 00:25:08 +0200465static int
466smp_fetch_ssl_fc_has_early(const struct arg *args, struct sample *smp, const char *kw, void *private)
467{
468 SSL *ssl;
469 struct connection *conn;
470
471 conn = objt_conn(smp->sess->origin);
472 ssl = ssl_sock_get_ssl_object(conn);
473 if (!ssl)
474 return 0;
475
476 smp->flags = 0;
477 smp->data.type = SMP_T_BOOL;
478#ifdef OPENSSL_IS_BORINGSSL
479 {
480 smp->data.u.sint = (SSL_in_early_data(ssl) &&
481 SSL_early_data_accepted(ssl));
482 }
483#else
484 smp->data.u.sint = ((conn->flags & CO_FL_EARLY_DATA) &&
485 (conn->flags & (CO_FL_EARLY_SSL_HS | CO_FL_SSL_WAIT_HS))) ? 1 : 0;
486#endif
487 return 1;
488}
489
490/* boolean, returns true if client cert was present */
491static int
492smp_fetch_ssl_fc_has_crt(const struct arg *args, struct sample *smp, const char *kw, void *private)
493{
494 struct connection *conn;
495 struct ssl_sock_ctx *ctx;
496
497 conn = objt_conn(smp->sess->origin);
498 if (!conn || conn->xprt != &ssl_sock)
499 return 0;
500
501 ctx = conn->xprt_ctx;
502
503 if (conn->flags & CO_FL_WAIT_XPRT) {
504 smp->flags |= SMP_F_MAY_CHANGE;
505 return 0;
506 }
507
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200508 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200509 smp->data.type = SMP_T_BOOL;
510 smp->data.u.sint = SSL_SOCK_ST_FL_VERIFY_DONE & ctx->xprt_st ? 1 : 0;
511
512 return 1;
513}
514
515/* binary, returns a certificate in a binary chunk (der/raw).
516 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
517 * should be use.
518 */
519static int
520smp_fetch_ssl_x_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
521{
William Lallemandbfa3e812020-06-25 20:07:18 +0200522 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
523 int conn_server = (kw[4] == 's') ? 1 : 0;
524
William Lallemand15e16942020-05-15 00:25:08 +0200525 X509 *crt = NULL;
526 int ret = 0;
527 struct buffer *smp_trash;
528 struct connection *conn;
529 SSL *ssl;
530
William Lallemandbfa3e812020-06-25 20:07:18 +0200531 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100532 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200533 else
534 conn = objt_conn(smp->sess->origin);
535
William Lallemand15e16942020-05-15 00:25:08 +0200536 ssl = ssl_sock_get_ssl_object(conn);
537 if (!ssl)
538 return 0;
539
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200540 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200541 smp->flags |= SMP_F_MAY_CHANGE;
542 return 0;
543 }
544
545 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200546 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200547 else
548 crt = SSL_get_certificate(ssl);
549
550 if (!crt)
551 goto out;
552
553 smp_trash = get_trash_chunk();
554 if (ssl_sock_crt2der(crt, smp_trash) <= 0)
555 goto out;
556
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200557 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200558 smp->data.u.str = *smp_trash;
559 smp->data.type = SMP_T_BIN;
560 ret = 1;
561out:
562 /* SSL_get_peer_certificate, it increase X509 * ref count */
563 if (cert_peer && crt)
564 X509_free(crt);
565 return ret;
566}
567
William Dauchya598b502020-08-06 18:11:38 +0200568/* binary, returns a chain certificate in a binary chunk (der/raw).
569 * The 5th keyword char is used to support only peer cert
570 */
571static int
572smp_fetch_ssl_x_chain_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
573{
574 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
575 int conn_server = (kw[4] == 's') ? 1 : 0;
576 struct buffer *smp_trash;
577 struct buffer *tmp_trash = NULL;
578 struct connection *conn;
579 STACK_OF(X509) *certs = NULL;
580 X509 *crt = NULL;
581 SSL *ssl;
582 int ret = 0;
583 int num_certs;
584 int i;
585
586 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100587 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Dauchya598b502020-08-06 18:11:38 +0200588 else
589 conn = objt_conn(smp->sess->origin);
590
591 if (!conn)
592 return 0;
593
594 ssl = ssl_sock_get_ssl_object(conn);
595 if (!ssl)
596 return 0;
597
598 if (conn->flags & CO_FL_WAIT_XPRT) {
599 smp->flags |= SMP_F_MAY_CHANGE;
600 return 0;
601 }
602
603 if (!cert_peer)
604 return 0;
605
606 certs = SSL_get_peer_cert_chain(ssl);
607 if (!certs)
608 return 0;
609
610 num_certs = sk_X509_num(certs);
611 if (!num_certs)
612 goto out;
613 smp_trash = get_trash_chunk();
614 tmp_trash = alloc_trash_chunk();
615 if (!tmp_trash)
616 goto out;
617 for (i = 0; i < num_certs; i++) {
618 crt = sk_X509_value(certs, i);
619 if (ssl_sock_crt2der(crt, tmp_trash) <= 0)
620 goto out;
621 chunk_cat(smp_trash, tmp_trash);
622 }
623
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200624 smp->flags = SMP_F_VOL_SESS;
William Dauchya598b502020-08-06 18:11:38 +0200625 smp->data.u.str = *smp_trash;
626 smp->data.type = SMP_T_BIN;
627 ret = 1;
628out:
629 if (tmp_trash)
630 free_trash_chunk(tmp_trash);
William Dauchya598b502020-08-06 18:11:38 +0200631 return ret;
632}
633
William Lallemand15e16942020-05-15 00:25:08 +0200634/* binary, returns serial of certificate in a binary chunk.
635 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
636 * should be use.
637 */
638static int
639smp_fetch_ssl_x_serial(const struct arg *args, struct sample *smp, const char *kw, void *private)
640{
William Lallemandbfa3e812020-06-25 20:07:18 +0200641 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
642 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200643 X509 *crt = NULL;
644 int ret = 0;
645 struct buffer *smp_trash;
646 struct connection *conn;
647 SSL *ssl;
648
William Lallemandbfa3e812020-06-25 20:07:18 +0200649 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100650 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200651 else
652 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +0200653 ssl = ssl_sock_get_ssl_object(conn);
654 if (!ssl)
655 return 0;
656
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200657 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200658 smp->flags |= SMP_F_MAY_CHANGE;
659 return 0;
660 }
661
662 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200663 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200664 else
665 crt = SSL_get_certificate(ssl);
666
667 if (!crt)
668 goto out;
669
670 smp_trash = get_trash_chunk();
671 if (ssl_sock_get_serial(crt, smp_trash) <= 0)
672 goto out;
673
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200674 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200675 smp->data.u.str = *smp_trash;
676 smp->data.type = SMP_T_BIN;
677 ret = 1;
678out:
679 /* SSL_get_peer_certificate, it increase X509 * ref count */
680 if (cert_peer && crt)
681 X509_free(crt);
682 return ret;
683}
684
685/* binary, returns the client certificate's SHA-1 fingerprint (SHA-1 hash of DER-encoded certificate) in a binary chunk.
686 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
687 * should be use.
688 */
689static int
690smp_fetch_ssl_x_sha1(const struct arg *args, struct sample *smp, const char *kw, void *private)
691{
William Lallemandbfa3e812020-06-25 20:07:18 +0200692 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
693 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200694 X509 *crt = NULL;
695 const EVP_MD *digest;
696 int ret = 0;
697 unsigned int len = 0;
698 struct buffer *smp_trash;
699 struct connection *conn;
700 SSL *ssl;
701
William Lallemandbfa3e812020-06-25 20:07:18 +0200702 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100703 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200704 else
705 conn = objt_conn(smp->sess->origin);
706
William Lallemand15e16942020-05-15 00:25:08 +0200707 ssl = ssl_sock_get_ssl_object(conn);
708 if (!ssl)
709 return 0;
710
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200711 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200712 smp->flags |= SMP_F_MAY_CHANGE;
713 return 0;
714 }
715
716 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200717 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200718 else
719 crt = SSL_get_certificate(ssl);
720 if (!crt)
721 goto out;
722
723 smp_trash = get_trash_chunk();
724 digest = EVP_sha1();
725 X509_digest(crt, digest, (unsigned char *) smp_trash->area, &len);
726 smp_trash->data = len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200727 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200728 smp->data.u.str = *smp_trash;
729 smp->data.type = SMP_T_BIN;
730 ret = 1;
731out:
732 /* SSL_get_peer_certificate, it increase X509 * ref count */
733 if (cert_peer && crt)
734 X509_free(crt);
735 return ret;
736}
737
738/* string, returns certificate's notafter date in ASN1_UTCTIME format.
739 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
740 * should be use.
741 */
742static int
743smp_fetch_ssl_x_notafter(const struct arg *args, struct sample *smp, const char *kw, void *private)
744{
William Lallemandbfa3e812020-06-25 20:07:18 +0200745 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
746 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200747 X509 *crt = NULL;
748 int ret = 0;
749 struct buffer *smp_trash;
750 struct connection *conn;
751 SSL *ssl;
752
William Lallemandbfa3e812020-06-25 20:07:18 +0200753 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100754 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200755 else
756 conn = objt_conn(smp->sess->origin);
757
William Lallemand15e16942020-05-15 00:25:08 +0200758 ssl = ssl_sock_get_ssl_object(conn);
759 if (!ssl)
760 return 0;
761
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200762 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200763 smp->flags |= SMP_F_MAY_CHANGE;
764 return 0;
765 }
766
767 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200768 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200769 else
770 crt = SSL_get_certificate(ssl);
771 if (!crt)
772 goto out;
773
774 smp_trash = get_trash_chunk();
775 if (ssl_sock_get_time(X509_getm_notAfter(crt), smp_trash) <= 0)
776 goto out;
777
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200778 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200779 smp->data.u.str = *smp_trash;
780 smp->data.type = SMP_T_STR;
781 ret = 1;
782out:
783 /* SSL_get_peer_certificate, it increase X509 * ref count */
784 if (cert_peer && crt)
785 X509_free(crt);
786 return ret;
787}
788
789/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's issuer
790 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
791 * should be use.
792 */
793static int
794smp_fetch_ssl_x_i_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
795{
William Lallemandbfa3e812020-06-25 20:07:18 +0200796 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
797 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200798 X509 *crt = NULL;
799 X509_NAME *name;
800 int ret = 0;
801 struct buffer *smp_trash;
802 struct connection *conn;
803 SSL *ssl;
804
William Lallemandbfa3e812020-06-25 20:07:18 +0200805 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100806 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200807 else
808 conn = objt_conn(smp->sess->origin);
809
William Lallemand15e16942020-05-15 00:25:08 +0200810 ssl = ssl_sock_get_ssl_object(conn);
811 if (!ssl)
812 return 0;
813
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200814 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200815 smp->flags |= SMP_F_MAY_CHANGE;
816 return 0;
817 }
818
819 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200820 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200821 else
822 crt = SSL_get_certificate(ssl);
823 if (!crt)
824 goto out;
825
826 name = X509_get_issuer_name(crt);
827 if (!name)
828 goto out;
829
830 smp_trash = get_trash_chunk();
Christopher Faulet3702f782021-01-29 11:30:37 +0100831 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200832 int pos = 1;
833
834 if (args[1].type == ARGT_SINT)
835 pos = args[1].data.sint;
836
837 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
838 goto out;
839 }
Christopher Faulet3702f782021-01-29 11:30:37 +0100840 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200841 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
842 goto out;
843 }
844 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
845 goto out;
846
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200847 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200848 smp->data.type = SMP_T_STR;
849 smp->data.u.str = *smp_trash;
850 ret = 1;
851out:
852 /* SSL_get_peer_certificate, it increase X509 * ref count */
853 if (cert_peer && crt)
854 X509_free(crt);
855 return ret;
856}
857
858/* string, returns notbefore date in ASN1_UTCTIME format.
859 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
860 * should be use.
861 */
862static int
863smp_fetch_ssl_x_notbefore(const struct arg *args, struct sample *smp, const char *kw, void *private)
864{
William Lallemandbfa3e812020-06-25 20:07:18 +0200865 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
866 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200867 X509 *crt = NULL;
868 int ret = 0;
869 struct buffer *smp_trash;
870 struct connection *conn;
871 SSL *ssl;
872
William Lallemandbfa3e812020-06-25 20:07:18 +0200873 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100874 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200875 else
876 conn = objt_conn(smp->sess->origin);
877
William Lallemand15e16942020-05-15 00:25:08 +0200878 ssl = ssl_sock_get_ssl_object(conn);
879 if (!ssl)
880 return 0;
881
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200882 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200883 smp->flags |= SMP_F_MAY_CHANGE;
884 return 0;
885 }
886
887 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200888 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200889 else
890 crt = SSL_get_certificate(ssl);
891 if (!crt)
892 goto out;
893
894 smp_trash = get_trash_chunk();
895 if (ssl_sock_get_time(X509_getm_notBefore(crt), smp_trash) <= 0)
896 goto out;
897
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200898 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200899 smp->data.u.str = *smp_trash;
900 smp->data.type = SMP_T_STR;
901 ret = 1;
902out:
903 /* SSL_get_peer_certificate, it increase X509 * ref count */
904 if (cert_peer && crt)
905 X509_free(crt);
906 return ret;
907}
908
909/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's subject
910 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
911 * should be use.
912 */
913static int
914smp_fetch_ssl_x_s_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
915{
William Lallemandbfa3e812020-06-25 20:07:18 +0200916 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
917 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200918 X509 *crt = NULL;
919 X509_NAME *name;
920 int ret = 0;
921 struct buffer *smp_trash;
922 struct connection *conn;
923 SSL *ssl;
924
William Lallemandbfa3e812020-06-25 20:07:18 +0200925 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100926 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200927 else
928 conn = objt_conn(smp->sess->origin);
929
William Lallemand15e16942020-05-15 00:25:08 +0200930 ssl = ssl_sock_get_ssl_object(conn);
931 if (!ssl)
932 return 0;
933
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200934 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200935 smp->flags |= SMP_F_MAY_CHANGE;
936 return 0;
937 }
938
939 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200940 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200941 else
942 crt = SSL_get_certificate(ssl);
943 if (!crt)
944 goto out;
945
946 name = X509_get_subject_name(crt);
947 if (!name)
948 goto out;
949
950 smp_trash = get_trash_chunk();
Christopher Faulet3702f782021-01-29 11:30:37 +0100951 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200952 int pos = 1;
953
954 if (args[1].type == ARGT_SINT)
955 pos = args[1].data.sint;
956
957 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
958 goto out;
959 }
Christopher Faulet3702f782021-01-29 11:30:37 +0100960 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200961 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
962 goto out;
963 }
964 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
965 goto out;
966
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200967 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200968 smp->data.type = SMP_T_STR;
969 smp->data.u.str = *smp_trash;
970 ret = 1;
971out:
972 /* SSL_get_peer_certificate, it increase X509 * ref count */
973 if (cert_peer && crt)
974 X509_free(crt);
975 return ret;
976}
977
978/* integer, returns true if current session use a client certificate */
979static int
980smp_fetch_ssl_c_used(const struct arg *args, struct sample *smp, const char *kw, void *private)
981{
982 X509 *crt;
983 struct connection *conn;
984 SSL *ssl;
985
986 conn = objt_conn(smp->sess->origin);
987 ssl = ssl_sock_get_ssl_object(conn);
988 if (!ssl)
989 return 0;
990
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200991 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200992 smp->flags |= SMP_F_MAY_CHANGE;
993 return 0;
994 }
995
996 /* SSL_get_peer_certificate returns a ptr on allocated X509 struct */
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200997 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200998 if (crt) {
999 X509_free(crt);
1000 }
1001
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001002 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001003 smp->data.type = SMP_T_BOOL;
1004 smp->data.u.sint = (crt != NULL);
1005 return 1;
1006}
1007
1008/* integer, returns the certificate version
1009 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1010 * should be use.
1011 */
1012static int
1013smp_fetch_ssl_x_version(const struct arg *args, struct sample *smp, const char *kw, void *private)
1014{
William Lallemandbfa3e812020-06-25 20:07:18 +02001015 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1016 int conn_server = (kw[4] == 's') ? 1 : 0;
1017
William Lallemand15e16942020-05-15 00:25:08 +02001018 X509 *crt;
1019 struct connection *conn;
1020 SSL *ssl;
1021
William Lallemandbfa3e812020-06-25 20:07:18 +02001022 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +01001023 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001024 else
1025 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +02001026 ssl = ssl_sock_get_ssl_object(conn);
1027 if (!ssl)
1028 return 0;
1029
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001030 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001031 smp->flags |= SMP_F_MAY_CHANGE;
1032 return 0;
1033 }
1034
1035 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001036 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001037 else
1038 crt = SSL_get_certificate(ssl);
1039 if (!crt)
1040 return 0;
1041
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001042 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001043 smp->data.u.sint = (unsigned int)(1 + X509_get_version(crt));
1044 /* SSL_get_peer_certificate increase X509 * ref count */
1045 if (cert_peer)
1046 X509_free(crt);
1047 smp->data.type = SMP_T_SINT;
1048
1049 return 1;
1050}
1051
1052/* string, returns the certificate's signature algorithm.
1053 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1054 * should be use.
1055 */
1056static int
1057smp_fetch_ssl_x_sig_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
1058{
William Lallemandbfa3e812020-06-25 20:07:18 +02001059 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1060 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +02001061 X509 *crt;
1062 __OPENSSL_110_CONST__ ASN1_OBJECT *algorithm;
1063 int nid;
1064 struct connection *conn;
1065 SSL *ssl;
1066
William Lallemandbfa3e812020-06-25 20:07:18 +02001067 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +01001068 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001069 else
1070 conn = objt_conn(smp->sess->origin);
1071
William Lallemand15e16942020-05-15 00:25:08 +02001072 ssl = ssl_sock_get_ssl_object(conn);
1073 if (!ssl)
1074 return 0;
1075
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001076 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001077 smp->flags |= SMP_F_MAY_CHANGE;
1078 return 0;
1079 }
1080
1081 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001082 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001083 else
1084 crt = SSL_get_certificate(ssl);
1085 if (!crt)
1086 return 0;
1087
1088 X509_ALGOR_get0(&algorithm, NULL, NULL, X509_get0_tbs_sigalg(crt));
1089 nid = OBJ_obj2nid(algorithm);
1090
1091 smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
1092 if (!smp->data.u.str.area) {
1093 /* SSL_get_peer_certificate increase X509 * ref count */
1094 if (cert_peer)
1095 X509_free(crt);
1096 return 0;
1097 }
1098
1099 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001100 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001101 smp->data.u.str.data = strlen(smp->data.u.str.area);
1102 /* SSL_get_peer_certificate increase X509 * ref count */
1103 if (cert_peer)
1104 X509_free(crt);
1105
1106 return 1;
1107}
1108
1109/* string, returns the certificate's key algorithm.
1110 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1111 * should be use.
1112 */
1113static int
1114smp_fetch_ssl_x_key_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
1115{
William Lallemandbfa3e812020-06-25 20:07:18 +02001116 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1117 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +02001118 X509 *crt;
1119 ASN1_OBJECT *algorithm;
1120 int nid;
1121 struct connection *conn;
1122 SSL *ssl;
1123
William Lallemandbfa3e812020-06-25 20:07:18 +02001124 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +01001125 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001126 else
1127 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +02001128 ssl = ssl_sock_get_ssl_object(conn);
1129 if (!ssl)
1130 return 0;
1131
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001132 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001133 smp->flags |= SMP_F_MAY_CHANGE;
1134 return 0;
1135 }
1136
1137 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001138 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001139 else
1140 crt = SSL_get_certificate(ssl);
1141 if (!crt)
1142 return 0;
1143
1144 X509_PUBKEY_get0_param(&algorithm, NULL, NULL, NULL, X509_get_X509_PUBKEY(crt));
1145 nid = OBJ_obj2nid(algorithm);
1146
1147 smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
1148 if (!smp->data.u.str.area) {
1149 /* SSL_get_peer_certificate increase X509 * ref count */
1150 if (cert_peer)
1151 X509_free(crt);
1152 return 0;
1153 }
1154
1155 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001156 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001157 smp->data.u.str.data = strlen(smp->data.u.str.area);
1158 if (cert_peer)
1159 X509_free(crt);
1160
1161 return 1;
1162}
1163
1164/* boolean, returns true if front conn. transport layer is SSL.
1165 * This function is also usable on backend conn if the fetch keyword 5th
1166 * char is 'b'.
1167 */
1168static int
1169smp_fetch_ssl_fc(const struct arg *args, struct sample *smp, const char *kw, void *private)
1170{
1171 struct connection *conn;
1172
1173 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001174 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001175 else
1176 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001177 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001178
1179 smp->data.type = SMP_T_BOOL;
1180 smp->data.u.sint = (conn && conn->xprt == &ssl_sock);
1181 return 1;
1182}
1183
1184/* boolean, returns true if client present a SNI */
1185static int
1186smp_fetch_ssl_fc_has_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
1187{
1188#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1189 struct connection *conn = objt_conn(smp->sess->origin);
1190 SSL *ssl = ssl_sock_get_ssl_object(conn);
1191
1192 smp->data.type = SMP_T_BOOL;
1193 smp->data.u.sint = ssl && SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name) != NULL;
1194 return 1;
1195#else
1196 return 0;
1197#endif
1198}
1199
1200/* boolean, returns true if client session has been resumed.
1201 * This function is also usable on backend conn if the fetch keyword 5th
1202 * char is 'b'.
1203 */
1204static int
1205smp_fetch_ssl_fc_is_resumed(const struct arg *args, struct sample *smp, const char *kw, void *private)
1206{
1207 struct connection *conn;
1208 SSL *ssl;
1209
1210 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001211 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001212 else
1213 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001214 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001215
1216 ssl = ssl_sock_get_ssl_object(conn);
1217
1218 smp->data.type = SMP_T_BOOL;
1219 smp->data.u.sint = ssl && SSL_session_reused(ssl);
1220 return 1;
1221}
1222
1223/* string, returns the used cipher if front conn. transport layer is SSL.
1224 * This function is also usable on backend conn if the fetch keyword 5th
1225 * char is 'b'.
1226 */
1227static int
1228smp_fetch_ssl_fc_cipher(const struct arg *args, struct sample *smp, const char *kw, void *private)
1229{
1230 struct connection *conn;
1231 SSL *ssl;
1232
1233 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001234 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001235 else
1236 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001237 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001238
1239 smp->flags = 0;
1240 ssl = ssl_sock_get_ssl_object(conn);
1241 if (!ssl)
1242 return 0;
1243
1244 smp->data.u.str.area = (char *)SSL_get_cipher_name(ssl);
1245 if (!smp->data.u.str.area)
1246 return 0;
1247
1248 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001249 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001250 smp->data.u.str.data = strlen(smp->data.u.str.area);
1251
1252 return 1;
1253}
1254
1255/* integer, returns the algoritm's keysize if front conn. transport layer
1256 * is SSL.
1257 * This function is also usable on backend conn if the fetch keyword 5th
1258 * char is 'b'.
1259 */
1260static int
1261smp_fetch_ssl_fc_alg_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
1262{
1263 struct connection *conn;
1264 SSL *ssl;
1265 int sint;
1266
1267 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001268 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001269 else
1270 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001271 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001272
1273 smp->flags = 0;
1274 ssl = ssl_sock_get_ssl_object(conn);
1275 if (!ssl)
1276 return 0;
1277
1278 if (!SSL_get_cipher_bits(ssl, &sint))
1279 return 0;
1280
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001281 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001282 smp->data.u.sint = sint;
1283 smp->data.type = SMP_T_SINT;
1284
1285 return 1;
1286}
1287
1288/* integer, returns the used keysize if front conn. transport layer is SSL.
1289 * This function is also usable on backend conn if the fetch keyword 5th
1290 * char is 'b'.
1291 */
1292static int
1293smp_fetch_ssl_fc_use_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
1294{
1295 struct connection *conn;
1296 SSL *ssl;
1297
1298 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001299 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001300 else
1301 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001302 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001303
1304 smp->flags = 0;
1305 ssl = ssl_sock_get_ssl_object(conn);
1306 if (!ssl)
1307 return 0;
1308
1309 smp->data.u.sint = (unsigned int)SSL_get_cipher_bits(ssl, NULL);
1310 if (!smp->data.u.sint)
1311 return 0;
1312
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001313 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001314 smp->data.type = SMP_T_SINT;
1315
1316 return 1;
1317}
1318
1319#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
1320static int
1321smp_fetch_ssl_fc_npn(const struct arg *args, struct sample *smp, const char *kw, void *private)
1322{
1323 struct connection *conn;
1324 SSL *ssl;
1325 unsigned int len = 0;
1326
1327 smp->flags = SMP_F_CONST;
1328 smp->data.type = SMP_T_STR;
1329
1330 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001331 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001332 else
1333 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001334 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001335
1336 ssl = ssl_sock_get_ssl_object(conn);
1337 if (!ssl)
1338 return 0;
1339
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001340 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001341 smp->data.u.str.area = NULL;
1342 SSL_get0_next_proto_negotiated(ssl,
1343 (const unsigned char **)&smp->data.u.str.area,
1344 &len);
1345
1346 if (!smp->data.u.str.area)
1347 return 0;
1348
1349 smp->data.u.str.data = len;
1350 return 1;
1351}
1352#endif
1353
1354#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1355static int
1356smp_fetch_ssl_fc_alpn(const struct arg *args, struct sample *smp, const char *kw, void *private)
1357{
1358 struct connection *conn;
1359 SSL *ssl;
1360 unsigned int len = 0;
1361
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001362 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001363 smp->data.type = SMP_T_STR;
1364
1365 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001366 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001367 else
1368 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001369 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001370
1371 ssl = ssl_sock_get_ssl_object(conn);
1372 if (!ssl)
1373 return 0;
1374
1375 smp->data.u.str.area = NULL;
1376 SSL_get0_alpn_selected(ssl,
1377 (const unsigned char **)&smp->data.u.str.area,
1378 &len);
1379
1380 if (!smp->data.u.str.area)
1381 return 0;
1382
1383 smp->data.u.str.data = len;
1384 return 1;
1385}
1386#endif
1387
1388/* string, returns the used protocol if front conn. transport layer is SSL.
1389 * This function is also usable on backend conn if the fetch keyword 5th
1390 * char is 'b'.
1391 */
1392static int
1393smp_fetch_ssl_fc_protocol(const struct arg *args, struct sample *smp, const char *kw, void *private)
1394{
1395 struct connection *conn;
1396 SSL *ssl;
1397
1398 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001399 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001400 else
1401 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001402 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001403
1404 smp->flags = 0;
1405 ssl = ssl_sock_get_ssl_object(conn);
1406 if (!ssl)
1407 return 0;
1408
1409 smp->data.u.str.area = (char *)SSL_get_version(ssl);
1410 if (!smp->data.u.str.area)
1411 return 0;
1412
1413 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001414 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001415 smp->data.u.str.data = strlen(smp->data.u.str.area);
1416
1417 return 1;
1418}
1419
1420/* binary, returns the SSL stream id if front conn. transport layer is SSL.
1421 * This function is also usable on backend conn if the fetch keyword 5th
1422 * char is 'b'.
1423 */
1424#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1425static int
1426smp_fetch_ssl_fc_session_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1427{
1428 struct connection *conn;
1429 SSL_SESSION *ssl_sess;
1430 SSL *ssl;
1431 unsigned int len = 0;
1432
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001433 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001434 smp->data.type = SMP_T_BIN;
1435
1436 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001437 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001438 else
1439 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001440 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001441
1442 ssl = ssl_sock_get_ssl_object(conn);
1443 if (!ssl)
1444 return 0;
1445
1446 ssl_sess = SSL_get_session(ssl);
1447 if (!ssl_sess)
1448 return 0;
1449
1450 smp->data.u.str.area = (char *)SSL_SESSION_get_id(ssl_sess, &len);
1451 if (!smp->data.u.str.area || !len)
1452 return 0;
1453
1454 smp->data.u.str.data = len;
1455 return 1;
1456}
1457#endif
1458
1459
Ilya Shipitsindf627942021-03-25 00:41:41 +05001460#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02001461static int
1462smp_fetch_ssl_fc_random(const struct arg *args, struct sample *smp, const char *kw, void *private)
1463{
1464 struct connection *conn;
1465 struct buffer *data;
1466 SSL *ssl;
1467
1468 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001469 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001470 else
1471 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001472 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001473
1474 ssl = ssl_sock_get_ssl_object(conn);
1475 if (!ssl)
1476 return 0;
1477
1478 data = get_trash_chunk();
1479 if (kw[7] == 'c')
1480 data->data = SSL_get_client_random(ssl,
1481 (unsigned char *) data->area,
1482 data->size);
1483 else
1484 data->data = SSL_get_server_random(ssl,
1485 (unsigned char *) data->area,
1486 data->size);
1487 if (!data->data)
1488 return 0;
1489
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001490 smp->flags = SMP_F_VOL_TEST;
William Lallemand15e16942020-05-15 00:25:08 +02001491 smp->data.type = SMP_T_BIN;
1492 smp->data.u.str = *data;
1493
1494 return 1;
1495}
1496
1497static int
1498smp_fetch_ssl_fc_session_key(const struct arg *args, struct sample *smp, const char *kw, void *private)
1499{
1500 struct connection *conn;
1501 SSL_SESSION *ssl_sess;
1502 struct buffer *data;
1503 SSL *ssl;
1504
1505 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001506 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001507 else
1508 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001509 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001510
1511 ssl = ssl_sock_get_ssl_object(conn);
1512 if (!ssl)
1513 return 0;
1514
1515 ssl_sess = SSL_get_session(ssl);
1516 if (!ssl_sess)
1517 return 0;
1518
1519 data = get_trash_chunk();
1520 data->data = SSL_SESSION_get_master_key(ssl_sess,
1521 (unsigned char *) data->area,
1522 data->size);
1523 if (!data->data)
1524 return 0;
1525
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001526 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001527 smp->data.type = SMP_T_BIN;
1528 smp->data.u.str = *data;
1529
1530 return 1;
1531}
1532#endif
1533
William Lallemand15e16942020-05-15 00:25:08 +02001534static int
1535smp_fetch_ssl_fc_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
1536{
Willy Tarreau579259d2021-11-05 19:12:54 +01001537#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
William Lallemand15e16942020-05-15 00:25:08 +02001538 struct connection *conn;
1539 SSL *ssl;
1540
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001541 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001542 smp->data.type = SMP_T_STR;
1543
1544 conn = objt_conn(smp->sess->origin);
1545 ssl = ssl_sock_get_ssl_object(conn);
1546 if (!ssl)
1547 return 0;
1548
1549 smp->data.u.str.area = (char *)SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
Remi Tricot-Le Bretona9967632022-01-07 17:12:01 +01001550 if (!smp->data.u.str.area) {
1551 /* We might have stored the SNI ourselves, look for it in the
1552 * context's ex_data.
1553 */
1554 smp->data.u.str.area = SSL_get_ex_data(ssl, ssl_client_sni_index);
1555
1556 if (!smp->data.u.str.area)
1557 return 0;
1558 }
William Lallemand15e16942020-05-15 00:25:08 +02001559
1560 smp->data.u.str.data = strlen(smp->data.u.str.area);
Remi Tricot-Le Bretona9967632022-01-07 17:12:01 +01001561
William Lallemand15e16942020-05-15 00:25:08 +02001562 return 1;
Willy Tarreau579259d2021-11-05 19:12:54 +01001563#else
1564 /* SNI not supported */
1565 return 0;
William Lallemand15e16942020-05-15 00:25:08 +02001566#endif
Willy Tarreau579259d2021-11-05 19:12:54 +01001567}
William Lallemand15e16942020-05-15 00:25:08 +02001568
Marcin Deranek959a48c2021-07-13 15:14:21 +02001569/* binary, returns tls client hello cipher list.
1570 * Arguments: filter_option (0,1)
1571 */
William Lallemand15e16942020-05-15 00:25:08 +02001572static int
1573smp_fetch_ssl_fc_cl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1574{
Marcin Deranek959a48c2021-07-13 15:14:21 +02001575 struct buffer *smp_trash;
William Lallemand15e16942020-05-15 00:25:08 +02001576 struct connection *conn;
1577 struct ssl_capture *capture;
1578 SSL *ssl;
1579
1580 conn = objt_conn(smp->sess->origin);
1581 ssl = ssl_sock_get_ssl_object(conn);
1582 if (!ssl)
1583 return 0;
1584
1585 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1586 if (!capture)
1587 return 0;
1588
Marcin Deranek959a48c2021-07-13 15:14:21 +02001589 if (args[0].data.sint) {
1590 smp_trash = get_trash_chunk();
1591 exclude_tls_grease(capture->data + capture->ciphersuite_offset, capture->ciphersuite_len, smp_trash);
1592 smp->data.u.str.area = smp_trash->area;
1593 smp->data.u.str.data = smp_trash->data;
1594 smp->flags = SMP_F_VOL_SESS;
1595 }
1596 else {
1597 smp->data.u.str.area = capture->data + capture->ciphersuite_offset;
1598 smp->data.u.str.data = capture->ciphersuite_len;
1599 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1600 }
1601
William Lallemand15e16942020-05-15 00:25:08 +02001602 smp->data.type = SMP_T_BIN;
William Lallemand15e16942020-05-15 00:25:08 +02001603 return 1;
1604}
1605
Marcin Deranek959a48c2021-07-13 15:14:21 +02001606/* binary, returns tls client hello cipher list as hexadecimal string.
1607 * Arguments: filter_option (0,1)
1608 */
William Lallemand15e16942020-05-15 00:25:08 +02001609static int
1610smp_fetch_ssl_fc_cl_hex(const struct arg *args, struct sample *smp, const char *kw, void *private)
1611{
1612 struct buffer *data;
1613
1614 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1615 return 0;
1616
1617 data = get_trash_chunk();
1618 dump_binary(data, smp->data.u.str.area, smp->data.u.str.data);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001619 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001620 smp->data.type = SMP_T_BIN;
1621 smp->data.u.str = *data;
1622 return 1;
1623}
1624
Marcin Deranek959a48c2021-07-13 15:14:21 +02001625/* integer, returns xxh64 hash of tls client hello cipher list. */
William Lallemand15e16942020-05-15 00:25:08 +02001626static int
1627smp_fetch_ssl_fc_cl_xxh64(const struct arg *args, struct sample *smp, const char *kw, void *private)
1628{
1629 struct connection *conn;
1630 struct ssl_capture *capture;
1631 SSL *ssl;
1632
1633 conn = objt_conn(smp->sess->origin);
1634 ssl = ssl_sock_get_ssl_object(conn);
1635 if (!ssl)
1636 return 0;
1637
1638 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1639 if (!capture)
1640 return 0;
1641
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001642 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001643 smp->data.type = SMP_T_SINT;
1644 smp->data.u.sint = capture->xxh64;
1645 return 1;
1646}
1647
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001648static int
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001649smp_fetch_ssl_fc_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001650{
1651 struct connection *conn;
1652 struct ssl_sock_ctx *ctx;
1653
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001654 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
1655 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
1656 else
1657 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001658 smp->strm ? cs_conn(smp->strm->csb) : NULL;
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001659
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001660 if (!conn || conn->xprt != &ssl_sock)
1661 return 0;
1662 ctx = conn->xprt_ctx;
1663
1664 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1665 smp->flags = SMP_F_MAY_CHANGE;
1666 return 0;
1667 }
1668
1669 if (!ctx)
1670 return 0;
1671
1672 smp->flags = SMP_F_VOL_SESS;
1673 smp->data.type = SMP_T_SINT;
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001674 smp->data.u.sint = ctx->error_code;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001675 return 1;
1676}
1677
1678static int
Marcin Deranek959a48c2021-07-13 15:14:21 +02001679smp_fetch_ssl_fc_protocol_hello_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1680{
1681 struct connection *conn;
1682 struct ssl_capture *capture;
1683 SSL *ssl;
1684
1685 conn = objt_conn(smp->sess->origin);
1686 ssl = ssl_sock_get_ssl_object(conn);
1687 if (!ssl)
1688 return 0;
1689
1690 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1691 if (!capture)
1692 return 0;
1693
1694 smp->flags = SMP_F_VOL_SESS;
1695 smp->data.type = SMP_T_SINT;
1696 smp->data.u.sint = capture->protocol_version;
1697 return 1;
1698}
1699
1700static int
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001701smp_fetch_ssl_fc_err_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001702{
1703 struct connection *conn;
1704 struct ssl_sock_ctx *ctx;
1705 const char *err_code_str;
1706
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001707 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
1708 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
1709 else
1710 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001711 smp->strm ? cs_conn(smp->strm->csb) : NULL;
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001712
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001713 if (!conn || conn->xprt != &ssl_sock)
1714 return 0;
1715 ctx = conn->xprt_ctx;
1716
1717 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1718 smp->flags = SMP_F_MAY_CHANGE;
1719 return 0;
1720 }
1721
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001722 if (!ctx || !ctx->error_code)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001723 return 0;
1724
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001725 err_code_str = ERR_error_string(ctx->error_code, NULL);
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001726
1727 smp->flags = SMP_F_VOL_SESS;
1728 smp->data.type = SMP_T_STR;
1729 smp->data.u.str.area = (char*)err_code_str;
1730 smp->data.u.str.data = strlen(err_code_str);
1731
Marcin Deranek959a48c2021-07-13 15:14:21 +02001732 return 1;
1733}
1734
1735/* binary, returns tls client hello extensions list.
1736 * Arguments: filter_option (0,1)
1737 */
1738static int
1739smp_fetch_ssl_fc_ext_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1740{
1741 struct buffer *smp_trash;
1742 struct connection *conn;
1743 struct ssl_capture *capture;
1744 SSL *ssl;
1745
1746 conn = objt_conn(smp->sess->origin);
1747 ssl = ssl_sock_get_ssl_object(conn);
1748 if (!ssl)
1749 return 0;
1750
1751 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1752 if (!capture)
1753 return 0;
1754
1755 if (args[0].data.sint) {
1756 smp_trash = get_trash_chunk();
1757 exclude_tls_grease(capture->data + capture->extensions_offset, capture->extensions_len, smp_trash);
1758 smp->data.u.str.area = smp_trash->area;
1759 smp->data.u.str.data = smp_trash->data;
1760 smp->flags = SMP_F_VOL_SESS;
1761 }
1762 else {
1763 smp->data.u.str.area = capture->data + capture->extensions_offset;
1764 smp->data.u.str.data = capture->extensions_len;
1765 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1766 }
1767
1768 smp->data.type = SMP_T_BIN;
1769 return 1;
1770}
1771
1772/* binary, returns tls client hello supported elliptic curves.
1773 * Arguments: filter_option (0,1)
1774 */
1775static int
1776smp_fetch_ssl_fc_ecl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1777{
1778 struct buffer *smp_trash;
1779 struct connection *conn;
1780 struct ssl_capture *capture;
1781 SSL *ssl;
1782
1783 conn = objt_conn(smp->sess->origin);
1784 ssl = ssl_sock_get_ssl_object(conn);
1785 if (!ssl)
1786 return 0;
1787
1788 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1789 if (!capture)
1790 return 0;
1791
1792 if (args[0].data.sint) {
1793 smp_trash = get_trash_chunk();
1794 exclude_tls_grease(capture->data + capture->ec_offset, capture->ec_len, smp_trash);
1795 smp->data.u.str.area = smp_trash->area;
1796 smp->data.u.str.data = smp_trash->data;
1797 smp->flags = SMP_F_VOL_SESS;
1798 }
1799 else {
1800 smp->data.u.str.area = capture->data + capture->ec_offset;
1801 smp->data.u.str.data = capture->ec_len;
1802 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1803 }
1804
1805 smp->data.type = SMP_T_BIN;
1806 return 1;
1807}
1808
1809/* binary, returns tls client hello supported elliptic curve point formats */
1810static int
1811smp_fetch_ssl_fc_ecf_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1812{
1813 struct connection *conn;
1814 struct ssl_capture *capture;
1815 SSL *ssl;
1816
1817 conn = objt_conn(smp->sess->origin);
1818 ssl = ssl_sock_get_ssl_object(conn);
1819 if (!ssl)
1820 return 0;
1821
1822 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1823 if (!capture)
1824 return 0;
1825
1826 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1827 smp->data.type = SMP_T_BIN;
1828 smp->data.u.str.area = capture->data + capture->ec_formats_offset;
1829 smp->data.u.str.data = capture->ec_formats_len;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001830 return 1;
1831}
1832
William Lallemand7d42ef52020-07-06 11:41:30 +02001833/* Dump the SSL keylog, it only works with "tune.ssl.keylog 1" */
William Lallemand722180a2021-06-09 16:46:12 +02001834#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02001835static int smp_fetch_ssl_x_keylog(const struct arg *args, struct sample *smp, const char *kw, void *private)
1836{
1837 struct connection *conn;
1838 struct ssl_keylog *keylog;
1839 SSL *ssl;
1840 char *src = NULL;
1841 const char *sfx;
1842
1843 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001844 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand7d42ef52020-07-06 11:41:30 +02001845
William Lallemandeec1d452020-07-07 10:48:13 +02001846 if (!conn)
1847 return 0;
1848
William Lallemand7d42ef52020-07-06 11:41:30 +02001849 if (conn->flags & CO_FL_WAIT_XPRT) {
1850 smp->flags |= SMP_F_MAY_CHANGE;
1851 return 0;
1852 }
1853
1854 ssl = ssl_sock_get_ssl_object(conn);
1855 if (!ssl)
1856 return 0;
1857
1858 keylog = SSL_get_ex_data(ssl, ssl_keylog_index);
1859 if (!keylog)
1860 return 0;
1861
1862 sfx = kw + strlen("ssl_xx_");
1863
1864 if (strcmp(sfx, "client_early_traffic_secret") == 0) {
1865 src = keylog->client_early_traffic_secret;
1866 } else if (strcmp(sfx, "client_handshake_traffic_secret") == 0) {
1867 src = keylog->client_handshake_traffic_secret;
1868 } else if (strcmp(sfx, "server_handshake_traffic_secret") == 0) {
1869 src = keylog->server_handshake_traffic_secret;
1870 } else if (strcmp(sfx, "client_traffic_secret_0") == 0) {
1871 src = keylog->client_traffic_secret_0;
1872 } else if (strcmp(sfx, "server_traffic_secret_0") == 0) {
1873 src = keylog->server_traffic_secret_0;
1874 } else if (strcmp(sfx, "exporter_secret") == 0) {
1875 src = keylog->exporter_secret;
1876 } else if (strcmp(sfx, "early_exporter_secret") == 0) {
1877 src = keylog->early_exporter_secret;
1878 }
1879
1880 if (!src || !*src)
1881 return 0;
1882
1883 smp->data.u.str.area = src;
1884 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001885 smp->flags |= SMP_F_VOL_TEST | SMP_F_CONST;
William Lallemand7d42ef52020-07-06 11:41:30 +02001886 smp->data.u.str.data = strlen(smp->data.u.str.area);
1887 return 1;
William Lallemand7d42ef52020-07-06 11:41:30 +02001888}
1889#endif
1890
William Lallemand15e16942020-05-15 00:25:08 +02001891static int
1892smp_fetch_ssl_fc_cl_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
1893{
Ilya Shipitsinc9dfee42020-10-31 02:10:02 +05001894#if defined(OPENSSL_IS_BORINGSSL) || defined(SSL_CTRL_GET_RAW_CIPHERLIST)
William Lallemand15e16942020-05-15 00:25:08 +02001895 struct buffer *data;
1896 int i;
1897
1898 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1899 return 0;
1900
1901 data = get_trash_chunk();
1902 for (i = 0; i + 1 < smp->data.u.str.data; i += 2) {
1903 const char *str;
1904 const SSL_CIPHER *cipher;
1905 const unsigned char *bin = (const unsigned char *) smp->data.u.str.area + i;
1906 uint16_t id = (bin[0] << 8) | bin[1];
1907#if defined(OPENSSL_IS_BORINGSSL)
1908 cipher = SSL_get_cipher_by_value(id);
1909#else
1910 struct connection *conn = __objt_conn(smp->sess->origin);
1911 SSL *ssl = ssl_sock_get_ssl_object(conn);
1912 cipher = SSL_CIPHER_find(ssl, bin);
1913#endif
1914 str = SSL_CIPHER_get_name(cipher);
1915 if (!str || strcmp(str, "(NONE)") == 0)
1916 chunk_appendf(data, "%sUNKNOWN(%04x)", i == 0 ? "" : ",", id);
1917 else
1918 chunk_appendf(data, "%s%s", i == 0 ? "" : ",", str);
1919 }
1920 smp->data.type = SMP_T_STR;
1921 smp->data.u.str = *data;
1922 return 1;
1923#else
1924 return smp_fetch_ssl_fc_cl_xxh64(args, smp, kw, private);
1925#endif
1926}
1927
1928#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1929static int
1930smp_fetch_ssl_fc_unique_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1931{
1932 struct connection *conn;
1933 int finished_len;
1934 struct buffer *finished_trash;
1935 SSL *ssl;
1936
1937 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001938 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001939 else
1940 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001941 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001942
1943 smp->flags = 0;
1944 ssl = ssl_sock_get_ssl_object(conn);
1945 if (!ssl)
1946 return 0;
1947
1948 if (conn->flags & CO_FL_WAIT_XPRT) {
1949 smp->flags |= SMP_F_MAY_CHANGE;
1950 return 0;
1951 }
1952
1953 finished_trash = get_trash_chunk();
1954 if (!SSL_session_reused(ssl))
1955 finished_len = SSL_get_peer_finished(ssl,
1956 finished_trash->area,
1957 finished_trash->size);
1958 else
1959 finished_len = SSL_get_finished(ssl,
1960 finished_trash->area,
1961 finished_trash->size);
1962
1963 if (!finished_len)
1964 return 0;
1965
1966 finished_trash->data = finished_len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001967 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001968 smp->data.u.str = *finished_trash;
1969 smp->data.type = SMP_T_BIN;
1970
1971 return 1;
1972}
1973#endif
1974
1975/* integer, returns the first verify error in CA chain of client certificate chain. */
1976static int
1977smp_fetch_ssl_c_ca_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
1978{
1979 struct connection *conn;
1980 struct ssl_sock_ctx *ctx;
1981
1982 conn = objt_conn(smp->sess->origin);
1983 if (!conn || conn->xprt != &ssl_sock)
1984 return 0;
1985 ctx = conn->xprt_ctx;
1986
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001987 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001988 smp->flags = SMP_F_MAY_CHANGE;
1989 return 0;
1990 }
1991
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001992 if (!ctx)
1993 return 0;
1994
William Lallemand15e16942020-05-15 00:25:08 +02001995 smp->data.type = SMP_T_SINT;
1996 smp->data.u.sint = (unsigned long long int)SSL_SOCK_ST_TO_CA_ERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001997 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001998
1999 return 1;
2000}
2001
2002/* integer, returns the depth of the first verify error in CA chain of client certificate chain. */
2003static int
2004smp_fetch_ssl_c_ca_err_depth(const struct arg *args, struct sample *smp, const char *kw, void *private)
2005{
2006 struct connection *conn;
2007 struct ssl_sock_ctx *ctx;
2008
2009 conn = objt_conn(smp->sess->origin);
2010 if (!conn || conn->xprt != &ssl_sock)
2011 return 0;
2012
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002013 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02002014 smp->flags = SMP_F_MAY_CHANGE;
2015 return 0;
2016 }
2017 ctx = conn->xprt_ctx;
2018
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002019 if (!ctx)
2020 return 0;
2021
William Lallemand15e16942020-05-15 00:25:08 +02002022 smp->data.type = SMP_T_SINT;
2023 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CAEDEPTH(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002024 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002025
2026 return 1;
2027}
2028
2029/* integer, returns the first verify error on client certificate */
2030static int
2031smp_fetch_ssl_c_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
2032{
2033 struct connection *conn;
2034 struct ssl_sock_ctx *ctx;
2035
2036 conn = objt_conn(smp->sess->origin);
2037 if (!conn || conn->xprt != &ssl_sock)
2038 return 0;
2039
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002040 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02002041 smp->flags = SMP_F_MAY_CHANGE;
2042 return 0;
2043 }
2044
2045 ctx = conn->xprt_ctx;
2046
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002047 if (!ctx)
2048 return 0;
2049
William Lallemand15e16942020-05-15 00:25:08 +02002050 smp->data.type = SMP_T_SINT;
2051 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CRTERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002052 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002053
2054 return 1;
2055}
2056
2057/* integer, returns the verify result on client cert */
2058static int
2059smp_fetch_ssl_c_verify(const struct arg *args, struct sample *smp, const char *kw, void *private)
2060{
2061 struct connection *conn;
2062 SSL *ssl;
2063
2064 conn = objt_conn(smp->sess->origin);
2065 ssl = ssl_sock_get_ssl_object(conn);
2066 if (!ssl)
2067 return 0;
2068
2069 if (conn->flags & CO_FL_WAIT_XPRT) {
2070 smp->flags = SMP_F_MAY_CHANGE;
2071 return 0;
2072 }
2073
2074 smp->data.type = SMP_T_SINT;
2075 smp->data.u.sint = (long long int)SSL_get_verify_result(ssl);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002076 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002077
2078 return 1;
2079}
2080
2081/* Argument validation functions */
2082
2083/* This function is used to validate the arguments passed to any "x_dn" ssl
2084 * keywords. These keywords support specifying a third parameter that must be
2085 * either empty or the value "rfc2253". Returns 0 on error, non-zero if OK.
2086 */
2087int val_dnfmt(struct arg *arg, char **err_msg)
2088{
2089 if (arg && arg[2].type == ARGT_STR && arg[2].data.str.data > 0 && (strcmp(arg[2].data.str.area, "rfc2253") != 0)) {
2090 memprintf(err_msg, "only rfc2253 or a blank value are currently supported as the format argument.");
2091 return 0;
2092 }
2093 return 1;
2094}
2095
2096/* Note: must not be declared <const> as its list will be overwritten.
2097 * Please take care of keeping this list alphabetically sorted.
2098 */
2099static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
2100 { "ssl_bc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
2101 { "ssl_bc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2102#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2103 { "ssl_bc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2104#endif
2105 { "ssl_bc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2106#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2107 { "ssl_bc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2108#endif
2109 { "ssl_bc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
2110 { "ssl_bc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2111 { "ssl_bc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2112 { "ssl_bc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2113#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2114 { "ssl_bc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2115#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05002116#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02002117 { "ssl_bc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2118 { "ssl_bc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2119 { "ssl_bc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2120#endif
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02002121 { "ssl_bc_err", smp_fetch_ssl_fc_err, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2122 { "ssl_bc_err_str", smp_fetch_ssl_fc_err_str, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
William Lallemand15e16942020-05-15 00:25:08 +02002123 { "ssl_c_ca_err", smp_fetch_ssl_c_ca_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2124 { "ssl_c_ca_err_depth", smp_fetch_ssl_c_ca_err_depth, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2125 { "ssl_c_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02002126 { "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 +02002127 { "ssl_c_err", smp_fetch_ssl_c_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2128 { "ssl_c_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2129 { "ssl_c_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2130 { "ssl_c_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2131 { "ssl_c_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2132 { "ssl_c_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2133 { "ssl_c_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2134 { "ssl_c_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2135 { "ssl_c_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2136 { "ssl_c_used", smp_fetch_ssl_c_used, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2137 { "ssl_c_verify", smp_fetch_ssl_c_verify, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2138 { "ssl_c_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2139 { "ssl_f_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2140 { "ssl_f_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2141 { "ssl_f_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2142 { "ssl_f_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2143 { "ssl_f_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2144 { "ssl_f_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2145 { "ssl_f_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2146 { "ssl_f_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2147 { "ssl_f_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2148 { "ssl_f_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2149 { "ssl_fc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2150 { "ssl_fc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2151 { "ssl_fc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2152 { "ssl_fc_has_crt", smp_fetch_ssl_fc_has_crt, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2153 { "ssl_fc_has_early", smp_fetch_ssl_fc_has_early, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2154 { "ssl_fc_has_sni", smp_fetch_ssl_fc_has_sni, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2155 { "ssl_fc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2156#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2157 { "ssl_fc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2158#endif
2159#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2160 { "ssl_fc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2161#endif
2162 { "ssl_fc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2163#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2164 { "ssl_fc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2165#endif
2166 { "ssl_fc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2167#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2168 { "ssl_fc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2169#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05002170#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02002171 { "ssl_fc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2172 { "ssl_fc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2173 { "ssl_fc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2174#endif
William Lallemand7d42ef52020-07-06 11:41:30 +02002175
William Lallemand722180a2021-06-09 16:46:12 +02002176#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02002177 { "ssl_fc_client_early_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2178 { "ssl_fc_client_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2179 { "ssl_fc_server_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2180 { "ssl_fc_client_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2181 { "ssl_fc_server_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2182 { "ssl_fc_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2183 { "ssl_fc_early_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2184#endif
2185
William Lallemand15e16942020-05-15 00:25:08 +02002186 { "ssl_fc_sni", smp_fetch_ssl_fc_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
Marcin Deranek959a48c2021-07-13 15:14:21 +02002187 { "ssl_fc_cipherlist_bin", smp_fetch_ssl_fc_cl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2188 { "ssl_fc_cipherlist_hex", smp_fetch_ssl_fc_cl_hex, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_USE_L5CLI },
2189 { "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 +02002190 { "ssl_fc_cipherlist_xxh", smp_fetch_ssl_fc_cl_xxh64, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02002191 { "ssl_fc_err", smp_fetch_ssl_fc_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2192 { "ssl_fc_err_str", smp_fetch_ssl_fc_err_str, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
Marcin Deranek959a48c2021-07-13 15:14:21 +02002193 { "ssl_fc_protocol_hello_id",smp_fetch_ssl_fc_protocol_hello_id,0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2194 { "ssl_fc_extlist_bin", smp_fetch_ssl_fc_ext_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2195 { "ssl_fc_eclist_bin", smp_fetch_ssl_fc_ecl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2196 { "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 +02002197
2198/* SSL server certificate fetches */
2199 { "ssl_s_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02002200 { "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 +02002201 { "ssl_s_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2202 { "ssl_s_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2203 { "ssl_s_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2204 { "ssl_s_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2205 { "ssl_s_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2206 { "ssl_s_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2207 { "ssl_s_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2208 { "ssl_s_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2209 { "ssl_s_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
William Lallemand15e16942020-05-15 00:25:08 +02002210 { NULL, NULL, 0, 0, 0 },
2211}};
2212
2213INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
2214
Willy Tarreau99ea1882021-10-06 15:37:17 +02002215/* Note: must not be declared <const> as its list will be overwritten */
2216static struct sample_conv_kw_list sample_conv_kws = {ILH, {
2217 { "sha2", sample_conv_sha2, ARG1(0, SINT), smp_check_sha2, SMP_T_BIN, SMP_T_BIN },
2218#ifdef EVP_CIPH_GCM_MODE
2219 { "aes_gcm_dec", sample_conv_aes_gcm_dec, ARG4(4,SINT,STR,STR,STR), check_aes_gcm, SMP_T_BIN, SMP_T_BIN },
2220#endif
2221 { "digest", sample_conv_crypto_digest, ARG1(1,STR), check_crypto_digest, SMP_T_BIN, SMP_T_BIN },
2222 { "hmac", sample_conv_crypto_hmac, ARG2(2,STR,STR), check_crypto_hmac, SMP_T_BIN, SMP_T_BIN },
2223#if defined(HAVE_CRYPTO_memcmp)
2224 { "secure_memcmp", sample_conv_secure_memcmp, ARG1(1,STR), smp_check_secure_memcmp, SMP_T_BIN, SMP_T_BOOL },
2225#endif
2226 { NULL, NULL, 0, 0, 0 },
2227}};
2228
2229INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
2230
2231
William Lallemand15e16942020-05-15 00:25:08 +02002232/* Note: must not be declared <const> as its list will be overwritten.
2233 * Please take care of keeping this list alphabetically sorted.
2234 */
2235static struct acl_kw_list acl_kws = {ILH, {
2236 { "ssl_fc_sni_end", "ssl_fc_sni", PAT_MATCH_END },
2237 { "ssl_fc_sni_reg", "ssl_fc_sni", PAT_MATCH_REG },
2238 { /* END */ },
2239}};
2240
2241INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);