blob: 9031dc49865c7f877b7a42d293cd1be33b9e0649 [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>
William Lallemand15e16942020-05-15 00:25:08 +020017#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <unistd.h>
21
Willy Tarreaudcc048a2020-06-04 19:11:43 +020022#include <haproxy/acl.h>
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020023#include <haproxy/api.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020024#include <haproxy/arg.h>
Willy Tarreau99ea1882021-10-06 15:37:17 +020025#include <haproxy/base64.h>
Willy Tarreau2741c8c2020-06-02 11:28:02 +020026#include <haproxy/buf-t.h>
Willy Tarreau939b0bf2022-04-11 11:29:11 +020027#include <haproxy/connection.h>
Christopher Faulet1329f2a2021-12-16 17:32:56 +010028#include <haproxy/conn_stream.h>
Willy Tarreau8efbdfb2020-06-04 11:29:21 +020029#include <haproxy/obj_type.h>
Willy Tarreau6019fab2020-05-27 16:26:00 +020030#include <haproxy/openssl-compat.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020031#include <haproxy/sample.h>
Willy Tarreau209108d2020-06-04 20:30:20 +020032#include <haproxy/ssl_sock.h>
Willy Tarreaub2bd8652020-06-04 14:21:22 +020033#include <haproxy/ssl_utils.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020034#include <haproxy/tools.h>
Willy Tarreau99ea1882021-10-06 15:37:17 +020035#include <haproxy/vars.h>
William Lallemand15e16942020-05-15 00:25:08 +020036
William Lallemand15e16942020-05-15 00:25:08 +020037
38/***** Below are some sample fetching functions for ACL/patterns *****/
39
Willy Tarreau99ea1882021-10-06 15:37:17 +020040#if defined(HAVE_CRYPTO_memcmp)
41/* Compares bytestring with a variable containing a bytestring. Return value
42 * is `true` if both bytestrings are bytewise identical and `false` otherwise.
43 *
44 * Comparison will be performed in constant time if both bytestrings are of
45 * the same length. If the lengths differ execution time will not be constant.
46 */
47static int sample_conv_secure_memcmp(const struct arg *arg_p, struct sample *smp, void *private)
48{
49 struct sample tmp;
50 int result;
51
52 smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
53 if (arg_p[0].type != ARGT_VAR)
54 return 0;
55
56 if (!sample_conv_var2smp(&arg_p[0].data.var, &tmp, SMP_T_BIN))
57 return 0;
58
59 if (smp->data.u.str.data != tmp.data.u.str.data) {
60 smp->data.u.sint = 0;
61 smp->data.type = SMP_T_BOOL;
62 return 1;
63 }
64
65 /* The following comparison is performed in constant time. */
66 result = CRYPTO_memcmp(smp->data.u.str.area, tmp.data.u.str.area, smp->data.u.str.data);
67
68 smp->data.u.sint = result == 0;
69 smp->data.type = SMP_T_BOOL;
70 return 1;
71}
72
73/* This function checks the "secure_memcmp" converter's arguments and extracts the
74 * variable name and its scope.
75 */
76static int smp_check_secure_memcmp(struct arg *args, struct sample_conv *conv,
77 const char *file, int line, char **err)
78{
79 if (!args[0].data.str.data) {
80 memprintf(err, "missing variable name");
81 return 0;
82 }
83
84 /* Try to decode a variable. */
85 if (vars_check_arg(&args[0], NULL))
86 return 1;
87
88 memprintf(err, "failed to register variable name '%s'",
89 args[0].data.str.area);
90 return 0;
91}
92#endif // HAVE_secure_memcmp()
93
94static int smp_check_sha2(struct arg *args, struct sample_conv *conv,
95 const char *file, int line, char **err)
96{
97 if (args[0].type == ARGT_STOP)
98 return 1;
99 if (args[0].type != ARGT_SINT) {
100 memprintf(err, "Invalid type '%s'", arg_type_names[args[0].type]);
101 return 0;
102 }
103
104 switch (args[0].data.sint) {
105 case 224:
106 case 256:
107 case 384:
108 case 512:
109 /* this is okay */
110 return 1;
111 default:
112 memprintf(err, "Unsupported number of bits: '%lld'", args[0].data.sint);
113 return 0;
114 }
115}
116
117static int sample_conv_sha2(const struct arg *arg_p, struct sample *smp, void *private)
118{
119 struct buffer *trash = get_trash_chunk();
120 int bits = 256;
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100121 EVP_MD_CTX *mdctx;
122 const EVP_MD *evp = NULL;
123 unsigned int digest_length = 0;
Willy Tarreau99ea1882021-10-06 15:37:17 +0200124 if (arg_p->data.sint)
125 bits = arg_p->data.sint;
126
127 switch (bits) {
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100128 case 224:
129 evp = EVP_sha224();
Willy Tarreau99ea1882021-10-06 15:37:17 +0200130 break;
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100131 case 256:
132 evp = EVP_sha256();
Willy Tarreau99ea1882021-10-06 15:37:17 +0200133 break;
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100134 case 384:
135 evp = EVP_sha384();
Willy Tarreau99ea1882021-10-06 15:37:17 +0200136 break;
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100137 case 512:
138 evp = EVP_sha512();
Willy Tarreau99ea1882021-10-06 15:37:17 +0200139 break;
Willy Tarreau99ea1882021-10-06 15:37:17 +0200140 default:
141 return 0;
142 }
143
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100144 mdctx = EVP_MD_CTX_new();
145 if (!mdctx)
146 return 0;
147 EVP_DigestInit_ex(mdctx, evp, NULL);
148 EVP_DigestUpdate(mdctx, smp->data.u.str.area, smp->data.u.str.data);
149 EVP_DigestFinal_ex(mdctx, (unsigned char*)trash->area, &digest_length);
150 trash->data = digest_length;
151
152 EVP_MD_CTX_free(mdctx);
153
Willy Tarreau99ea1882021-10-06 15:37:17 +0200154 smp->data.u.str = *trash;
155 smp->data.type = SMP_T_BIN;
156 smp->flags &= ~SMP_F_CONST;
157 return 1;
158}
159
160/* This function checks an <arg> and fills it with a variable type if the
161 * <arg> string contains a valid variable name. If failed, the function
162 * tries to perform a base64 decode operation on the same string, and
163 * fills the <arg> with the decoded content.
164 *
165 * Validation is skipped if the <arg> string is empty.
166 *
167 * This function returns 0 if the variable lookup fails and the specified
168 * <arg> string is not a valid base64 encoded string, as well if
169 * unexpected argument type is specified or memory allocation error
170 * occurs. Otherwise it returns 1.
171 */
172static inline int sample_check_arg_base64(struct arg *arg, char **err)
173{
174 char *dec = NULL;
175 int dec_size;
176
177 if (arg->type != ARGT_STR) {
178 memprintf(err, "unexpected argument type");
179 return 0;
180 }
181
182 if (arg->data.str.data == 0) /* empty */
183 return 1;
184
185 if (vars_check_arg(arg, NULL))
186 return 1;
187
188 if (arg->data.str.data % 4) {
189 memprintf(err, "argument needs to be base64 encoded, and "
190 "can either be a string or a variable");
191 return 0;
192 }
193
194 dec_size = (arg->data.str.data / 4 * 3)
195 - (arg->data.str.area[arg->data.str.data-1] == '=' ? 1 : 0)
196 - (arg->data.str.area[arg->data.str.data-2] == '=' ? 1 : 0);
197
198 if ((dec = malloc(dec_size)) == NULL) {
199 memprintf(err, "memory allocation error");
200 return 0;
201 }
202
203 dec_size = base64dec(arg->data.str.area, arg->data.str.data, dec, dec_size);
204 if (dec_size < 0) {
205 memprintf(err, "argument needs to be base64 encoded, and "
206 "can either be a string or a variable");
207 free(dec);
208 return 0;
209 }
210
211 /* base64 decoded */
212 chunk_destroy(&arg->data.str);
213 arg->data.str.area = dec;
214 arg->data.str.data = dec_size;
215 return 1;
216}
217
218#ifdef EVP_CIPH_GCM_MODE
219static int check_aes_gcm(struct arg *args, struct sample_conv *conv,
220 const char *file, int line, char **err)
221{
222 switch(args[0].data.sint) {
223 case 128:
224 case 192:
225 case 256:
226 break;
227 default:
228 memprintf(err, "key size must be 128, 192 or 256 (bits).");
229 return 0;
230 }
231
232 /* Try to decode variables. */
233 if (!sample_check_arg_base64(&args[1], err)) {
234 memprintf(err, "failed to parse nonce : %s", *err);
235 return 0;
236 }
237 if (!sample_check_arg_base64(&args[2], err)) {
238 memprintf(err, "failed to parse key : %s", *err);
239 return 0;
240 }
241 if (!sample_check_arg_base64(&args[3], err)) {
242 memprintf(err, "failed to parse aead_tag : %s", *err);
243 return 0;
244 }
245
246 return 1;
247}
248
249/* Arguments: AES size in bits, nonce, key, tag. The last three arguments are base64 encoded */
250static int sample_conv_aes_gcm_dec(const struct arg *arg_p, struct sample *smp, void *private)
251{
252 struct sample nonce, key, aead_tag;
253 struct buffer *smp_trash = NULL, *smp_trash_alloc = NULL;
254 EVP_CIPHER_CTX *ctx;
255 int dec_size, ret;
256
257 smp_trash_alloc = alloc_trash_chunk();
258 if (!smp_trash_alloc)
259 return 0;
260
261 /* smp copy */
262 smp_trash_alloc->data = smp->data.u.str.data;
263 if (unlikely(smp_trash_alloc->data > smp_trash_alloc->size))
264 smp_trash_alloc->data = smp_trash_alloc->size;
265 memcpy(smp_trash_alloc->area, smp->data.u.str.area, smp_trash_alloc->data);
266
267 ctx = EVP_CIPHER_CTX_new();
268
269 if (!ctx)
270 goto err;
271
272 smp_trash = alloc_trash_chunk();
273 if (!smp_trash)
274 goto err;
275
276 smp_set_owner(&nonce, smp->px, smp->sess, smp->strm, smp->opt);
277 if (!sample_conv_var2smp_str(&arg_p[1], &nonce))
278 goto err;
279
280 if (arg_p[1].type == ARGT_VAR) {
281 dec_size = base64dec(nonce.data.u.str.area, nonce.data.u.str.data, smp_trash->area, smp_trash->size);
282 if (dec_size < 0)
283 goto err;
284 smp_trash->data = dec_size;
285 nonce.data.u.str = *smp_trash;
286 }
287
288 /* Set cipher type and mode */
289 switch(arg_p[0].data.sint) {
290 case 128:
291 EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);
292 break;
293 case 192:
294 EVP_DecryptInit_ex(ctx, EVP_aes_192_gcm(), NULL, NULL, NULL);
295 break;
296 case 256:
297 EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
298 break;
299 }
300
301 EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce.data.u.str.data, NULL);
302
303 /* Initialise IV */
304 if(!EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, (unsigned char *) nonce.data.u.str.area))
305 goto err;
306
307 smp_set_owner(&key, smp->px, smp->sess, smp->strm, smp->opt);
308 if (!sample_conv_var2smp_str(&arg_p[2], &key))
309 goto err;
310
311 if (arg_p[2].type == ARGT_VAR) {
312 dec_size = base64dec(key.data.u.str.area, key.data.u.str.data, smp_trash->area, smp_trash->size);
313 if (dec_size < 0)
314 goto err;
315 smp_trash->data = dec_size;
316 key.data.u.str = *smp_trash;
317 }
318
319 /* Initialise key */
320 if (!EVP_DecryptInit_ex(ctx, NULL, NULL, (unsigned char *) key.data.u.str.area, NULL))
321 goto err;
322
323 if (!EVP_DecryptUpdate(ctx, (unsigned char *) smp_trash->area, (int *) &smp_trash->data,
324 (unsigned char *) smp_trash_alloc->area, (int) smp_trash_alloc->data))
325 goto err;
326
327 smp_set_owner(&aead_tag, smp->px, smp->sess, smp->strm, smp->opt);
328 if (!sample_conv_var2smp_str(&arg_p[3], &aead_tag))
329 goto err;
330
331 if (arg_p[3].type == ARGT_VAR) {
332 dec_size = base64dec(aead_tag.data.u.str.area, aead_tag.data.u.str.data, smp_trash_alloc->area, smp_trash_alloc->size);
333 if (dec_size < 0)
334 goto err;
335 smp_trash_alloc->data = dec_size;
336 aead_tag.data.u.str = *smp_trash_alloc;
337 }
338
339 dec_size = smp_trash->data;
340
341 EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, aead_tag.data.u.str.data, (void *) aead_tag.data.u.str.area);
342 ret = EVP_DecryptFinal_ex(ctx, (unsigned char *) smp_trash->area + smp_trash->data, (int *) &smp_trash->data);
343
344 if (ret <= 0)
345 goto err;
346
347 smp->data.u.str.data = dec_size + smp_trash->data;
348 smp->data.u.str.area = smp_trash->area;
349 smp->data.type = SMP_T_BIN;
350 smp_dup(smp);
351 free_trash_chunk(smp_trash_alloc);
352 free_trash_chunk(smp_trash);
353 return 1;
354
355err:
356 free_trash_chunk(smp_trash_alloc);
357 free_trash_chunk(smp_trash);
358 return 0;
359}
360#endif
361
362static int check_crypto_digest(struct arg *args, struct sample_conv *conv,
363 const char *file, int line, char **err)
364{
365 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
366
367 if (evp)
368 return 1;
369
370 memprintf(err, "algorithm must be a valid OpenSSL message digest name.");
371 return 0;
372}
373
374static int sample_conv_crypto_digest(const struct arg *args, struct sample *smp, void *private)
375{
376 struct buffer *trash = get_trash_chunk();
377 unsigned char *md = (unsigned char*) trash->area;
378 unsigned int md_len = trash->size;
379 EVP_MD_CTX *ctx = EVP_MD_CTX_new();
380 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
381
382 if (!ctx)
383 return 0;
384
385 if (!EVP_DigestInit_ex(ctx, evp, NULL) ||
386 !EVP_DigestUpdate(ctx, smp->data.u.str.area, smp->data.u.str.data) ||
387 !EVP_DigestFinal_ex(ctx, md, &md_len)) {
388 EVP_MD_CTX_free(ctx);
389 return 0;
390 }
391
392 EVP_MD_CTX_free(ctx);
393
394 trash->data = md_len;
395 smp->data.u.str = *trash;
396 smp->data.type = SMP_T_BIN;
397 smp->flags &= ~SMP_F_CONST;
398 return 1;
399}
400
401static int check_crypto_hmac(struct arg *args, struct sample_conv *conv,
402 const char *file, int line, char **err)
403{
404 if (!check_crypto_digest(args, conv, file, line, err))
405 return 0;
406
407 if (!sample_check_arg_base64(&args[1], err)) {
408 memprintf(err, "failed to parse key : %s", *err);
409 return 0;
410 }
411
412 return 1;
413}
414
415static int sample_conv_crypto_hmac(const struct arg *args, struct sample *smp, void *private)
416{
417 struct sample key;
418 struct buffer *trash = NULL, *key_trash = NULL;
419 unsigned char *md;
420 unsigned int md_len;
421 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
422 int dec_size;
423
424 smp_set_owner(&key, smp->px, smp->sess, smp->strm, smp->opt);
425 if (!sample_conv_var2smp_str(&args[1], &key))
426 return 0;
427
428 if (args[1].type == ARGT_VAR) {
429 key_trash = alloc_trash_chunk();
430 if (!key_trash)
431 goto err;
432
433 dec_size = base64dec(key.data.u.str.area, key.data.u.str.data, key_trash->area, key_trash->size);
434 if (dec_size < 0)
435 goto err;
436 key_trash->data = dec_size;
437 key.data.u.str = *key_trash;
438 }
439
440 trash = alloc_trash_chunk();
441 if (!trash)
442 goto err;
443
444 md = (unsigned char*) trash->area;
445 md_len = trash->size;
446 if (!HMAC(evp, key.data.u.str.area, key.data.u.str.data, (const unsigned char*) smp->data.u.str.area,
447 smp->data.u.str.data, md, &md_len))
448 goto err;
449
450 free_trash_chunk(key_trash);
451
452 trash->data = md_len;
453 smp->data.u.str = *trash;
454 smp->data.type = SMP_T_BIN;
455 smp_dup(smp);
456 free_trash_chunk(trash);
457 return 1;
458
459err:
460 free_trash_chunk(key_trash);
461 free_trash_chunk(trash);
462 return 0;
463}
464
William Lallemand15e16942020-05-15 00:25:08 +0200465static int
466smp_fetch_ssl_fc_has_early(const struct arg *args, struct sample *smp, const char *kw, void *private)
467{
468 SSL *ssl;
469 struct connection *conn;
470
471 conn = objt_conn(smp->sess->origin);
472 ssl = ssl_sock_get_ssl_object(conn);
473 if (!ssl)
474 return 0;
475
476 smp->flags = 0;
477 smp->data.type = SMP_T_BOOL;
478#ifdef OPENSSL_IS_BORINGSSL
479 {
480 smp->data.u.sint = (SSL_in_early_data(ssl) &&
481 SSL_early_data_accepted(ssl));
482 }
483#else
484 smp->data.u.sint = ((conn->flags & CO_FL_EARLY_DATA) &&
485 (conn->flags & (CO_FL_EARLY_SSL_HS | CO_FL_SSL_WAIT_HS))) ? 1 : 0;
486#endif
487 return 1;
488}
489
490/* boolean, returns true if client cert was present */
491static int
492smp_fetch_ssl_fc_has_crt(const struct arg *args, struct sample *smp, const char *kw, void *private)
493{
Willy Tarreau939b0bf2022-04-11 11:29:11 +0200494 struct connection *conn = objt_conn(smp->sess->origin);
495 struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
William Lallemand15e16942020-05-15 00:25:08 +0200496
Willy Tarreau939b0bf2022-04-11 11:29:11 +0200497 if (!ctx)
William Lallemand15e16942020-05-15 00:25:08 +0200498 return 0;
499
William Lallemand15e16942020-05-15 00:25:08 +0200500 if (conn->flags & CO_FL_WAIT_XPRT) {
501 smp->flags |= SMP_F_MAY_CHANGE;
502 return 0;
503 }
504
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200505 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200506 smp->data.type = SMP_T_BOOL;
507 smp->data.u.sint = SSL_SOCK_ST_FL_VERIFY_DONE & ctx->xprt_st ? 1 : 0;
508
509 return 1;
510}
511
512/* binary, returns a certificate in a binary chunk (der/raw).
513 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
514 * should be use.
515 */
516static int
517smp_fetch_ssl_x_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
518{
William Lallemandbfa3e812020-06-25 20:07:18 +0200519 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
520 int conn_server = (kw[4] == 's') ? 1 : 0;
521
William Lallemand15e16942020-05-15 00:25:08 +0200522 X509 *crt = NULL;
523 int ret = 0;
524 struct buffer *smp_trash;
525 struct connection *conn;
526 SSL *ssl;
527
William Lallemandbfa3e812020-06-25 20:07:18 +0200528 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200529 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200530 else
531 conn = objt_conn(smp->sess->origin);
532
William Lallemand15e16942020-05-15 00:25:08 +0200533 ssl = ssl_sock_get_ssl_object(conn);
534 if (!ssl)
535 return 0;
536
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200537 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200538 smp->flags |= SMP_F_MAY_CHANGE;
539 return 0;
540 }
541
542 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200543 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200544 else
545 crt = SSL_get_certificate(ssl);
546
547 if (!crt)
548 goto out;
549
550 smp_trash = get_trash_chunk();
551 if (ssl_sock_crt2der(crt, smp_trash) <= 0)
552 goto out;
553
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200554 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200555 smp->data.u.str = *smp_trash;
556 smp->data.type = SMP_T_BIN;
557 ret = 1;
558out:
559 /* SSL_get_peer_certificate, it increase X509 * ref count */
560 if (cert_peer && crt)
561 X509_free(crt);
562 return ret;
563}
564
William Dauchya598b502020-08-06 18:11:38 +0200565/* binary, returns a chain certificate in a binary chunk (der/raw).
566 * The 5th keyword char is used to support only peer cert
567 */
568static int
569smp_fetch_ssl_x_chain_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
570{
571 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
572 int conn_server = (kw[4] == 's') ? 1 : 0;
573 struct buffer *smp_trash;
574 struct buffer *tmp_trash = NULL;
575 struct connection *conn;
576 STACK_OF(X509) *certs = NULL;
577 X509 *crt = NULL;
578 SSL *ssl;
579 int ret = 0;
580 int num_certs;
581 int i;
582
583 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200584 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Dauchya598b502020-08-06 18:11:38 +0200585 else
586 conn = objt_conn(smp->sess->origin);
587
588 if (!conn)
589 return 0;
590
591 ssl = ssl_sock_get_ssl_object(conn);
592 if (!ssl)
593 return 0;
594
595 if (conn->flags & CO_FL_WAIT_XPRT) {
596 smp->flags |= SMP_F_MAY_CHANGE;
597 return 0;
598 }
599
600 if (!cert_peer)
601 return 0;
602
603 certs = SSL_get_peer_cert_chain(ssl);
604 if (!certs)
605 return 0;
606
607 num_certs = sk_X509_num(certs);
608 if (!num_certs)
609 goto out;
610 smp_trash = get_trash_chunk();
611 tmp_trash = alloc_trash_chunk();
612 if (!tmp_trash)
613 goto out;
614 for (i = 0; i < num_certs; i++) {
615 crt = sk_X509_value(certs, i);
616 if (ssl_sock_crt2der(crt, tmp_trash) <= 0)
617 goto out;
618 chunk_cat(smp_trash, tmp_trash);
619 }
620
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200621 smp->flags = SMP_F_VOL_SESS;
William Dauchya598b502020-08-06 18:11:38 +0200622 smp->data.u.str = *smp_trash;
623 smp->data.type = SMP_T_BIN;
624 ret = 1;
625out:
626 if (tmp_trash)
627 free_trash_chunk(tmp_trash);
William Dauchya598b502020-08-06 18:11:38 +0200628 return ret;
629}
630
William Lallemand15e16942020-05-15 00:25:08 +0200631/* binary, returns serial of certificate in a binary chunk.
632 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
633 * should be use.
634 */
635static int
636smp_fetch_ssl_x_serial(const struct arg *args, struct sample *smp, const char *kw, void *private)
637{
William Lallemandbfa3e812020-06-25 20:07:18 +0200638 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
639 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200640 X509 *crt = NULL;
641 int ret = 0;
642 struct buffer *smp_trash;
643 struct connection *conn;
644 SSL *ssl;
645
William Lallemandbfa3e812020-06-25 20:07:18 +0200646 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200647 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200648 else
649 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +0200650 ssl = ssl_sock_get_ssl_object(conn);
651 if (!ssl)
652 return 0;
653
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200654 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200655 smp->flags |= SMP_F_MAY_CHANGE;
656 return 0;
657 }
658
659 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200660 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200661 else
662 crt = SSL_get_certificate(ssl);
663
664 if (!crt)
665 goto out;
666
667 smp_trash = get_trash_chunk();
668 if (ssl_sock_get_serial(crt, smp_trash) <= 0)
669 goto out;
670
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200671 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200672 smp->data.u.str = *smp_trash;
673 smp->data.type = SMP_T_BIN;
674 ret = 1;
675out:
676 /* SSL_get_peer_certificate, it increase X509 * ref count */
677 if (cert_peer && crt)
678 X509_free(crt);
679 return ret;
680}
681
682/* binary, returns the client certificate's SHA-1 fingerprint (SHA-1 hash of DER-encoded certificate) in a binary chunk.
683 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
684 * should be use.
685 */
686static int
687smp_fetch_ssl_x_sha1(const struct arg *args, struct sample *smp, const char *kw, void *private)
688{
William Lallemandbfa3e812020-06-25 20:07:18 +0200689 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
690 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200691 X509 *crt = NULL;
692 const EVP_MD *digest;
693 int ret = 0;
694 unsigned int len = 0;
695 struct buffer *smp_trash;
696 struct connection *conn;
697 SSL *ssl;
698
William Lallemandbfa3e812020-06-25 20:07:18 +0200699 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200700 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200701 else
702 conn = objt_conn(smp->sess->origin);
703
William Lallemand15e16942020-05-15 00:25:08 +0200704 ssl = ssl_sock_get_ssl_object(conn);
705 if (!ssl)
706 return 0;
707
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200708 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200709 smp->flags |= SMP_F_MAY_CHANGE;
710 return 0;
711 }
712
713 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200714 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200715 else
716 crt = SSL_get_certificate(ssl);
717 if (!crt)
718 goto out;
719
720 smp_trash = get_trash_chunk();
721 digest = EVP_sha1();
722 X509_digest(crt, digest, (unsigned char *) smp_trash->area, &len);
723 smp_trash->data = len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200724 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200725 smp->data.u.str = *smp_trash;
726 smp->data.type = SMP_T_BIN;
727 ret = 1;
728out:
729 /* SSL_get_peer_certificate, it increase X509 * ref count */
730 if (cert_peer && crt)
731 X509_free(crt);
732 return ret;
733}
734
735/* string, returns certificate's notafter date in ASN1_UTCTIME format.
736 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
737 * should be use.
738 */
739static int
740smp_fetch_ssl_x_notafter(const struct arg *args, struct sample *smp, const char *kw, void *private)
741{
William Lallemandbfa3e812020-06-25 20:07:18 +0200742 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
743 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200744 X509 *crt = NULL;
745 int ret = 0;
746 struct buffer *smp_trash;
747 struct connection *conn;
748 SSL *ssl;
749
William Lallemandbfa3e812020-06-25 20:07:18 +0200750 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200751 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200752 else
753 conn = objt_conn(smp->sess->origin);
754
William Lallemand15e16942020-05-15 00:25:08 +0200755 ssl = ssl_sock_get_ssl_object(conn);
756 if (!ssl)
757 return 0;
758
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200759 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200760 smp->flags |= SMP_F_MAY_CHANGE;
761 return 0;
762 }
763
764 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200765 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200766 else
767 crt = SSL_get_certificate(ssl);
768 if (!crt)
769 goto out;
770
771 smp_trash = get_trash_chunk();
772 if (ssl_sock_get_time(X509_getm_notAfter(crt), smp_trash) <= 0)
773 goto out;
774
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200775 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200776 smp->data.u.str = *smp_trash;
777 smp->data.type = SMP_T_STR;
778 ret = 1;
779out:
780 /* SSL_get_peer_certificate, it increase X509 * ref count */
781 if (cert_peer && crt)
782 X509_free(crt);
783 return ret;
784}
785
786/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's issuer
787 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
788 * should be use.
789 */
790static int
791smp_fetch_ssl_x_i_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
792{
William Lallemandbfa3e812020-06-25 20:07:18 +0200793 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
794 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200795 X509 *crt = NULL;
796 X509_NAME *name;
797 int ret = 0;
798 struct buffer *smp_trash;
799 struct connection *conn;
800 SSL *ssl;
801
William Lallemandbfa3e812020-06-25 20:07:18 +0200802 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200803 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200804 else
805 conn = objt_conn(smp->sess->origin);
806
William Lallemand15e16942020-05-15 00:25:08 +0200807 ssl = ssl_sock_get_ssl_object(conn);
808 if (!ssl)
809 return 0;
810
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200811 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200812 smp->flags |= SMP_F_MAY_CHANGE;
813 return 0;
814 }
815
816 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200817 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200818 else
819 crt = SSL_get_certificate(ssl);
820 if (!crt)
821 goto out;
822
823 name = X509_get_issuer_name(crt);
824 if (!name)
825 goto out;
826
827 smp_trash = get_trash_chunk();
Christopher Faulet3702f782021-01-29 11:30:37 +0100828 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200829 int pos = 1;
830
831 if (args[1].type == ARGT_SINT)
832 pos = args[1].data.sint;
833
834 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
835 goto out;
836 }
Christopher Faulet3702f782021-01-29 11:30:37 +0100837 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200838 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
839 goto out;
840 }
841 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
842 goto out;
843
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200844 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200845 smp->data.type = SMP_T_STR;
846 smp->data.u.str = *smp_trash;
847 ret = 1;
848out:
849 /* SSL_get_peer_certificate, it increase X509 * ref count */
850 if (cert_peer && crt)
851 X509_free(crt);
852 return ret;
853}
854
855/* string, returns notbefore date in ASN1_UTCTIME format.
856 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
857 * should be use.
858 */
859static int
860smp_fetch_ssl_x_notbefore(const struct arg *args, struct sample *smp, const char *kw, void *private)
861{
William Lallemandbfa3e812020-06-25 20:07:18 +0200862 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
863 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200864 X509 *crt = NULL;
865 int ret = 0;
866 struct buffer *smp_trash;
867 struct connection *conn;
868 SSL *ssl;
869
William Lallemandbfa3e812020-06-25 20:07:18 +0200870 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200871 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200872 else
873 conn = objt_conn(smp->sess->origin);
874
William Lallemand15e16942020-05-15 00:25:08 +0200875 ssl = ssl_sock_get_ssl_object(conn);
876 if (!ssl)
877 return 0;
878
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200879 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200880 smp->flags |= SMP_F_MAY_CHANGE;
881 return 0;
882 }
883
884 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200885 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200886 else
887 crt = SSL_get_certificate(ssl);
888 if (!crt)
889 goto out;
890
891 smp_trash = get_trash_chunk();
892 if (ssl_sock_get_time(X509_getm_notBefore(crt), smp_trash) <= 0)
893 goto out;
894
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200895 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200896 smp->data.u.str = *smp_trash;
897 smp->data.type = SMP_T_STR;
898 ret = 1;
899out:
900 /* SSL_get_peer_certificate, it increase X509 * ref count */
901 if (cert_peer && crt)
902 X509_free(crt);
903 return ret;
904}
905
906/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's subject
907 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
908 * should be use.
909 */
910static int
911smp_fetch_ssl_x_s_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
912{
William Lallemandbfa3e812020-06-25 20:07:18 +0200913 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
914 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200915 X509 *crt = NULL;
916 X509_NAME *name;
917 int ret = 0;
918 struct buffer *smp_trash;
919 struct connection *conn;
920 SSL *ssl;
921
William Lallemandbfa3e812020-06-25 20:07:18 +0200922 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200923 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200924 else
925 conn = objt_conn(smp->sess->origin);
926
William Lallemand15e16942020-05-15 00:25:08 +0200927 ssl = ssl_sock_get_ssl_object(conn);
928 if (!ssl)
929 return 0;
930
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200931 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200932 smp->flags |= SMP_F_MAY_CHANGE;
933 return 0;
934 }
935
936 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200937 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200938 else
939 crt = SSL_get_certificate(ssl);
940 if (!crt)
941 goto out;
942
943 name = X509_get_subject_name(crt);
944 if (!name)
945 goto out;
946
947 smp_trash = get_trash_chunk();
Christopher Faulet3702f782021-01-29 11:30:37 +0100948 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200949 int pos = 1;
950
951 if (args[1].type == ARGT_SINT)
952 pos = args[1].data.sint;
953
954 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
955 goto out;
956 }
Christopher Faulet3702f782021-01-29 11:30:37 +0100957 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200958 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
959 goto out;
960 }
961 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
962 goto out;
963
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200964 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200965 smp->data.type = SMP_T_STR;
966 smp->data.u.str = *smp_trash;
967 ret = 1;
968out:
969 /* SSL_get_peer_certificate, it increase X509 * ref count */
970 if (cert_peer && crt)
971 X509_free(crt);
972 return ret;
973}
974
975/* integer, returns true if current session use a client certificate */
976static int
977smp_fetch_ssl_c_used(const struct arg *args, struct sample *smp, const char *kw, void *private)
978{
979 X509 *crt;
980 struct connection *conn;
981 SSL *ssl;
982
983 conn = objt_conn(smp->sess->origin);
984 ssl = ssl_sock_get_ssl_object(conn);
985 if (!ssl)
986 return 0;
987
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200988 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200989 smp->flags |= SMP_F_MAY_CHANGE;
990 return 0;
991 }
992
993 /* SSL_get_peer_certificate returns a ptr on allocated X509 struct */
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200994 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200995 if (crt) {
996 X509_free(crt);
997 }
998
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200999 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001000 smp->data.type = SMP_T_BOOL;
1001 smp->data.u.sint = (crt != NULL);
1002 return 1;
1003}
1004
1005/* integer, returns the certificate version
1006 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1007 * should be use.
1008 */
1009static int
1010smp_fetch_ssl_x_version(const struct arg *args, struct sample *smp, const char *kw, void *private)
1011{
William Lallemandbfa3e812020-06-25 20:07:18 +02001012 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1013 int conn_server = (kw[4] == 's') ? 1 : 0;
1014
William Lallemand15e16942020-05-15 00:25:08 +02001015 X509 *crt;
1016 struct connection *conn;
1017 SSL *ssl;
1018
William Lallemandbfa3e812020-06-25 20:07:18 +02001019 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001020 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001021 else
1022 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +02001023 ssl = ssl_sock_get_ssl_object(conn);
1024 if (!ssl)
1025 return 0;
1026
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001027 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001028 smp->flags |= SMP_F_MAY_CHANGE;
1029 return 0;
1030 }
1031
1032 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001033 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001034 else
1035 crt = SSL_get_certificate(ssl);
1036 if (!crt)
1037 return 0;
1038
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001039 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001040 smp->data.u.sint = (unsigned int)(1 + X509_get_version(crt));
1041 /* SSL_get_peer_certificate increase X509 * ref count */
1042 if (cert_peer)
1043 X509_free(crt);
1044 smp->data.type = SMP_T_SINT;
1045
1046 return 1;
1047}
1048
1049/* string, returns the certificate's signature algorithm.
1050 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1051 * should be use.
1052 */
1053static int
1054smp_fetch_ssl_x_sig_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
1055{
William Lallemandbfa3e812020-06-25 20:07:18 +02001056 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1057 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +02001058 X509 *crt;
1059 __OPENSSL_110_CONST__ ASN1_OBJECT *algorithm;
1060 int nid;
1061 struct connection *conn;
1062 SSL *ssl;
1063
William Lallemandbfa3e812020-06-25 20:07:18 +02001064 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001065 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001066 else
1067 conn = objt_conn(smp->sess->origin);
1068
William Lallemand15e16942020-05-15 00:25:08 +02001069 ssl = ssl_sock_get_ssl_object(conn);
1070 if (!ssl)
1071 return 0;
1072
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001073 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001074 smp->flags |= SMP_F_MAY_CHANGE;
1075 return 0;
1076 }
1077
1078 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001079 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001080 else
1081 crt = SSL_get_certificate(ssl);
1082 if (!crt)
1083 return 0;
1084
1085 X509_ALGOR_get0(&algorithm, NULL, NULL, X509_get0_tbs_sigalg(crt));
1086 nid = OBJ_obj2nid(algorithm);
1087
1088 smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
1089 if (!smp->data.u.str.area) {
1090 /* SSL_get_peer_certificate increase X509 * ref count */
1091 if (cert_peer)
1092 X509_free(crt);
1093 return 0;
1094 }
1095
1096 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001097 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001098 smp->data.u.str.data = strlen(smp->data.u.str.area);
1099 /* SSL_get_peer_certificate increase X509 * ref count */
1100 if (cert_peer)
1101 X509_free(crt);
1102
1103 return 1;
1104}
1105
1106/* string, returns the certificate's key algorithm.
1107 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1108 * should be use.
1109 */
1110static int
1111smp_fetch_ssl_x_key_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
1112{
William Lallemandbfa3e812020-06-25 20:07:18 +02001113 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1114 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +02001115 X509 *crt;
1116 ASN1_OBJECT *algorithm;
1117 int nid;
1118 struct connection *conn;
1119 SSL *ssl;
1120
William Lallemandbfa3e812020-06-25 20:07:18 +02001121 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001122 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001123 else
1124 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +02001125 ssl = ssl_sock_get_ssl_object(conn);
1126 if (!ssl)
1127 return 0;
1128
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001129 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001130 smp->flags |= SMP_F_MAY_CHANGE;
1131 return 0;
1132 }
1133
1134 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001135 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001136 else
1137 crt = SSL_get_certificate(ssl);
1138 if (!crt)
1139 return 0;
1140
1141 X509_PUBKEY_get0_param(&algorithm, NULL, NULL, NULL, X509_get_X509_PUBKEY(crt));
1142 nid = OBJ_obj2nid(algorithm);
1143
1144 smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
1145 if (!smp->data.u.str.area) {
1146 /* SSL_get_peer_certificate increase X509 * ref count */
1147 if (cert_peer)
1148 X509_free(crt);
1149 return 0;
1150 }
1151
1152 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001153 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001154 smp->data.u.str.data = strlen(smp->data.u.str.area);
1155 if (cert_peer)
1156 X509_free(crt);
1157
1158 return 1;
1159}
1160
1161/* boolean, returns true if front conn. transport layer is SSL.
1162 * This function is also usable on backend conn if the fetch keyword 5th
1163 * char is 'b'.
1164 */
1165static int
1166smp_fetch_ssl_fc(const struct arg *args, struct sample *smp, const char *kw, void *private)
1167{
1168 struct connection *conn;
1169
1170 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001171 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001172 else
1173 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001174 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001175
1176 smp->data.type = SMP_T_BOOL;
Willy Tarreau939b0bf2022-04-11 11:29:11 +02001177 smp->data.u.sint = conn_is_ssl(conn);
William Lallemand15e16942020-05-15 00:25:08 +02001178 return 1;
1179}
1180
1181/* boolean, returns true if client present a SNI */
1182static int
1183smp_fetch_ssl_fc_has_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
1184{
1185#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1186 struct connection *conn = objt_conn(smp->sess->origin);
1187 SSL *ssl = ssl_sock_get_ssl_object(conn);
1188
1189 smp->data.type = SMP_T_BOOL;
1190 smp->data.u.sint = ssl && SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name) != NULL;
1191 return 1;
1192#else
1193 return 0;
1194#endif
1195}
1196
1197/* boolean, returns true if client session has been resumed.
1198 * This function is also usable on backend conn if the fetch keyword 5th
1199 * char is 'b'.
1200 */
1201static int
1202smp_fetch_ssl_fc_is_resumed(const struct arg *args, struct sample *smp, const char *kw, void *private)
1203{
1204 struct connection *conn;
1205 SSL *ssl;
1206
1207 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001208 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001209 else
1210 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001211 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001212
1213 ssl = ssl_sock_get_ssl_object(conn);
1214
1215 smp->data.type = SMP_T_BOOL;
1216 smp->data.u.sint = ssl && SSL_session_reused(ssl);
1217 return 1;
1218}
1219
1220/* string, returns the used cipher if front conn. transport layer is SSL.
1221 * This function is also usable on backend conn if the fetch keyword 5th
1222 * char is 'b'.
1223 */
1224static int
1225smp_fetch_ssl_fc_cipher(const struct arg *args, struct sample *smp, const char *kw, void *private)
1226{
1227 struct connection *conn;
1228 SSL *ssl;
1229
1230 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001231 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001232 else
1233 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001234 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001235
1236 smp->flags = 0;
1237 ssl = ssl_sock_get_ssl_object(conn);
1238 if (!ssl)
1239 return 0;
1240
1241 smp->data.u.str.area = (char *)SSL_get_cipher_name(ssl);
1242 if (!smp->data.u.str.area)
1243 return 0;
1244
1245 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001246 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001247 smp->data.u.str.data = strlen(smp->data.u.str.area);
1248
1249 return 1;
1250}
1251
1252/* integer, returns the algoritm's keysize if front conn. transport layer
1253 * is SSL.
1254 * This function is also usable on backend conn if the fetch keyword 5th
1255 * char is 'b'.
1256 */
1257static int
1258smp_fetch_ssl_fc_alg_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
1259{
1260 struct connection *conn;
1261 SSL *ssl;
1262 int sint;
1263
1264 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001265 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001266 else
1267 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001268 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001269
1270 smp->flags = 0;
1271 ssl = ssl_sock_get_ssl_object(conn);
1272 if (!ssl)
1273 return 0;
1274
1275 if (!SSL_get_cipher_bits(ssl, &sint))
1276 return 0;
1277
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001278 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001279 smp->data.u.sint = sint;
1280 smp->data.type = SMP_T_SINT;
1281
1282 return 1;
1283}
1284
1285/* integer, returns the used keysize if front conn. transport layer is SSL.
1286 * This function is also usable on backend conn if the fetch keyword 5th
1287 * char is 'b'.
1288 */
1289static int
1290smp_fetch_ssl_fc_use_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
1291{
1292 struct connection *conn;
1293 SSL *ssl;
1294
1295 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001296 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001297 else
1298 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001299 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001300
1301 smp->flags = 0;
1302 ssl = ssl_sock_get_ssl_object(conn);
1303 if (!ssl)
1304 return 0;
1305
1306 smp->data.u.sint = (unsigned int)SSL_get_cipher_bits(ssl, NULL);
1307 if (!smp->data.u.sint)
1308 return 0;
1309
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001310 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001311 smp->data.type = SMP_T_SINT;
1312
1313 return 1;
1314}
1315
1316#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
1317static int
1318smp_fetch_ssl_fc_npn(const struct arg *args, struct sample *smp, const char *kw, void *private)
1319{
1320 struct connection *conn;
1321 SSL *ssl;
1322 unsigned int len = 0;
1323
1324 smp->flags = SMP_F_CONST;
1325 smp->data.type = SMP_T_STR;
1326
1327 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001328 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001329 else
1330 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001331 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001332
1333 ssl = ssl_sock_get_ssl_object(conn);
1334 if (!ssl)
1335 return 0;
1336
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001337 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001338 smp->data.u.str.area = NULL;
1339 SSL_get0_next_proto_negotiated(ssl,
1340 (const unsigned char **)&smp->data.u.str.area,
1341 &len);
1342
1343 if (!smp->data.u.str.area)
1344 return 0;
1345
1346 smp->data.u.str.data = len;
1347 return 1;
1348}
1349#endif
1350
1351#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1352static int
1353smp_fetch_ssl_fc_alpn(const struct arg *args, struct sample *smp, const char *kw, void *private)
1354{
1355 struct connection *conn;
1356 SSL *ssl;
1357 unsigned int len = 0;
1358
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001359 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001360 smp->data.type = SMP_T_STR;
1361
1362 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001363 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001364 else
1365 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001366 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001367
1368 ssl = ssl_sock_get_ssl_object(conn);
1369 if (!ssl)
1370 return 0;
1371
1372 smp->data.u.str.area = NULL;
1373 SSL_get0_alpn_selected(ssl,
1374 (const unsigned char **)&smp->data.u.str.area,
1375 &len);
1376
1377 if (!smp->data.u.str.area)
1378 return 0;
1379
1380 smp->data.u.str.data = len;
1381 return 1;
1382}
1383#endif
1384
1385/* string, returns the used protocol if front conn. transport layer is SSL.
1386 * This function is also usable on backend conn if the fetch keyword 5th
1387 * char is 'b'.
1388 */
1389static int
1390smp_fetch_ssl_fc_protocol(const struct arg *args, struct sample *smp, const char *kw, void *private)
1391{
1392 struct connection *conn;
1393 SSL *ssl;
1394
1395 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001396 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001397 else
1398 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001399 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001400
1401 smp->flags = 0;
1402 ssl = ssl_sock_get_ssl_object(conn);
1403 if (!ssl)
1404 return 0;
1405
1406 smp->data.u.str.area = (char *)SSL_get_version(ssl);
1407 if (!smp->data.u.str.area)
1408 return 0;
1409
1410 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001411 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001412 smp->data.u.str.data = strlen(smp->data.u.str.area);
1413
1414 return 1;
1415}
1416
1417/* binary, returns the SSL stream id if front conn. transport layer is SSL.
1418 * This function is also usable on backend conn if the fetch keyword 5th
1419 * char is 'b'.
1420 */
1421#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1422static int
1423smp_fetch_ssl_fc_session_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1424{
1425 struct connection *conn;
1426 SSL_SESSION *ssl_sess;
1427 SSL *ssl;
1428 unsigned int len = 0;
1429
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001430 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001431 smp->data.type = SMP_T_BIN;
1432
1433 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001434 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001435 else
1436 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001437 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001438
1439 ssl = ssl_sock_get_ssl_object(conn);
1440 if (!ssl)
1441 return 0;
1442
1443 ssl_sess = SSL_get_session(ssl);
1444 if (!ssl_sess)
1445 return 0;
1446
1447 smp->data.u.str.area = (char *)SSL_SESSION_get_id(ssl_sess, &len);
1448 if (!smp->data.u.str.area || !len)
1449 return 0;
1450
1451 smp->data.u.str.data = len;
1452 return 1;
1453}
1454#endif
1455
1456
Ilya Shipitsindf627942021-03-25 00:41:41 +05001457#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02001458static int
1459smp_fetch_ssl_fc_random(const struct arg *args, struct sample *smp, const char *kw, void *private)
1460{
1461 struct connection *conn;
1462 struct buffer *data;
1463 SSL *ssl;
1464
1465 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001466 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001467 else
1468 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001469 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001470
1471 ssl = ssl_sock_get_ssl_object(conn);
1472 if (!ssl)
1473 return 0;
1474
1475 data = get_trash_chunk();
1476 if (kw[7] == 'c')
1477 data->data = SSL_get_client_random(ssl,
1478 (unsigned char *) data->area,
1479 data->size);
1480 else
1481 data->data = SSL_get_server_random(ssl,
1482 (unsigned char *) data->area,
1483 data->size);
1484 if (!data->data)
1485 return 0;
1486
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001487 smp->flags = SMP_F_VOL_TEST;
William Lallemand15e16942020-05-15 00:25:08 +02001488 smp->data.type = SMP_T_BIN;
1489 smp->data.u.str = *data;
1490
1491 return 1;
1492}
1493
1494static int
1495smp_fetch_ssl_fc_session_key(const struct arg *args, struct sample *smp, const char *kw, void *private)
1496{
1497 struct connection *conn;
1498 SSL_SESSION *ssl_sess;
1499 struct buffer *data;
1500 SSL *ssl;
1501
1502 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001503 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001504 else
1505 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001506 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001507
1508 ssl = ssl_sock_get_ssl_object(conn);
1509 if (!ssl)
1510 return 0;
1511
1512 ssl_sess = SSL_get_session(ssl);
1513 if (!ssl_sess)
1514 return 0;
1515
1516 data = get_trash_chunk();
1517 data->data = SSL_SESSION_get_master_key(ssl_sess,
1518 (unsigned char *) data->area,
1519 data->size);
1520 if (!data->data)
1521 return 0;
1522
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001523 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001524 smp->data.type = SMP_T_BIN;
1525 smp->data.u.str = *data;
1526
1527 return 1;
1528}
1529#endif
1530
William Lallemand15e16942020-05-15 00:25:08 +02001531static int
1532smp_fetch_ssl_fc_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
1533{
Willy Tarreau579259d2021-11-05 19:12:54 +01001534#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
William Lallemand15e16942020-05-15 00:25:08 +02001535 struct connection *conn;
1536 SSL *ssl;
1537
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001538 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001539 smp->data.type = SMP_T_STR;
1540
1541 conn = objt_conn(smp->sess->origin);
1542 ssl = ssl_sock_get_ssl_object(conn);
1543 if (!ssl)
1544 return 0;
1545
1546 smp->data.u.str.area = (char *)SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
Remi Tricot-Le Bretona9967632022-01-07 17:12:01 +01001547 if (!smp->data.u.str.area) {
1548 /* We might have stored the SNI ourselves, look for it in the
1549 * context's ex_data.
1550 */
1551 smp->data.u.str.area = SSL_get_ex_data(ssl, ssl_client_sni_index);
1552
1553 if (!smp->data.u.str.area)
1554 return 0;
1555 }
William Lallemand15e16942020-05-15 00:25:08 +02001556
1557 smp->data.u.str.data = strlen(smp->data.u.str.area);
Remi Tricot-Le Bretona9967632022-01-07 17:12:01 +01001558
William Lallemand15e16942020-05-15 00:25:08 +02001559 return 1;
Willy Tarreau579259d2021-11-05 19:12:54 +01001560#else
1561 /* SNI not supported */
1562 return 0;
William Lallemand15e16942020-05-15 00:25:08 +02001563#endif
Willy Tarreau579259d2021-11-05 19:12:54 +01001564}
William Lallemand15e16942020-05-15 00:25:08 +02001565
Marcin Deranek959a48c2021-07-13 15:14:21 +02001566/* binary, returns tls client hello cipher list.
1567 * Arguments: filter_option (0,1)
1568 */
William Lallemand15e16942020-05-15 00:25:08 +02001569static int
1570smp_fetch_ssl_fc_cl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1571{
Marcin Deranek959a48c2021-07-13 15:14:21 +02001572 struct buffer *smp_trash;
William Lallemand15e16942020-05-15 00:25:08 +02001573 struct connection *conn;
1574 struct ssl_capture *capture;
1575 SSL *ssl;
1576
1577 conn = objt_conn(smp->sess->origin);
1578 ssl = ssl_sock_get_ssl_object(conn);
1579 if (!ssl)
1580 return 0;
1581
1582 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1583 if (!capture)
1584 return 0;
1585
Marcin Deranek959a48c2021-07-13 15:14:21 +02001586 if (args[0].data.sint) {
1587 smp_trash = get_trash_chunk();
1588 exclude_tls_grease(capture->data + capture->ciphersuite_offset, capture->ciphersuite_len, smp_trash);
1589 smp->data.u.str.area = smp_trash->area;
1590 smp->data.u.str.data = smp_trash->data;
1591 smp->flags = SMP_F_VOL_SESS;
1592 }
1593 else {
1594 smp->data.u.str.area = capture->data + capture->ciphersuite_offset;
1595 smp->data.u.str.data = capture->ciphersuite_len;
1596 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1597 }
1598
William Lallemand15e16942020-05-15 00:25:08 +02001599 smp->data.type = SMP_T_BIN;
William Lallemand15e16942020-05-15 00:25:08 +02001600 return 1;
1601}
1602
Marcin Deranek959a48c2021-07-13 15:14:21 +02001603/* binary, returns tls client hello cipher list as hexadecimal string.
1604 * Arguments: filter_option (0,1)
1605 */
William Lallemand15e16942020-05-15 00:25:08 +02001606static int
1607smp_fetch_ssl_fc_cl_hex(const struct arg *args, struct sample *smp, const char *kw, void *private)
1608{
1609 struct buffer *data;
1610
1611 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1612 return 0;
1613
1614 data = get_trash_chunk();
1615 dump_binary(data, smp->data.u.str.area, smp->data.u.str.data);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001616 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001617 smp->data.type = SMP_T_BIN;
1618 smp->data.u.str = *data;
1619 return 1;
1620}
1621
Marcin Deranek959a48c2021-07-13 15:14:21 +02001622/* integer, returns xxh64 hash of tls client hello cipher list. */
William Lallemand15e16942020-05-15 00:25:08 +02001623static int
1624smp_fetch_ssl_fc_cl_xxh64(const struct arg *args, struct sample *smp, const char *kw, void *private)
1625{
1626 struct connection *conn;
1627 struct ssl_capture *capture;
1628 SSL *ssl;
1629
1630 conn = objt_conn(smp->sess->origin);
1631 ssl = ssl_sock_get_ssl_object(conn);
1632 if (!ssl)
1633 return 0;
1634
1635 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1636 if (!capture)
1637 return 0;
1638
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001639 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001640 smp->data.type = SMP_T_SINT;
1641 smp->data.u.sint = capture->xxh64;
1642 return 1;
1643}
1644
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001645static int
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001646smp_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 +02001647{
1648 struct connection *conn;
1649 struct ssl_sock_ctx *ctx;
1650
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001651 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001652 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->cs) : NULL;
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001653 else
1654 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001655 smp->strm ? sc_conn(smp->strm->scb) : NULL;
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001656
Willy Tarreauce7a5e02022-04-12 07:40:42 +02001657 if (!conn)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001658 return 0;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001659
1660 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1661 smp->flags = SMP_F_MAY_CHANGE;
1662 return 0;
1663 }
1664
Willy Tarreauce7a5e02022-04-12 07:40:42 +02001665 ctx = conn_get_ssl_sock_ctx(conn);
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001666 if (!ctx)
1667 return 0;
1668
1669 smp->flags = SMP_F_VOL_SESS;
1670 smp->data.type = SMP_T_SINT;
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001671 smp->data.u.sint = ctx->error_code;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001672 return 1;
1673}
1674
1675static int
Marcin Deranek959a48c2021-07-13 15:14:21 +02001676smp_fetch_ssl_fc_protocol_hello_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1677{
1678 struct connection *conn;
1679 struct ssl_capture *capture;
1680 SSL *ssl;
1681
1682 conn = objt_conn(smp->sess->origin);
1683 ssl = ssl_sock_get_ssl_object(conn);
1684 if (!ssl)
1685 return 0;
1686
1687 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1688 if (!capture)
1689 return 0;
1690
1691 smp->flags = SMP_F_VOL_SESS;
1692 smp->data.type = SMP_T_SINT;
1693 smp->data.u.sint = capture->protocol_version;
1694 return 1;
1695}
1696
1697static int
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001698smp_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 +02001699{
1700 struct connection *conn;
1701 struct ssl_sock_ctx *ctx;
1702 const char *err_code_str;
1703
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001704 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001705 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->cs) : NULL;
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001706 else
1707 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001708 smp->strm ? sc_conn(smp->strm->scb) : NULL;
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001709
Willy Tarreauce7a5e02022-04-12 07:40:42 +02001710 if (!conn)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001711 return 0;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001712
1713 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1714 smp->flags = SMP_F_MAY_CHANGE;
1715 return 0;
1716 }
1717
Willy Tarreauce7a5e02022-04-12 07:40:42 +02001718 ctx = conn_get_ssl_sock_ctx(conn);
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001719 if (!ctx || !ctx->error_code)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001720 return 0;
1721
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001722 err_code_str = ERR_error_string(ctx->error_code, NULL);
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001723
1724 smp->flags = SMP_F_VOL_SESS;
1725 smp->data.type = SMP_T_STR;
1726 smp->data.u.str.area = (char*)err_code_str;
1727 smp->data.u.str.data = strlen(err_code_str);
1728
Marcin Deranek959a48c2021-07-13 15:14:21 +02001729 return 1;
1730}
1731
1732/* binary, returns tls client hello extensions list.
1733 * Arguments: filter_option (0,1)
1734 */
1735static int
1736smp_fetch_ssl_fc_ext_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1737{
1738 struct buffer *smp_trash;
1739 struct connection *conn;
1740 struct ssl_capture *capture;
1741 SSL *ssl;
1742
1743 conn = objt_conn(smp->sess->origin);
1744 ssl = ssl_sock_get_ssl_object(conn);
1745 if (!ssl)
1746 return 0;
1747
1748 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1749 if (!capture)
1750 return 0;
1751
1752 if (args[0].data.sint) {
1753 smp_trash = get_trash_chunk();
1754 exclude_tls_grease(capture->data + capture->extensions_offset, capture->extensions_len, smp_trash);
1755 smp->data.u.str.area = smp_trash->area;
1756 smp->data.u.str.data = smp_trash->data;
1757 smp->flags = SMP_F_VOL_SESS;
1758 }
1759 else {
1760 smp->data.u.str.area = capture->data + capture->extensions_offset;
1761 smp->data.u.str.data = capture->extensions_len;
1762 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1763 }
1764
1765 smp->data.type = SMP_T_BIN;
1766 return 1;
1767}
1768
1769/* binary, returns tls client hello supported elliptic curves.
1770 * Arguments: filter_option (0,1)
1771 */
1772static int
1773smp_fetch_ssl_fc_ecl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1774{
1775 struct buffer *smp_trash;
1776 struct connection *conn;
1777 struct ssl_capture *capture;
1778 SSL *ssl;
1779
1780 conn = objt_conn(smp->sess->origin);
1781 ssl = ssl_sock_get_ssl_object(conn);
1782 if (!ssl)
1783 return 0;
1784
1785 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1786 if (!capture)
1787 return 0;
1788
1789 if (args[0].data.sint) {
1790 smp_trash = get_trash_chunk();
1791 exclude_tls_grease(capture->data + capture->ec_offset, capture->ec_len, smp_trash);
1792 smp->data.u.str.area = smp_trash->area;
1793 smp->data.u.str.data = smp_trash->data;
1794 smp->flags = SMP_F_VOL_SESS;
1795 }
1796 else {
1797 smp->data.u.str.area = capture->data + capture->ec_offset;
1798 smp->data.u.str.data = capture->ec_len;
1799 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1800 }
1801
1802 smp->data.type = SMP_T_BIN;
1803 return 1;
1804}
1805
1806/* binary, returns tls client hello supported elliptic curve point formats */
1807static int
1808smp_fetch_ssl_fc_ecf_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1809{
1810 struct connection *conn;
1811 struct ssl_capture *capture;
1812 SSL *ssl;
1813
1814 conn = objt_conn(smp->sess->origin);
1815 ssl = ssl_sock_get_ssl_object(conn);
1816 if (!ssl)
1817 return 0;
1818
1819 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1820 if (!capture)
1821 return 0;
1822
1823 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1824 smp->data.type = SMP_T_BIN;
1825 smp->data.u.str.area = capture->data + capture->ec_formats_offset;
1826 smp->data.u.str.data = capture->ec_formats_len;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001827 return 1;
1828}
1829
William Lallemand7d42ef52020-07-06 11:41:30 +02001830/* Dump the SSL keylog, it only works with "tune.ssl.keylog 1" */
William Lallemand722180a2021-06-09 16:46:12 +02001831#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02001832static int smp_fetch_ssl_x_keylog(const struct arg *args, struct sample *smp, const char *kw, void *private)
1833{
1834 struct connection *conn;
1835 struct ssl_keylog *keylog;
1836 SSL *ssl;
1837 char *src = NULL;
1838 const char *sfx;
1839
1840 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001841 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand7d42ef52020-07-06 11:41:30 +02001842
William Lallemandeec1d452020-07-07 10:48:13 +02001843 if (!conn)
1844 return 0;
1845
William Lallemand7d42ef52020-07-06 11:41:30 +02001846 if (conn->flags & CO_FL_WAIT_XPRT) {
1847 smp->flags |= SMP_F_MAY_CHANGE;
1848 return 0;
1849 }
1850
1851 ssl = ssl_sock_get_ssl_object(conn);
1852 if (!ssl)
1853 return 0;
1854
1855 keylog = SSL_get_ex_data(ssl, ssl_keylog_index);
1856 if (!keylog)
1857 return 0;
1858
1859 sfx = kw + strlen("ssl_xx_");
1860
1861 if (strcmp(sfx, "client_early_traffic_secret") == 0) {
1862 src = keylog->client_early_traffic_secret;
1863 } else if (strcmp(sfx, "client_handshake_traffic_secret") == 0) {
1864 src = keylog->client_handshake_traffic_secret;
1865 } else if (strcmp(sfx, "server_handshake_traffic_secret") == 0) {
1866 src = keylog->server_handshake_traffic_secret;
1867 } else if (strcmp(sfx, "client_traffic_secret_0") == 0) {
1868 src = keylog->client_traffic_secret_0;
1869 } else if (strcmp(sfx, "server_traffic_secret_0") == 0) {
1870 src = keylog->server_traffic_secret_0;
1871 } else if (strcmp(sfx, "exporter_secret") == 0) {
1872 src = keylog->exporter_secret;
1873 } else if (strcmp(sfx, "early_exporter_secret") == 0) {
1874 src = keylog->early_exporter_secret;
1875 }
1876
1877 if (!src || !*src)
1878 return 0;
1879
1880 smp->data.u.str.area = src;
1881 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001882 smp->flags |= SMP_F_VOL_TEST | SMP_F_CONST;
William Lallemand7d42ef52020-07-06 11:41:30 +02001883 smp->data.u.str.data = strlen(smp->data.u.str.area);
1884 return 1;
William Lallemand7d42ef52020-07-06 11:41:30 +02001885}
1886#endif
1887
William Lallemand15e16942020-05-15 00:25:08 +02001888static int
1889smp_fetch_ssl_fc_cl_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
1890{
Ilya Shipitsinc9dfee42020-10-31 02:10:02 +05001891#if defined(OPENSSL_IS_BORINGSSL) || defined(SSL_CTRL_GET_RAW_CIPHERLIST)
William Lallemand15e16942020-05-15 00:25:08 +02001892 struct buffer *data;
1893 int i;
1894
1895 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1896 return 0;
1897
1898 data = get_trash_chunk();
1899 for (i = 0; i + 1 < smp->data.u.str.data; i += 2) {
1900 const char *str;
1901 const SSL_CIPHER *cipher;
1902 const unsigned char *bin = (const unsigned char *) smp->data.u.str.area + i;
1903 uint16_t id = (bin[0] << 8) | bin[1];
1904#if defined(OPENSSL_IS_BORINGSSL)
1905 cipher = SSL_get_cipher_by_value(id);
1906#else
1907 struct connection *conn = __objt_conn(smp->sess->origin);
1908 SSL *ssl = ssl_sock_get_ssl_object(conn);
1909 cipher = SSL_CIPHER_find(ssl, bin);
1910#endif
1911 str = SSL_CIPHER_get_name(cipher);
1912 if (!str || strcmp(str, "(NONE)") == 0)
1913 chunk_appendf(data, "%sUNKNOWN(%04x)", i == 0 ? "" : ",", id);
1914 else
1915 chunk_appendf(data, "%s%s", i == 0 ? "" : ",", str);
1916 }
1917 smp->data.type = SMP_T_STR;
1918 smp->data.u.str = *data;
1919 return 1;
1920#else
1921 return smp_fetch_ssl_fc_cl_xxh64(args, smp, kw, private);
1922#endif
1923}
1924
1925#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1926static int
1927smp_fetch_ssl_fc_unique_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1928{
1929 struct connection *conn;
1930 int finished_len;
1931 struct buffer *finished_trash;
1932 SSL *ssl;
1933
1934 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001935 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001936 else
1937 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001938 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001939
1940 smp->flags = 0;
1941 ssl = ssl_sock_get_ssl_object(conn);
1942 if (!ssl)
1943 return 0;
1944
1945 if (conn->flags & CO_FL_WAIT_XPRT) {
1946 smp->flags |= SMP_F_MAY_CHANGE;
1947 return 0;
1948 }
1949
1950 finished_trash = get_trash_chunk();
1951 if (!SSL_session_reused(ssl))
1952 finished_len = SSL_get_peer_finished(ssl,
1953 finished_trash->area,
1954 finished_trash->size);
1955 else
1956 finished_len = SSL_get_finished(ssl,
1957 finished_trash->area,
1958 finished_trash->size);
1959
1960 if (!finished_len)
1961 return 0;
1962
1963 finished_trash->data = finished_len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001964 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001965 smp->data.u.str = *finished_trash;
1966 smp->data.type = SMP_T_BIN;
1967
1968 return 1;
1969}
1970#endif
1971
1972/* integer, returns the first verify error in CA chain of client certificate chain. */
1973static int
1974smp_fetch_ssl_c_ca_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
1975{
Willy Tarreau939b0bf2022-04-11 11:29:11 +02001976 struct connection *conn = objt_conn(smp->sess->origin);
1977 struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
William Lallemand15e16942020-05-15 00:25:08 +02001978
Willy Tarreau939b0bf2022-04-11 11:29:11 +02001979 if (conn && conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001980 smp->flags = SMP_F_MAY_CHANGE;
1981 return 0;
1982 }
1983
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001984 if (!ctx)
1985 return 0;
1986
William Lallemand15e16942020-05-15 00:25:08 +02001987 smp->data.type = SMP_T_SINT;
1988 smp->data.u.sint = (unsigned long long int)SSL_SOCK_ST_TO_CA_ERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001989 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001990
1991 return 1;
1992}
1993
1994/* integer, returns the depth of the first verify error in CA chain of client certificate chain. */
1995static int
1996smp_fetch_ssl_c_ca_err_depth(const struct arg *args, struct sample *smp, const char *kw, void *private)
1997{
Willy Tarreau939b0bf2022-04-11 11:29:11 +02001998 struct connection *conn = objt_conn(smp->sess->origin);
1999 struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
William Lallemand15e16942020-05-15 00:25:08 +02002000
Willy Tarreau939b0bf2022-04-11 11:29:11 +02002001 if (conn && conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02002002 smp->flags = SMP_F_MAY_CHANGE;
2003 return 0;
2004 }
William Lallemand15e16942020-05-15 00:25:08 +02002005
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002006 if (!ctx)
2007 return 0;
2008
William Lallemand15e16942020-05-15 00:25:08 +02002009 smp->data.type = SMP_T_SINT;
2010 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CAEDEPTH(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002011 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002012
2013 return 1;
2014}
2015
2016/* integer, returns the first verify error on client certificate */
2017static int
2018smp_fetch_ssl_c_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
2019{
Willy Tarreau939b0bf2022-04-11 11:29:11 +02002020 struct connection *conn = objt_conn(smp->sess->origin);
2021 struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
William Lallemand15e16942020-05-15 00:25:08 +02002022
Willy Tarreau939b0bf2022-04-11 11:29:11 +02002023 if (conn && conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02002024 smp->flags = SMP_F_MAY_CHANGE;
2025 return 0;
2026 }
2027
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002028 if (!ctx)
2029 return 0;
2030
William Lallemand15e16942020-05-15 00:25:08 +02002031 smp->data.type = SMP_T_SINT;
2032 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CRTERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002033 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002034
2035 return 1;
2036}
2037
2038/* integer, returns the verify result on client cert */
2039static int
2040smp_fetch_ssl_c_verify(const struct arg *args, struct sample *smp, const char *kw, void *private)
2041{
2042 struct connection *conn;
2043 SSL *ssl;
2044
2045 conn = objt_conn(smp->sess->origin);
2046 ssl = ssl_sock_get_ssl_object(conn);
2047 if (!ssl)
2048 return 0;
2049
2050 if (conn->flags & CO_FL_WAIT_XPRT) {
2051 smp->flags = SMP_F_MAY_CHANGE;
2052 return 0;
2053 }
2054
2055 smp->data.type = SMP_T_SINT;
2056 smp->data.u.sint = (long long int)SSL_get_verify_result(ssl);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002057 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002058
2059 return 1;
2060}
2061
2062/* Argument validation functions */
2063
2064/* This function is used to validate the arguments passed to any "x_dn" ssl
2065 * keywords. These keywords support specifying a third parameter that must be
2066 * either empty or the value "rfc2253". Returns 0 on error, non-zero if OK.
2067 */
2068int val_dnfmt(struct arg *arg, char **err_msg)
2069{
2070 if (arg && arg[2].type == ARGT_STR && arg[2].data.str.data > 0 && (strcmp(arg[2].data.str.area, "rfc2253") != 0)) {
2071 memprintf(err_msg, "only rfc2253 or a blank value are currently supported as the format argument.");
2072 return 0;
2073 }
2074 return 1;
2075}
2076
2077/* Note: must not be declared <const> as its list will be overwritten.
2078 * Please take care of keeping this list alphabetically sorted.
2079 */
2080static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
2081 { "ssl_bc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
2082 { "ssl_bc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2083#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2084 { "ssl_bc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2085#endif
2086 { "ssl_bc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2087#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2088 { "ssl_bc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2089#endif
2090 { "ssl_bc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
2091 { "ssl_bc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2092 { "ssl_bc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2093 { "ssl_bc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2094#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2095 { "ssl_bc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2096#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05002097#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02002098 { "ssl_bc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2099 { "ssl_bc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2100 { "ssl_bc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2101#endif
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02002102 { "ssl_bc_err", smp_fetch_ssl_fc_err, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2103 { "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 +02002104 { "ssl_c_ca_err", smp_fetch_ssl_c_ca_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2105 { "ssl_c_ca_err_depth", smp_fetch_ssl_c_ca_err_depth, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2106 { "ssl_c_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02002107 { "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 +02002108 { "ssl_c_err", smp_fetch_ssl_c_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2109 { "ssl_c_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2110 { "ssl_c_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2111 { "ssl_c_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2112 { "ssl_c_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2113 { "ssl_c_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2114 { "ssl_c_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2115 { "ssl_c_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2116 { "ssl_c_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2117 { "ssl_c_used", smp_fetch_ssl_c_used, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2118 { "ssl_c_verify", smp_fetch_ssl_c_verify, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2119 { "ssl_c_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2120 { "ssl_f_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2121 { "ssl_f_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2122 { "ssl_f_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2123 { "ssl_f_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2124 { "ssl_f_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2125 { "ssl_f_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2126 { "ssl_f_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2127 { "ssl_f_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2128 { "ssl_f_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2129 { "ssl_f_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2130 { "ssl_fc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2131 { "ssl_fc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2132 { "ssl_fc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2133 { "ssl_fc_has_crt", smp_fetch_ssl_fc_has_crt, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2134 { "ssl_fc_has_early", smp_fetch_ssl_fc_has_early, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2135 { "ssl_fc_has_sni", smp_fetch_ssl_fc_has_sni, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2136 { "ssl_fc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2137#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2138 { "ssl_fc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2139#endif
2140#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2141 { "ssl_fc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2142#endif
2143 { "ssl_fc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2144#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2145 { "ssl_fc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2146#endif
2147 { "ssl_fc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2148#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2149 { "ssl_fc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2150#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05002151#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02002152 { "ssl_fc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2153 { "ssl_fc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2154 { "ssl_fc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2155#endif
William Lallemand7d42ef52020-07-06 11:41:30 +02002156
William Lallemand722180a2021-06-09 16:46:12 +02002157#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02002158 { "ssl_fc_client_early_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2159 { "ssl_fc_client_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2160 { "ssl_fc_server_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2161 { "ssl_fc_client_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2162 { "ssl_fc_server_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2163 { "ssl_fc_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2164 { "ssl_fc_early_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2165#endif
2166
William Lallemand15e16942020-05-15 00:25:08 +02002167 { "ssl_fc_sni", smp_fetch_ssl_fc_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
Marcin Deranek959a48c2021-07-13 15:14:21 +02002168 { "ssl_fc_cipherlist_bin", smp_fetch_ssl_fc_cl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2169 { "ssl_fc_cipherlist_hex", smp_fetch_ssl_fc_cl_hex, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_USE_L5CLI },
2170 { "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 +02002171 { "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 +02002172 { "ssl_fc_err", smp_fetch_ssl_fc_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2173 { "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 +02002174 { "ssl_fc_protocol_hello_id",smp_fetch_ssl_fc_protocol_hello_id,0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2175 { "ssl_fc_extlist_bin", smp_fetch_ssl_fc_ext_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2176 { "ssl_fc_eclist_bin", smp_fetch_ssl_fc_ecl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2177 { "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 +02002178
2179/* SSL server certificate fetches */
2180 { "ssl_s_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02002181 { "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 +02002182 { "ssl_s_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2183 { "ssl_s_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2184 { "ssl_s_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2185 { "ssl_s_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2186 { "ssl_s_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2187 { "ssl_s_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2188 { "ssl_s_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2189 { "ssl_s_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2190 { "ssl_s_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
William Lallemand15e16942020-05-15 00:25:08 +02002191 { NULL, NULL, 0, 0, 0 },
2192}};
2193
2194INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
2195
Willy Tarreau99ea1882021-10-06 15:37:17 +02002196/* Note: must not be declared <const> as its list will be overwritten */
2197static struct sample_conv_kw_list sample_conv_kws = {ILH, {
2198 { "sha2", sample_conv_sha2, ARG1(0, SINT), smp_check_sha2, SMP_T_BIN, SMP_T_BIN },
2199#ifdef EVP_CIPH_GCM_MODE
2200 { "aes_gcm_dec", sample_conv_aes_gcm_dec, ARG4(4,SINT,STR,STR,STR), check_aes_gcm, SMP_T_BIN, SMP_T_BIN },
2201#endif
2202 { "digest", sample_conv_crypto_digest, ARG1(1,STR), check_crypto_digest, SMP_T_BIN, SMP_T_BIN },
2203 { "hmac", sample_conv_crypto_hmac, ARG2(2,STR,STR), check_crypto_hmac, SMP_T_BIN, SMP_T_BIN },
2204#if defined(HAVE_CRYPTO_memcmp)
2205 { "secure_memcmp", sample_conv_secure_memcmp, ARG1(1,STR), smp_check_secure_memcmp, SMP_T_BIN, SMP_T_BOOL },
2206#endif
2207 { NULL, NULL, 0, 0, 0 },
2208}};
2209
2210INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
2211
2212
William Lallemand15e16942020-05-15 00:25:08 +02002213/* Note: must not be declared <const> as its list will be overwritten.
2214 * Please take care of keeping this list alphabetically sorted.
2215 */
2216static struct acl_kw_list acl_kws = {ILH, {
2217 { "ssl_fc_sni_end", "ssl_fc_sni", PAT_MATCH_END },
2218 { "ssl_fc_sni_reg", "ssl_fc_sni", PAT_MATCH_REG },
2219 { /* END */ },
2220}};
2221
2222INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);