blob: e9098e9cba6ec3dbb1023047ea905120f7a89107 [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;
120 if (arg_p->data.sint)
121 bits = arg_p->data.sint;
122
123 switch (bits) {
124 case 224: {
125 SHA256_CTX ctx;
126
127 memset(&ctx, 0, sizeof(ctx));
128
129 SHA224_Init(&ctx);
130 SHA224_Update(&ctx, smp->data.u.str.area, smp->data.u.str.data);
131 SHA224_Final((unsigned char *) trash->area, &ctx);
132 trash->data = SHA224_DIGEST_LENGTH;
133 break;
134 }
135 case 256: {
136 SHA256_CTX ctx;
137
138 memset(&ctx, 0, sizeof(ctx));
139
140 SHA256_Init(&ctx);
141 SHA256_Update(&ctx, smp->data.u.str.area, smp->data.u.str.data);
142 SHA256_Final((unsigned char *) trash->area, &ctx);
143 trash->data = SHA256_DIGEST_LENGTH;
144 break;
145 }
146 case 384: {
147 SHA512_CTX ctx;
148
149 memset(&ctx, 0, sizeof(ctx));
150
151 SHA384_Init(&ctx);
152 SHA384_Update(&ctx, smp->data.u.str.area, smp->data.u.str.data);
153 SHA384_Final((unsigned char *) trash->area, &ctx);
154 trash->data = SHA384_DIGEST_LENGTH;
155 break;
156 }
157 case 512: {
158 SHA512_CTX ctx;
159
160 memset(&ctx, 0, sizeof(ctx));
161
162 SHA512_Init(&ctx);
163 SHA512_Update(&ctx, smp->data.u.str.area, smp->data.u.str.data);
164 SHA512_Final((unsigned char *) trash->area, &ctx);
165 trash->data = SHA512_DIGEST_LENGTH;
166 break;
167 }
168 default:
169 return 0;
170 }
171
172 smp->data.u.str = *trash;
173 smp->data.type = SMP_T_BIN;
174 smp->flags &= ~SMP_F_CONST;
175 return 1;
176}
177
178/* This function checks an <arg> and fills it with a variable type if the
179 * <arg> string contains a valid variable name. If failed, the function
180 * tries to perform a base64 decode operation on the same string, and
181 * fills the <arg> with the decoded content.
182 *
183 * Validation is skipped if the <arg> string is empty.
184 *
185 * This function returns 0 if the variable lookup fails and the specified
186 * <arg> string is not a valid base64 encoded string, as well if
187 * unexpected argument type is specified or memory allocation error
188 * occurs. Otherwise it returns 1.
189 */
190static inline int sample_check_arg_base64(struct arg *arg, char **err)
191{
192 char *dec = NULL;
193 int dec_size;
194
195 if (arg->type != ARGT_STR) {
196 memprintf(err, "unexpected argument type");
197 return 0;
198 }
199
200 if (arg->data.str.data == 0) /* empty */
201 return 1;
202
203 if (vars_check_arg(arg, NULL))
204 return 1;
205
206 if (arg->data.str.data % 4) {
207 memprintf(err, "argument needs to be base64 encoded, and "
208 "can either be a string or a variable");
209 return 0;
210 }
211
212 dec_size = (arg->data.str.data / 4 * 3)
213 - (arg->data.str.area[arg->data.str.data-1] == '=' ? 1 : 0)
214 - (arg->data.str.area[arg->data.str.data-2] == '=' ? 1 : 0);
215
216 if ((dec = malloc(dec_size)) == NULL) {
217 memprintf(err, "memory allocation error");
218 return 0;
219 }
220
221 dec_size = base64dec(arg->data.str.area, arg->data.str.data, dec, dec_size);
222 if (dec_size < 0) {
223 memprintf(err, "argument needs to be base64 encoded, and "
224 "can either be a string or a variable");
225 free(dec);
226 return 0;
227 }
228
229 /* base64 decoded */
230 chunk_destroy(&arg->data.str);
231 arg->data.str.area = dec;
232 arg->data.str.data = dec_size;
233 return 1;
234}
235
236#ifdef EVP_CIPH_GCM_MODE
237static int check_aes_gcm(struct arg *args, struct sample_conv *conv,
238 const char *file, int line, char **err)
239{
240 switch(args[0].data.sint) {
241 case 128:
242 case 192:
243 case 256:
244 break;
245 default:
246 memprintf(err, "key size must be 128, 192 or 256 (bits).");
247 return 0;
248 }
249
250 /* Try to decode variables. */
251 if (!sample_check_arg_base64(&args[1], err)) {
252 memprintf(err, "failed to parse nonce : %s", *err);
253 return 0;
254 }
255 if (!sample_check_arg_base64(&args[2], err)) {
256 memprintf(err, "failed to parse key : %s", *err);
257 return 0;
258 }
259 if (!sample_check_arg_base64(&args[3], err)) {
260 memprintf(err, "failed to parse aead_tag : %s", *err);
261 return 0;
262 }
263
264 return 1;
265}
266
267/* Arguments: AES size in bits, nonce, key, tag. The last three arguments are base64 encoded */
268static int sample_conv_aes_gcm_dec(const struct arg *arg_p, struct sample *smp, void *private)
269{
270 struct sample nonce, key, aead_tag;
271 struct buffer *smp_trash = NULL, *smp_trash_alloc = NULL;
272 EVP_CIPHER_CTX *ctx;
273 int dec_size, ret;
274
275 smp_trash_alloc = alloc_trash_chunk();
276 if (!smp_trash_alloc)
277 return 0;
278
279 /* smp copy */
280 smp_trash_alloc->data = smp->data.u.str.data;
281 if (unlikely(smp_trash_alloc->data > smp_trash_alloc->size))
282 smp_trash_alloc->data = smp_trash_alloc->size;
283 memcpy(smp_trash_alloc->area, smp->data.u.str.area, smp_trash_alloc->data);
284
285 ctx = EVP_CIPHER_CTX_new();
286
287 if (!ctx)
288 goto err;
289
290 smp_trash = alloc_trash_chunk();
291 if (!smp_trash)
292 goto err;
293
294 smp_set_owner(&nonce, smp->px, smp->sess, smp->strm, smp->opt);
295 if (!sample_conv_var2smp_str(&arg_p[1], &nonce))
296 goto err;
297
298 if (arg_p[1].type == ARGT_VAR) {
299 dec_size = base64dec(nonce.data.u.str.area, nonce.data.u.str.data, smp_trash->area, smp_trash->size);
300 if (dec_size < 0)
301 goto err;
302 smp_trash->data = dec_size;
303 nonce.data.u.str = *smp_trash;
304 }
305
306 /* Set cipher type and mode */
307 switch(arg_p[0].data.sint) {
308 case 128:
309 EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);
310 break;
311 case 192:
312 EVP_DecryptInit_ex(ctx, EVP_aes_192_gcm(), NULL, NULL, NULL);
313 break;
314 case 256:
315 EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
316 break;
317 }
318
319 EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce.data.u.str.data, NULL);
320
321 /* Initialise IV */
322 if(!EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, (unsigned char *) nonce.data.u.str.area))
323 goto err;
324
325 smp_set_owner(&key, smp->px, smp->sess, smp->strm, smp->opt);
326 if (!sample_conv_var2smp_str(&arg_p[2], &key))
327 goto err;
328
329 if (arg_p[2].type == ARGT_VAR) {
330 dec_size = base64dec(key.data.u.str.area, key.data.u.str.data, smp_trash->area, smp_trash->size);
331 if (dec_size < 0)
332 goto err;
333 smp_trash->data = dec_size;
334 key.data.u.str = *smp_trash;
335 }
336
337 /* Initialise key */
338 if (!EVP_DecryptInit_ex(ctx, NULL, NULL, (unsigned char *) key.data.u.str.area, NULL))
339 goto err;
340
341 if (!EVP_DecryptUpdate(ctx, (unsigned char *) smp_trash->area, (int *) &smp_trash->data,
342 (unsigned char *) smp_trash_alloc->area, (int) smp_trash_alloc->data))
343 goto err;
344
345 smp_set_owner(&aead_tag, smp->px, smp->sess, smp->strm, smp->opt);
346 if (!sample_conv_var2smp_str(&arg_p[3], &aead_tag))
347 goto err;
348
349 if (arg_p[3].type == ARGT_VAR) {
350 dec_size = base64dec(aead_tag.data.u.str.area, aead_tag.data.u.str.data, smp_trash_alloc->area, smp_trash_alloc->size);
351 if (dec_size < 0)
352 goto err;
353 smp_trash_alloc->data = dec_size;
354 aead_tag.data.u.str = *smp_trash_alloc;
355 }
356
357 dec_size = smp_trash->data;
358
359 EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, aead_tag.data.u.str.data, (void *) aead_tag.data.u.str.area);
360 ret = EVP_DecryptFinal_ex(ctx, (unsigned char *) smp_trash->area + smp_trash->data, (int *) &smp_trash->data);
361
362 if (ret <= 0)
363 goto err;
364
365 smp->data.u.str.data = dec_size + smp_trash->data;
366 smp->data.u.str.area = smp_trash->area;
367 smp->data.type = SMP_T_BIN;
368 smp_dup(smp);
369 free_trash_chunk(smp_trash_alloc);
370 free_trash_chunk(smp_trash);
371 return 1;
372
373err:
374 free_trash_chunk(smp_trash_alloc);
375 free_trash_chunk(smp_trash);
376 return 0;
377}
378#endif
379
380static int check_crypto_digest(struct arg *args, struct sample_conv *conv,
381 const char *file, int line, char **err)
382{
383 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
384
385 if (evp)
386 return 1;
387
388 memprintf(err, "algorithm must be a valid OpenSSL message digest name.");
389 return 0;
390}
391
392static int sample_conv_crypto_digest(const struct arg *args, struct sample *smp, void *private)
393{
394 struct buffer *trash = get_trash_chunk();
395 unsigned char *md = (unsigned char*) trash->area;
396 unsigned int md_len = trash->size;
397 EVP_MD_CTX *ctx = EVP_MD_CTX_new();
398 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
399
400 if (!ctx)
401 return 0;
402
403 if (!EVP_DigestInit_ex(ctx, evp, NULL) ||
404 !EVP_DigestUpdate(ctx, smp->data.u.str.area, smp->data.u.str.data) ||
405 !EVP_DigestFinal_ex(ctx, md, &md_len)) {
406 EVP_MD_CTX_free(ctx);
407 return 0;
408 }
409
410 EVP_MD_CTX_free(ctx);
411
412 trash->data = md_len;
413 smp->data.u.str = *trash;
414 smp->data.type = SMP_T_BIN;
415 smp->flags &= ~SMP_F_CONST;
416 return 1;
417}
418
419static int check_crypto_hmac(struct arg *args, struct sample_conv *conv,
420 const char *file, int line, char **err)
421{
422 if (!check_crypto_digest(args, conv, file, line, err))
423 return 0;
424
425 if (!sample_check_arg_base64(&args[1], err)) {
426 memprintf(err, "failed to parse key : %s", *err);
427 return 0;
428 }
429
430 return 1;
431}
432
433static int sample_conv_crypto_hmac(const struct arg *args, struct sample *smp, void *private)
434{
435 struct sample key;
436 struct buffer *trash = NULL, *key_trash = NULL;
437 unsigned char *md;
438 unsigned int md_len;
439 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
440 int dec_size;
441
442 smp_set_owner(&key, smp->px, smp->sess, smp->strm, smp->opt);
443 if (!sample_conv_var2smp_str(&args[1], &key))
444 return 0;
445
446 if (args[1].type == ARGT_VAR) {
447 key_trash = alloc_trash_chunk();
448 if (!key_trash)
449 goto err;
450
451 dec_size = base64dec(key.data.u.str.area, key.data.u.str.data, key_trash->area, key_trash->size);
452 if (dec_size < 0)
453 goto err;
454 key_trash->data = dec_size;
455 key.data.u.str = *key_trash;
456 }
457
458 trash = alloc_trash_chunk();
459 if (!trash)
460 goto err;
461
462 md = (unsigned char*) trash->area;
463 md_len = trash->size;
464 if (!HMAC(evp, key.data.u.str.area, key.data.u.str.data, (const unsigned char*) smp->data.u.str.area,
465 smp->data.u.str.data, md, &md_len))
466 goto err;
467
468 free_trash_chunk(key_trash);
469
470 trash->data = md_len;
471 smp->data.u.str = *trash;
472 smp->data.type = SMP_T_BIN;
473 smp_dup(smp);
474 free_trash_chunk(trash);
475 return 1;
476
477err:
478 free_trash_chunk(key_trash);
479 free_trash_chunk(trash);
480 return 0;
481}
482
William Lallemand15e16942020-05-15 00:25:08 +0200483static int
484smp_fetch_ssl_fc_has_early(const struct arg *args, struct sample *smp, const char *kw, void *private)
485{
486 SSL *ssl;
487 struct connection *conn;
488
489 conn = objt_conn(smp->sess->origin);
490 ssl = ssl_sock_get_ssl_object(conn);
491 if (!ssl)
492 return 0;
493
494 smp->flags = 0;
495 smp->data.type = SMP_T_BOOL;
496#ifdef OPENSSL_IS_BORINGSSL
497 {
498 smp->data.u.sint = (SSL_in_early_data(ssl) &&
499 SSL_early_data_accepted(ssl));
500 }
501#else
502 smp->data.u.sint = ((conn->flags & CO_FL_EARLY_DATA) &&
503 (conn->flags & (CO_FL_EARLY_SSL_HS | CO_FL_SSL_WAIT_HS))) ? 1 : 0;
504#endif
505 return 1;
506}
507
508/* boolean, returns true if client cert was present */
509static int
510smp_fetch_ssl_fc_has_crt(const struct arg *args, struct sample *smp, const char *kw, void *private)
511{
512 struct connection *conn;
513 struct ssl_sock_ctx *ctx;
514
515 conn = objt_conn(smp->sess->origin);
516 if (!conn || conn->xprt != &ssl_sock)
517 return 0;
518
519 ctx = conn->xprt_ctx;
520
521 if (conn->flags & CO_FL_WAIT_XPRT) {
522 smp->flags |= SMP_F_MAY_CHANGE;
523 return 0;
524 }
525
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200526 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200527 smp->data.type = SMP_T_BOOL;
528 smp->data.u.sint = SSL_SOCK_ST_FL_VERIFY_DONE & ctx->xprt_st ? 1 : 0;
529
530 return 1;
531}
532
533/* binary, returns a certificate in a binary chunk (der/raw).
534 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
535 * should be use.
536 */
537static int
538smp_fetch_ssl_x_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
539{
William Lallemandbfa3e812020-06-25 20:07:18 +0200540 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
541 int conn_server = (kw[4] == 's') ? 1 : 0;
542
William Lallemand15e16942020-05-15 00:25:08 +0200543 X509 *crt = NULL;
544 int ret = 0;
545 struct buffer *smp_trash;
546 struct connection *conn;
547 SSL *ssl;
548
William Lallemandbfa3e812020-06-25 20:07:18 +0200549 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200550 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200551 else
552 conn = objt_conn(smp->sess->origin);
553
William Lallemand15e16942020-05-15 00:25:08 +0200554 ssl = ssl_sock_get_ssl_object(conn);
555 if (!ssl)
556 return 0;
557
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200558 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200559 smp->flags |= SMP_F_MAY_CHANGE;
560 return 0;
561 }
562
563 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200564 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200565 else
566 crt = SSL_get_certificate(ssl);
567
568 if (!crt)
569 goto out;
570
571 smp_trash = get_trash_chunk();
572 if (ssl_sock_crt2der(crt, smp_trash) <= 0)
573 goto out;
574
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200575 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200576 smp->data.u.str = *smp_trash;
577 smp->data.type = SMP_T_BIN;
578 ret = 1;
579out:
580 /* SSL_get_peer_certificate, it increase X509 * ref count */
581 if (cert_peer && crt)
582 X509_free(crt);
583 return ret;
584}
585
William Dauchya598b502020-08-06 18:11:38 +0200586/* binary, returns a chain certificate in a binary chunk (der/raw).
587 * The 5th keyword char is used to support only peer cert
588 */
589static int
590smp_fetch_ssl_x_chain_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
591{
592 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
593 int conn_server = (kw[4] == 's') ? 1 : 0;
594 struct buffer *smp_trash;
595 struct buffer *tmp_trash = NULL;
596 struct connection *conn;
597 STACK_OF(X509) *certs = NULL;
598 X509 *crt = NULL;
599 SSL *ssl;
600 int ret = 0;
601 int num_certs;
602 int i;
603
604 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200605 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Dauchya598b502020-08-06 18:11:38 +0200606 else
607 conn = objt_conn(smp->sess->origin);
608
609 if (!conn)
610 return 0;
611
612 ssl = ssl_sock_get_ssl_object(conn);
613 if (!ssl)
614 return 0;
615
616 if (conn->flags & CO_FL_WAIT_XPRT) {
617 smp->flags |= SMP_F_MAY_CHANGE;
618 return 0;
619 }
620
621 if (!cert_peer)
622 return 0;
623
624 certs = SSL_get_peer_cert_chain(ssl);
625 if (!certs)
626 return 0;
627
628 num_certs = sk_X509_num(certs);
629 if (!num_certs)
630 goto out;
631 smp_trash = get_trash_chunk();
632 tmp_trash = alloc_trash_chunk();
633 if (!tmp_trash)
634 goto out;
635 for (i = 0; i < num_certs; i++) {
636 crt = sk_X509_value(certs, i);
637 if (ssl_sock_crt2der(crt, tmp_trash) <= 0)
638 goto out;
639 chunk_cat(smp_trash, tmp_trash);
640 }
641
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200642 smp->flags = SMP_F_VOL_SESS;
William Dauchya598b502020-08-06 18:11:38 +0200643 smp->data.u.str = *smp_trash;
644 smp->data.type = SMP_T_BIN;
645 ret = 1;
646out:
647 if (tmp_trash)
648 free_trash_chunk(tmp_trash);
William Dauchya598b502020-08-06 18:11:38 +0200649 return ret;
650}
651
William Lallemand15e16942020-05-15 00:25:08 +0200652/* binary, returns serial of certificate in a binary chunk.
653 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
654 * should be use.
655 */
656static int
657smp_fetch_ssl_x_serial(const struct arg *args, struct sample *smp, const char *kw, void *private)
658{
William Lallemandbfa3e812020-06-25 20:07:18 +0200659 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
660 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200661 X509 *crt = NULL;
662 int ret = 0;
663 struct buffer *smp_trash;
664 struct connection *conn;
665 SSL *ssl;
666
William Lallemandbfa3e812020-06-25 20:07:18 +0200667 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200668 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200669 else
670 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +0200671 ssl = ssl_sock_get_ssl_object(conn);
672 if (!ssl)
673 return 0;
674
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200675 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200676 smp->flags |= SMP_F_MAY_CHANGE;
677 return 0;
678 }
679
680 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200681 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200682 else
683 crt = SSL_get_certificate(ssl);
684
685 if (!crt)
686 goto out;
687
688 smp_trash = get_trash_chunk();
689 if (ssl_sock_get_serial(crt, smp_trash) <= 0)
690 goto out;
691
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200692 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200693 smp->data.u.str = *smp_trash;
694 smp->data.type = SMP_T_BIN;
695 ret = 1;
696out:
697 /* SSL_get_peer_certificate, it increase X509 * ref count */
698 if (cert_peer && crt)
699 X509_free(crt);
700 return ret;
701}
702
703/* binary, returns the client certificate's SHA-1 fingerprint (SHA-1 hash of DER-encoded certificate) in a binary chunk.
704 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
705 * should be use.
706 */
707static int
708smp_fetch_ssl_x_sha1(const struct arg *args, struct sample *smp, const char *kw, void *private)
709{
William Lallemandbfa3e812020-06-25 20:07:18 +0200710 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
711 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200712 X509 *crt = NULL;
713 const EVP_MD *digest;
714 int ret = 0;
715 unsigned int len = 0;
716 struct buffer *smp_trash;
717 struct connection *conn;
718 SSL *ssl;
719
William Lallemandbfa3e812020-06-25 20:07:18 +0200720 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200721 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200722 else
723 conn = objt_conn(smp->sess->origin);
724
William Lallemand15e16942020-05-15 00:25:08 +0200725 ssl = ssl_sock_get_ssl_object(conn);
726 if (!ssl)
727 return 0;
728
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200729 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200730 smp->flags |= SMP_F_MAY_CHANGE;
731 return 0;
732 }
733
734 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200735 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200736 else
737 crt = SSL_get_certificate(ssl);
738 if (!crt)
739 goto out;
740
741 smp_trash = get_trash_chunk();
742 digest = EVP_sha1();
743 X509_digest(crt, digest, (unsigned char *) smp_trash->area, &len);
744 smp_trash->data = len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200745 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200746 smp->data.u.str = *smp_trash;
747 smp->data.type = SMP_T_BIN;
748 ret = 1;
749out:
750 /* SSL_get_peer_certificate, it increase X509 * ref count */
751 if (cert_peer && crt)
752 X509_free(crt);
753 return ret;
754}
755
756/* string, returns certificate's notafter date in ASN1_UTCTIME format.
757 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
758 * should be use.
759 */
760static int
761smp_fetch_ssl_x_notafter(const struct arg *args, struct sample *smp, const char *kw, void *private)
762{
William Lallemandbfa3e812020-06-25 20:07:18 +0200763 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
764 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200765 X509 *crt = NULL;
766 int ret = 0;
767 struct buffer *smp_trash;
768 struct connection *conn;
769 SSL *ssl;
770
William Lallemandbfa3e812020-06-25 20:07:18 +0200771 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200772 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200773 else
774 conn = objt_conn(smp->sess->origin);
775
William Lallemand15e16942020-05-15 00:25:08 +0200776 ssl = ssl_sock_get_ssl_object(conn);
777 if (!ssl)
778 return 0;
779
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200780 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200781 smp->flags |= SMP_F_MAY_CHANGE;
782 return 0;
783 }
784
785 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200786 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200787 else
788 crt = SSL_get_certificate(ssl);
789 if (!crt)
790 goto out;
791
792 smp_trash = get_trash_chunk();
793 if (ssl_sock_get_time(X509_getm_notAfter(crt), smp_trash) <= 0)
794 goto out;
795
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200796 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200797 smp->data.u.str = *smp_trash;
798 smp->data.type = SMP_T_STR;
799 ret = 1;
800out:
801 /* SSL_get_peer_certificate, it increase X509 * ref count */
802 if (cert_peer && crt)
803 X509_free(crt);
804 return ret;
805}
806
807/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's issuer
808 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
809 * should be use.
810 */
811static int
812smp_fetch_ssl_x_i_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
813{
William Lallemandbfa3e812020-06-25 20:07:18 +0200814 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
815 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200816 X509 *crt = NULL;
817 X509_NAME *name;
818 int ret = 0;
819 struct buffer *smp_trash;
820 struct connection *conn;
821 SSL *ssl;
822
William Lallemandbfa3e812020-06-25 20:07:18 +0200823 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200824 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200825 else
826 conn = objt_conn(smp->sess->origin);
827
William Lallemand15e16942020-05-15 00:25:08 +0200828 ssl = ssl_sock_get_ssl_object(conn);
829 if (!ssl)
830 return 0;
831
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200832 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200833 smp->flags |= SMP_F_MAY_CHANGE;
834 return 0;
835 }
836
837 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200838 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200839 else
840 crt = SSL_get_certificate(ssl);
841 if (!crt)
842 goto out;
843
844 name = X509_get_issuer_name(crt);
845 if (!name)
846 goto out;
847
848 smp_trash = get_trash_chunk();
Christopher Faulet3702f782021-01-29 11:30:37 +0100849 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200850 int pos = 1;
851
852 if (args[1].type == ARGT_SINT)
853 pos = args[1].data.sint;
854
855 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
856 goto out;
857 }
Christopher Faulet3702f782021-01-29 11:30:37 +0100858 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200859 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
860 goto out;
861 }
862 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
863 goto out;
864
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200865 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200866 smp->data.type = SMP_T_STR;
867 smp->data.u.str = *smp_trash;
868 ret = 1;
869out:
870 /* SSL_get_peer_certificate, it increase X509 * ref count */
871 if (cert_peer && crt)
872 X509_free(crt);
873 return ret;
874}
875
876/* string, returns notbefore date in ASN1_UTCTIME format.
877 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
878 * should be use.
879 */
880static int
881smp_fetch_ssl_x_notbefore(const struct arg *args, struct sample *smp, const char *kw, void *private)
882{
William Lallemandbfa3e812020-06-25 20:07:18 +0200883 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
884 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200885 X509 *crt = NULL;
886 int ret = 0;
887 struct buffer *smp_trash;
888 struct connection *conn;
889 SSL *ssl;
890
William Lallemandbfa3e812020-06-25 20:07:18 +0200891 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200892 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200893 else
894 conn = objt_conn(smp->sess->origin);
895
William Lallemand15e16942020-05-15 00:25:08 +0200896 ssl = ssl_sock_get_ssl_object(conn);
897 if (!ssl)
898 return 0;
899
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200900 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200901 smp->flags |= SMP_F_MAY_CHANGE;
902 return 0;
903 }
904
905 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200906 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200907 else
908 crt = SSL_get_certificate(ssl);
909 if (!crt)
910 goto out;
911
912 smp_trash = get_trash_chunk();
913 if (ssl_sock_get_time(X509_getm_notBefore(crt), smp_trash) <= 0)
914 goto out;
915
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200916 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200917 smp->data.u.str = *smp_trash;
918 smp->data.type = SMP_T_STR;
919 ret = 1;
920out:
921 /* SSL_get_peer_certificate, it increase X509 * ref count */
922 if (cert_peer && crt)
923 X509_free(crt);
924 return ret;
925}
926
927/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's subject
928 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
929 * should be use.
930 */
931static int
932smp_fetch_ssl_x_s_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
933{
William Lallemandbfa3e812020-06-25 20:07:18 +0200934 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
935 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200936 X509 *crt = NULL;
937 X509_NAME *name;
938 int ret = 0;
939 struct buffer *smp_trash;
940 struct connection *conn;
941 SSL *ssl;
942
William Lallemandbfa3e812020-06-25 20:07:18 +0200943 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +0200944 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200945 else
946 conn = objt_conn(smp->sess->origin);
947
William Lallemand15e16942020-05-15 00:25:08 +0200948 ssl = ssl_sock_get_ssl_object(conn);
949 if (!ssl)
950 return 0;
951
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200952 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200953 smp->flags |= SMP_F_MAY_CHANGE;
954 return 0;
955 }
956
957 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200958 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200959 else
960 crt = SSL_get_certificate(ssl);
961 if (!crt)
962 goto out;
963
964 name = X509_get_subject_name(crt);
965 if (!name)
966 goto out;
967
968 smp_trash = get_trash_chunk();
Christopher Faulet3702f782021-01-29 11:30:37 +0100969 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200970 int pos = 1;
971
972 if (args[1].type == ARGT_SINT)
973 pos = args[1].data.sint;
974
975 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
976 goto out;
977 }
Christopher Faulet3702f782021-01-29 11:30:37 +0100978 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200979 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
980 goto out;
981 }
982 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
983 goto out;
984
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200985 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200986 smp->data.type = SMP_T_STR;
987 smp->data.u.str = *smp_trash;
988 ret = 1;
989out:
990 /* SSL_get_peer_certificate, it increase X509 * ref count */
991 if (cert_peer && crt)
992 X509_free(crt);
993 return ret;
994}
995
996/* integer, returns true if current session use a client certificate */
997static int
998smp_fetch_ssl_c_used(const struct arg *args, struct sample *smp, const char *kw, void *private)
999{
1000 X509 *crt;
1001 struct connection *conn;
1002 SSL *ssl;
1003
1004 conn = objt_conn(smp->sess->origin);
1005 ssl = ssl_sock_get_ssl_object(conn);
1006 if (!ssl)
1007 return 0;
1008
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001009 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001010 smp->flags |= SMP_F_MAY_CHANGE;
1011 return 0;
1012 }
1013
1014 /* SSL_get_peer_certificate returns a ptr on allocated X509 struct */
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001015 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001016 if (crt) {
1017 X509_free(crt);
1018 }
1019
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001020 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001021 smp->data.type = SMP_T_BOOL;
1022 smp->data.u.sint = (crt != NULL);
1023 return 1;
1024}
1025
1026/* integer, returns the certificate version
1027 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1028 * should be use.
1029 */
1030static int
1031smp_fetch_ssl_x_version(const struct arg *args, struct sample *smp, const char *kw, void *private)
1032{
William Lallemandbfa3e812020-06-25 20:07:18 +02001033 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1034 int conn_server = (kw[4] == 's') ? 1 : 0;
1035
William Lallemand15e16942020-05-15 00:25:08 +02001036 X509 *crt;
1037 struct connection *conn;
1038 SSL *ssl;
1039
William Lallemandbfa3e812020-06-25 20:07:18 +02001040 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +02001041 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001042 else
1043 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +02001044 ssl = ssl_sock_get_ssl_object(conn);
1045 if (!ssl)
1046 return 0;
1047
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001048 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001049 smp->flags |= SMP_F_MAY_CHANGE;
1050 return 0;
1051 }
1052
1053 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001054 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001055 else
1056 crt = SSL_get_certificate(ssl);
1057 if (!crt)
1058 return 0;
1059
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001060 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001061 smp->data.u.sint = (unsigned int)(1 + X509_get_version(crt));
1062 /* SSL_get_peer_certificate increase X509 * ref count */
1063 if (cert_peer)
1064 X509_free(crt);
1065 smp->data.type = SMP_T_SINT;
1066
1067 return 1;
1068}
1069
1070/* string, returns the certificate's signature algorithm.
1071 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1072 * should be use.
1073 */
1074static int
1075smp_fetch_ssl_x_sig_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
1076{
William Lallemandbfa3e812020-06-25 20:07:18 +02001077 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1078 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +02001079 X509 *crt;
1080 __OPENSSL_110_CONST__ ASN1_OBJECT *algorithm;
1081 int nid;
1082 struct connection *conn;
1083 SSL *ssl;
1084
William Lallemandbfa3e812020-06-25 20:07:18 +02001085 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +02001086 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001087 else
1088 conn = objt_conn(smp->sess->origin);
1089
William Lallemand15e16942020-05-15 00:25:08 +02001090 ssl = ssl_sock_get_ssl_object(conn);
1091 if (!ssl)
1092 return 0;
1093
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001094 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001095 smp->flags |= SMP_F_MAY_CHANGE;
1096 return 0;
1097 }
1098
1099 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001100 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001101 else
1102 crt = SSL_get_certificate(ssl);
1103 if (!crt)
1104 return 0;
1105
1106 X509_ALGOR_get0(&algorithm, NULL, NULL, X509_get0_tbs_sigalg(crt));
1107 nid = OBJ_obj2nid(algorithm);
1108
1109 smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
1110 if (!smp->data.u.str.area) {
1111 /* SSL_get_peer_certificate increase X509 * ref count */
1112 if (cert_peer)
1113 X509_free(crt);
1114 return 0;
1115 }
1116
1117 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001118 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001119 smp->data.u.str.data = strlen(smp->data.u.str.area);
1120 /* SSL_get_peer_certificate increase X509 * ref count */
1121 if (cert_peer)
1122 X509_free(crt);
1123
1124 return 1;
1125}
1126
1127/* string, returns the certificate's key algorithm.
1128 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1129 * should be use.
1130 */
1131static int
1132smp_fetch_ssl_x_key_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
1133{
William Lallemandbfa3e812020-06-25 20:07:18 +02001134 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1135 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +02001136 X509 *crt;
1137 ASN1_OBJECT *algorithm;
1138 int nid;
1139 struct connection *conn;
1140 SSL *ssl;
1141
William Lallemandbfa3e812020-06-25 20:07:18 +02001142 if (conn_server)
Amaury Denoyelle5fcd4282021-07-21 11:50:12 +02001143 conn = smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001144 else
1145 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +02001146 ssl = ssl_sock_get_ssl_object(conn);
1147 if (!ssl)
1148 return 0;
1149
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001150 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001151 smp->flags |= SMP_F_MAY_CHANGE;
1152 return 0;
1153 }
1154
1155 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001156 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001157 else
1158 crt = SSL_get_certificate(ssl);
1159 if (!crt)
1160 return 0;
1161
1162 X509_PUBKEY_get0_param(&algorithm, NULL, NULL, NULL, X509_get_X509_PUBKEY(crt));
1163 nid = OBJ_obj2nid(algorithm);
1164
1165 smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
1166 if (!smp->data.u.str.area) {
1167 /* SSL_get_peer_certificate increase X509 * ref count */
1168 if (cert_peer)
1169 X509_free(crt);
1170 return 0;
1171 }
1172
1173 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001174 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001175 smp->data.u.str.data = strlen(smp->data.u.str.area);
1176 if (cert_peer)
1177 X509_free(crt);
1178
1179 return 1;
1180}
1181
1182/* boolean, returns true if front conn. transport layer is SSL.
1183 * This function is also usable on backend conn if the fetch keyword 5th
1184 * char is 'b'.
1185 */
1186static int
1187smp_fetch_ssl_fc(const struct arg *args, struct sample *smp, const char *kw, void *private)
1188{
1189 struct connection *conn;
1190
1191 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001192 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001193 else
1194 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1195 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1196
1197 smp->data.type = SMP_T_BOOL;
1198 smp->data.u.sint = (conn && conn->xprt == &ssl_sock);
1199 return 1;
1200}
1201
1202/* boolean, returns true if client present a SNI */
1203static int
1204smp_fetch_ssl_fc_has_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
1205{
1206#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1207 struct connection *conn = objt_conn(smp->sess->origin);
1208 SSL *ssl = ssl_sock_get_ssl_object(conn);
1209
1210 smp->data.type = SMP_T_BOOL;
1211 smp->data.u.sint = ssl && SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name) != NULL;
1212 return 1;
1213#else
1214 return 0;
1215#endif
1216}
1217
1218/* boolean, returns true if client session has been resumed.
1219 * This function is also usable on backend conn if the fetch keyword 5th
1220 * char is 'b'.
1221 */
1222static int
1223smp_fetch_ssl_fc_is_resumed(const struct arg *args, struct sample *smp, const char *kw, void *private)
1224{
1225 struct connection *conn;
1226 SSL *ssl;
1227
1228 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001229 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001230 else
1231 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1232 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1233
1234 ssl = ssl_sock_get_ssl_object(conn);
1235
1236 smp->data.type = SMP_T_BOOL;
1237 smp->data.u.sint = ssl && SSL_session_reused(ssl);
1238 return 1;
1239}
1240
1241/* string, returns the used cipher if front conn. transport layer is SSL.
1242 * This function is also usable on backend conn if the fetch keyword 5th
1243 * char is 'b'.
1244 */
1245static int
1246smp_fetch_ssl_fc_cipher(const struct arg *args, struct sample *smp, const char *kw, void *private)
1247{
1248 struct connection *conn;
1249 SSL *ssl;
1250
1251 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001252 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001253 else
1254 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1255 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1256
1257 smp->flags = 0;
1258 ssl = ssl_sock_get_ssl_object(conn);
1259 if (!ssl)
1260 return 0;
1261
1262 smp->data.u.str.area = (char *)SSL_get_cipher_name(ssl);
1263 if (!smp->data.u.str.area)
1264 return 0;
1265
1266 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001267 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001268 smp->data.u.str.data = strlen(smp->data.u.str.area);
1269
1270 return 1;
1271}
1272
1273/* integer, returns the algoritm's keysize if front conn. transport layer
1274 * is SSL.
1275 * This function is also usable on backend conn if the fetch keyword 5th
1276 * char is 'b'.
1277 */
1278static int
1279smp_fetch_ssl_fc_alg_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
1280{
1281 struct connection *conn;
1282 SSL *ssl;
1283 int sint;
1284
1285 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001286 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001287 else
1288 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1289 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1290
1291 smp->flags = 0;
1292 ssl = ssl_sock_get_ssl_object(conn);
1293 if (!ssl)
1294 return 0;
1295
1296 if (!SSL_get_cipher_bits(ssl, &sint))
1297 return 0;
1298
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001299 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001300 smp->data.u.sint = sint;
1301 smp->data.type = SMP_T_SINT;
1302
1303 return 1;
1304}
1305
1306/* integer, returns the used keysize if front conn. transport layer is SSL.
1307 * This function is also usable on backend conn if the fetch keyword 5th
1308 * char is 'b'.
1309 */
1310static int
1311smp_fetch_ssl_fc_use_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
1312{
1313 struct connection *conn;
1314 SSL *ssl;
1315
1316 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001317 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001318 else
1319 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1320 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1321
1322 smp->flags = 0;
1323 ssl = ssl_sock_get_ssl_object(conn);
1324 if (!ssl)
1325 return 0;
1326
1327 smp->data.u.sint = (unsigned int)SSL_get_cipher_bits(ssl, NULL);
1328 if (!smp->data.u.sint)
1329 return 0;
1330
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001331 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001332 smp->data.type = SMP_T_SINT;
1333
1334 return 1;
1335}
1336
1337#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
1338static int
1339smp_fetch_ssl_fc_npn(const struct arg *args, struct sample *smp, const char *kw, void *private)
1340{
1341 struct connection *conn;
1342 SSL *ssl;
1343 unsigned int len = 0;
1344
1345 smp->flags = SMP_F_CONST;
1346 smp->data.type = SMP_T_STR;
1347
1348 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001349 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001350 else
1351 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1352 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1353
1354 ssl = ssl_sock_get_ssl_object(conn);
1355 if (!ssl)
1356 return 0;
1357
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001358 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001359 smp->data.u.str.area = NULL;
1360 SSL_get0_next_proto_negotiated(ssl,
1361 (const unsigned char **)&smp->data.u.str.area,
1362 &len);
1363
1364 if (!smp->data.u.str.area)
1365 return 0;
1366
1367 smp->data.u.str.data = len;
1368 return 1;
1369}
1370#endif
1371
1372#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1373static int
1374smp_fetch_ssl_fc_alpn(const struct arg *args, struct sample *smp, const char *kw, void *private)
1375{
1376 struct connection *conn;
1377 SSL *ssl;
1378 unsigned int len = 0;
1379
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001380 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001381 smp->data.type = SMP_T_STR;
1382
1383 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001384 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001385 else
1386 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1387 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1388
1389 ssl = ssl_sock_get_ssl_object(conn);
1390 if (!ssl)
1391 return 0;
1392
1393 smp->data.u.str.area = NULL;
1394 SSL_get0_alpn_selected(ssl,
1395 (const unsigned char **)&smp->data.u.str.area,
1396 &len);
1397
1398 if (!smp->data.u.str.area)
1399 return 0;
1400
1401 smp->data.u.str.data = len;
1402 return 1;
1403}
1404#endif
1405
1406/* string, returns the used protocol if front conn. transport layer is SSL.
1407 * This function is also usable on backend conn if the fetch keyword 5th
1408 * char is 'b'.
1409 */
1410static int
1411smp_fetch_ssl_fc_protocol(const struct arg *args, struct sample *smp, const char *kw, void *private)
1412{
1413 struct connection *conn;
1414 SSL *ssl;
1415
1416 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001417 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001418 else
1419 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1420 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1421
1422 smp->flags = 0;
1423 ssl = ssl_sock_get_ssl_object(conn);
1424 if (!ssl)
1425 return 0;
1426
1427 smp->data.u.str.area = (char *)SSL_get_version(ssl);
1428 if (!smp->data.u.str.area)
1429 return 0;
1430
1431 smp->data.type = SMP_T_STR;
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.u.str.data = strlen(smp->data.u.str.area);
1434
1435 return 1;
1436}
1437
1438/* binary, returns the SSL stream id if front conn. transport layer is SSL.
1439 * This function is also usable on backend conn if the fetch keyword 5th
1440 * char is 'b'.
1441 */
1442#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1443static int
1444smp_fetch_ssl_fc_session_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1445{
1446 struct connection *conn;
1447 SSL_SESSION *ssl_sess;
1448 SSL *ssl;
1449 unsigned int len = 0;
1450
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001451 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001452 smp->data.type = SMP_T_BIN;
1453
1454 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001455 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001456 else
1457 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1458 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1459
1460 ssl = ssl_sock_get_ssl_object(conn);
1461 if (!ssl)
1462 return 0;
1463
1464 ssl_sess = SSL_get_session(ssl);
1465 if (!ssl_sess)
1466 return 0;
1467
1468 smp->data.u.str.area = (char *)SSL_SESSION_get_id(ssl_sess, &len);
1469 if (!smp->data.u.str.area || !len)
1470 return 0;
1471
1472 smp->data.u.str.data = len;
1473 return 1;
1474}
1475#endif
1476
1477
Ilya Shipitsindf627942021-03-25 00:41:41 +05001478#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02001479static int
1480smp_fetch_ssl_fc_random(const struct arg *args, struct sample *smp, const char *kw, void *private)
1481{
1482 struct connection *conn;
1483 struct buffer *data;
1484 SSL *ssl;
1485
1486 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001487 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001488 else
1489 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1490 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1491
1492 ssl = ssl_sock_get_ssl_object(conn);
1493 if (!ssl)
1494 return 0;
1495
1496 data = get_trash_chunk();
1497 if (kw[7] == 'c')
1498 data->data = SSL_get_client_random(ssl,
1499 (unsigned char *) data->area,
1500 data->size);
1501 else
1502 data->data = SSL_get_server_random(ssl,
1503 (unsigned char *) data->area,
1504 data->size);
1505 if (!data->data)
1506 return 0;
1507
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001508 smp->flags = SMP_F_VOL_TEST;
William Lallemand15e16942020-05-15 00:25:08 +02001509 smp->data.type = SMP_T_BIN;
1510 smp->data.u.str = *data;
1511
1512 return 1;
1513}
1514
1515static int
1516smp_fetch_ssl_fc_session_key(const struct arg *args, struct sample *smp, const char *kw, void *private)
1517{
1518 struct connection *conn;
1519 SSL_SESSION *ssl_sess;
1520 struct buffer *data;
1521 SSL *ssl;
1522
1523 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001524 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001525 else
1526 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1527 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1528
1529 ssl = ssl_sock_get_ssl_object(conn);
1530 if (!ssl)
1531 return 0;
1532
1533 ssl_sess = SSL_get_session(ssl);
1534 if (!ssl_sess)
1535 return 0;
1536
1537 data = get_trash_chunk();
1538 data->data = SSL_SESSION_get_master_key(ssl_sess,
1539 (unsigned char *) data->area,
1540 data->size);
1541 if (!data->data)
1542 return 0;
1543
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001544 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001545 smp->data.type = SMP_T_BIN;
1546 smp->data.u.str = *data;
1547
1548 return 1;
1549}
1550#endif
1551
1552#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1553static int
1554smp_fetch_ssl_fc_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
1555{
1556 struct connection *conn;
1557 SSL *ssl;
1558
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001559 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001560 smp->data.type = SMP_T_STR;
1561
1562 conn = objt_conn(smp->sess->origin);
1563 ssl = ssl_sock_get_ssl_object(conn);
1564 if (!ssl)
1565 return 0;
1566
1567 smp->data.u.str.area = (char *)SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
1568 if (!smp->data.u.str.area)
1569 return 0;
1570
1571 smp->data.u.str.data = strlen(smp->data.u.str.area);
1572 return 1;
1573}
1574#endif
1575
Marcin Deranek959a48c2021-07-13 15:14:21 +02001576/* binary, returns tls client hello cipher list.
1577 * Arguments: filter_option (0,1)
1578 */
William Lallemand15e16942020-05-15 00:25:08 +02001579static int
1580smp_fetch_ssl_fc_cl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1581{
Marcin Deranek959a48c2021-07-13 15:14:21 +02001582 struct buffer *smp_trash;
William Lallemand15e16942020-05-15 00:25:08 +02001583 struct connection *conn;
1584 struct ssl_capture *capture;
1585 SSL *ssl;
1586
1587 conn = objt_conn(smp->sess->origin);
1588 ssl = ssl_sock_get_ssl_object(conn);
1589 if (!ssl)
1590 return 0;
1591
1592 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1593 if (!capture)
1594 return 0;
1595
Marcin Deranek959a48c2021-07-13 15:14:21 +02001596 if (args[0].data.sint) {
1597 smp_trash = get_trash_chunk();
1598 exclude_tls_grease(capture->data + capture->ciphersuite_offset, capture->ciphersuite_len, smp_trash);
1599 smp->data.u.str.area = smp_trash->area;
1600 smp->data.u.str.data = smp_trash->data;
1601 smp->flags = SMP_F_VOL_SESS;
1602 }
1603 else {
1604 smp->data.u.str.area = capture->data + capture->ciphersuite_offset;
1605 smp->data.u.str.data = capture->ciphersuite_len;
1606 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1607 }
1608
William Lallemand15e16942020-05-15 00:25:08 +02001609 smp->data.type = SMP_T_BIN;
William Lallemand15e16942020-05-15 00:25:08 +02001610 return 1;
1611}
1612
Marcin Deranek959a48c2021-07-13 15:14:21 +02001613/* binary, returns tls client hello cipher list as hexadecimal string.
1614 * Arguments: filter_option (0,1)
1615 */
William Lallemand15e16942020-05-15 00:25:08 +02001616static int
1617smp_fetch_ssl_fc_cl_hex(const struct arg *args, struct sample *smp, const char *kw, void *private)
1618{
1619 struct buffer *data;
1620
1621 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1622 return 0;
1623
1624 data = get_trash_chunk();
1625 dump_binary(data, smp->data.u.str.area, smp->data.u.str.data);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001626 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001627 smp->data.type = SMP_T_BIN;
1628 smp->data.u.str = *data;
1629 return 1;
1630}
1631
Marcin Deranek959a48c2021-07-13 15:14:21 +02001632/* integer, returns xxh64 hash of tls client hello cipher list. */
William Lallemand15e16942020-05-15 00:25:08 +02001633static int
1634smp_fetch_ssl_fc_cl_xxh64(const struct arg *args, struct sample *smp, const char *kw, void *private)
1635{
1636 struct connection *conn;
1637 struct ssl_capture *capture;
1638 SSL *ssl;
1639
1640 conn = objt_conn(smp->sess->origin);
1641 ssl = ssl_sock_get_ssl_object(conn);
1642 if (!ssl)
1643 return 0;
1644
1645 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1646 if (!capture)
1647 return 0;
1648
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001649 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001650 smp->data.type = SMP_T_SINT;
1651 smp->data.u.sint = capture->xxh64;
1652 return 1;
1653}
1654
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001655static int
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001656smp_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 +02001657{
1658 struct connection *conn;
1659 struct ssl_sock_ctx *ctx;
1660
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001661 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
1662 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
1663 else
1664 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1665 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1666
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001667 if (!conn || conn->xprt != &ssl_sock)
1668 return 0;
1669 ctx = conn->xprt_ctx;
1670
1671 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1672 smp->flags = SMP_F_MAY_CHANGE;
1673 return 0;
1674 }
1675
1676 if (!ctx)
1677 return 0;
1678
1679 smp->flags = SMP_F_VOL_SESS;
1680 smp->data.type = SMP_T_SINT;
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001681 smp->data.u.sint = ctx->error_code;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001682 return 1;
1683}
1684
1685static int
Marcin Deranek959a48c2021-07-13 15:14:21 +02001686smp_fetch_ssl_fc_protocol_hello_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1687{
1688 struct connection *conn;
1689 struct ssl_capture *capture;
1690 SSL *ssl;
1691
1692 conn = objt_conn(smp->sess->origin);
1693 ssl = ssl_sock_get_ssl_object(conn);
1694 if (!ssl)
1695 return 0;
1696
1697 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1698 if (!capture)
1699 return 0;
1700
1701 smp->flags = SMP_F_VOL_SESS;
1702 smp->data.type = SMP_T_SINT;
1703 smp->data.u.sint = capture->protocol_version;
1704 return 1;
1705}
1706
1707static int
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001708smp_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 +02001709{
1710 struct connection *conn;
1711 struct ssl_sock_ctx *ctx;
1712 const char *err_code_str;
1713
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001714 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
1715 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
1716 else
1717 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1718 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1719
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001720 if (!conn || conn->xprt != &ssl_sock)
1721 return 0;
1722 ctx = conn->xprt_ctx;
1723
1724 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1725 smp->flags = SMP_F_MAY_CHANGE;
1726 return 0;
1727 }
1728
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001729 if (!ctx || !ctx->error_code)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001730 return 0;
1731
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001732 err_code_str = ERR_error_string(ctx->error_code, NULL);
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001733
1734 smp->flags = SMP_F_VOL_SESS;
1735 smp->data.type = SMP_T_STR;
1736 smp->data.u.str.area = (char*)err_code_str;
1737 smp->data.u.str.data = strlen(err_code_str);
1738
Marcin Deranek959a48c2021-07-13 15:14:21 +02001739 return 1;
1740}
1741
1742/* binary, returns tls client hello extensions list.
1743 * Arguments: filter_option (0,1)
1744 */
1745static int
1746smp_fetch_ssl_fc_ext_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1747{
1748 struct buffer *smp_trash;
1749 struct connection *conn;
1750 struct ssl_capture *capture;
1751 SSL *ssl;
1752
1753 conn = objt_conn(smp->sess->origin);
1754 ssl = ssl_sock_get_ssl_object(conn);
1755 if (!ssl)
1756 return 0;
1757
1758 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1759 if (!capture)
1760 return 0;
1761
1762 if (args[0].data.sint) {
1763 smp_trash = get_trash_chunk();
1764 exclude_tls_grease(capture->data + capture->extensions_offset, capture->extensions_len, smp_trash);
1765 smp->data.u.str.area = smp_trash->area;
1766 smp->data.u.str.data = smp_trash->data;
1767 smp->flags = SMP_F_VOL_SESS;
1768 }
1769 else {
1770 smp->data.u.str.area = capture->data + capture->extensions_offset;
1771 smp->data.u.str.data = capture->extensions_len;
1772 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1773 }
1774
1775 smp->data.type = SMP_T_BIN;
1776 return 1;
1777}
1778
1779/* binary, returns tls client hello supported elliptic curves.
1780 * Arguments: filter_option (0,1)
1781 */
1782static int
1783smp_fetch_ssl_fc_ecl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1784{
1785 struct buffer *smp_trash;
1786 struct connection *conn;
1787 struct ssl_capture *capture;
1788 SSL *ssl;
1789
1790 conn = objt_conn(smp->sess->origin);
1791 ssl = ssl_sock_get_ssl_object(conn);
1792 if (!ssl)
1793 return 0;
1794
1795 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1796 if (!capture)
1797 return 0;
1798
1799 if (args[0].data.sint) {
1800 smp_trash = get_trash_chunk();
1801 exclude_tls_grease(capture->data + capture->ec_offset, capture->ec_len, smp_trash);
1802 smp->data.u.str.area = smp_trash->area;
1803 smp->data.u.str.data = smp_trash->data;
1804 smp->flags = SMP_F_VOL_SESS;
1805 }
1806 else {
1807 smp->data.u.str.area = capture->data + capture->ec_offset;
1808 smp->data.u.str.data = capture->ec_len;
1809 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1810 }
1811
1812 smp->data.type = SMP_T_BIN;
1813 return 1;
1814}
1815
1816/* binary, returns tls client hello supported elliptic curve point formats */
1817static int
1818smp_fetch_ssl_fc_ecf_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1819{
1820 struct connection *conn;
1821 struct ssl_capture *capture;
1822 SSL *ssl;
1823
1824 conn = objt_conn(smp->sess->origin);
1825 ssl = ssl_sock_get_ssl_object(conn);
1826 if (!ssl)
1827 return 0;
1828
1829 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1830 if (!capture)
1831 return 0;
1832
1833 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1834 smp->data.type = SMP_T_BIN;
1835 smp->data.u.str.area = capture->data + capture->ec_formats_offset;
1836 smp->data.u.str.data = capture->ec_formats_len;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001837 return 1;
1838}
1839
William Lallemand7d42ef52020-07-06 11:41:30 +02001840/* Dump the SSL keylog, it only works with "tune.ssl.keylog 1" */
William Lallemand722180a2021-06-09 16:46:12 +02001841#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02001842static int smp_fetch_ssl_x_keylog(const struct arg *args, struct sample *smp, const char *kw, void *private)
1843{
1844 struct connection *conn;
1845 struct ssl_keylog *keylog;
1846 SSL *ssl;
1847 char *src = NULL;
1848 const char *sfx;
1849
1850 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1851 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1852
William Lallemandeec1d452020-07-07 10:48:13 +02001853 if (!conn)
1854 return 0;
1855
William Lallemand7d42ef52020-07-06 11:41:30 +02001856 if (conn->flags & CO_FL_WAIT_XPRT) {
1857 smp->flags |= SMP_F_MAY_CHANGE;
1858 return 0;
1859 }
1860
1861 ssl = ssl_sock_get_ssl_object(conn);
1862 if (!ssl)
1863 return 0;
1864
1865 keylog = SSL_get_ex_data(ssl, ssl_keylog_index);
1866 if (!keylog)
1867 return 0;
1868
1869 sfx = kw + strlen("ssl_xx_");
1870
1871 if (strcmp(sfx, "client_early_traffic_secret") == 0) {
1872 src = keylog->client_early_traffic_secret;
1873 } else if (strcmp(sfx, "client_handshake_traffic_secret") == 0) {
1874 src = keylog->client_handshake_traffic_secret;
1875 } else if (strcmp(sfx, "server_handshake_traffic_secret") == 0) {
1876 src = keylog->server_handshake_traffic_secret;
1877 } else if (strcmp(sfx, "client_traffic_secret_0") == 0) {
1878 src = keylog->client_traffic_secret_0;
1879 } else if (strcmp(sfx, "server_traffic_secret_0") == 0) {
1880 src = keylog->server_traffic_secret_0;
1881 } else if (strcmp(sfx, "exporter_secret") == 0) {
1882 src = keylog->exporter_secret;
1883 } else if (strcmp(sfx, "early_exporter_secret") == 0) {
1884 src = keylog->early_exporter_secret;
1885 }
1886
1887 if (!src || !*src)
1888 return 0;
1889
1890 smp->data.u.str.area = src;
1891 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001892 smp->flags |= SMP_F_VOL_TEST | SMP_F_CONST;
William Lallemand7d42ef52020-07-06 11:41:30 +02001893 smp->data.u.str.data = strlen(smp->data.u.str.area);
1894 return 1;
William Lallemand7d42ef52020-07-06 11:41:30 +02001895}
1896#endif
1897
William Lallemand15e16942020-05-15 00:25:08 +02001898static int
1899smp_fetch_ssl_fc_cl_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
1900{
Ilya Shipitsinc9dfee42020-10-31 02:10:02 +05001901#if defined(OPENSSL_IS_BORINGSSL) || defined(SSL_CTRL_GET_RAW_CIPHERLIST)
William Lallemand15e16942020-05-15 00:25:08 +02001902 struct buffer *data;
1903 int i;
1904
1905 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1906 return 0;
1907
1908 data = get_trash_chunk();
1909 for (i = 0; i + 1 < smp->data.u.str.data; i += 2) {
1910 const char *str;
1911 const SSL_CIPHER *cipher;
1912 const unsigned char *bin = (const unsigned char *) smp->data.u.str.area + i;
1913 uint16_t id = (bin[0] << 8) | bin[1];
1914#if defined(OPENSSL_IS_BORINGSSL)
1915 cipher = SSL_get_cipher_by_value(id);
1916#else
1917 struct connection *conn = __objt_conn(smp->sess->origin);
1918 SSL *ssl = ssl_sock_get_ssl_object(conn);
1919 cipher = SSL_CIPHER_find(ssl, bin);
1920#endif
1921 str = SSL_CIPHER_get_name(cipher);
1922 if (!str || strcmp(str, "(NONE)") == 0)
1923 chunk_appendf(data, "%sUNKNOWN(%04x)", i == 0 ? "" : ",", id);
1924 else
1925 chunk_appendf(data, "%s%s", i == 0 ? "" : ",", str);
1926 }
1927 smp->data.type = SMP_T_STR;
1928 smp->data.u.str = *data;
1929 return 1;
1930#else
1931 return smp_fetch_ssl_fc_cl_xxh64(args, smp, kw, private);
1932#endif
1933}
1934
1935#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1936static int
1937smp_fetch_ssl_fc_unique_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1938{
1939 struct connection *conn;
1940 int finished_len;
1941 struct buffer *finished_trash;
1942 SSL *ssl;
1943
1944 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001945 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001946 else
1947 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
1948 smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
1949
1950 smp->flags = 0;
1951 ssl = ssl_sock_get_ssl_object(conn);
1952 if (!ssl)
1953 return 0;
1954
1955 if (conn->flags & CO_FL_WAIT_XPRT) {
1956 smp->flags |= SMP_F_MAY_CHANGE;
1957 return 0;
1958 }
1959
1960 finished_trash = get_trash_chunk();
1961 if (!SSL_session_reused(ssl))
1962 finished_len = SSL_get_peer_finished(ssl,
1963 finished_trash->area,
1964 finished_trash->size);
1965 else
1966 finished_len = SSL_get_finished(ssl,
1967 finished_trash->area,
1968 finished_trash->size);
1969
1970 if (!finished_len)
1971 return 0;
1972
1973 finished_trash->data = finished_len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001974 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001975 smp->data.u.str = *finished_trash;
1976 smp->data.type = SMP_T_BIN;
1977
1978 return 1;
1979}
1980#endif
1981
1982/* integer, returns the first verify error in CA chain of client certificate chain. */
1983static int
1984smp_fetch_ssl_c_ca_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
1985{
1986 struct connection *conn;
1987 struct ssl_sock_ctx *ctx;
1988
1989 conn = objt_conn(smp->sess->origin);
1990 if (!conn || conn->xprt != &ssl_sock)
1991 return 0;
1992 ctx = conn->xprt_ctx;
1993
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001994 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001995 smp->flags = SMP_F_MAY_CHANGE;
1996 return 0;
1997 }
1998
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001999 if (!ctx)
2000 return 0;
2001
William Lallemand15e16942020-05-15 00:25:08 +02002002 smp->data.type = SMP_T_SINT;
2003 smp->data.u.sint = (unsigned long long int)SSL_SOCK_ST_TO_CA_ERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002004 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002005
2006 return 1;
2007}
2008
2009/* integer, returns the depth of the first verify error in CA chain of client certificate chain. */
2010static int
2011smp_fetch_ssl_c_ca_err_depth(const struct arg *args, struct sample *smp, const char *kw, void *private)
2012{
2013 struct connection *conn;
2014 struct ssl_sock_ctx *ctx;
2015
2016 conn = objt_conn(smp->sess->origin);
2017 if (!conn || conn->xprt != &ssl_sock)
2018 return 0;
2019
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002020 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02002021 smp->flags = SMP_F_MAY_CHANGE;
2022 return 0;
2023 }
2024 ctx = conn->xprt_ctx;
2025
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002026 if (!ctx)
2027 return 0;
2028
William Lallemand15e16942020-05-15 00:25:08 +02002029 smp->data.type = SMP_T_SINT;
2030 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CAEDEPTH(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002031 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002032
2033 return 1;
2034}
2035
2036/* integer, returns the first verify error on client certificate */
2037static int
2038smp_fetch_ssl_c_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
2039{
2040 struct connection *conn;
2041 struct ssl_sock_ctx *ctx;
2042
2043 conn = objt_conn(smp->sess->origin);
2044 if (!conn || conn->xprt != &ssl_sock)
2045 return 0;
2046
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002047 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02002048 smp->flags = SMP_F_MAY_CHANGE;
2049 return 0;
2050 }
2051
2052 ctx = conn->xprt_ctx;
2053
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002054 if (!ctx)
2055 return 0;
2056
William Lallemand15e16942020-05-15 00:25:08 +02002057 smp->data.type = SMP_T_SINT;
2058 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CRTERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002059 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002060
2061 return 1;
2062}
2063
2064/* integer, returns the verify result on client cert */
2065static int
2066smp_fetch_ssl_c_verify(const struct arg *args, struct sample *smp, const char *kw, void *private)
2067{
2068 struct connection *conn;
2069 SSL *ssl;
2070
2071 conn = objt_conn(smp->sess->origin);
2072 ssl = ssl_sock_get_ssl_object(conn);
2073 if (!ssl)
2074 return 0;
2075
2076 if (conn->flags & CO_FL_WAIT_XPRT) {
2077 smp->flags = SMP_F_MAY_CHANGE;
2078 return 0;
2079 }
2080
2081 smp->data.type = SMP_T_SINT;
2082 smp->data.u.sint = (long long int)SSL_get_verify_result(ssl);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002083 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002084
2085 return 1;
2086}
2087
2088/* Argument validation functions */
2089
2090/* This function is used to validate the arguments passed to any "x_dn" ssl
2091 * keywords. These keywords support specifying a third parameter that must be
2092 * either empty or the value "rfc2253". Returns 0 on error, non-zero if OK.
2093 */
2094int val_dnfmt(struct arg *arg, char **err_msg)
2095{
2096 if (arg && arg[2].type == ARGT_STR && arg[2].data.str.data > 0 && (strcmp(arg[2].data.str.area, "rfc2253") != 0)) {
2097 memprintf(err_msg, "only rfc2253 or a blank value are currently supported as the format argument.");
2098 return 0;
2099 }
2100 return 1;
2101}
2102
2103/* Note: must not be declared <const> as its list will be overwritten.
2104 * Please take care of keeping this list alphabetically sorted.
2105 */
2106static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
2107 { "ssl_bc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
2108 { "ssl_bc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2109#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2110 { "ssl_bc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2111#endif
2112 { "ssl_bc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2113#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2114 { "ssl_bc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2115#endif
2116 { "ssl_bc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
2117 { "ssl_bc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2118 { "ssl_bc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2119 { "ssl_bc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2120#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2121 { "ssl_bc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2122#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05002123#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02002124 { "ssl_bc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2125 { "ssl_bc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2126 { "ssl_bc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2127#endif
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02002128 { "ssl_bc_err", smp_fetch_ssl_fc_err, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2129 { "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 +02002130 { "ssl_c_ca_err", smp_fetch_ssl_c_ca_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2131 { "ssl_c_ca_err_depth", smp_fetch_ssl_c_ca_err_depth, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2132 { "ssl_c_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02002133 { "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 +02002134 { "ssl_c_err", smp_fetch_ssl_c_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2135 { "ssl_c_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2136 { "ssl_c_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2137 { "ssl_c_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2138 { "ssl_c_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2139 { "ssl_c_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2140 { "ssl_c_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2141 { "ssl_c_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2142 { "ssl_c_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2143 { "ssl_c_used", smp_fetch_ssl_c_used, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2144 { "ssl_c_verify", smp_fetch_ssl_c_verify, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2145 { "ssl_c_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2146 { "ssl_f_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2147 { "ssl_f_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2148 { "ssl_f_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2149 { "ssl_f_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2150 { "ssl_f_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2151 { "ssl_f_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2152 { "ssl_f_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2153 { "ssl_f_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2154 { "ssl_f_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2155 { "ssl_f_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2156 { "ssl_fc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2157 { "ssl_fc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2158 { "ssl_fc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2159 { "ssl_fc_has_crt", smp_fetch_ssl_fc_has_crt, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2160 { "ssl_fc_has_early", smp_fetch_ssl_fc_has_early, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2161 { "ssl_fc_has_sni", smp_fetch_ssl_fc_has_sni, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2162 { "ssl_fc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2163#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2164 { "ssl_fc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2165#endif
2166#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2167 { "ssl_fc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2168#endif
2169 { "ssl_fc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2170#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2171 { "ssl_fc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2172#endif
2173 { "ssl_fc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2174#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2175 { "ssl_fc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2176#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05002177#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02002178 { "ssl_fc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2179 { "ssl_fc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2180 { "ssl_fc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2181#endif
William Lallemand7d42ef52020-07-06 11:41:30 +02002182
William Lallemand722180a2021-06-09 16:46:12 +02002183#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02002184 { "ssl_fc_client_early_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2185 { "ssl_fc_client_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2186 { "ssl_fc_server_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2187 { "ssl_fc_client_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2188 { "ssl_fc_server_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2189 { "ssl_fc_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2190 { "ssl_fc_early_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2191#endif
2192
William Lallemand15e16942020-05-15 00:25:08 +02002193#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
2194 { "ssl_fc_sni", smp_fetch_ssl_fc_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2195#endif
Marcin Deranek959a48c2021-07-13 15:14:21 +02002196 { "ssl_fc_cipherlist_bin", smp_fetch_ssl_fc_cl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2197 { "ssl_fc_cipherlist_hex", smp_fetch_ssl_fc_cl_hex, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_USE_L5CLI },
2198 { "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 +02002199 { "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 +02002200 { "ssl_fc_err", smp_fetch_ssl_fc_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2201 { "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 +02002202 { "ssl_fc_protocol_hello_id",smp_fetch_ssl_fc_protocol_hello_id,0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2203 { "ssl_fc_extlist_bin", smp_fetch_ssl_fc_ext_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2204 { "ssl_fc_eclist_bin", smp_fetch_ssl_fc_ecl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2205 { "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 +02002206
2207/* SSL server certificate fetches */
2208 { "ssl_s_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02002209 { "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 +02002210 { "ssl_s_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2211 { "ssl_s_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2212 { "ssl_s_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2213 { "ssl_s_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2214 { "ssl_s_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2215 { "ssl_s_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2216 { "ssl_s_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2217 { "ssl_s_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2218 { "ssl_s_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
William Lallemand15e16942020-05-15 00:25:08 +02002219 { NULL, NULL, 0, 0, 0 },
2220}};
2221
2222INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
2223
Willy Tarreau99ea1882021-10-06 15:37:17 +02002224/* Note: must not be declared <const> as its list will be overwritten */
2225static struct sample_conv_kw_list sample_conv_kws = {ILH, {
2226 { "sha2", sample_conv_sha2, ARG1(0, SINT), smp_check_sha2, SMP_T_BIN, SMP_T_BIN },
2227#ifdef EVP_CIPH_GCM_MODE
2228 { "aes_gcm_dec", sample_conv_aes_gcm_dec, ARG4(4,SINT,STR,STR,STR), check_aes_gcm, SMP_T_BIN, SMP_T_BIN },
2229#endif
2230 { "digest", sample_conv_crypto_digest, ARG1(1,STR), check_crypto_digest, SMP_T_BIN, SMP_T_BIN },
2231 { "hmac", sample_conv_crypto_hmac, ARG2(2,STR,STR), check_crypto_hmac, SMP_T_BIN, SMP_T_BIN },
2232#if defined(HAVE_CRYPTO_memcmp)
2233 { "secure_memcmp", sample_conv_secure_memcmp, ARG1(1,STR), smp_check_secure_memcmp, SMP_T_BIN, SMP_T_BOOL },
2234#endif
2235 { NULL, NULL, 0, 0, 0 },
2236}};
2237
2238INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
2239
2240
William Lallemand15e16942020-05-15 00:25:08 +02002241/* Note: must not be declared <const> as its list will be overwritten.
2242 * Please take care of keeping this list alphabetically sorted.
2243 */
2244static struct acl_kw_list acl_kws = {ILH, {
2245 { "ssl_fc_sni_end", "ssl_fc_sni", PAT_MATCH_END },
2246 { "ssl_fc_sni_reg", "ssl_fc_sni", PAT_MATCH_REG },
2247 { /* END */ },
2248}};
2249
2250INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);