blob: 437952619c4efd8254472df8380979d4c040159b [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 Tarreau939b0bf2022-04-11 11:29:11 +020028#include <haproxy/connection.h>
Christopher Faulet1329f2a2021-12-16 17:32:56 +010029#include <haproxy/conn_stream.h>
Willy Tarreau8efbdfb2020-06-04 11:29:21 +020030#include <haproxy/obj_type.h>
Willy Tarreau6019fab2020-05-27 16:26:00 +020031#include <haproxy/openssl-compat.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020032#include <haproxy/sample.h>
Willy Tarreau209108d2020-06-04 20:30:20 +020033#include <haproxy/ssl_sock.h>
Willy Tarreaub2bd8652020-06-04 14:21:22 +020034#include <haproxy/ssl_utils.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020035#include <haproxy/tools.h>
Willy Tarreau99ea1882021-10-06 15:37:17 +020036#include <haproxy/vars.h>
William Lallemand15e16942020-05-15 00:25:08 +020037
William Lallemand15e16942020-05-15 00:25:08 +020038
39/***** Below are some sample fetching functions for ACL/patterns *****/
40
Willy Tarreau99ea1882021-10-06 15:37:17 +020041#if defined(HAVE_CRYPTO_memcmp)
42/* Compares bytestring with a variable containing a bytestring. Return value
43 * is `true` if both bytestrings are bytewise identical and `false` otherwise.
44 *
45 * Comparison will be performed in constant time if both bytestrings are of
46 * the same length. If the lengths differ execution time will not be constant.
47 */
48static int sample_conv_secure_memcmp(const struct arg *arg_p, struct sample *smp, void *private)
49{
50 struct sample tmp;
51 int result;
52
53 smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
54 if (arg_p[0].type != ARGT_VAR)
55 return 0;
56
57 if (!sample_conv_var2smp(&arg_p[0].data.var, &tmp, SMP_T_BIN))
58 return 0;
59
60 if (smp->data.u.str.data != tmp.data.u.str.data) {
61 smp->data.u.sint = 0;
62 smp->data.type = SMP_T_BOOL;
63 return 1;
64 }
65
66 /* The following comparison is performed in constant time. */
67 result = CRYPTO_memcmp(smp->data.u.str.area, tmp.data.u.str.area, smp->data.u.str.data);
68
69 smp->data.u.sint = result == 0;
70 smp->data.type = SMP_T_BOOL;
71 return 1;
72}
73
74/* This function checks the "secure_memcmp" converter's arguments and extracts the
75 * variable name and its scope.
76 */
77static int smp_check_secure_memcmp(struct arg *args, struct sample_conv *conv,
78 const char *file, int line, char **err)
79{
80 if (!args[0].data.str.data) {
81 memprintf(err, "missing variable name");
82 return 0;
83 }
84
85 /* Try to decode a variable. */
86 if (vars_check_arg(&args[0], NULL))
87 return 1;
88
89 memprintf(err, "failed to register variable name '%s'",
90 args[0].data.str.area);
91 return 0;
92}
93#endif // HAVE_secure_memcmp()
94
95static int smp_check_sha2(struct arg *args, struct sample_conv *conv,
96 const char *file, int line, char **err)
97{
98 if (args[0].type == ARGT_STOP)
99 return 1;
100 if (args[0].type != ARGT_SINT) {
101 memprintf(err, "Invalid type '%s'", arg_type_names[args[0].type]);
102 return 0;
103 }
104
105 switch (args[0].data.sint) {
106 case 224:
107 case 256:
108 case 384:
109 case 512:
110 /* this is okay */
111 return 1;
112 default:
113 memprintf(err, "Unsupported number of bits: '%lld'", args[0].data.sint);
114 return 0;
115 }
116}
117
118static int sample_conv_sha2(const struct arg *arg_p, struct sample *smp, void *private)
119{
120 struct buffer *trash = get_trash_chunk();
121 int bits = 256;
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100122 EVP_MD_CTX *mdctx;
123 const EVP_MD *evp = NULL;
124 unsigned int digest_length = 0;
Willy Tarreau99ea1882021-10-06 15:37:17 +0200125 if (arg_p->data.sint)
126 bits = arg_p->data.sint;
127
128 switch (bits) {
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100129 case 224:
130 evp = EVP_sha224();
Willy Tarreau99ea1882021-10-06 15:37:17 +0200131 break;
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100132 case 256:
133 evp = EVP_sha256();
Willy Tarreau99ea1882021-10-06 15:37:17 +0200134 break;
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100135 case 384:
136 evp = EVP_sha384();
Willy Tarreau99ea1882021-10-06 15:37:17 +0200137 break;
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100138 case 512:
139 evp = EVP_sha512();
Willy Tarreau99ea1882021-10-06 15:37:17 +0200140 break;
Willy Tarreau99ea1882021-10-06 15:37:17 +0200141 default:
142 return 0;
143 }
144
Remi Tricot-Le Breton2559bc82022-02-08 17:45:53 +0100145 mdctx = EVP_MD_CTX_new();
146 if (!mdctx)
147 return 0;
148 EVP_DigestInit_ex(mdctx, evp, NULL);
149 EVP_DigestUpdate(mdctx, smp->data.u.str.area, smp->data.u.str.data);
150 EVP_DigestFinal_ex(mdctx, (unsigned char*)trash->area, &digest_length);
151 trash->data = digest_length;
152
153 EVP_MD_CTX_free(mdctx);
154
Willy Tarreau99ea1882021-10-06 15:37:17 +0200155 smp->data.u.str = *trash;
156 smp->data.type = SMP_T_BIN;
157 smp->flags &= ~SMP_F_CONST;
158 return 1;
159}
160
161/* This function checks an <arg> and fills it with a variable type if the
162 * <arg> string contains a valid variable name. If failed, the function
163 * tries to perform a base64 decode operation on the same string, and
164 * fills the <arg> with the decoded content.
165 *
166 * Validation is skipped if the <arg> string is empty.
167 *
168 * This function returns 0 if the variable lookup fails and the specified
169 * <arg> string is not a valid base64 encoded string, as well if
170 * unexpected argument type is specified or memory allocation error
171 * occurs. Otherwise it returns 1.
172 */
173static inline int sample_check_arg_base64(struct arg *arg, char **err)
174{
175 char *dec = NULL;
176 int dec_size;
177
178 if (arg->type != ARGT_STR) {
179 memprintf(err, "unexpected argument type");
180 return 0;
181 }
182
183 if (arg->data.str.data == 0) /* empty */
184 return 1;
185
186 if (vars_check_arg(arg, NULL))
187 return 1;
188
189 if (arg->data.str.data % 4) {
190 memprintf(err, "argument needs to be base64 encoded, and "
191 "can either be a string or a variable");
192 return 0;
193 }
194
195 dec_size = (arg->data.str.data / 4 * 3)
196 - (arg->data.str.area[arg->data.str.data-1] == '=' ? 1 : 0)
197 - (arg->data.str.area[arg->data.str.data-2] == '=' ? 1 : 0);
198
199 if ((dec = malloc(dec_size)) == NULL) {
200 memprintf(err, "memory allocation error");
201 return 0;
202 }
203
204 dec_size = base64dec(arg->data.str.area, arg->data.str.data, dec, dec_size);
205 if (dec_size < 0) {
206 memprintf(err, "argument needs to be base64 encoded, and "
207 "can either be a string or a variable");
208 free(dec);
209 return 0;
210 }
211
212 /* base64 decoded */
213 chunk_destroy(&arg->data.str);
214 arg->data.str.area = dec;
215 arg->data.str.data = dec_size;
216 return 1;
217}
218
219#ifdef EVP_CIPH_GCM_MODE
220static int check_aes_gcm(struct arg *args, struct sample_conv *conv,
221 const char *file, int line, char **err)
222{
223 switch(args[0].data.sint) {
224 case 128:
225 case 192:
226 case 256:
227 break;
228 default:
229 memprintf(err, "key size must be 128, 192 or 256 (bits).");
230 return 0;
231 }
232
233 /* Try to decode variables. */
234 if (!sample_check_arg_base64(&args[1], err)) {
235 memprintf(err, "failed to parse nonce : %s", *err);
236 return 0;
237 }
238 if (!sample_check_arg_base64(&args[2], err)) {
239 memprintf(err, "failed to parse key : %s", *err);
240 return 0;
241 }
242 if (!sample_check_arg_base64(&args[3], err)) {
243 memprintf(err, "failed to parse aead_tag : %s", *err);
244 return 0;
245 }
246
247 return 1;
248}
249
250/* Arguments: AES size in bits, nonce, key, tag. The last three arguments are base64 encoded */
251static int sample_conv_aes_gcm_dec(const struct arg *arg_p, struct sample *smp, void *private)
252{
253 struct sample nonce, key, aead_tag;
254 struct buffer *smp_trash = NULL, *smp_trash_alloc = NULL;
255 EVP_CIPHER_CTX *ctx;
256 int dec_size, ret;
257
258 smp_trash_alloc = alloc_trash_chunk();
259 if (!smp_trash_alloc)
260 return 0;
261
262 /* smp copy */
263 smp_trash_alloc->data = smp->data.u.str.data;
264 if (unlikely(smp_trash_alloc->data > smp_trash_alloc->size))
265 smp_trash_alloc->data = smp_trash_alloc->size;
266 memcpy(smp_trash_alloc->area, smp->data.u.str.area, smp_trash_alloc->data);
267
268 ctx = EVP_CIPHER_CTX_new();
269
270 if (!ctx)
271 goto err;
272
273 smp_trash = alloc_trash_chunk();
274 if (!smp_trash)
275 goto err;
276
277 smp_set_owner(&nonce, smp->px, smp->sess, smp->strm, smp->opt);
278 if (!sample_conv_var2smp_str(&arg_p[1], &nonce))
279 goto err;
280
281 if (arg_p[1].type == ARGT_VAR) {
282 dec_size = base64dec(nonce.data.u.str.area, nonce.data.u.str.data, smp_trash->area, smp_trash->size);
283 if (dec_size < 0)
284 goto err;
285 smp_trash->data = dec_size;
286 nonce.data.u.str = *smp_trash;
287 }
288
289 /* Set cipher type and mode */
290 switch(arg_p[0].data.sint) {
291 case 128:
292 EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);
293 break;
294 case 192:
295 EVP_DecryptInit_ex(ctx, EVP_aes_192_gcm(), NULL, NULL, NULL);
296 break;
297 case 256:
298 EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
299 break;
300 }
301
302 EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce.data.u.str.data, NULL);
303
304 /* Initialise IV */
305 if(!EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, (unsigned char *) nonce.data.u.str.area))
306 goto err;
307
308 smp_set_owner(&key, smp->px, smp->sess, smp->strm, smp->opt);
309 if (!sample_conv_var2smp_str(&arg_p[2], &key))
310 goto err;
311
312 if (arg_p[2].type == ARGT_VAR) {
313 dec_size = base64dec(key.data.u.str.area, key.data.u.str.data, smp_trash->area, smp_trash->size);
314 if (dec_size < 0)
315 goto err;
316 smp_trash->data = dec_size;
317 key.data.u.str = *smp_trash;
318 }
319
320 /* Initialise key */
321 if (!EVP_DecryptInit_ex(ctx, NULL, NULL, (unsigned char *) key.data.u.str.area, NULL))
322 goto err;
323
324 if (!EVP_DecryptUpdate(ctx, (unsigned char *) smp_trash->area, (int *) &smp_trash->data,
325 (unsigned char *) smp_trash_alloc->area, (int) smp_trash_alloc->data))
326 goto err;
327
328 smp_set_owner(&aead_tag, smp->px, smp->sess, smp->strm, smp->opt);
329 if (!sample_conv_var2smp_str(&arg_p[3], &aead_tag))
330 goto err;
331
332 if (arg_p[3].type == ARGT_VAR) {
333 dec_size = base64dec(aead_tag.data.u.str.area, aead_tag.data.u.str.data, smp_trash_alloc->area, smp_trash_alloc->size);
334 if (dec_size < 0)
335 goto err;
336 smp_trash_alloc->data = dec_size;
337 aead_tag.data.u.str = *smp_trash_alloc;
338 }
339
340 dec_size = smp_trash->data;
341
342 EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, aead_tag.data.u.str.data, (void *) aead_tag.data.u.str.area);
343 ret = EVP_DecryptFinal_ex(ctx, (unsigned char *) smp_trash->area + smp_trash->data, (int *) &smp_trash->data);
344
345 if (ret <= 0)
346 goto err;
347
348 smp->data.u.str.data = dec_size + smp_trash->data;
349 smp->data.u.str.area = smp_trash->area;
350 smp->data.type = SMP_T_BIN;
351 smp_dup(smp);
352 free_trash_chunk(smp_trash_alloc);
353 free_trash_chunk(smp_trash);
354 return 1;
355
356err:
357 free_trash_chunk(smp_trash_alloc);
358 free_trash_chunk(smp_trash);
359 return 0;
360}
361#endif
362
363static int check_crypto_digest(struct arg *args, struct sample_conv *conv,
364 const char *file, int line, char **err)
365{
366 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
367
368 if (evp)
369 return 1;
370
371 memprintf(err, "algorithm must be a valid OpenSSL message digest name.");
372 return 0;
373}
374
375static int sample_conv_crypto_digest(const struct arg *args, struct sample *smp, void *private)
376{
377 struct buffer *trash = get_trash_chunk();
378 unsigned char *md = (unsigned char*) trash->area;
379 unsigned int md_len = trash->size;
380 EVP_MD_CTX *ctx = EVP_MD_CTX_new();
381 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
382
383 if (!ctx)
384 return 0;
385
386 if (!EVP_DigestInit_ex(ctx, evp, NULL) ||
387 !EVP_DigestUpdate(ctx, smp->data.u.str.area, smp->data.u.str.data) ||
388 !EVP_DigestFinal_ex(ctx, md, &md_len)) {
389 EVP_MD_CTX_free(ctx);
390 return 0;
391 }
392
393 EVP_MD_CTX_free(ctx);
394
395 trash->data = md_len;
396 smp->data.u.str = *trash;
397 smp->data.type = SMP_T_BIN;
398 smp->flags &= ~SMP_F_CONST;
399 return 1;
400}
401
402static int check_crypto_hmac(struct arg *args, struct sample_conv *conv,
403 const char *file, int line, char **err)
404{
405 if (!check_crypto_digest(args, conv, file, line, err))
406 return 0;
407
408 if (!sample_check_arg_base64(&args[1], err)) {
409 memprintf(err, "failed to parse key : %s", *err);
410 return 0;
411 }
412
413 return 1;
414}
415
416static int sample_conv_crypto_hmac(const struct arg *args, struct sample *smp, void *private)
417{
418 struct sample key;
419 struct buffer *trash = NULL, *key_trash = NULL;
420 unsigned char *md;
421 unsigned int md_len;
422 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
423 int dec_size;
424
425 smp_set_owner(&key, smp->px, smp->sess, smp->strm, smp->opt);
426 if (!sample_conv_var2smp_str(&args[1], &key))
427 return 0;
428
429 if (args[1].type == ARGT_VAR) {
430 key_trash = alloc_trash_chunk();
431 if (!key_trash)
432 goto err;
433
434 dec_size = base64dec(key.data.u.str.area, key.data.u.str.data, key_trash->area, key_trash->size);
435 if (dec_size < 0)
436 goto err;
437 key_trash->data = dec_size;
438 key.data.u.str = *key_trash;
439 }
440
441 trash = alloc_trash_chunk();
442 if (!trash)
443 goto err;
444
445 md = (unsigned char*) trash->area;
446 md_len = trash->size;
447 if (!HMAC(evp, key.data.u.str.area, key.data.u.str.data, (const unsigned char*) smp->data.u.str.area,
448 smp->data.u.str.data, md, &md_len))
449 goto err;
450
451 free_trash_chunk(key_trash);
452
453 trash->data = md_len;
454 smp->data.u.str = *trash;
455 smp->data.type = SMP_T_BIN;
456 smp_dup(smp);
457 free_trash_chunk(trash);
458 return 1;
459
460err:
461 free_trash_chunk(key_trash);
462 free_trash_chunk(trash);
463 return 0;
464}
465
William Lallemand15e16942020-05-15 00:25:08 +0200466static int
467smp_fetch_ssl_fc_has_early(const struct arg *args, struct sample *smp, const char *kw, void *private)
468{
469 SSL *ssl;
470 struct connection *conn;
471
472 conn = objt_conn(smp->sess->origin);
473 ssl = ssl_sock_get_ssl_object(conn);
474 if (!ssl)
475 return 0;
476
477 smp->flags = 0;
478 smp->data.type = SMP_T_BOOL;
479#ifdef OPENSSL_IS_BORINGSSL
480 {
481 smp->data.u.sint = (SSL_in_early_data(ssl) &&
482 SSL_early_data_accepted(ssl));
483 }
484#else
485 smp->data.u.sint = ((conn->flags & CO_FL_EARLY_DATA) &&
486 (conn->flags & (CO_FL_EARLY_SSL_HS | CO_FL_SSL_WAIT_HS))) ? 1 : 0;
487#endif
488 return 1;
489}
490
491/* boolean, returns true if client cert was present */
492static int
493smp_fetch_ssl_fc_has_crt(const struct arg *args, struct sample *smp, const char *kw, void *private)
494{
Willy Tarreau939b0bf2022-04-11 11:29:11 +0200495 struct connection *conn = objt_conn(smp->sess->origin);
496 struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
William Lallemand15e16942020-05-15 00:25:08 +0200497
Willy Tarreau939b0bf2022-04-11 11:29:11 +0200498 if (!ctx)
William Lallemand15e16942020-05-15 00:25:08 +0200499 return 0;
500
William Lallemand15e16942020-05-15 00:25:08 +0200501 if (conn->flags & CO_FL_WAIT_XPRT) {
502 smp->flags |= SMP_F_MAY_CHANGE;
503 return 0;
504 }
505
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200506 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200507 smp->data.type = SMP_T_BOOL;
508 smp->data.u.sint = SSL_SOCK_ST_FL_VERIFY_DONE & ctx->xprt_st ? 1 : 0;
509
510 return 1;
511}
512
513/* binary, returns a certificate in a binary chunk (der/raw).
514 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
515 * should be use.
516 */
517static int
518smp_fetch_ssl_x_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
519{
William Lallemandbfa3e812020-06-25 20:07:18 +0200520 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
521 int conn_server = (kw[4] == 's') ? 1 : 0;
522
William Lallemand15e16942020-05-15 00:25:08 +0200523 X509 *crt = NULL;
524 int ret = 0;
525 struct buffer *smp_trash;
526 struct connection *conn;
527 SSL *ssl;
528
William Lallemandbfa3e812020-06-25 20:07:18 +0200529 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100530 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200531 else
532 conn = objt_conn(smp->sess->origin);
533
William Lallemand15e16942020-05-15 00:25:08 +0200534 ssl = ssl_sock_get_ssl_object(conn);
535 if (!ssl)
536 return 0;
537
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200538 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200539 smp->flags |= SMP_F_MAY_CHANGE;
540 return 0;
541 }
542
543 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200544 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200545 else
546 crt = SSL_get_certificate(ssl);
547
548 if (!crt)
549 goto out;
550
551 smp_trash = get_trash_chunk();
552 if (ssl_sock_crt2der(crt, smp_trash) <= 0)
553 goto out;
554
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200555 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200556 smp->data.u.str = *smp_trash;
557 smp->data.type = SMP_T_BIN;
558 ret = 1;
559out:
560 /* SSL_get_peer_certificate, it increase X509 * ref count */
561 if (cert_peer && crt)
562 X509_free(crt);
563 return ret;
564}
565
William Dauchya598b502020-08-06 18:11:38 +0200566/* binary, returns a chain certificate in a binary chunk (der/raw).
567 * The 5th keyword char is used to support only peer cert
568 */
569static int
570smp_fetch_ssl_x_chain_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
571{
572 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
573 int conn_server = (kw[4] == 's') ? 1 : 0;
574 struct buffer *smp_trash;
575 struct buffer *tmp_trash = NULL;
576 struct connection *conn;
577 STACK_OF(X509) *certs = NULL;
578 X509 *crt = NULL;
579 SSL *ssl;
580 int ret = 0;
581 int num_certs;
582 int i;
583
584 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100585 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Dauchya598b502020-08-06 18:11:38 +0200586 else
587 conn = objt_conn(smp->sess->origin);
588
589 if (!conn)
590 return 0;
591
592 ssl = ssl_sock_get_ssl_object(conn);
593 if (!ssl)
594 return 0;
595
596 if (conn->flags & CO_FL_WAIT_XPRT) {
597 smp->flags |= SMP_F_MAY_CHANGE;
598 return 0;
599 }
600
601 if (!cert_peer)
602 return 0;
603
604 certs = SSL_get_peer_cert_chain(ssl);
605 if (!certs)
606 return 0;
607
608 num_certs = sk_X509_num(certs);
609 if (!num_certs)
610 goto out;
611 smp_trash = get_trash_chunk();
612 tmp_trash = alloc_trash_chunk();
613 if (!tmp_trash)
614 goto out;
615 for (i = 0; i < num_certs; i++) {
616 crt = sk_X509_value(certs, i);
617 if (ssl_sock_crt2der(crt, tmp_trash) <= 0)
618 goto out;
619 chunk_cat(smp_trash, tmp_trash);
620 }
621
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200622 smp->flags = SMP_F_VOL_SESS;
William Dauchya598b502020-08-06 18:11:38 +0200623 smp->data.u.str = *smp_trash;
624 smp->data.type = SMP_T_BIN;
625 ret = 1;
626out:
627 if (tmp_trash)
628 free_trash_chunk(tmp_trash);
William Dauchya598b502020-08-06 18:11:38 +0200629 return ret;
630}
631
William Lallemand15e16942020-05-15 00:25:08 +0200632/* binary, returns serial of certificate in a binary chunk.
633 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
634 * should be use.
635 */
636static int
637smp_fetch_ssl_x_serial(const struct arg *args, struct sample *smp, const char *kw, void *private)
638{
William Lallemandbfa3e812020-06-25 20:07:18 +0200639 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
640 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200641 X509 *crt = NULL;
642 int ret = 0;
643 struct buffer *smp_trash;
644 struct connection *conn;
645 SSL *ssl;
646
William Lallemandbfa3e812020-06-25 20:07:18 +0200647 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100648 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200649 else
650 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +0200651 ssl = ssl_sock_get_ssl_object(conn);
652 if (!ssl)
653 return 0;
654
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200655 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200656 smp->flags |= SMP_F_MAY_CHANGE;
657 return 0;
658 }
659
660 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200661 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200662 else
663 crt = SSL_get_certificate(ssl);
664
665 if (!crt)
666 goto out;
667
668 smp_trash = get_trash_chunk();
669 if (ssl_sock_get_serial(crt, smp_trash) <= 0)
670 goto out;
671
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200672 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200673 smp->data.u.str = *smp_trash;
674 smp->data.type = SMP_T_BIN;
675 ret = 1;
676out:
677 /* SSL_get_peer_certificate, it increase X509 * ref count */
678 if (cert_peer && crt)
679 X509_free(crt);
680 return ret;
681}
682
683/* binary, returns the client certificate's SHA-1 fingerprint (SHA-1 hash of DER-encoded certificate) in a binary chunk.
684 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
685 * should be use.
686 */
687static int
688smp_fetch_ssl_x_sha1(const struct arg *args, struct sample *smp, const char *kw, void *private)
689{
William Lallemandbfa3e812020-06-25 20:07:18 +0200690 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
691 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200692 X509 *crt = NULL;
693 const EVP_MD *digest;
694 int ret = 0;
695 unsigned int len = 0;
696 struct buffer *smp_trash;
697 struct connection *conn;
698 SSL *ssl;
699
William Lallemandbfa3e812020-06-25 20:07:18 +0200700 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100701 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200702 else
703 conn = objt_conn(smp->sess->origin);
704
William Lallemand15e16942020-05-15 00:25:08 +0200705 ssl = ssl_sock_get_ssl_object(conn);
706 if (!ssl)
707 return 0;
708
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200709 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200710 smp->flags |= SMP_F_MAY_CHANGE;
711 return 0;
712 }
713
714 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200715 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200716 else
717 crt = SSL_get_certificate(ssl);
718 if (!crt)
719 goto out;
720
721 smp_trash = get_trash_chunk();
722 digest = EVP_sha1();
723 X509_digest(crt, digest, (unsigned char *) smp_trash->area, &len);
724 smp_trash->data = len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200725 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200726 smp->data.u.str = *smp_trash;
727 smp->data.type = SMP_T_BIN;
728 ret = 1;
729out:
730 /* SSL_get_peer_certificate, it increase X509 * ref count */
731 if (cert_peer && crt)
732 X509_free(crt);
733 return ret;
734}
735
736/* string, returns certificate's notafter date in ASN1_UTCTIME format.
737 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
738 * should be use.
739 */
740static int
741smp_fetch_ssl_x_notafter(const struct arg *args, struct sample *smp, const char *kw, void *private)
742{
William Lallemandbfa3e812020-06-25 20:07:18 +0200743 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
744 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200745 X509 *crt = NULL;
746 int ret = 0;
747 struct buffer *smp_trash;
748 struct connection *conn;
749 SSL *ssl;
750
William Lallemandbfa3e812020-06-25 20:07:18 +0200751 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100752 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200753 else
754 conn = objt_conn(smp->sess->origin);
755
William Lallemand15e16942020-05-15 00:25:08 +0200756 ssl = ssl_sock_get_ssl_object(conn);
757 if (!ssl)
758 return 0;
759
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200760 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200761 smp->flags |= SMP_F_MAY_CHANGE;
762 return 0;
763 }
764
765 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200766 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200767 else
768 crt = SSL_get_certificate(ssl);
769 if (!crt)
770 goto out;
771
772 smp_trash = get_trash_chunk();
773 if (ssl_sock_get_time(X509_getm_notAfter(crt), smp_trash) <= 0)
774 goto out;
775
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200776 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200777 smp->data.u.str = *smp_trash;
778 smp->data.type = SMP_T_STR;
779 ret = 1;
780out:
781 /* SSL_get_peer_certificate, it increase X509 * ref count */
782 if (cert_peer && crt)
783 X509_free(crt);
784 return ret;
785}
786
787/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's issuer
788 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
789 * should be use.
790 */
791static int
792smp_fetch_ssl_x_i_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
793{
William Lallemandbfa3e812020-06-25 20:07:18 +0200794 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
795 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200796 X509 *crt = NULL;
797 X509_NAME *name;
798 int ret = 0;
799 struct buffer *smp_trash;
800 struct connection *conn;
801 SSL *ssl;
802
William Lallemandbfa3e812020-06-25 20:07:18 +0200803 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100804 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200805 else
806 conn = objt_conn(smp->sess->origin);
807
William Lallemand15e16942020-05-15 00:25:08 +0200808 ssl = ssl_sock_get_ssl_object(conn);
809 if (!ssl)
810 return 0;
811
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200812 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200813 smp->flags |= SMP_F_MAY_CHANGE;
814 return 0;
815 }
816
817 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200818 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200819 else
820 crt = SSL_get_certificate(ssl);
821 if (!crt)
822 goto out;
823
824 name = X509_get_issuer_name(crt);
825 if (!name)
826 goto out;
827
828 smp_trash = get_trash_chunk();
Christopher Faulet3702f782021-01-29 11:30:37 +0100829 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200830 int pos = 1;
831
832 if (args[1].type == ARGT_SINT)
833 pos = args[1].data.sint;
834
835 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
836 goto out;
837 }
Christopher Faulet3702f782021-01-29 11:30:37 +0100838 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200839 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
840 goto out;
841 }
842 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
843 goto out;
844
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200845 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200846 smp->data.type = SMP_T_STR;
847 smp->data.u.str = *smp_trash;
848 ret = 1;
849out:
850 /* SSL_get_peer_certificate, it increase X509 * ref count */
851 if (cert_peer && crt)
852 X509_free(crt);
853 return ret;
854}
855
856/* string, returns notbefore date in ASN1_UTCTIME format.
857 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
858 * should be use.
859 */
860static int
861smp_fetch_ssl_x_notbefore(const struct arg *args, struct sample *smp, const char *kw, void *private)
862{
William Lallemandbfa3e812020-06-25 20:07:18 +0200863 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
864 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200865 X509 *crt = NULL;
866 int ret = 0;
867 struct buffer *smp_trash;
868 struct connection *conn;
869 SSL *ssl;
870
William Lallemandbfa3e812020-06-25 20:07:18 +0200871 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100872 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200873 else
874 conn = objt_conn(smp->sess->origin);
875
William Lallemand15e16942020-05-15 00:25:08 +0200876 ssl = ssl_sock_get_ssl_object(conn);
877 if (!ssl)
878 return 0;
879
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200880 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200881 smp->flags |= SMP_F_MAY_CHANGE;
882 return 0;
883 }
884
885 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200886 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200887 else
888 crt = SSL_get_certificate(ssl);
889 if (!crt)
890 goto out;
891
892 smp_trash = get_trash_chunk();
893 if (ssl_sock_get_time(X509_getm_notBefore(crt), smp_trash) <= 0)
894 goto out;
895
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200896 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200897 smp->data.u.str = *smp_trash;
898 smp->data.type = SMP_T_STR;
899 ret = 1;
900out:
901 /* SSL_get_peer_certificate, it increase X509 * ref count */
902 if (cert_peer && crt)
903 X509_free(crt);
904 return ret;
905}
906
907/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's subject
908 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
909 * should be use.
910 */
911static int
912smp_fetch_ssl_x_s_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
913{
William Lallemandbfa3e812020-06-25 20:07:18 +0200914 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
915 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200916 X509 *crt = NULL;
917 X509_NAME *name;
918 int ret = 0;
919 struct buffer *smp_trash;
920 struct connection *conn;
921 SSL *ssl;
922
William Lallemandbfa3e812020-06-25 20:07:18 +0200923 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +0100924 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200925 else
926 conn = objt_conn(smp->sess->origin);
927
William Lallemand15e16942020-05-15 00:25:08 +0200928 ssl = ssl_sock_get_ssl_object(conn);
929 if (!ssl)
930 return 0;
931
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200932 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200933 smp->flags |= SMP_F_MAY_CHANGE;
934 return 0;
935 }
936
937 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200938 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200939 else
940 crt = SSL_get_certificate(ssl);
941 if (!crt)
942 goto out;
943
944 name = X509_get_subject_name(crt);
945 if (!name)
946 goto out;
947
948 smp_trash = get_trash_chunk();
Christopher Faulet3702f782021-01-29 11:30:37 +0100949 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200950 int pos = 1;
951
952 if (args[1].type == ARGT_SINT)
953 pos = args[1].data.sint;
954
955 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
956 goto out;
957 }
Christopher Faulet3702f782021-01-29 11:30:37 +0100958 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200959 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
960 goto out;
961 }
962 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
963 goto out;
964
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200965 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200966 smp->data.type = SMP_T_STR;
967 smp->data.u.str = *smp_trash;
968 ret = 1;
969out:
970 /* SSL_get_peer_certificate, it increase X509 * ref count */
971 if (cert_peer && crt)
972 X509_free(crt);
973 return ret;
974}
975
976/* integer, returns true if current session use a client certificate */
977static int
978smp_fetch_ssl_c_used(const struct arg *args, struct sample *smp, const char *kw, void *private)
979{
980 X509 *crt;
981 struct connection *conn;
982 SSL *ssl;
983
984 conn = objt_conn(smp->sess->origin);
985 ssl = ssl_sock_get_ssl_object(conn);
986 if (!ssl)
987 return 0;
988
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200989 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200990 smp->flags |= SMP_F_MAY_CHANGE;
991 return 0;
992 }
993
994 /* SSL_get_peer_certificate returns a ptr on allocated X509 struct */
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200995 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200996 if (crt) {
997 X509_free(crt);
998 }
999
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001000 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001001 smp->data.type = SMP_T_BOOL;
1002 smp->data.u.sint = (crt != NULL);
1003 return 1;
1004}
1005
1006/* integer, returns the certificate version
1007 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1008 * should be use.
1009 */
1010static int
1011smp_fetch_ssl_x_version(const struct arg *args, struct sample *smp, const char *kw, void *private)
1012{
William Lallemandbfa3e812020-06-25 20:07:18 +02001013 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1014 int conn_server = (kw[4] == 's') ? 1 : 0;
1015
William Lallemand15e16942020-05-15 00:25:08 +02001016 X509 *crt;
1017 struct connection *conn;
1018 SSL *ssl;
1019
William Lallemandbfa3e812020-06-25 20:07:18 +02001020 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +01001021 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001022 else
1023 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +02001024 ssl = ssl_sock_get_ssl_object(conn);
1025 if (!ssl)
1026 return 0;
1027
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001028 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001029 smp->flags |= SMP_F_MAY_CHANGE;
1030 return 0;
1031 }
1032
1033 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001034 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001035 else
1036 crt = SSL_get_certificate(ssl);
1037 if (!crt)
1038 return 0;
1039
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001040 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001041 smp->data.u.sint = (unsigned int)(1 + X509_get_version(crt));
1042 /* SSL_get_peer_certificate increase X509 * ref count */
1043 if (cert_peer)
1044 X509_free(crt);
1045 smp->data.type = SMP_T_SINT;
1046
1047 return 1;
1048}
1049
1050/* string, returns the certificate's signature algorithm.
1051 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1052 * should be use.
1053 */
1054static int
1055smp_fetch_ssl_x_sig_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
1056{
William Lallemandbfa3e812020-06-25 20:07:18 +02001057 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1058 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +02001059 X509 *crt;
1060 __OPENSSL_110_CONST__ ASN1_OBJECT *algorithm;
1061 int nid;
1062 struct connection *conn;
1063 SSL *ssl;
1064
William Lallemandbfa3e812020-06-25 20:07:18 +02001065 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +01001066 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001067 else
1068 conn = objt_conn(smp->sess->origin);
1069
William Lallemand15e16942020-05-15 00:25:08 +02001070 ssl = ssl_sock_get_ssl_object(conn);
1071 if (!ssl)
1072 return 0;
1073
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001074 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001075 smp->flags |= SMP_F_MAY_CHANGE;
1076 return 0;
1077 }
1078
1079 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001080 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001081 else
1082 crt = SSL_get_certificate(ssl);
1083 if (!crt)
1084 return 0;
1085
1086 X509_ALGOR_get0(&algorithm, NULL, NULL, X509_get0_tbs_sigalg(crt));
1087 nid = OBJ_obj2nid(algorithm);
1088
1089 smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
1090 if (!smp->data.u.str.area) {
1091 /* SSL_get_peer_certificate increase X509 * ref count */
1092 if (cert_peer)
1093 X509_free(crt);
1094 return 0;
1095 }
1096
1097 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001098 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001099 smp->data.u.str.data = strlen(smp->data.u.str.area);
1100 /* SSL_get_peer_certificate increase X509 * ref count */
1101 if (cert_peer)
1102 X509_free(crt);
1103
1104 return 1;
1105}
1106
1107/* string, returns the certificate's key algorithm.
1108 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1109 * should be use.
1110 */
1111static int
1112smp_fetch_ssl_x_key_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
1113{
William Lallemandbfa3e812020-06-25 20:07:18 +02001114 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1115 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +02001116 X509 *crt;
1117 ASN1_OBJECT *algorithm;
1118 int nid;
1119 struct connection *conn;
1120 SSL *ssl;
1121
William Lallemandbfa3e812020-06-25 20:07:18 +02001122 if (conn_server)
Christopher Faulet95a61e82021-12-22 14:22:03 +01001123 conn = smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001124 else
1125 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +02001126 ssl = ssl_sock_get_ssl_object(conn);
1127 if (!ssl)
1128 return 0;
1129
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001130 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001131 smp->flags |= SMP_F_MAY_CHANGE;
1132 return 0;
1133 }
1134
1135 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001136 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001137 else
1138 crt = SSL_get_certificate(ssl);
1139 if (!crt)
1140 return 0;
1141
1142 X509_PUBKEY_get0_param(&algorithm, NULL, NULL, NULL, X509_get_X509_PUBKEY(crt));
1143 nid = OBJ_obj2nid(algorithm);
1144
1145 smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
1146 if (!smp->data.u.str.area) {
1147 /* SSL_get_peer_certificate increase X509 * ref count */
1148 if (cert_peer)
1149 X509_free(crt);
1150 return 0;
1151 }
1152
1153 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001154 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001155 smp->data.u.str.data = strlen(smp->data.u.str.area);
1156 if (cert_peer)
1157 X509_free(crt);
1158
1159 return 1;
1160}
1161
1162/* boolean, returns true if front conn. transport layer is SSL.
1163 * This function is also usable on backend conn if the fetch keyword 5th
1164 * char is 'b'.
1165 */
1166static int
1167smp_fetch_ssl_fc(const struct arg *args, struct sample *smp, const char *kw, void *private)
1168{
1169 struct connection *conn;
1170
1171 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001172 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001173 else
1174 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001175 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001176
1177 smp->data.type = SMP_T_BOOL;
Willy Tarreau939b0bf2022-04-11 11:29:11 +02001178 smp->data.u.sint = conn_is_ssl(conn);
William Lallemand15e16942020-05-15 00:25:08 +02001179 return 1;
1180}
1181
1182/* boolean, returns true if client present a SNI */
1183static int
1184smp_fetch_ssl_fc_has_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
1185{
1186#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1187 struct connection *conn = objt_conn(smp->sess->origin);
1188 SSL *ssl = ssl_sock_get_ssl_object(conn);
1189
1190 smp->data.type = SMP_T_BOOL;
1191 smp->data.u.sint = ssl && SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name) != NULL;
1192 return 1;
1193#else
1194 return 0;
1195#endif
1196}
1197
1198/* boolean, returns true if client session has been resumed.
1199 * This function is also usable on backend conn if the fetch keyword 5th
1200 * char is 'b'.
1201 */
1202static int
1203smp_fetch_ssl_fc_is_resumed(const struct arg *args, struct sample *smp, const char *kw, void *private)
1204{
1205 struct connection *conn;
1206 SSL *ssl;
1207
1208 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001209 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001210 else
1211 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001212 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001213
1214 ssl = ssl_sock_get_ssl_object(conn);
1215
1216 smp->data.type = SMP_T_BOOL;
1217 smp->data.u.sint = ssl && SSL_session_reused(ssl);
1218 return 1;
1219}
1220
1221/* string, returns the used cipher if front conn. transport layer is SSL.
1222 * This function is also usable on backend conn if the fetch keyword 5th
1223 * char is 'b'.
1224 */
1225static int
1226smp_fetch_ssl_fc_cipher(const struct arg *args, struct sample *smp, const char *kw, void *private)
1227{
1228 struct connection *conn;
1229 SSL *ssl;
1230
1231 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001232 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001233 else
1234 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001235 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001236
1237 smp->flags = 0;
1238 ssl = ssl_sock_get_ssl_object(conn);
1239 if (!ssl)
1240 return 0;
1241
1242 smp->data.u.str.area = (char *)SSL_get_cipher_name(ssl);
1243 if (!smp->data.u.str.area)
1244 return 0;
1245
1246 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001247 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001248 smp->data.u.str.data = strlen(smp->data.u.str.area);
1249
1250 return 1;
1251}
1252
1253/* integer, returns the algoritm's keysize if front conn. transport layer
1254 * is SSL.
1255 * This function is also usable on backend conn if the fetch keyword 5th
1256 * char is 'b'.
1257 */
1258static int
1259smp_fetch_ssl_fc_alg_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
1260{
1261 struct connection *conn;
1262 SSL *ssl;
1263 int sint;
1264
1265 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001266 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001267 else
1268 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001269 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001270
1271 smp->flags = 0;
1272 ssl = ssl_sock_get_ssl_object(conn);
1273 if (!ssl)
1274 return 0;
1275
1276 if (!SSL_get_cipher_bits(ssl, &sint))
1277 return 0;
1278
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001279 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001280 smp->data.u.sint = sint;
1281 smp->data.type = SMP_T_SINT;
1282
1283 return 1;
1284}
1285
1286/* integer, returns the used keysize if front conn. transport layer is SSL.
1287 * This function is also usable on backend conn if the fetch keyword 5th
1288 * char is 'b'.
1289 */
1290static int
1291smp_fetch_ssl_fc_use_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
1292{
1293 struct connection *conn;
1294 SSL *ssl;
1295
1296 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001297 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001298 else
1299 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001300 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001301
1302 smp->flags = 0;
1303 ssl = ssl_sock_get_ssl_object(conn);
1304 if (!ssl)
1305 return 0;
1306
1307 smp->data.u.sint = (unsigned int)SSL_get_cipher_bits(ssl, NULL);
1308 if (!smp->data.u.sint)
1309 return 0;
1310
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001311 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001312 smp->data.type = SMP_T_SINT;
1313
1314 return 1;
1315}
1316
1317#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
1318static int
1319smp_fetch_ssl_fc_npn(const struct arg *args, struct sample *smp, const char *kw, void *private)
1320{
1321 struct connection *conn;
1322 SSL *ssl;
1323 unsigned int len = 0;
1324
1325 smp->flags = SMP_F_CONST;
1326 smp->data.type = SMP_T_STR;
1327
1328 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001329 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001330 else
1331 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001332 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001333
1334 ssl = ssl_sock_get_ssl_object(conn);
1335 if (!ssl)
1336 return 0;
1337
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001338 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001339 smp->data.u.str.area = NULL;
1340 SSL_get0_next_proto_negotiated(ssl,
1341 (const unsigned char **)&smp->data.u.str.area,
1342 &len);
1343
1344 if (!smp->data.u.str.area)
1345 return 0;
1346
1347 smp->data.u.str.data = len;
1348 return 1;
1349}
1350#endif
1351
1352#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1353static int
1354smp_fetch_ssl_fc_alpn(const struct arg *args, struct sample *smp, const char *kw, void *private)
1355{
1356 struct connection *conn;
1357 SSL *ssl;
1358 unsigned int len = 0;
1359
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001360 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001361 smp->data.type = SMP_T_STR;
1362
1363 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001364 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001365 else
1366 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001367 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001368
1369 ssl = ssl_sock_get_ssl_object(conn);
1370 if (!ssl)
1371 return 0;
1372
1373 smp->data.u.str.area = NULL;
1374 SSL_get0_alpn_selected(ssl,
1375 (const unsigned char **)&smp->data.u.str.area,
1376 &len);
1377
1378 if (!smp->data.u.str.area)
1379 return 0;
1380
1381 smp->data.u.str.data = len;
1382 return 1;
1383}
1384#endif
1385
1386/* string, returns the used protocol if front conn. transport layer is SSL.
1387 * This function is also usable on backend conn if the fetch keyword 5th
1388 * char is 'b'.
1389 */
1390static int
1391smp_fetch_ssl_fc_protocol(const struct arg *args, struct sample *smp, const char *kw, void *private)
1392{
1393 struct connection *conn;
1394 SSL *ssl;
1395
1396 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001397 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001398 else
1399 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001400 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001401
1402 smp->flags = 0;
1403 ssl = ssl_sock_get_ssl_object(conn);
1404 if (!ssl)
1405 return 0;
1406
1407 smp->data.u.str.area = (char *)SSL_get_version(ssl);
1408 if (!smp->data.u.str.area)
1409 return 0;
1410
1411 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001412 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001413 smp->data.u.str.data = strlen(smp->data.u.str.area);
1414
1415 return 1;
1416}
1417
1418/* binary, returns the SSL stream id if front conn. transport layer is SSL.
1419 * This function is also usable on backend conn if the fetch keyword 5th
1420 * char is 'b'.
1421 */
1422#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1423static int
1424smp_fetch_ssl_fc_session_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1425{
1426 struct connection *conn;
1427 SSL_SESSION *ssl_sess;
1428 SSL *ssl;
1429 unsigned int len = 0;
1430
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001431 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001432 smp->data.type = SMP_T_BIN;
1433
1434 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001435 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001436 else
1437 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001438 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001439
1440 ssl = ssl_sock_get_ssl_object(conn);
1441 if (!ssl)
1442 return 0;
1443
1444 ssl_sess = SSL_get_session(ssl);
1445 if (!ssl_sess)
1446 return 0;
1447
1448 smp->data.u.str.area = (char *)SSL_SESSION_get_id(ssl_sess, &len);
1449 if (!smp->data.u.str.area || !len)
1450 return 0;
1451
1452 smp->data.u.str.data = len;
1453 return 1;
1454}
1455#endif
1456
1457
Ilya Shipitsindf627942021-03-25 00:41:41 +05001458#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02001459static int
1460smp_fetch_ssl_fc_random(const struct arg *args, struct sample *smp, const char *kw, void *private)
1461{
1462 struct connection *conn;
1463 struct buffer *data;
1464 SSL *ssl;
1465
1466 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001467 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001468 else
1469 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001470 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001471
1472 ssl = ssl_sock_get_ssl_object(conn);
1473 if (!ssl)
1474 return 0;
1475
1476 data = get_trash_chunk();
1477 if (kw[7] == 'c')
1478 data->data = SSL_get_client_random(ssl,
1479 (unsigned char *) data->area,
1480 data->size);
1481 else
1482 data->data = SSL_get_server_random(ssl,
1483 (unsigned char *) data->area,
1484 data->size);
1485 if (!data->data)
1486 return 0;
1487
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001488 smp->flags = SMP_F_VOL_TEST;
William Lallemand15e16942020-05-15 00:25:08 +02001489 smp->data.type = SMP_T_BIN;
1490 smp->data.u.str = *data;
1491
1492 return 1;
1493}
1494
1495static int
1496smp_fetch_ssl_fc_session_key(const struct arg *args, struct sample *smp, const char *kw, void *private)
1497{
1498 struct connection *conn;
1499 SSL_SESSION *ssl_sess;
1500 struct buffer *data;
1501 SSL *ssl;
1502
1503 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001504 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001505 else
1506 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001507 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001508
1509 ssl = ssl_sock_get_ssl_object(conn);
1510 if (!ssl)
1511 return 0;
1512
1513 ssl_sess = SSL_get_session(ssl);
1514 if (!ssl_sess)
1515 return 0;
1516
1517 data = get_trash_chunk();
1518 data->data = SSL_SESSION_get_master_key(ssl_sess,
1519 (unsigned char *) data->area,
1520 data->size);
1521 if (!data->data)
1522 return 0;
1523
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001524 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001525 smp->data.type = SMP_T_BIN;
1526 smp->data.u.str = *data;
1527
1528 return 1;
1529}
1530#endif
1531
William Lallemand15e16942020-05-15 00:25:08 +02001532static int
1533smp_fetch_ssl_fc_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
1534{
Willy Tarreau579259d2021-11-05 19:12:54 +01001535#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
William Lallemand15e16942020-05-15 00:25:08 +02001536 struct connection *conn;
1537 SSL *ssl;
1538
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001539 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001540 smp->data.type = SMP_T_STR;
1541
1542 conn = objt_conn(smp->sess->origin);
1543 ssl = ssl_sock_get_ssl_object(conn);
1544 if (!ssl)
1545 return 0;
1546
1547 smp->data.u.str.area = (char *)SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
Remi Tricot-Le Bretona9967632022-01-07 17:12:01 +01001548 if (!smp->data.u.str.area) {
1549 /* We might have stored the SNI ourselves, look for it in the
1550 * context's ex_data.
1551 */
1552 smp->data.u.str.area = SSL_get_ex_data(ssl, ssl_client_sni_index);
1553
1554 if (!smp->data.u.str.area)
1555 return 0;
1556 }
William Lallemand15e16942020-05-15 00:25:08 +02001557
1558 smp->data.u.str.data = strlen(smp->data.u.str.area);
Remi Tricot-Le Bretona9967632022-01-07 17:12:01 +01001559
William Lallemand15e16942020-05-15 00:25:08 +02001560 return 1;
Willy Tarreau579259d2021-11-05 19:12:54 +01001561#else
1562 /* SNI not supported */
1563 return 0;
William Lallemand15e16942020-05-15 00:25:08 +02001564#endif
Willy Tarreau579259d2021-11-05 19:12:54 +01001565}
William Lallemand15e16942020-05-15 00:25:08 +02001566
Marcin Deranek959a48c2021-07-13 15:14:21 +02001567/* binary, returns tls client hello cipher list.
1568 * Arguments: filter_option (0,1)
1569 */
William Lallemand15e16942020-05-15 00:25:08 +02001570static int
1571smp_fetch_ssl_fc_cl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1572{
Marcin Deranek959a48c2021-07-13 15:14:21 +02001573 struct buffer *smp_trash;
William Lallemand15e16942020-05-15 00:25:08 +02001574 struct connection *conn;
1575 struct ssl_capture *capture;
1576 SSL *ssl;
1577
1578 conn = objt_conn(smp->sess->origin);
1579 ssl = ssl_sock_get_ssl_object(conn);
1580 if (!ssl)
1581 return 0;
1582
1583 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1584 if (!capture)
1585 return 0;
1586
Marcin Deranek959a48c2021-07-13 15:14:21 +02001587 if (args[0].data.sint) {
1588 smp_trash = get_trash_chunk();
1589 exclude_tls_grease(capture->data + capture->ciphersuite_offset, capture->ciphersuite_len, smp_trash);
1590 smp->data.u.str.area = smp_trash->area;
1591 smp->data.u.str.data = smp_trash->data;
1592 smp->flags = SMP_F_VOL_SESS;
1593 }
1594 else {
1595 smp->data.u.str.area = capture->data + capture->ciphersuite_offset;
1596 smp->data.u.str.data = capture->ciphersuite_len;
1597 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1598 }
1599
William Lallemand15e16942020-05-15 00:25:08 +02001600 smp->data.type = SMP_T_BIN;
William Lallemand15e16942020-05-15 00:25:08 +02001601 return 1;
1602}
1603
Marcin Deranek959a48c2021-07-13 15:14:21 +02001604/* binary, returns tls client hello cipher list as hexadecimal string.
1605 * Arguments: filter_option (0,1)
1606 */
William Lallemand15e16942020-05-15 00:25:08 +02001607static int
1608smp_fetch_ssl_fc_cl_hex(const struct arg *args, struct sample *smp, const char *kw, void *private)
1609{
1610 struct buffer *data;
1611
1612 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1613 return 0;
1614
1615 data = get_trash_chunk();
1616 dump_binary(data, smp->data.u.str.area, smp->data.u.str.data);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001617 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001618 smp->data.type = SMP_T_BIN;
1619 smp->data.u.str = *data;
1620 return 1;
1621}
1622
Marcin Deranek959a48c2021-07-13 15:14:21 +02001623/* integer, returns xxh64 hash of tls client hello cipher list. */
William Lallemand15e16942020-05-15 00:25:08 +02001624static int
1625smp_fetch_ssl_fc_cl_xxh64(const struct arg *args, struct sample *smp, const char *kw, void *private)
1626{
1627 struct connection *conn;
1628 struct ssl_capture *capture;
1629 SSL *ssl;
1630
1631 conn = objt_conn(smp->sess->origin);
1632 ssl = ssl_sock_get_ssl_object(conn);
1633 if (!ssl)
1634 return 0;
1635
1636 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1637 if (!capture)
1638 return 0;
1639
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001640 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001641 smp->data.type = SMP_T_SINT;
1642 smp->data.u.sint = capture->xxh64;
1643 return 1;
1644}
1645
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001646static int
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001647smp_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 +02001648{
1649 struct connection *conn;
1650 struct ssl_sock_ctx *ctx;
1651
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001652 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
1653 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
1654 else
1655 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001656 smp->strm ? cs_conn(smp->strm->csb) : NULL;
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001657
Willy Tarreauce7a5e02022-04-12 07:40:42 +02001658 if (!conn)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001659 return 0;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001660
1661 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1662 smp->flags = SMP_F_MAY_CHANGE;
1663 return 0;
1664 }
1665
Willy Tarreauce7a5e02022-04-12 07:40:42 +02001666 ctx = conn_get_ssl_sock_ctx(conn);
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001667 if (!ctx)
1668 return 0;
1669
1670 smp->flags = SMP_F_VOL_SESS;
1671 smp->data.type = SMP_T_SINT;
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001672 smp->data.u.sint = ctx->error_code;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001673 return 1;
1674}
1675
1676static int
Marcin Deranek959a48c2021-07-13 15:14:21 +02001677smp_fetch_ssl_fc_protocol_hello_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1678{
1679 struct connection *conn;
1680 struct ssl_capture *capture;
1681 SSL *ssl;
1682
1683 conn = objt_conn(smp->sess->origin);
1684 ssl = ssl_sock_get_ssl_object(conn);
1685 if (!ssl)
1686 return 0;
1687
1688 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1689 if (!capture)
1690 return 0;
1691
1692 smp->flags = SMP_F_VOL_SESS;
1693 smp->data.type = SMP_T_SINT;
1694 smp->data.u.sint = capture->protocol_version;
1695 return 1;
1696}
1697
1698static int
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001699smp_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 +02001700{
1701 struct connection *conn;
1702 struct ssl_sock_ctx *ctx;
1703 const char *err_code_str;
1704
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001705 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
1706 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
1707 else
1708 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001709 smp->strm ? cs_conn(smp->strm->csb) : NULL;
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001710
Willy Tarreauce7a5e02022-04-12 07:40:42 +02001711 if (!conn)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001712 return 0;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001713
1714 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1715 smp->flags = SMP_F_MAY_CHANGE;
1716 return 0;
1717 }
1718
Willy Tarreauce7a5e02022-04-12 07:40:42 +02001719 ctx = conn_get_ssl_sock_ctx(conn);
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001720 if (!ctx || !ctx->error_code)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001721 return 0;
1722
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001723 err_code_str = ERR_error_string(ctx->error_code, NULL);
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001724
1725 smp->flags = SMP_F_VOL_SESS;
1726 smp->data.type = SMP_T_STR;
1727 smp->data.u.str.area = (char*)err_code_str;
1728 smp->data.u.str.data = strlen(err_code_str);
1729
Marcin Deranek959a48c2021-07-13 15:14:21 +02001730 return 1;
1731}
1732
1733/* binary, returns tls client hello extensions list.
1734 * Arguments: filter_option (0,1)
1735 */
1736static int
1737smp_fetch_ssl_fc_ext_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1738{
1739 struct buffer *smp_trash;
1740 struct connection *conn;
1741 struct ssl_capture *capture;
1742 SSL *ssl;
1743
1744 conn = objt_conn(smp->sess->origin);
1745 ssl = ssl_sock_get_ssl_object(conn);
1746 if (!ssl)
1747 return 0;
1748
1749 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1750 if (!capture)
1751 return 0;
1752
1753 if (args[0].data.sint) {
1754 smp_trash = get_trash_chunk();
1755 exclude_tls_grease(capture->data + capture->extensions_offset, capture->extensions_len, smp_trash);
1756 smp->data.u.str.area = smp_trash->area;
1757 smp->data.u.str.data = smp_trash->data;
1758 smp->flags = SMP_F_VOL_SESS;
1759 }
1760 else {
1761 smp->data.u.str.area = capture->data + capture->extensions_offset;
1762 smp->data.u.str.data = capture->extensions_len;
1763 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1764 }
1765
1766 smp->data.type = SMP_T_BIN;
1767 return 1;
1768}
1769
1770/* binary, returns tls client hello supported elliptic curves.
1771 * Arguments: filter_option (0,1)
1772 */
1773static int
1774smp_fetch_ssl_fc_ecl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1775{
1776 struct buffer *smp_trash;
1777 struct connection *conn;
1778 struct ssl_capture *capture;
1779 SSL *ssl;
1780
1781 conn = objt_conn(smp->sess->origin);
1782 ssl = ssl_sock_get_ssl_object(conn);
1783 if (!ssl)
1784 return 0;
1785
1786 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1787 if (!capture)
1788 return 0;
1789
1790 if (args[0].data.sint) {
1791 smp_trash = get_trash_chunk();
1792 exclude_tls_grease(capture->data + capture->ec_offset, capture->ec_len, smp_trash);
1793 smp->data.u.str.area = smp_trash->area;
1794 smp->data.u.str.data = smp_trash->data;
1795 smp->flags = SMP_F_VOL_SESS;
1796 }
1797 else {
1798 smp->data.u.str.area = capture->data + capture->ec_offset;
1799 smp->data.u.str.data = capture->ec_len;
1800 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1801 }
1802
1803 smp->data.type = SMP_T_BIN;
1804 return 1;
1805}
1806
1807/* binary, returns tls client hello supported elliptic curve point formats */
1808static int
1809smp_fetch_ssl_fc_ecf_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1810{
1811 struct connection *conn;
1812 struct ssl_capture *capture;
1813 SSL *ssl;
1814
1815 conn = objt_conn(smp->sess->origin);
1816 ssl = ssl_sock_get_ssl_object(conn);
1817 if (!ssl)
1818 return 0;
1819
1820 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1821 if (!capture)
1822 return 0;
1823
1824 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1825 smp->data.type = SMP_T_BIN;
1826 smp->data.u.str.area = capture->data + capture->ec_formats_offset;
1827 smp->data.u.str.data = capture->ec_formats_len;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001828 return 1;
1829}
1830
William Lallemand7d42ef52020-07-06 11:41:30 +02001831/* Dump the SSL keylog, it only works with "tune.ssl.keylog 1" */
William Lallemand722180a2021-06-09 16:46:12 +02001832#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02001833static int smp_fetch_ssl_x_keylog(const struct arg *args, struct sample *smp, const char *kw, void *private)
1834{
1835 struct connection *conn;
1836 struct ssl_keylog *keylog;
1837 SSL *ssl;
1838 char *src = NULL;
1839 const char *sfx;
1840
1841 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001842 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand7d42ef52020-07-06 11:41:30 +02001843
William Lallemandeec1d452020-07-07 10:48:13 +02001844 if (!conn)
1845 return 0;
1846
William Lallemand7d42ef52020-07-06 11:41:30 +02001847 if (conn->flags & CO_FL_WAIT_XPRT) {
1848 smp->flags |= SMP_F_MAY_CHANGE;
1849 return 0;
1850 }
1851
1852 ssl = ssl_sock_get_ssl_object(conn);
1853 if (!ssl)
1854 return 0;
1855
1856 keylog = SSL_get_ex_data(ssl, ssl_keylog_index);
1857 if (!keylog)
1858 return 0;
1859
1860 sfx = kw + strlen("ssl_xx_");
1861
1862 if (strcmp(sfx, "client_early_traffic_secret") == 0) {
1863 src = keylog->client_early_traffic_secret;
1864 } else if (strcmp(sfx, "client_handshake_traffic_secret") == 0) {
1865 src = keylog->client_handshake_traffic_secret;
1866 } else if (strcmp(sfx, "server_handshake_traffic_secret") == 0) {
1867 src = keylog->server_handshake_traffic_secret;
1868 } else if (strcmp(sfx, "client_traffic_secret_0") == 0) {
1869 src = keylog->client_traffic_secret_0;
1870 } else if (strcmp(sfx, "server_traffic_secret_0") == 0) {
1871 src = keylog->server_traffic_secret_0;
1872 } else if (strcmp(sfx, "exporter_secret") == 0) {
1873 src = keylog->exporter_secret;
1874 } else if (strcmp(sfx, "early_exporter_secret") == 0) {
1875 src = keylog->early_exporter_secret;
1876 }
1877
1878 if (!src || !*src)
1879 return 0;
1880
1881 smp->data.u.str.area = src;
1882 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001883 smp->flags |= SMP_F_VOL_TEST | SMP_F_CONST;
William Lallemand7d42ef52020-07-06 11:41:30 +02001884 smp->data.u.str.data = strlen(smp->data.u.str.area);
1885 return 1;
William Lallemand7d42ef52020-07-06 11:41:30 +02001886}
1887#endif
1888
William Lallemand15e16942020-05-15 00:25:08 +02001889static int
1890smp_fetch_ssl_fc_cl_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
1891{
Ilya Shipitsinc9dfee42020-10-31 02:10:02 +05001892#if defined(OPENSSL_IS_BORINGSSL) || defined(SSL_CTRL_GET_RAW_CIPHERLIST)
William Lallemand15e16942020-05-15 00:25:08 +02001893 struct buffer *data;
1894 int i;
1895
1896 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1897 return 0;
1898
1899 data = get_trash_chunk();
1900 for (i = 0; i + 1 < smp->data.u.str.data; i += 2) {
1901 const char *str;
1902 const SSL_CIPHER *cipher;
1903 const unsigned char *bin = (const unsigned char *) smp->data.u.str.area + i;
1904 uint16_t id = (bin[0] << 8) | bin[1];
1905#if defined(OPENSSL_IS_BORINGSSL)
1906 cipher = SSL_get_cipher_by_value(id);
1907#else
1908 struct connection *conn = __objt_conn(smp->sess->origin);
1909 SSL *ssl = ssl_sock_get_ssl_object(conn);
1910 cipher = SSL_CIPHER_find(ssl, bin);
1911#endif
1912 str = SSL_CIPHER_get_name(cipher);
1913 if (!str || strcmp(str, "(NONE)") == 0)
1914 chunk_appendf(data, "%sUNKNOWN(%04x)", i == 0 ? "" : ",", id);
1915 else
1916 chunk_appendf(data, "%s%s", i == 0 ? "" : ",", str);
1917 }
1918 smp->data.type = SMP_T_STR;
1919 smp->data.u.str = *data;
1920 return 1;
1921#else
1922 return smp_fetch_ssl_fc_cl_xxh64(args, smp, kw, private);
1923#endif
1924}
1925
1926#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1927static int
1928smp_fetch_ssl_fc_unique_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1929{
1930 struct connection *conn;
1931 int finished_len;
1932 struct buffer *finished_trash;
1933 SSL *ssl;
1934
1935 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Christopher Faulet4bef8d12021-04-14 15:49:41 +02001936 conn = (kw[4] == 'b') ? cs_conn(__objt_check(smp->sess->origin)->cs) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001937 else
1938 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Christopher Faulet95a61e82021-12-22 14:22:03 +01001939 smp->strm ? cs_conn(smp->strm->csb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001940
1941 smp->flags = 0;
1942 ssl = ssl_sock_get_ssl_object(conn);
1943 if (!ssl)
1944 return 0;
1945
1946 if (conn->flags & CO_FL_WAIT_XPRT) {
1947 smp->flags |= SMP_F_MAY_CHANGE;
1948 return 0;
1949 }
1950
1951 finished_trash = get_trash_chunk();
1952 if (!SSL_session_reused(ssl))
1953 finished_len = SSL_get_peer_finished(ssl,
1954 finished_trash->area,
1955 finished_trash->size);
1956 else
1957 finished_len = SSL_get_finished(ssl,
1958 finished_trash->area,
1959 finished_trash->size);
1960
1961 if (!finished_len)
1962 return 0;
1963
1964 finished_trash->data = finished_len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001965 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001966 smp->data.u.str = *finished_trash;
1967 smp->data.type = SMP_T_BIN;
1968
1969 return 1;
1970}
1971#endif
1972
1973/* integer, returns the first verify error in CA chain of client certificate chain. */
1974static int
1975smp_fetch_ssl_c_ca_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
1976{
Willy Tarreau939b0bf2022-04-11 11:29:11 +02001977 struct connection *conn = objt_conn(smp->sess->origin);
1978 struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
William Lallemand15e16942020-05-15 00:25:08 +02001979
Willy Tarreau939b0bf2022-04-11 11:29:11 +02001980 if (conn && conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001981 smp->flags = SMP_F_MAY_CHANGE;
1982 return 0;
1983 }
1984
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02001985 if (!ctx)
1986 return 0;
1987
William Lallemand15e16942020-05-15 00:25:08 +02001988 smp->data.type = SMP_T_SINT;
1989 smp->data.u.sint = (unsigned long long int)SSL_SOCK_ST_TO_CA_ERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001990 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001991
1992 return 1;
1993}
1994
1995/* integer, returns the depth of the first verify error in CA chain of client certificate chain. */
1996static int
1997smp_fetch_ssl_c_ca_err_depth(const struct arg *args, struct sample *smp, const char *kw, void *private)
1998{
Willy Tarreau939b0bf2022-04-11 11:29:11 +02001999 struct connection *conn = objt_conn(smp->sess->origin);
2000 struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
William Lallemand15e16942020-05-15 00:25:08 +02002001
Willy Tarreau939b0bf2022-04-11 11:29:11 +02002002 if (conn && conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02002003 smp->flags = SMP_F_MAY_CHANGE;
2004 return 0;
2005 }
William Lallemand15e16942020-05-15 00:25:08 +02002006
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002007 if (!ctx)
2008 return 0;
2009
William Lallemand15e16942020-05-15 00:25:08 +02002010 smp->data.type = SMP_T_SINT;
2011 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CAEDEPTH(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002012 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002013
2014 return 1;
2015}
2016
2017/* integer, returns the first verify error on client certificate */
2018static int
2019smp_fetch_ssl_c_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
2020{
Willy Tarreau939b0bf2022-04-11 11:29:11 +02002021 struct connection *conn = objt_conn(smp->sess->origin);
2022 struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
William Lallemand15e16942020-05-15 00:25:08 +02002023
Willy Tarreau939b0bf2022-04-11 11:29:11 +02002024 if (conn && conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02002025 smp->flags = SMP_F_MAY_CHANGE;
2026 return 0;
2027 }
2028
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002029 if (!ctx)
2030 return 0;
2031
William Lallemand15e16942020-05-15 00:25:08 +02002032 smp->data.type = SMP_T_SINT;
2033 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CRTERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002034 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002035
2036 return 1;
2037}
2038
2039/* integer, returns the verify result on client cert */
2040static int
2041smp_fetch_ssl_c_verify(const struct arg *args, struct sample *smp, const char *kw, void *private)
2042{
2043 struct connection *conn;
2044 SSL *ssl;
2045
2046 conn = objt_conn(smp->sess->origin);
2047 ssl = ssl_sock_get_ssl_object(conn);
2048 if (!ssl)
2049 return 0;
2050
2051 if (conn->flags & CO_FL_WAIT_XPRT) {
2052 smp->flags = SMP_F_MAY_CHANGE;
2053 return 0;
2054 }
2055
2056 smp->data.type = SMP_T_SINT;
2057 smp->data.u.sint = (long long int)SSL_get_verify_result(ssl);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002058 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002059
2060 return 1;
2061}
2062
2063/* Argument validation functions */
2064
2065/* This function is used to validate the arguments passed to any "x_dn" ssl
2066 * keywords. These keywords support specifying a third parameter that must be
2067 * either empty or the value "rfc2253". Returns 0 on error, non-zero if OK.
2068 */
2069int val_dnfmt(struct arg *arg, char **err_msg)
2070{
2071 if (arg && arg[2].type == ARGT_STR && arg[2].data.str.data > 0 && (strcmp(arg[2].data.str.area, "rfc2253") != 0)) {
2072 memprintf(err_msg, "only rfc2253 or a blank value are currently supported as the format argument.");
2073 return 0;
2074 }
2075 return 1;
2076}
2077
2078/* Note: must not be declared <const> as its list will be overwritten.
2079 * Please take care of keeping this list alphabetically sorted.
2080 */
2081static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
2082 { "ssl_bc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
2083 { "ssl_bc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2084#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2085 { "ssl_bc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2086#endif
2087 { "ssl_bc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2088#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2089 { "ssl_bc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2090#endif
2091 { "ssl_bc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
2092 { "ssl_bc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2093 { "ssl_bc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2094 { "ssl_bc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2095#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2096 { "ssl_bc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2097#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05002098#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02002099 { "ssl_bc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2100 { "ssl_bc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2101 { "ssl_bc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2102#endif
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02002103 { "ssl_bc_err", smp_fetch_ssl_fc_err, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2104 { "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 +02002105 { "ssl_c_ca_err", smp_fetch_ssl_c_ca_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2106 { "ssl_c_ca_err_depth", smp_fetch_ssl_c_ca_err_depth, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2107 { "ssl_c_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02002108 { "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 +02002109 { "ssl_c_err", smp_fetch_ssl_c_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2110 { "ssl_c_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2111 { "ssl_c_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2112 { "ssl_c_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2113 { "ssl_c_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2114 { "ssl_c_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2115 { "ssl_c_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2116 { "ssl_c_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2117 { "ssl_c_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2118 { "ssl_c_used", smp_fetch_ssl_c_used, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2119 { "ssl_c_verify", smp_fetch_ssl_c_verify, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2120 { "ssl_c_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2121 { "ssl_f_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2122 { "ssl_f_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2123 { "ssl_f_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2124 { "ssl_f_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2125 { "ssl_f_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2126 { "ssl_f_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2127 { "ssl_f_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2128 { "ssl_f_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2129 { "ssl_f_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2130 { "ssl_f_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2131 { "ssl_fc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2132 { "ssl_fc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2133 { "ssl_fc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2134 { "ssl_fc_has_crt", smp_fetch_ssl_fc_has_crt, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2135 { "ssl_fc_has_early", smp_fetch_ssl_fc_has_early, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2136 { "ssl_fc_has_sni", smp_fetch_ssl_fc_has_sni, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2137 { "ssl_fc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2138#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2139 { "ssl_fc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2140#endif
2141#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2142 { "ssl_fc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2143#endif
2144 { "ssl_fc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2145#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2146 { "ssl_fc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2147#endif
2148 { "ssl_fc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2149#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2150 { "ssl_fc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2151#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05002152#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02002153 { "ssl_fc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2154 { "ssl_fc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2155 { "ssl_fc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2156#endif
William Lallemand7d42ef52020-07-06 11:41:30 +02002157
William Lallemand722180a2021-06-09 16:46:12 +02002158#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02002159 { "ssl_fc_client_early_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2160 { "ssl_fc_client_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2161 { "ssl_fc_server_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2162 { "ssl_fc_client_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2163 { "ssl_fc_server_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2164 { "ssl_fc_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2165 { "ssl_fc_early_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2166#endif
2167
William Lallemand15e16942020-05-15 00:25:08 +02002168 { "ssl_fc_sni", smp_fetch_ssl_fc_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
Marcin Deranek959a48c2021-07-13 15:14:21 +02002169 { "ssl_fc_cipherlist_bin", smp_fetch_ssl_fc_cl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2170 { "ssl_fc_cipherlist_hex", smp_fetch_ssl_fc_cl_hex, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_USE_L5CLI },
2171 { "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 +02002172 { "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 +02002173 { "ssl_fc_err", smp_fetch_ssl_fc_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2174 { "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 +02002175 { "ssl_fc_protocol_hello_id",smp_fetch_ssl_fc_protocol_hello_id,0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2176 { "ssl_fc_extlist_bin", smp_fetch_ssl_fc_ext_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2177 { "ssl_fc_eclist_bin", smp_fetch_ssl_fc_ecl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2178 { "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 +02002179
2180/* SSL server certificate fetches */
2181 { "ssl_s_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02002182 { "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 +02002183 { "ssl_s_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2184 { "ssl_s_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2185 { "ssl_s_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2186 { "ssl_s_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2187 { "ssl_s_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2188 { "ssl_s_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2189 { "ssl_s_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2190 { "ssl_s_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2191 { "ssl_s_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
William Lallemand15e16942020-05-15 00:25:08 +02002192 { NULL, NULL, 0, 0, 0 },
2193}};
2194
2195INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
2196
Willy Tarreau99ea1882021-10-06 15:37:17 +02002197/* Note: must not be declared <const> as its list will be overwritten */
2198static struct sample_conv_kw_list sample_conv_kws = {ILH, {
2199 { "sha2", sample_conv_sha2, ARG1(0, SINT), smp_check_sha2, SMP_T_BIN, SMP_T_BIN },
2200#ifdef EVP_CIPH_GCM_MODE
2201 { "aes_gcm_dec", sample_conv_aes_gcm_dec, ARG4(4,SINT,STR,STR,STR), check_aes_gcm, SMP_T_BIN, SMP_T_BIN },
2202#endif
2203 { "digest", sample_conv_crypto_digest, ARG1(1,STR), check_crypto_digest, SMP_T_BIN, SMP_T_BIN },
2204 { "hmac", sample_conv_crypto_hmac, ARG2(2,STR,STR), check_crypto_hmac, SMP_T_BIN, SMP_T_BIN },
2205#if defined(HAVE_CRYPTO_memcmp)
2206 { "secure_memcmp", sample_conv_secure_memcmp, ARG1(1,STR), smp_check_secure_memcmp, SMP_T_BIN, SMP_T_BOOL },
2207#endif
2208 { NULL, NULL, 0, 0, 0 },
2209}};
2210
2211INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
2212
2213
William Lallemand15e16942020-05-15 00:25:08 +02002214/* Note: must not be declared <const> as its list will be overwritten.
2215 * Please take care of keeping this list alphabetically sorted.
2216 */
2217static struct acl_kw_list acl_kws = {ILH, {
2218 { "ssl_fc_sni_end", "ssl_fc_sni", PAT_MATCH_END },
2219 { "ssl_fc_sni_reg", "ssl_fc_sni", PAT_MATCH_REG },
2220 { /* END */ },
2221}};
2222
2223INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);