blob: 191c54a40fde43d0f0de9233e63e36262f362b59 [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>
Willy Tarreau8efbdfb2020-06-04 11:29:21 +020028#include <haproxy/obj_type.h>
Willy Tarreau6019fab2020-05-27 16:26:00 +020029#include <haproxy/openssl-compat.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020030#include <haproxy/sample.h>
Willy Tarreau209108d2020-06-04 20:30:20 +020031#include <haproxy/ssl_sock.h>
Willy Tarreaub2bd8652020-06-04 14:21:22 +020032#include <haproxy/ssl_utils.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020033#include <haproxy/tools.h>
Willy Tarreau99ea1882021-10-06 15:37:17 +020034#include <haproxy/vars.h>
William Lallemand15e16942020-05-15 00:25:08 +020035
William Lallemand15e16942020-05-15 00:25:08 +020036
37/***** Below are some sample fetching functions for ACL/patterns *****/
38
Willy Tarreau99ea1882021-10-06 15:37:17 +020039#if defined(HAVE_CRYPTO_memcmp)
40/* Compares bytestring with a variable containing a bytestring. Return value
41 * is `true` if both bytestrings are bytewise identical and `false` otherwise.
42 *
43 * Comparison will be performed in constant time if both bytestrings are of
44 * the same length. If the lengths differ execution time will not be constant.
45 */
46static int sample_conv_secure_memcmp(const struct arg *arg_p, struct sample *smp, void *private)
47{
48 struct sample tmp;
49 int result;
50
51 smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
52 if (arg_p[0].type != ARGT_VAR)
53 return 0;
54
55 if (!sample_conv_var2smp(&arg_p[0].data.var, &tmp, SMP_T_BIN))
56 return 0;
57
58 if (smp->data.u.str.data != tmp.data.u.str.data) {
59 smp->data.u.sint = 0;
60 smp->data.type = SMP_T_BOOL;
61 return 1;
62 }
63
64 /* The following comparison is performed in constant time. */
65 result = CRYPTO_memcmp(smp->data.u.str.area, tmp.data.u.str.area, smp->data.u.str.data);
66
67 smp->data.u.sint = result == 0;
68 smp->data.type = SMP_T_BOOL;
69 return 1;
70}
71
72/* This function checks the "secure_memcmp" converter's arguments and extracts the
73 * variable name and its scope.
74 */
75static int smp_check_secure_memcmp(struct arg *args, struct sample_conv *conv,
76 const char *file, int line, char **err)
77{
78 if (!args[0].data.str.data) {
79 memprintf(err, "missing variable name");
80 return 0;
81 }
82
83 /* Try to decode a variable. */
84 if (vars_check_arg(&args[0], NULL))
85 return 1;
86
87 memprintf(err, "failed to register variable name '%s'",
88 args[0].data.str.area);
89 return 0;
90}
91#endif // HAVE_secure_memcmp()
92
93static int smp_check_sha2(struct arg *args, struct sample_conv *conv,
94 const char *file, int line, char **err)
95{
96 if (args[0].type == ARGT_STOP)
97 return 1;
98 if (args[0].type != ARGT_SINT) {
99 memprintf(err, "Invalid type '%s'", arg_type_names[args[0].type]);
100 return 0;
101 }
102
103 switch (args[0].data.sint) {
104 case 224:
105 case 256:
106 case 384:
107 case 512:
108 /* this is okay */
109 return 1;
110 default:
111 memprintf(err, "Unsupported number of bits: '%lld'", args[0].data.sint);
112 return 0;
113 }
114}
115
116static int sample_conv_sha2(const struct arg *arg_p, struct sample *smp, void *private)
117{
118 struct buffer *trash = get_trash_chunk();
119 int bits = 256;
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100120 EVP_MD_CTX *mdctx;
121 const EVP_MD *evp = NULL;
122 unsigned int digest_length = 0;
Willy Tarreau99ea1882021-10-06 15:37:17 +0200123 if (arg_p->data.sint)
124 bits = arg_p->data.sint;
125
126 switch (bits) {
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100127 case 224:
128 evp = EVP_sha224();
Willy Tarreau99ea1882021-10-06 15:37:17 +0200129 break;
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100130 case 256:
131 evp = EVP_sha256();
Willy Tarreau99ea1882021-10-06 15:37:17 +0200132 break;
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100133 case 384:
134 evp = EVP_sha384();
Willy Tarreau99ea1882021-10-06 15:37:17 +0200135 break;
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100136 case 512:
137 evp = EVP_sha512();
Willy Tarreau99ea1882021-10-06 15:37:17 +0200138 break;
Willy Tarreau99ea1882021-10-06 15:37:17 +0200139 default:
140 return 0;
141 }
142
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100143 mdctx = EVP_MD_CTX_new();
144 if (!mdctx)
145 return 0;
146 EVP_DigestInit_ex(mdctx, evp, NULL);
147 EVP_DigestUpdate(mdctx, smp->data.u.str.area, smp->data.u.str.data);
148 EVP_DigestFinal_ex(mdctx, (unsigned char*)trash->area, &digest_length);
149 trash->data = digest_length;
150
151 EVP_MD_CTX_free(mdctx);
152
Willy Tarreau99ea1882021-10-06 15:37:17 +0200153 smp->data.u.str = *trash;
154 smp->data.type = SMP_T_BIN;
155 smp->flags &= ~SMP_F_CONST;
156 return 1;
157}
158
159/* This function checks an <arg> and fills it with a variable type if the
160 * <arg> string contains a valid variable name. If failed, the function
161 * tries to perform a base64 decode operation on the same string, and
162 * fills the <arg> with the decoded content.
163 *
164 * Validation is skipped if the <arg> string is empty.
165 *
166 * This function returns 0 if the variable lookup fails and the specified
167 * <arg> string is not a valid base64 encoded string, as well if
168 * unexpected argument type is specified or memory allocation error
169 * occurs. Otherwise it returns 1.
170 */
171static inline int sample_check_arg_base64(struct arg *arg, char **err)
172{
173 char *dec = NULL;
174 int dec_size;
175
176 if (arg->type != ARGT_STR) {
177 memprintf(err, "unexpected argument type");
178 return 0;
179 }
180
181 if (arg->data.str.data == 0) /* empty */
182 return 1;
183
184 if (vars_check_arg(arg, NULL))
185 return 1;
186
187 if (arg->data.str.data % 4) {
188 memprintf(err, "argument needs to be base64 encoded, and "
189 "can either be a string or a variable");
190 return 0;
191 }
192
193 dec_size = (arg->data.str.data / 4 * 3)
194 - (arg->data.str.area[arg->data.str.data-1] == '=' ? 1 : 0)
195 - (arg->data.str.area[arg->data.str.data-2] == '=' ? 1 : 0);
196
197 if ((dec = malloc(dec_size)) == NULL) {
198 memprintf(err, "memory allocation error");
199 return 0;
200 }
201
202 dec_size = base64dec(arg->data.str.area, arg->data.str.data, dec, dec_size);
203 if (dec_size < 0) {
204 memprintf(err, "argument needs to be base64 encoded, and "
205 "can either be a string or a variable");
206 free(dec);
207 return 0;
208 }
209
210 /* base64 decoded */
211 chunk_destroy(&arg->data.str);
212 arg->data.str.area = dec;
213 arg->data.str.data = dec_size;
214 return 1;
215}
216
217#ifdef EVP_CIPH_GCM_MODE
218static int check_aes_gcm(struct arg *args, struct sample_conv *conv,
219 const char *file, int line, char **err)
220{
221 switch(args[0].data.sint) {
222 case 128:
223 case 192:
224 case 256:
225 break;
226 default:
227 memprintf(err, "key size must be 128, 192 or 256 (bits).");
228 return 0;
229 }
230
231 /* Try to decode variables. */
232 if (!sample_check_arg_base64(&args[1], err)) {
233 memprintf(err, "failed to parse nonce : %s", *err);
234 return 0;
235 }
236 if (!sample_check_arg_base64(&args[2], err)) {
237 memprintf(err, "failed to parse key : %s", *err);
238 return 0;
239 }
240 if (!sample_check_arg_base64(&args[3], err)) {
241 memprintf(err, "failed to parse aead_tag : %s", *err);
242 return 0;
243 }
244
245 return 1;
246}
247
248/* Arguments: AES size in bits, nonce, key, tag. The last three arguments are base64 encoded */
249static int sample_conv_aes_gcm_dec(const struct arg *arg_p, struct sample *smp, void *private)
250{
251 struct sample nonce, key, aead_tag;
252 struct buffer *smp_trash = NULL, *smp_trash_alloc = NULL;
253 EVP_CIPHER_CTX *ctx;
254 int dec_size, ret;
255
256 smp_trash_alloc = alloc_trash_chunk();
257 if (!smp_trash_alloc)
258 return 0;
259
260 /* smp copy */
261 smp_trash_alloc->data = smp->data.u.str.data;
262 if (unlikely(smp_trash_alloc->data > smp_trash_alloc->size))
263 smp_trash_alloc->data = smp_trash_alloc->size;
264 memcpy(smp_trash_alloc->area, smp->data.u.str.area, smp_trash_alloc->data);
265
266 ctx = EVP_CIPHER_CTX_new();
267
268 if (!ctx)
269 goto err;
270
271 smp_trash = alloc_trash_chunk();
272 if (!smp_trash)
273 goto err;
274
275 smp_set_owner(&nonce, smp->px, smp->sess, smp->strm, smp->opt);
276 if (!sample_conv_var2smp_str(&arg_p[1], &nonce))
277 goto err;
278
279 if (arg_p[1].type == ARGT_VAR) {
280 dec_size = base64dec(nonce.data.u.str.area, nonce.data.u.str.data, smp_trash->area, smp_trash->size);
281 if (dec_size < 0)
282 goto err;
283 smp_trash->data = dec_size;
284 nonce.data.u.str = *smp_trash;
285 }
286
287 /* Set cipher type and mode */
288 switch(arg_p[0].data.sint) {
289 case 128:
290 EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);
291 break;
292 case 192:
293 EVP_DecryptInit_ex(ctx, EVP_aes_192_gcm(), NULL, NULL, NULL);
294 break;
295 case 256:
296 EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
297 break;
298 }
299
300 EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce.data.u.str.data, NULL);
301
302 /* Initialise IV */
303 if(!EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, (unsigned char *) nonce.data.u.str.area))
304 goto err;
305
306 smp_set_owner(&key, smp->px, smp->sess, smp->strm, smp->opt);
307 if (!sample_conv_var2smp_str(&arg_p[2], &key))
308 goto err;
309
310 if (arg_p[2].type == ARGT_VAR) {
311 dec_size = base64dec(key.data.u.str.area, key.data.u.str.data, smp_trash->area, smp_trash->size);
312 if (dec_size < 0)
313 goto err;
314 smp_trash->data = dec_size;
315 key.data.u.str = *smp_trash;
316 }
317
318 /* Initialise key */
319 if (!EVP_DecryptInit_ex(ctx, NULL, NULL, (unsigned char *) key.data.u.str.area, NULL))
320 goto err;
321
322 if (!EVP_DecryptUpdate(ctx, (unsigned char *) smp_trash->area, (int *) &smp_trash->data,
323 (unsigned char *) smp_trash_alloc->area, (int) smp_trash_alloc->data))
324 goto err;
325
326 smp_set_owner(&aead_tag, smp->px, smp->sess, smp->strm, smp->opt);
327 if (!sample_conv_var2smp_str(&arg_p[3], &aead_tag))
328 goto err;
329
330 if (arg_p[3].type == ARGT_VAR) {
331 dec_size = base64dec(aead_tag.data.u.str.area, aead_tag.data.u.str.data, smp_trash_alloc->area, smp_trash_alloc->size);
332 if (dec_size < 0)
333 goto err;
334 smp_trash_alloc->data = dec_size;
335 aead_tag.data.u.str = *smp_trash_alloc;
336 }
337
338 dec_size = smp_trash->data;
339
340 EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, aead_tag.data.u.str.data, (void *) aead_tag.data.u.str.area);
341 ret = EVP_DecryptFinal_ex(ctx, (unsigned char *) smp_trash->area + smp_trash->data, (int *) &smp_trash->data);
342
343 if (ret <= 0)
344 goto err;
345
346 smp->data.u.str.data = dec_size + smp_trash->data;
347 smp->data.u.str.area = smp_trash->area;
348 smp->data.type = SMP_T_BIN;
349 smp_dup(smp);
350 free_trash_chunk(smp_trash_alloc);
351 free_trash_chunk(smp_trash);
352 return 1;
353
354err:
355 free_trash_chunk(smp_trash_alloc);
356 free_trash_chunk(smp_trash);
357 return 0;
358}
359#endif
360
361static int check_crypto_digest(struct arg *args, struct sample_conv *conv,
362 const char *file, int line, char **err)
363{
364 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
365
366 if (evp)
367 return 1;
368
369 memprintf(err, "algorithm must be a valid OpenSSL message digest name.");
370 return 0;
371}
372
373static int sample_conv_crypto_digest(const struct arg *args, struct sample *smp, void *private)
374{
375 struct buffer *trash = get_trash_chunk();
376 unsigned char *md = (unsigned char*) trash->area;
377 unsigned int md_len = trash->size;
378 EVP_MD_CTX *ctx = EVP_MD_CTX_new();
379 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
380
381 if (!ctx)
382 return 0;
383
384 if (!EVP_DigestInit_ex(ctx, evp, NULL) ||
385 !EVP_DigestUpdate(ctx, smp->data.u.str.area, smp->data.u.str.data) ||
386 !EVP_DigestFinal_ex(ctx, md, &md_len)) {
387 EVP_MD_CTX_free(ctx);
388 return 0;
389 }
390
391 EVP_MD_CTX_free(ctx);
392
393 trash->data = md_len;
394 smp->data.u.str = *trash;
395 smp->data.type = SMP_T_BIN;
396 smp->flags &= ~SMP_F_CONST;
397 return 1;
398}
399
400static int check_crypto_hmac(struct arg *args, struct sample_conv *conv,
401 const char *file, int line, char **err)
402{
403 if (!check_crypto_digest(args, conv, file, line, err))
404 return 0;
405
406 if (!sample_check_arg_base64(&args[1], err)) {
407 memprintf(err, "failed to parse key : %s", *err);
408 return 0;
409 }
410
411 return 1;
412}
413
414static int sample_conv_crypto_hmac(const struct arg *args, struct sample *smp, void *private)
415{
416 struct sample key;
417 struct buffer *trash = NULL, *key_trash = NULL;
418 unsigned char *md;
419 unsigned int md_len;
420 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
421 int dec_size;
422
423 smp_set_owner(&key, smp->px, smp->sess, smp->strm, smp->opt);
424 if (!sample_conv_var2smp_str(&args[1], &key))
425 return 0;
426
427 if (args[1].type == ARGT_VAR) {
428 key_trash = alloc_trash_chunk();
429 if (!key_trash)
430 goto err;
431
432 dec_size = base64dec(key.data.u.str.area, key.data.u.str.data, key_trash->area, key_trash->size);
433 if (dec_size < 0)
434 goto err;
435 key_trash->data = dec_size;
436 key.data.u.str = *key_trash;
437 }
438
439 trash = alloc_trash_chunk();
440 if (!trash)
441 goto err;
442
443 md = (unsigned char*) trash->area;
444 md_len = trash->size;
445 if (!HMAC(evp, key.data.u.str.area, key.data.u.str.data, (const unsigned char*) smp->data.u.str.area,
446 smp->data.u.str.data, md, &md_len))
447 goto err;
448
449 free_trash_chunk(key_trash);
450
451 trash->data = md_len;
452 smp->data.u.str = *trash;
453 smp->data.type = SMP_T_BIN;
454 smp_dup(smp);
455 free_trash_chunk(trash);
456 return 1;
457
458err:
459 free_trash_chunk(key_trash);
460 free_trash_chunk(trash);
461 return 0;
462}
463
William Lallemand15e16942020-05-15 00:25:08 +0200464static int
465smp_fetch_ssl_fc_has_early(const struct arg *args, struct sample *smp, const char *kw, void *private)
466{
467 SSL *ssl;
468 struct connection *conn;
469
470 conn = objt_conn(smp->sess->origin);
471 ssl = ssl_sock_get_ssl_object(conn);
472 if (!ssl)
473 return 0;
474
475 smp->flags = 0;
476 smp->data.type = SMP_T_BOOL;
477#ifdef OPENSSL_IS_BORINGSSL
478 {
479 smp->data.u.sint = (SSL_in_early_data(ssl) &&
480 SSL_early_data_accepted(ssl));
481 }
482#else
483 smp->data.u.sint = ((conn->flags & CO_FL_EARLY_DATA) &&
484 (conn->flags & (CO_FL_EARLY_SSL_HS | CO_FL_SSL_WAIT_HS))) ? 1 : 0;
485#endif
486 return 1;
487}
488
489/* boolean, returns true if client cert was present */
490static int
491smp_fetch_ssl_fc_has_crt(const struct arg *args, struct sample *smp, const char *kw, void *private)
492{
493 struct connection *conn;
494 struct ssl_sock_ctx *ctx;
495
496 conn = objt_conn(smp->sess->origin);
497 if (!conn || conn->xprt != &ssl_sock)
498 return 0;
499
500 ctx = conn->xprt_ctx;
501
502 if (conn->flags & CO_FL_WAIT_XPRT) {
503 smp->flags |= SMP_F_MAY_CHANGE;
504 return 0;
505 }
506
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200507 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200508 smp->data.type = SMP_T_BOOL;
509 smp->data.u.sint = SSL_SOCK_ST_FL_VERIFY_DONE & ctx->xprt_st ? 1 : 0;
510
511 return 1;
512}
513
514/* binary, returns a certificate in a binary chunk (der/raw).
515 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
516 * should be use.
517 */
518static int
519smp_fetch_ssl_x_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
520{
William Lallemandbfa3e812020-06-25 20:07:18 +0200521 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
522 int conn_server = (kw[4] == 's') ? 1 : 0;
523
William Lallemand15e16942020-05-15 00:25:08 +0200524 X509 *crt = NULL;
525 int ret = 0;
526 struct buffer *smp_trash;
527 struct connection *conn;
528 SSL *ssl;
529
William Lallemandbfa3e812020-06-25 20:07:18 +0200530 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200531 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200532 else
533 conn = objt_conn(smp->sess->origin);
534
William Lallemand15e16942020-05-15 00:25:08 +0200535 ssl = ssl_sock_get_ssl_object(conn);
536 if (!ssl)
537 return 0;
538
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200539 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200540 smp->flags |= SMP_F_MAY_CHANGE;
541 return 0;
542 }
543
544 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200545 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200546 else
547 crt = SSL_get_certificate(ssl);
548
549 if (!crt)
550 goto out;
551
552 smp_trash = get_trash_chunk();
553 if (ssl_sock_crt2der(crt, smp_trash) <= 0)
554 goto out;
555
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200556 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200557 smp->data.u.str = *smp_trash;
558 smp->data.type = SMP_T_BIN;
559 ret = 1;
560out:
561 /* SSL_get_peer_certificate, it increase X509 * ref count */
562 if (cert_peer && crt)
563 X509_free(crt);
564 return ret;
565}
566
William Dauchya598b502020-08-06 18:11:38 +0200567/* binary, returns a chain certificate in a binary chunk (der/raw).
568 * The 5th keyword char is used to support only peer cert
569 */
570static int
571smp_fetch_ssl_x_chain_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
572{
573 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
574 int conn_server = (kw[4] == 's') ? 1 : 0;
575 struct buffer *smp_trash;
576 struct buffer *tmp_trash = NULL;
577 struct connection *conn;
578 STACK_OF(X509) *certs = NULL;
579 X509 *crt = NULL;
580 SSL *ssl;
581 int ret = 0;
582 int num_certs;
583 int i;
584
585 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200586 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Dauchya598b502020-08-06 18:11:38 +0200587 else
588 conn = objt_conn(smp->sess->origin);
589
590 if (!conn)
591 return 0;
592
593 ssl = ssl_sock_get_ssl_object(conn);
594 if (!ssl)
595 return 0;
596
597 if (conn->flags & CO_FL_WAIT_XPRT) {
598 smp->flags |= SMP_F_MAY_CHANGE;
599 return 0;
600 }
601
602 if (!cert_peer)
603 return 0;
604
605 certs = SSL_get_peer_cert_chain(ssl);
606 if (!certs)
607 return 0;
608
609 num_certs = sk_X509_num(certs);
610 if (!num_certs)
611 goto out;
612 smp_trash = get_trash_chunk();
613 tmp_trash = alloc_trash_chunk();
614 if (!tmp_trash)
615 goto out;
616 for (i = 0; i < num_certs; i++) {
617 crt = sk_X509_value(certs, i);
618 if (ssl_sock_crt2der(crt, tmp_trash) <= 0)
619 goto out;
620 chunk_cat(smp_trash, tmp_trash);
621 }
622
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200623 smp->flags = SMP_F_VOL_SESS;
William Dauchya598b502020-08-06 18:11:38 +0200624 smp->data.u.str = *smp_trash;
625 smp->data.type = SMP_T_BIN;
626 ret = 1;
627out:
628 if (tmp_trash)
629 free_trash_chunk(tmp_trash);
William Dauchya598b502020-08-06 18:11:38 +0200630 return ret;
631}
632
William Lallemand15e16942020-05-15 00:25:08 +0200633/* binary, returns serial of certificate in a binary chunk.
634 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
635 * should be use.
636 */
637static int
638smp_fetch_ssl_x_serial(const struct arg *args, struct sample *smp, const char *kw, void *private)
639{
William Lallemandbfa3e812020-06-25 20:07:18 +0200640 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
641 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200642 X509 *crt = NULL;
643 int ret = 0;
644 struct buffer *smp_trash;
645 struct connection *conn;
646 SSL *ssl;
647
William Lallemandbfa3e812020-06-25 20:07:18 +0200648 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200649 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200650 else
651 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +0200652 ssl = ssl_sock_get_ssl_object(conn);
653 if (!ssl)
654 return 0;
655
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200656 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200657 smp->flags |= SMP_F_MAY_CHANGE;
658 return 0;
659 }
660
661 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200662 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200663 else
664 crt = SSL_get_certificate(ssl);
665
666 if (!crt)
667 goto out;
668
669 smp_trash = get_trash_chunk();
670 if (ssl_sock_get_serial(crt, smp_trash) <= 0)
671 goto out;
672
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200673 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200674 smp->data.u.str = *smp_trash;
675 smp->data.type = SMP_T_BIN;
676 ret = 1;
677out:
678 /* SSL_get_peer_certificate, it increase X509 * ref count */
679 if (cert_peer && crt)
680 X509_free(crt);
681 return ret;
682}
683
684/* binary, returns the client certificate's SHA-1 fingerprint (SHA-1 hash of DER-encoded certificate) in a binary chunk.
685 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
686 * should be use.
687 */
688static int
689smp_fetch_ssl_x_sha1(const struct arg *args, struct sample *smp, const char *kw, void *private)
690{
William Lallemandbfa3e812020-06-25 20:07:18 +0200691 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
692 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200693 X509 *crt = NULL;
694 const EVP_MD *digest;
695 int ret = 0;
696 unsigned int len = 0;
697 struct buffer *smp_trash;
698 struct connection *conn;
699 SSL *ssl;
700
William Lallemandbfa3e812020-06-25 20:07:18 +0200701 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200702 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200703 else
704 conn = objt_conn(smp->sess->origin);
705
William Lallemand15e16942020-05-15 00:25:08 +0200706 ssl = ssl_sock_get_ssl_object(conn);
707 if (!ssl)
708 return 0;
709
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200710 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200711 smp->flags |= SMP_F_MAY_CHANGE;
712 return 0;
713 }
714
715 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200716 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200717 else
718 crt = SSL_get_certificate(ssl);
719 if (!crt)
720 goto out;
721
722 smp_trash = get_trash_chunk();
723 digest = EVP_sha1();
724 X509_digest(crt, digest, (unsigned char *) smp_trash->area, &len);
725 smp_trash->data = len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200726 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200727 smp->data.u.str = *smp_trash;
728 smp->data.type = SMP_T_BIN;
729 ret = 1;
730out:
731 /* SSL_get_peer_certificate, it increase X509 * ref count */
732 if (cert_peer && crt)
733 X509_free(crt);
734 return ret;
735}
736
737/* string, returns certificate's notafter date in ASN1_UTCTIME format.
738 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
739 * should be use.
740 */
741static int
742smp_fetch_ssl_x_notafter(const struct arg *args, struct sample *smp, const char *kw, void *private)
743{
William Lallemandbfa3e812020-06-25 20:07:18 +0200744 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
745 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200746 X509 *crt = NULL;
747 int ret = 0;
748 struct buffer *smp_trash;
749 struct connection *conn;
750 SSL *ssl;
751
William Lallemandbfa3e812020-06-25 20:07:18 +0200752 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200753 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200754 else
755 conn = objt_conn(smp->sess->origin);
756
William Lallemand15e16942020-05-15 00:25:08 +0200757 ssl = ssl_sock_get_ssl_object(conn);
758 if (!ssl)
759 return 0;
760
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200761 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200762 smp->flags |= SMP_F_MAY_CHANGE;
763 return 0;
764 }
765
766 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200767 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200768 else
769 crt = SSL_get_certificate(ssl);
770 if (!crt)
771 goto out;
772
773 smp_trash = get_trash_chunk();
774 if (ssl_sock_get_time(X509_getm_notAfter(crt), smp_trash) <= 0)
775 goto out;
776
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200777 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200778 smp->data.u.str = *smp_trash;
779 smp->data.type = SMP_T_STR;
780 ret = 1;
781out:
782 /* SSL_get_peer_certificate, it increase X509 * ref count */
783 if (cert_peer && crt)
784 X509_free(crt);
785 return ret;
786}
787
788/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's issuer
789 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
790 * should be use.
791 */
792static int
793smp_fetch_ssl_x_i_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
794{
William Lallemandbfa3e812020-06-25 20:07:18 +0200795 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
796 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200797 X509 *crt = NULL;
798 X509_NAME *name;
799 int ret = 0;
800 struct buffer *smp_trash;
801 struct connection *conn;
802 SSL *ssl;
803
William Lallemandbfa3e812020-06-25 20:07:18 +0200804 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200805 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200806 else
807 conn = objt_conn(smp->sess->origin);
808
William Lallemand15e16942020-05-15 00:25:08 +0200809 ssl = ssl_sock_get_ssl_object(conn);
810 if (!ssl)
811 return 0;
812
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200813 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200814 smp->flags |= SMP_F_MAY_CHANGE;
815 return 0;
816 }
817
818 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200819 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200820 else
821 crt = SSL_get_certificate(ssl);
822 if (!crt)
823 goto out;
824
825 name = X509_get_issuer_name(crt);
826 if (!name)
827 goto out;
828
829 smp_trash = get_trash_chunk();
Christopher Faulet3702f782021-01-29 11:30:37 +0100830 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200831 int pos = 1;
832
833 if (args[1].type == ARGT_SINT)
834 pos = args[1].data.sint;
835
836 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
837 goto out;
838 }
Christopher Faulet3702f782021-01-29 11:30:37 +0100839 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200840 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
841 goto out;
842 }
843 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
844 goto out;
845
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200846 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200847 smp->data.type = SMP_T_STR;
848 smp->data.u.str = *smp_trash;
849 ret = 1;
850out:
851 /* SSL_get_peer_certificate, it increase X509 * ref count */
852 if (cert_peer && crt)
853 X509_free(crt);
854 return ret;
855}
856
857/* string, returns notbefore date in ASN1_UTCTIME format.
858 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
859 * should be use.
860 */
861static int
862smp_fetch_ssl_x_notbefore(const struct arg *args, struct sample *smp, const char *kw, void *private)
863{
William Lallemandbfa3e812020-06-25 20:07:18 +0200864 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
865 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200866 X509 *crt = NULL;
867 int ret = 0;
868 struct buffer *smp_trash;
869 struct connection *conn;
870 SSL *ssl;
871
William Lallemandbfa3e812020-06-25 20:07:18 +0200872 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200873 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200874 else
875 conn = objt_conn(smp->sess->origin);
876
William Lallemand15e16942020-05-15 00:25:08 +0200877 ssl = ssl_sock_get_ssl_object(conn);
878 if (!ssl)
879 return 0;
880
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200881 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200882 smp->flags |= SMP_F_MAY_CHANGE;
883 return 0;
884 }
885
886 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200887 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200888 else
889 crt = SSL_get_certificate(ssl);
890 if (!crt)
891 goto out;
892
893 smp_trash = get_trash_chunk();
894 if (ssl_sock_get_time(X509_getm_notBefore(crt), smp_trash) <= 0)
895 goto out;
896
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200897 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200898 smp->data.u.str = *smp_trash;
899 smp->data.type = SMP_T_STR;
900 ret = 1;
901out:
902 /* SSL_get_peer_certificate, it increase X509 * ref count */
903 if (cert_peer && crt)
904 X509_free(crt);
905 return ret;
906}
907
908/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's subject
909 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
910 * should be use.
911 */
912static int
913smp_fetch_ssl_x_s_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
914{
William Lallemandbfa3e812020-06-25 20:07:18 +0200915 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
916 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200917 X509 *crt = NULL;
918 X509_NAME *name;
919 int ret = 0;
920 struct buffer *smp_trash;
921 struct connection *conn;
922 SSL *ssl;
923
William Lallemandbfa3e812020-06-25 20:07:18 +0200924 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200925 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200926 else
927 conn = objt_conn(smp->sess->origin);
928
William Lallemand15e16942020-05-15 00:25:08 +0200929 ssl = ssl_sock_get_ssl_object(conn);
930 if (!ssl)
931 return 0;
932
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200933 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200934 smp->flags |= SMP_F_MAY_CHANGE;
935 return 0;
936 }
937
938 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200939 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200940 else
941 crt = SSL_get_certificate(ssl);
942 if (!crt)
943 goto out;
944
945 name = X509_get_subject_name(crt);
946 if (!name)
947 goto out;
948
949 smp_trash = get_trash_chunk();
Christopher Faulet3702f782021-01-29 11:30:37 +0100950 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200951 int pos = 1;
952
953 if (args[1].type == ARGT_SINT)
954 pos = args[1].data.sint;
955
956 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
957 goto out;
958 }
Christopher Faulet3702f782021-01-29 11:30:37 +0100959 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200960 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
961 goto out;
962 }
963 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
964 goto out;
965
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200966 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200967 smp->data.type = SMP_T_STR;
968 smp->data.u.str = *smp_trash;
969 ret = 1;
970out:
971 /* SSL_get_peer_certificate, it increase X509 * ref count */
972 if (cert_peer && crt)
973 X509_free(crt);
974 return ret;
975}
976
977/* integer, returns true if current session use a client certificate */
978static int
979smp_fetch_ssl_c_used(const struct arg *args, struct sample *smp, const char *kw, void *private)
980{
981 X509 *crt;
982 struct connection *conn;
983 SSL *ssl;
984
985 conn = objt_conn(smp->sess->origin);
986 ssl = ssl_sock_get_ssl_object(conn);
987 if (!ssl)
988 return 0;
989
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200990 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200991 smp->flags |= SMP_F_MAY_CHANGE;
992 return 0;
993 }
994
995 /* SSL_get_peer_certificate returns a ptr on allocated X509 struct */
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200996 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200997 if (crt) {
998 X509_free(crt);
999 }
1000
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001001 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001002 smp->data.type = SMP_T_BOOL;
1003 smp->data.u.sint = (crt != NULL);
1004 return 1;
1005}
1006
1007/* integer, returns the certificate version
1008 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1009 * should be use.
1010 */
1011static int
1012smp_fetch_ssl_x_version(const struct arg *args, struct sample *smp, const char *kw, void *private)
1013{
William Lallemandbfa3e812020-06-25 20:07:18 +02001014 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1015 int conn_server = (kw[4] == 's') ? 1 : 0;
1016
William Lallemand15e16942020-05-15 00:25:08 +02001017 X509 *crt;
1018 struct connection *conn;
1019 SSL *ssl;
1020
William Lallemandbfa3e812020-06-25 20:07:18 +02001021 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +02001022 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001023 else
1024 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +02001025 ssl = ssl_sock_get_ssl_object(conn);
1026 if (!ssl)
1027 return 0;
1028
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001029 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001030 smp->flags |= SMP_F_MAY_CHANGE;
1031 return 0;
1032 }
1033
1034 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001035 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001036 else
1037 crt = SSL_get_certificate(ssl);
1038 if (!crt)
1039 return 0;
1040
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001041 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001042 smp->data.u.sint = (unsigned int)(1 + X509_get_version(crt));
1043 /* SSL_get_peer_certificate increase X509 * ref count */
1044 if (cert_peer)
1045 X509_free(crt);
1046 smp->data.type = SMP_T_SINT;
1047
1048 return 1;
1049}
1050
1051/* string, returns the certificate's signature algorithm.
1052 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1053 * should be use.
1054 */
1055static int
1056smp_fetch_ssl_x_sig_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
1057{
William Lallemandbfa3e812020-06-25 20:07:18 +02001058 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1059 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +02001060 X509 *crt;
1061 __OPENSSL_110_CONST__ ASN1_OBJECT *algorithm;
1062 int nid;
1063 struct connection *conn;
1064 SSL *ssl;
1065
William Lallemandbfa3e812020-06-25 20:07:18 +02001066 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +02001067 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001068 else
1069 conn = objt_conn(smp->sess->origin);
1070
William Lallemand15e16942020-05-15 00:25:08 +02001071 ssl = ssl_sock_get_ssl_object(conn);
1072 if (!ssl)
1073 return 0;
1074
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001075 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001076 smp->flags |= SMP_F_MAY_CHANGE;
1077 return 0;
1078 }
1079
1080 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001081 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001082 else
1083 crt = SSL_get_certificate(ssl);
1084 if (!crt)
1085 return 0;
1086
1087 X509_ALGOR_get0(&algorithm, NULL, NULL, X509_get0_tbs_sigalg(crt));
1088 nid = OBJ_obj2nid(algorithm);
1089
1090 smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
1091 if (!smp->data.u.str.area) {
1092 /* SSL_get_peer_certificate increase X509 * ref count */
1093 if (cert_peer)
1094 X509_free(crt);
1095 return 0;
1096 }
1097
1098 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001099 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001100 smp->data.u.str.data = strlen(smp->data.u.str.area);
1101 /* SSL_get_peer_certificate increase X509 * ref count */
1102 if (cert_peer)
1103 X509_free(crt);
1104
1105 return 1;
1106}
1107
1108/* string, returns the certificate's key algorithm.
1109 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1110 * should be use.
1111 */
1112static int
1113smp_fetch_ssl_x_key_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
1114{
William Lallemandbfa3e812020-06-25 20:07:18 +02001115 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1116 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +02001117 X509 *crt;
1118 ASN1_OBJECT *algorithm;
1119 int nid;
1120 struct connection *conn;
1121 SSL *ssl;
1122
William Lallemandbfa3e812020-06-25 20:07:18 +02001123 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +02001124 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001125 else
1126 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +02001127 ssl = ssl_sock_get_ssl_object(conn);
1128 if (!ssl)
1129 return 0;
1130
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001131 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001132 smp->flags |= SMP_F_MAY_CHANGE;
1133 return 0;
1134 }
1135
1136 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001137 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001138 else
1139 crt = SSL_get_certificate(ssl);
1140 if (!crt)
1141 return 0;
1142
1143 X509_PUBKEY_get0_param(&algorithm, NULL, NULL, NULL, X509_get_X509_PUBKEY(crt));
1144 nid = OBJ_obj2nid(algorithm);
1145
1146 smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
1147 if (!smp->data.u.str.area) {
1148 /* SSL_get_peer_certificate increase X509 * ref count */
1149 if (cert_peer)
1150 X509_free(crt);
1151 return 0;
1152 }
1153
1154 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001155 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001156 smp->data.u.str.data = strlen(smp->data.u.str.area);
1157 if (cert_peer)
1158 X509_free(crt);
1159
1160 return 1;
1161}
1162
1163/* boolean, returns true if front conn. transport layer is SSL.
1164 * This function is also usable on backend conn if the fetch keyword 5th
1165 * char is 'b'.
1166 */
1167static int
1168smp_fetch_ssl_fc(const struct arg *args, struct sample *smp, const char *kw, void *private)
1169{
1170 struct connection *conn;
1171
1172 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001173 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001174 else
1175 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1176 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1177
1178 smp->data.type = SMP_T_BOOL;
1179 smp->data.u.sint = (conn && conn->xprt == &ssl_sock);
1180 return 1;
1181}
1182
1183/* boolean, returns true if client present a SNI */
1184static int
1185smp_fetch_ssl_fc_has_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
1186{
1187#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1188 struct connection *conn = objt_conn(smp->sess->origin);
1189 SSL *ssl = ssl_sock_get_ssl_object(conn);
1190
1191 smp->data.type = SMP_T_BOOL;
1192 smp->data.u.sint = ssl && SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name) != NULL;
1193 return 1;
1194#else
1195 return 0;
1196#endif
1197}
1198
1199/* boolean, returns true if client session has been resumed.
1200 * This function is also usable on backend conn if the fetch keyword 5th
1201 * char is 'b'.
1202 */
1203static int
1204smp_fetch_ssl_fc_is_resumed(const struct arg *args, struct sample *smp, const char *kw, void *private)
1205{
1206 struct connection *conn;
1207 SSL *ssl;
1208
1209 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001210 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001211 else
1212 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1213 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1214
1215 ssl = ssl_sock_get_ssl_object(conn);
1216
1217 smp->data.type = SMP_T_BOOL;
1218 smp->data.u.sint = ssl && SSL_session_reused(ssl);
1219 return 1;
1220}
1221
1222/* string, returns the used cipher if front conn. transport layer is SSL.
1223 * This function is also usable on backend conn if the fetch keyword 5th
1224 * char is 'b'.
1225 */
1226static int
1227smp_fetch_ssl_fc_cipher(const struct arg *args, struct sample *smp, const char *kw, void *private)
1228{
1229 struct connection *conn;
1230 SSL *ssl;
1231
1232 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001233 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001234 else
1235 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1236 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1237
1238 smp->flags = 0;
1239 ssl = ssl_sock_get_ssl_object(conn);
1240 if (!ssl)
1241 return 0;
1242
1243 smp->data.u.str.area = (char *)SSL_get_cipher_name(ssl);
1244 if (!smp->data.u.str.area)
1245 return 0;
1246
1247 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001248 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001249 smp->data.u.str.data = strlen(smp->data.u.str.area);
1250
1251 return 1;
1252}
1253
1254/* integer, returns the algoritm's keysize if front conn. transport layer
1255 * is SSL.
1256 * This function is also usable on backend conn if the fetch keyword 5th
1257 * char is 'b'.
1258 */
1259static int
1260smp_fetch_ssl_fc_alg_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
1261{
1262 struct connection *conn;
1263 SSL *ssl;
1264 int sint;
1265
1266 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001267 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001268 else
1269 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1270 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1271
1272 smp->flags = 0;
1273 ssl = ssl_sock_get_ssl_object(conn);
1274 if (!ssl)
1275 return 0;
1276
1277 if (!SSL_get_cipher_bits(ssl, &sint))
1278 return 0;
1279
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001280 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001281 smp->data.u.sint = sint;
1282 smp->data.type = SMP_T_SINT;
1283
1284 return 1;
1285}
1286
1287/* integer, returns the used keysize if front conn. transport layer is SSL.
1288 * This function is also usable on backend conn if the fetch keyword 5th
1289 * char is 'b'.
1290 */
1291static int
1292smp_fetch_ssl_fc_use_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
1293{
1294 struct connection *conn;
1295 SSL *ssl;
1296
1297 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001298 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001299 else
1300 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1301 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1302
1303 smp->flags = 0;
1304 ssl = ssl_sock_get_ssl_object(conn);
1305 if (!ssl)
1306 return 0;
1307
1308 smp->data.u.sint = (unsigned int)SSL_get_cipher_bits(ssl, NULL);
1309 if (!smp->data.u.sint)
1310 return 0;
1311
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001312 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001313 smp->data.type = SMP_T_SINT;
1314
1315 return 1;
1316}
1317
1318#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
1319static int
1320smp_fetch_ssl_fc_npn(const struct arg *args, struct sample *smp, const char *kw, void *private)
1321{
1322 struct connection *conn;
1323 SSL *ssl;
1324 unsigned int len = 0;
1325
1326 smp->flags = SMP_F_CONST;
1327 smp->data.type = SMP_T_STR;
1328
1329 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001330 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001331 else
1332 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1333 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1334
1335 ssl = ssl_sock_get_ssl_object(conn);
1336 if (!ssl)
1337 return 0;
1338
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001339 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001340 smp->data.u.str.area = NULL;
1341 SSL_get0_next_proto_negotiated(ssl,
1342 (const unsigned char **)&smp->data.u.str.area,
1343 &len);
1344
1345 if (!smp->data.u.str.area)
1346 return 0;
1347
1348 smp->data.u.str.data = len;
1349 return 1;
1350}
1351#endif
1352
1353#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1354static int
1355smp_fetch_ssl_fc_alpn(const struct arg *args, struct sample *smp, const char *kw, void *private)
1356{
1357 struct connection *conn;
1358 SSL *ssl;
1359 unsigned int len = 0;
1360
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001361 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001362 smp->data.type = SMP_T_STR;
1363
1364 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001365 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001366 else
1367 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1368 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1369
1370 ssl = ssl_sock_get_ssl_object(conn);
1371 if (!ssl)
1372 return 0;
1373
1374 smp->data.u.str.area = NULL;
1375 SSL_get0_alpn_selected(ssl,
1376 (const unsigned char **)&smp->data.u.str.area,
1377 &len);
1378
1379 if (!smp->data.u.str.area)
1380 return 0;
1381
1382 smp->data.u.str.data = len;
1383 return 1;
1384}
1385#endif
1386
1387/* string, returns the used protocol if front conn. transport layer is SSL.
1388 * This function is also usable on backend conn if the fetch keyword 5th
1389 * char is 'b'.
1390 */
1391static int
1392smp_fetch_ssl_fc_protocol(const struct arg *args, struct sample *smp, const char *kw, void *private)
1393{
1394 struct connection *conn;
1395 SSL *ssl;
1396
1397 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001398 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001399 else
1400 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1401 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1402
1403 smp->flags = 0;
1404 ssl = ssl_sock_get_ssl_object(conn);
1405 if (!ssl)
1406 return 0;
1407
1408 smp->data.u.str.area = (char *)SSL_get_version(ssl);
1409 if (!smp->data.u.str.area)
1410 return 0;
1411
1412 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001413 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001414 smp->data.u.str.data = strlen(smp->data.u.str.area);
1415
1416 return 1;
1417}
1418
1419/* binary, returns the SSL stream id if front conn. transport layer is SSL.
1420 * This function is also usable on backend conn if the fetch keyword 5th
1421 * char is 'b'.
1422 */
1423#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1424static int
1425smp_fetch_ssl_fc_session_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1426{
1427 struct connection *conn;
1428 SSL_SESSION *ssl_sess;
1429 SSL *ssl;
1430 unsigned int len = 0;
1431
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001432 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001433 smp->data.type = SMP_T_BIN;
1434
1435 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001436 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001437 else
1438 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1439 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1440
1441 ssl = ssl_sock_get_ssl_object(conn);
1442 if (!ssl)
1443 return 0;
1444
1445 ssl_sess = SSL_get_session(ssl);
1446 if (!ssl_sess)
1447 return 0;
1448
1449 smp->data.u.str.area = (char *)SSL_SESSION_get_id(ssl_sess, &len);
1450 if (!smp->data.u.str.area || !len)
1451 return 0;
1452
1453 smp->data.u.str.data = len;
1454 return 1;
1455}
1456#endif
1457
1458
Ilya Shipitsindf627942021-03-25 00:41:41 +05001459#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02001460static int
1461smp_fetch_ssl_fc_random(const struct arg *args, struct sample *smp, const char *kw, void *private)
1462{
1463 struct connection *conn;
1464 struct buffer *data;
1465 SSL *ssl;
1466
1467 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001468 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001469 else
1470 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1471 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1472
1473 ssl = ssl_sock_get_ssl_object(conn);
1474 if (!ssl)
1475 return 0;
1476
1477 data = get_trash_chunk();
1478 if (kw[7] == 'c')
1479 data->data = SSL_get_client_random(ssl,
1480 (unsigned char *) data->area,
1481 data->size);
1482 else
1483 data->data = SSL_get_server_random(ssl,
1484 (unsigned char *) data->area,
1485 data->size);
1486 if (!data->data)
1487 return 0;
1488
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001489 smp->flags = SMP_F_VOL_TEST;
William Lallemand15e16942020-05-15 00:25:08 +02001490 smp->data.type = SMP_T_BIN;
1491 smp->data.u.str = *data;
1492
1493 return 1;
1494}
1495
1496static int
1497smp_fetch_ssl_fc_session_key(const struct arg *args, struct sample *smp, const char *kw, void *private)
1498{
1499 struct connection *conn;
1500 SSL_SESSION *ssl_sess;
1501 struct buffer *data;
1502 SSL *ssl;
1503
1504 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001505 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001506 else
1507 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1508 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1509
1510 ssl = ssl_sock_get_ssl_object(conn);
1511 if (!ssl)
1512 return 0;
1513
1514 ssl_sess = SSL_get_session(ssl);
1515 if (!ssl_sess)
1516 return 0;
1517
1518 data = get_trash_chunk();
1519 data->data = SSL_SESSION_get_master_key(ssl_sess,
1520 (unsigned char *) data->area,
1521 data->size);
1522 if (!data->data)
1523 return 0;
1524
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001525 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001526 smp->data.type = SMP_T_BIN;
1527 smp->data.u.str = *data;
1528
1529 return 1;
1530}
1531#endif
1532
William Lallemand15e16942020-05-15 00:25:08 +02001533static int
1534smp_fetch_ssl_fc_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
1535{
Willy Tarreau579259d2021-11-05 19:12:54 +01001536#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
William Lallemand15e16942020-05-15 00:25:08 +02001537 struct connection *conn;
1538 SSL *ssl;
1539
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001540 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001541 smp->data.type = SMP_T_STR;
1542
1543 conn = objt_conn(smp->sess->origin);
1544 ssl = ssl_sock_get_ssl_object(conn);
1545 if (!ssl)
1546 return 0;
1547
1548 smp->data.u.str.area = (char *)SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
Remi Tricot-Le Bretona9967632022-01-07 17:12:01 +01001549 if (!smp->data.u.str.area) {
1550 /* We might have stored the SNI ourselves, look for it in the
1551 * context's ex_data.
1552 */
1553 smp->data.u.str.area = SSL_get_ex_data(ssl, ssl_client_sni_index);
1554
1555 if (!smp->data.u.str.area)
1556 return 0;
1557 }
William Lallemand15e16942020-05-15 00:25:08 +02001558
1559 smp->data.u.str.data = strlen(smp->data.u.str.area);
Remi Tricot-Le Bretona9967632022-01-07 17:12:01 +01001560
William Lallemand15e16942020-05-15 00:25:08 +02001561 return 1;
Willy Tarreau579259d2021-11-05 19:12:54 +01001562#else
1563 /* SNI not supported */
1564 return 0;
William Lallemand15e16942020-05-15 00:25:08 +02001565#endif
Willy Tarreau579259d2021-11-05 19:12:54 +01001566}
William Lallemand15e16942020-05-15 00:25:08 +02001567
Marcin Deranek959a48c2021-07-13 15:14:21 +02001568/* binary, returns tls client hello cipher list.
1569 * Arguments: filter_option (0,1)
1570 */
William Lallemand15e16942020-05-15 00:25:08 +02001571static int
1572smp_fetch_ssl_fc_cl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1573{
Marcin Deranek959a48c2021-07-13 15:14:21 +02001574 struct buffer *smp_trash;
William Lallemand15e16942020-05-15 00:25:08 +02001575 struct connection *conn;
1576 struct ssl_capture *capture;
1577 SSL *ssl;
1578
1579 conn = objt_conn(smp->sess->origin);
1580 ssl = ssl_sock_get_ssl_object(conn);
1581 if (!ssl)
1582 return 0;
1583
1584 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1585 if (!capture)
1586 return 0;
1587
Marcin Deranek959a48c2021-07-13 15:14:21 +02001588 if (args[0].data.sint) {
1589 smp_trash = get_trash_chunk();
1590 exclude_tls_grease(capture->data + capture->ciphersuite_offset, capture->ciphersuite_len, smp_trash);
1591 smp->data.u.str.area = smp_trash->area;
1592 smp->data.u.str.data = smp_trash->data;
1593 smp->flags = SMP_F_VOL_SESS;
1594 }
1595 else {
1596 smp->data.u.str.area = capture->data + capture->ciphersuite_offset;
1597 smp->data.u.str.data = capture->ciphersuite_len;
1598 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1599 }
1600
William Lallemand15e16942020-05-15 00:25:08 +02001601 smp->data.type = SMP_T_BIN;
William Lallemand15e16942020-05-15 00:25:08 +02001602 return 1;
1603}
1604
Marcin Deranek959a48c2021-07-13 15:14:21 +02001605/* binary, returns tls client hello cipher list as hexadecimal string.
1606 * Arguments: filter_option (0,1)
1607 */
William Lallemand15e16942020-05-15 00:25:08 +02001608static int
1609smp_fetch_ssl_fc_cl_hex(const struct arg *args, struct sample *smp, const char *kw, void *private)
1610{
1611 struct buffer *data;
1612
1613 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1614 return 0;
1615
1616 data = get_trash_chunk();
1617 dump_binary(data, smp->data.u.str.area, smp->data.u.str.data);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001618 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001619 smp->data.type = SMP_T_BIN;
1620 smp->data.u.str = *data;
1621 return 1;
1622}
1623
Marcin Deranek959a48c2021-07-13 15:14:21 +02001624/* integer, returns xxh64 hash of tls client hello cipher list. */
William Lallemand15e16942020-05-15 00:25:08 +02001625static int
1626smp_fetch_ssl_fc_cl_xxh64(const struct arg *args, struct sample *smp, const char *kw, void *private)
1627{
1628 struct connection *conn;
1629 struct ssl_capture *capture;
1630 SSL *ssl;
1631
1632 conn = objt_conn(smp->sess->origin);
1633 ssl = ssl_sock_get_ssl_object(conn);
1634 if (!ssl)
1635 return 0;
1636
1637 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1638 if (!capture)
1639 return 0;
1640
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001641 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001642 smp->data.type = SMP_T_SINT;
1643 smp->data.u.sint = capture->xxh64;
1644 return 1;
1645}
1646
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001647static int
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001648smp_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 +02001649{
1650 struct connection *conn;
1651 struct ssl_sock_ctx *ctx;
1652
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001653 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
1654 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
1655 else
1656 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1657 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1658
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001659 if (!conn || conn->xprt != &ssl_sock)
1660 return 0;
1661 ctx = conn->xprt_ctx;
1662
1663 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1664 smp->flags = SMP_F_MAY_CHANGE;
1665 return 0;
1666 }
1667
1668 if (!ctx)
1669 return 0;
1670
1671 smp->flags = SMP_F_VOL_SESS;
1672 smp->data.type = SMP_T_SINT;
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001673 smp->data.u.sint = ctx->error_code;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001674 return 1;
1675}
1676
1677static int
Marcin Deranek959a48c2021-07-13 15:14:21 +02001678smp_fetch_ssl_fc_protocol_hello_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1679{
1680 struct connection *conn;
1681 struct ssl_capture *capture;
1682 SSL *ssl;
1683
1684 conn = objt_conn(smp->sess->origin);
1685 ssl = ssl_sock_get_ssl_object(conn);
1686 if (!ssl)
1687 return 0;
1688
1689 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1690 if (!capture)
1691 return 0;
1692
1693 smp->flags = SMP_F_VOL_SESS;
1694 smp->data.type = SMP_T_SINT;
1695 smp->data.u.sint = capture->protocol_version;
1696 return 1;
1697}
1698
1699static int
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001700smp_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 +02001701{
1702 struct connection *conn;
1703 struct ssl_sock_ctx *ctx;
1704 const char *err_code_str;
1705
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001706 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
1707 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
1708 else
1709 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1710 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1711
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001712 if (!conn || conn->xprt != &ssl_sock)
1713 return 0;
1714 ctx = conn->xprt_ctx;
1715
1716 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1717 smp->flags = SMP_F_MAY_CHANGE;
1718 return 0;
1719 }
1720
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001721 if (!ctx || !ctx->error_code)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001722 return 0;
1723
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001724 err_code_str = ERR_error_string(ctx->error_code, NULL);
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001725
1726 smp->flags = SMP_F_VOL_SESS;
1727 smp->data.type = SMP_T_STR;
1728 smp->data.u.str.area = (char*)err_code_str;
1729 smp->data.u.str.data = strlen(err_code_str);
1730
Marcin Deranek959a48c2021-07-13 15:14:21 +02001731 return 1;
1732}
1733
1734/* binary, returns tls client hello extensions list.
1735 * Arguments: filter_option (0,1)
1736 */
1737static int
1738smp_fetch_ssl_fc_ext_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1739{
1740 struct buffer *smp_trash;
1741 struct connection *conn;
1742 struct ssl_capture *capture;
1743 SSL *ssl;
1744
1745 conn = objt_conn(smp->sess->origin);
1746 ssl = ssl_sock_get_ssl_object(conn);
1747 if (!ssl)
1748 return 0;
1749
1750 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1751 if (!capture)
1752 return 0;
1753
1754 if (args[0].data.sint) {
1755 smp_trash = get_trash_chunk();
1756 exclude_tls_grease(capture->data + capture->extensions_offset, capture->extensions_len, smp_trash);
1757 smp->data.u.str.area = smp_trash->area;
1758 smp->data.u.str.data = smp_trash->data;
1759 smp->flags = SMP_F_VOL_SESS;
1760 }
1761 else {
1762 smp->data.u.str.area = capture->data + capture->extensions_offset;
1763 smp->data.u.str.data = capture->extensions_len;
1764 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1765 }
1766
1767 smp->data.type = SMP_T_BIN;
1768 return 1;
1769}
1770
1771/* binary, returns tls client hello supported elliptic curves.
1772 * Arguments: filter_option (0,1)
1773 */
1774static int
1775smp_fetch_ssl_fc_ecl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1776{
1777 struct buffer *smp_trash;
1778 struct connection *conn;
1779 struct ssl_capture *capture;
1780 SSL *ssl;
1781
1782 conn = objt_conn(smp->sess->origin);
1783 ssl = ssl_sock_get_ssl_object(conn);
1784 if (!ssl)
1785 return 0;
1786
1787 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1788 if (!capture)
1789 return 0;
1790
1791 if (args[0].data.sint) {
1792 smp_trash = get_trash_chunk();
1793 exclude_tls_grease(capture->data + capture->ec_offset, capture->ec_len, smp_trash);
1794 smp->data.u.str.area = smp_trash->area;
1795 smp->data.u.str.data = smp_trash->data;
1796 smp->flags = SMP_F_VOL_SESS;
1797 }
1798 else {
1799 smp->data.u.str.area = capture->data + capture->ec_offset;
1800 smp->data.u.str.data = capture->ec_len;
1801 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1802 }
1803
1804 smp->data.type = SMP_T_BIN;
1805 return 1;
1806}
1807
1808/* binary, returns tls client hello supported elliptic curve point formats */
1809static int
1810smp_fetch_ssl_fc_ecf_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1811{
1812 struct connection *conn;
1813 struct ssl_capture *capture;
1814 SSL *ssl;
1815
1816 conn = objt_conn(smp->sess->origin);
1817 ssl = ssl_sock_get_ssl_object(conn);
1818 if (!ssl)
1819 return 0;
1820
1821 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1822 if (!capture)
1823 return 0;
1824
1825 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1826 smp->data.type = SMP_T_BIN;
1827 smp->data.u.str.area = capture->data + capture->ec_formats_offset;
1828 smp->data.u.str.data = capture->ec_formats_len;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001829 return 1;
1830}
1831
William Lallemand7d42ef52020-07-06 11:41:30 +02001832/* Dump the SSL keylog, it only works with "tune.ssl.keylog 1" */
William Lallemand722180a2021-06-09 16:46:12 +02001833#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02001834static int smp_fetch_ssl_x_keylog(const struct arg *args, struct sample *smp, const char *kw, void *private)
1835{
1836 struct connection *conn;
1837 struct ssl_keylog *keylog;
1838 SSL *ssl;
1839 char *src = NULL;
1840 const char *sfx;
1841
1842 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1843 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1844
William Lallemandeec1d452020-07-07 10:48:13 +02001845 if (!conn)
1846 return 0;
1847
William Lallemand7d42ef52020-07-06 11:41:30 +02001848 if (conn->flags & CO_FL_WAIT_XPRT) {
1849 smp->flags |= SMP_F_MAY_CHANGE;
1850 return 0;
1851 }
1852
1853 ssl = ssl_sock_get_ssl_object(conn);
1854 if (!ssl)
1855 return 0;
1856
1857 keylog = SSL_get_ex_data(ssl, ssl_keylog_index);
1858 if (!keylog)
1859 return 0;
1860
1861 sfx = kw + strlen("ssl_xx_");
1862
1863 if (strcmp(sfx, "client_early_traffic_secret") == 0) {
1864 src = keylog->client_early_traffic_secret;
1865 } else if (strcmp(sfx, "client_handshake_traffic_secret") == 0) {
1866 src = keylog->client_handshake_traffic_secret;
1867 } else if (strcmp(sfx, "server_handshake_traffic_secret") == 0) {
1868 src = keylog->server_handshake_traffic_secret;
1869 } else if (strcmp(sfx, "client_traffic_secret_0") == 0) {
1870 src = keylog->client_traffic_secret_0;
1871 } else if (strcmp(sfx, "server_traffic_secret_0") == 0) {
1872 src = keylog->server_traffic_secret_0;
1873 } else if (strcmp(sfx, "exporter_secret") == 0) {
1874 src = keylog->exporter_secret;
1875 } else if (strcmp(sfx, "early_exporter_secret") == 0) {
1876 src = keylog->early_exporter_secret;
1877 }
1878
1879 if (!src || !*src)
1880 return 0;
1881
1882 smp->data.u.str.area = src;
1883 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001884 smp->flags |= SMP_F_VOL_TEST | SMP_F_CONST;
William Lallemand7d42ef52020-07-06 11:41:30 +02001885 smp->data.u.str.data = strlen(smp->data.u.str.area);
1886 return 1;
William Lallemand7d42ef52020-07-06 11:41:30 +02001887}
1888#endif
1889
William Lallemand15e16942020-05-15 00:25:08 +02001890static int
1891smp_fetch_ssl_fc_cl_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
1892{
Ilya Shipitsinc9dfee42020-10-31 02:10:02 +05001893#if defined(OPENSSL_IS_BORINGSSL) || defined(SSL_CTRL_GET_RAW_CIPHERLIST)
William Lallemand15e16942020-05-15 00:25:08 +02001894 struct buffer *data;
1895 int i;
1896
1897 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1898 return 0;
1899
1900 data = get_trash_chunk();
1901 for (i = 0; i + 1 < smp->data.u.str.data; i += 2) {
1902 const char *str;
1903 const SSL_CIPHER *cipher;
1904 const unsigned char *bin = (const unsigned char *) smp->data.u.str.area + i;
1905 uint16_t id = (bin[0] << 8) | bin[1];
1906#if defined(OPENSSL_IS_BORINGSSL)
1907 cipher = SSL_get_cipher_by_value(id);
1908#else
1909 struct connection *conn = __objt_conn(smp->sess->origin);
1910 SSL *ssl = ssl_sock_get_ssl_object(conn);
1911 cipher = SSL_CIPHER_find(ssl, bin);
1912#endif
1913 str = SSL_CIPHER_get_name(cipher);
1914 if (!str || strcmp(str, "(NONE)") == 0)
1915 chunk_appendf(data, "%sUNKNOWN(%04x)", i == 0 ? "" : ",", id);
1916 else
1917 chunk_appendf(data, "%s%s", i == 0 ? "" : ",", str);
1918 }
1919 smp->data.type = SMP_T_STR;
1920 smp->data.u.str = *data;
1921 return 1;
1922#else
1923 return smp_fetch_ssl_fc_cl_xxh64(args, smp, kw, private);
1924#endif
1925}
1926
1927#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1928static int
1929smp_fetch_ssl_fc_unique_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1930{
1931 struct connection *conn;
1932 int finished_len;
1933 struct buffer *finished_trash;
1934 SSL *ssl;
1935
1936 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001937 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001938 else
1939 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1940 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1941
1942 smp->flags = 0;
1943 ssl = ssl_sock_get_ssl_object(conn);
1944 if (!ssl)
1945 return 0;
1946
1947 if (conn->flags & CO_FL_WAIT_XPRT) {
1948 smp->flags |= SMP_F_MAY_CHANGE;
1949 return 0;
1950 }
1951
1952 finished_trash = get_trash_chunk();
1953 if (!SSL_session_reused(ssl))
1954 finished_len = SSL_get_peer_finished(ssl,
1955 finished_trash->area,
1956 finished_trash->size);
1957 else
1958 finished_len = SSL_get_finished(ssl,
1959 finished_trash->area,
1960 finished_trash->size);
1961
1962 if (!finished_len)
1963 return 0;
1964
1965 finished_trash->data = finished_len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001966 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001967 smp->data.u.str = *finished_trash;
1968 smp->data.type = SMP_T_BIN;
1969
1970 return 1;
1971}
1972#endif
1973
1974/* integer, returns the first verify error in CA chain of client certificate chain. */
1975static int
1976smp_fetch_ssl_c_ca_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
1977{
1978 struct connection *conn;
1979 struct ssl_sock_ctx *ctx;
1980
1981 conn = objt_conn(smp->sess->origin);
1982 if (!conn || conn->xprt != &ssl_sock)
1983 return 0;
1984 ctx = conn->xprt_ctx;
1985
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001986 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001987 smp->flags = SMP_F_MAY_CHANGE;
1988 return 0;
1989 }
1990
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001991 if (!ctx)
1992 return 0;
1993
William Lallemand15e16942020-05-15 00:25:08 +02001994 smp->data.type = SMP_T_SINT;
1995 smp->data.u.sint = (unsigned long long int)SSL_SOCK_ST_TO_CA_ERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001996 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001997
1998 return 1;
1999}
2000
2001/* integer, returns the depth of the first verify error in CA chain of client certificate chain. */
2002static int
2003smp_fetch_ssl_c_ca_err_depth(const struct arg *args, struct sample *smp, const char *kw, void *private)
2004{
2005 struct connection *conn;
2006 struct ssl_sock_ctx *ctx;
2007
2008 conn = objt_conn(smp->sess->origin);
2009 if (!conn || conn->xprt != &ssl_sock)
2010 return 0;
2011
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002012 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02002013 smp->flags = SMP_F_MAY_CHANGE;
2014 return 0;
2015 }
2016 ctx = conn->xprt_ctx;
2017
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002018 if (!ctx)
2019 return 0;
2020
William Lallemand15e16942020-05-15 00:25:08 +02002021 smp->data.type = SMP_T_SINT;
2022 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CAEDEPTH(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002023 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002024
2025 return 1;
2026}
2027
2028/* integer, returns the first verify error on client certificate */
2029static int
2030smp_fetch_ssl_c_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
2031{
2032 struct connection *conn;
2033 struct ssl_sock_ctx *ctx;
2034
2035 conn = objt_conn(smp->sess->origin);
2036 if (!conn || conn->xprt != &ssl_sock)
2037 return 0;
2038
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002039 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02002040 smp->flags = SMP_F_MAY_CHANGE;
2041 return 0;
2042 }
2043
2044 ctx = conn->xprt_ctx;
2045
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002046 if (!ctx)
2047 return 0;
2048
William Lallemand15e16942020-05-15 00:25:08 +02002049 smp->data.type = SMP_T_SINT;
2050 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CRTERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002051 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002052
2053 return 1;
2054}
2055
2056/* integer, returns the verify result on client cert */
2057static int
2058smp_fetch_ssl_c_verify(const struct arg *args, struct sample *smp, const char *kw, void *private)
2059{
2060 struct connection *conn;
2061 SSL *ssl;
2062
2063 conn = objt_conn(smp->sess->origin);
2064 ssl = ssl_sock_get_ssl_object(conn);
2065 if (!ssl)
2066 return 0;
2067
2068 if (conn->flags & CO_FL_WAIT_XPRT) {
2069 smp->flags = SMP_F_MAY_CHANGE;
2070 return 0;
2071 }
2072
2073 smp->data.type = SMP_T_SINT;
2074 smp->data.u.sint = (long long int)SSL_get_verify_result(ssl);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002075 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002076
2077 return 1;
2078}
2079
2080/* Argument validation functions */
2081
2082/* This function is used to validate the arguments passed to any "x_dn" ssl
2083 * keywords. These keywords support specifying a third parameter that must be
2084 * either empty or the value "rfc2253". Returns 0 on error, non-zero if OK.
2085 */
2086int val_dnfmt(struct arg *arg, char **err_msg)
2087{
2088 if (arg && arg[2].type == ARGT_STR && arg[2].data.str.data > 0 && (strcmp(arg[2].data.str.area, "rfc2253") != 0)) {
2089 memprintf(err_msg, "only rfc2253 or a blank value are currently supported as the format argument.");
2090 return 0;
2091 }
2092 return 1;
2093}
2094
2095/* Note: must not be declared <const> as its list will be overwritten.
2096 * Please take care of keeping this list alphabetically sorted.
2097 */
2098static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
2099 { "ssl_bc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
2100 { "ssl_bc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2101#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2102 { "ssl_bc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2103#endif
2104 { "ssl_bc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2105#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2106 { "ssl_bc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2107#endif
2108 { "ssl_bc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
2109 { "ssl_bc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2110 { "ssl_bc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2111 { "ssl_bc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2112#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2113 { "ssl_bc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2114#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05002115#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02002116 { "ssl_bc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2117 { "ssl_bc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2118 { "ssl_bc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2119#endif
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02002120 { "ssl_bc_err", smp_fetch_ssl_fc_err, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2121 { "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 +02002122 { "ssl_c_ca_err", smp_fetch_ssl_c_ca_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2123 { "ssl_c_ca_err_depth", smp_fetch_ssl_c_ca_err_depth, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2124 { "ssl_c_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02002125 { "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 +02002126 { "ssl_c_err", smp_fetch_ssl_c_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2127 { "ssl_c_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2128 { "ssl_c_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2129 { "ssl_c_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2130 { "ssl_c_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2131 { "ssl_c_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2132 { "ssl_c_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2133 { "ssl_c_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2134 { "ssl_c_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2135 { "ssl_c_used", smp_fetch_ssl_c_used, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2136 { "ssl_c_verify", smp_fetch_ssl_c_verify, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2137 { "ssl_c_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2138 { "ssl_f_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2139 { "ssl_f_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2140 { "ssl_f_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2141 { "ssl_f_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2142 { "ssl_f_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2143 { "ssl_f_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2144 { "ssl_f_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2145 { "ssl_f_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2146 { "ssl_f_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2147 { "ssl_f_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2148 { "ssl_fc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2149 { "ssl_fc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2150 { "ssl_fc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2151 { "ssl_fc_has_crt", smp_fetch_ssl_fc_has_crt, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2152 { "ssl_fc_has_early", smp_fetch_ssl_fc_has_early, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2153 { "ssl_fc_has_sni", smp_fetch_ssl_fc_has_sni, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2154 { "ssl_fc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2155#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2156 { "ssl_fc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2157#endif
2158#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2159 { "ssl_fc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2160#endif
2161 { "ssl_fc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2162#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2163 { "ssl_fc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2164#endif
2165 { "ssl_fc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2166#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2167 { "ssl_fc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2168#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05002169#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02002170 { "ssl_fc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2171 { "ssl_fc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2172 { "ssl_fc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2173#endif
William Lallemand7d42ef52020-07-06 11:41:30 +02002174
William Lallemand722180a2021-06-09 16:46:12 +02002175#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02002176 { "ssl_fc_client_early_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2177 { "ssl_fc_client_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2178 { "ssl_fc_server_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2179 { "ssl_fc_client_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2180 { "ssl_fc_server_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2181 { "ssl_fc_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2182 { "ssl_fc_early_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2183#endif
2184
William Lallemand15e16942020-05-15 00:25:08 +02002185 { "ssl_fc_sni", smp_fetch_ssl_fc_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
Marcin Deranek959a48c2021-07-13 15:14:21 +02002186 { "ssl_fc_cipherlist_bin", smp_fetch_ssl_fc_cl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2187 { "ssl_fc_cipherlist_hex", smp_fetch_ssl_fc_cl_hex, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_USE_L5CLI },
2188 { "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 +02002189 { "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 +02002190 { "ssl_fc_err", smp_fetch_ssl_fc_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2191 { "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 +02002192 { "ssl_fc_protocol_hello_id",smp_fetch_ssl_fc_protocol_hello_id,0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2193 { "ssl_fc_extlist_bin", smp_fetch_ssl_fc_ext_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2194 { "ssl_fc_eclist_bin", smp_fetch_ssl_fc_ecl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2195 { "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 +02002196
2197/* SSL server certificate fetches */
2198 { "ssl_s_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02002199 { "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 +02002200 { "ssl_s_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2201 { "ssl_s_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2202 { "ssl_s_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2203 { "ssl_s_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2204 { "ssl_s_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2205 { "ssl_s_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2206 { "ssl_s_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2207 { "ssl_s_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2208 { "ssl_s_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
William Lallemand15e16942020-05-15 00:25:08 +02002209 { NULL, NULL, 0, 0, 0 },
2210}};
2211
2212INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
2213
Willy Tarreau99ea1882021-10-06 15:37:17 +02002214/* Note: must not be declared <const> as its list will be overwritten */
2215static struct sample_conv_kw_list sample_conv_kws = {ILH, {
2216 { "sha2", sample_conv_sha2, ARG1(0, SINT), smp_check_sha2, SMP_T_BIN, SMP_T_BIN },
2217#ifdef EVP_CIPH_GCM_MODE
2218 { "aes_gcm_dec", sample_conv_aes_gcm_dec, ARG4(4,SINT,STR,STR,STR), check_aes_gcm, SMP_T_BIN, SMP_T_BIN },
2219#endif
2220 { "digest", sample_conv_crypto_digest, ARG1(1,STR), check_crypto_digest, SMP_T_BIN, SMP_T_BIN },
2221 { "hmac", sample_conv_crypto_hmac, ARG2(2,STR,STR), check_crypto_hmac, SMP_T_BIN, SMP_T_BIN },
2222#if defined(HAVE_CRYPTO_memcmp)
2223 { "secure_memcmp", sample_conv_secure_memcmp, ARG1(1,STR), smp_check_secure_memcmp, SMP_T_BIN, SMP_T_BOOL },
2224#endif
2225 { NULL, NULL, 0, 0, 0 },
2226}};
2227
2228INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
2229
2230
William Lallemand15e16942020-05-15 00:25:08 +02002231/* Note: must not be declared <const> as its list will be overwritten.
2232 * Please take care of keeping this list alphabetically sorted.
2233 */
2234static struct acl_kw_list acl_kws = {ILH, {
2235 { "ssl_fc_sni_end", "ssl_fc_sni", PAT_MATCH_END },
2236 { "ssl_fc_sni_reg", "ssl_fc_sni", PAT_MATCH_REG },
2237 { /* END */ },
2238}};
2239
2240INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);