blob: 7eee065fde17bea8d58a19455fb76f53b66a1dea [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>
Willy Tarreau8efbdfb2020-06-04 11:29:21 +020028#include <haproxy/obj_type.h>
Willy Tarreau6019fab2020-05-27 16:26:00 +020029#include <haproxy/openssl-compat.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020030#include <haproxy/sample.h>
Willy Tarreau209108d2020-06-04 20:30:20 +020031#include <haproxy/ssl_sock.h>
Willy Tarreaub2bd8652020-06-04 14:21:22 +020032#include <haproxy/ssl_utils.h>
Willy Tarreaucb086c62022-05-27 09:47:12 +020033#include <haproxy/stconn.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
William Lallemand9fbc84e2022-11-03 18:56:37 +0100401/* Take a numerical X509_V_ERR and return its constant name */
402static int sample_conv_x509_v_err(const struct arg *arg_p, struct sample *smp, void *private)
403{
404 const char *res = x509_v_err_int_to_str(smp->data.u.sint);
405
406 /* if the value was found return its string */
407 if (res) {
408 smp->data.u.str.area = (char *)res;
409 smp->data.u.str.data = strlen(res);
410 smp->data.type = SMP_T_STR;
411 smp->flags |= SMP_F_CONST;
412
413 return 1;
414 }
415
416 return 0;
417}
418
Willy Tarreau99ea1882021-10-06 15:37:17 +0200419static int check_crypto_hmac(struct arg *args, struct sample_conv *conv,
420 const char *file, int line, char **err)
421{
422 if (!check_crypto_digest(args, conv, file, line, err))
423 return 0;
424
425 if (!sample_check_arg_base64(&args[1], err)) {
426 memprintf(err, "failed to parse key : %s", *err);
427 return 0;
428 }
429
430 return 1;
431}
432
433static int sample_conv_crypto_hmac(const struct arg *args, struct sample *smp, void *private)
434{
435 struct sample key;
436 struct buffer *trash = NULL, *key_trash = NULL;
437 unsigned char *md;
438 unsigned int md_len;
439 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
440 int dec_size;
441
442 smp_set_owner(&key, smp->px, smp->sess, smp->strm, smp->opt);
443 if (!sample_conv_var2smp_str(&args[1], &key))
444 return 0;
445
446 if (args[1].type == ARGT_VAR) {
447 key_trash = alloc_trash_chunk();
448 if (!key_trash)
449 goto err;
450
451 dec_size = base64dec(key.data.u.str.area, key.data.u.str.data, key_trash->area, key_trash->size);
452 if (dec_size < 0)
453 goto err;
454 key_trash->data = dec_size;
455 key.data.u.str = *key_trash;
456 }
457
458 trash = alloc_trash_chunk();
459 if (!trash)
460 goto err;
461
462 md = (unsigned char*) trash->area;
463 md_len = trash->size;
464 if (!HMAC(evp, key.data.u.str.area, key.data.u.str.data, (const unsigned char*) smp->data.u.str.area,
465 smp->data.u.str.data, md, &md_len))
466 goto err;
467
468 free_trash_chunk(key_trash);
469
470 trash->data = md_len;
471 smp->data.u.str = *trash;
472 smp->data.type = SMP_T_BIN;
473 smp_dup(smp);
474 free_trash_chunk(trash);
475 return 1;
476
477err:
478 free_trash_chunk(key_trash);
479 free_trash_chunk(trash);
480 return 0;
481}
482
William Lallemand15e16942020-05-15 00:25:08 +0200483static int
484smp_fetch_ssl_fc_has_early(const struct arg *args, struct sample *smp, const char *kw, void *private)
485{
486 SSL *ssl;
487 struct connection *conn;
488
489 conn = objt_conn(smp->sess->origin);
490 ssl = ssl_sock_get_ssl_object(conn);
491 if (!ssl)
492 return 0;
493
494 smp->flags = 0;
495 smp->data.type = SMP_T_BOOL;
496#ifdef OPENSSL_IS_BORINGSSL
497 {
498 smp->data.u.sint = (SSL_in_early_data(ssl) &&
499 SSL_early_data_accepted(ssl));
500 }
501#else
502 smp->data.u.sint = ((conn->flags & CO_FL_EARLY_DATA) &&
503 (conn->flags & (CO_FL_EARLY_SSL_HS | CO_FL_SSL_WAIT_HS))) ? 1 : 0;
504#endif
505 return 1;
506}
507
508/* boolean, returns true if client cert was present */
509static int
510smp_fetch_ssl_fc_has_crt(const struct arg *args, struct sample *smp, const char *kw, void *private)
511{
Willy Tarreau939b0bf2022-04-11 11:29:11 +0200512 struct connection *conn = objt_conn(smp->sess->origin);
513 struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
William Lallemand15e16942020-05-15 00:25:08 +0200514
Willy Tarreau939b0bf2022-04-11 11:29:11 +0200515 if (!ctx)
William Lallemand15e16942020-05-15 00:25:08 +0200516 return 0;
517
William Lallemand15e16942020-05-15 00:25:08 +0200518 if (conn->flags & CO_FL_WAIT_XPRT) {
519 smp->flags |= SMP_F_MAY_CHANGE;
520 return 0;
521 }
522
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200523 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200524 smp->data.type = SMP_T_BOOL;
525 smp->data.u.sint = SSL_SOCK_ST_FL_VERIFY_DONE & ctx->xprt_st ? 1 : 0;
526
527 return 1;
528}
529
530/* binary, returns a certificate in a binary chunk (der/raw).
531 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
532 * should be use.
533 */
534static int
535smp_fetch_ssl_x_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
536{
William Lallemandbfa3e812020-06-25 20:07:18 +0200537 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
538 int conn_server = (kw[4] == 's') ? 1 : 0;
539
William Lallemand15e16942020-05-15 00:25:08 +0200540 X509 *crt = NULL;
541 int ret = 0;
542 struct buffer *smp_trash;
543 struct connection *conn;
544 SSL *ssl;
545
William Lallemandbfa3e812020-06-25 20:07:18 +0200546 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200547 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200548 else
549 conn = objt_conn(smp->sess->origin);
550
William Lallemand15e16942020-05-15 00:25:08 +0200551 ssl = ssl_sock_get_ssl_object(conn);
552 if (!ssl)
553 return 0;
554
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200555 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200556 smp->flags |= SMP_F_MAY_CHANGE;
557 return 0;
558 }
559
560 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200561 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200562 else
563 crt = SSL_get_certificate(ssl);
564
565 if (!crt)
566 goto out;
567
568 smp_trash = get_trash_chunk();
569 if (ssl_sock_crt2der(crt, smp_trash) <= 0)
570 goto out;
571
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200572 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200573 smp->data.u.str = *smp_trash;
574 smp->data.type = SMP_T_BIN;
575 ret = 1;
576out:
577 /* SSL_get_peer_certificate, it increase X509 * ref count */
578 if (cert_peer && crt)
579 X509_free(crt);
580 return ret;
581}
582
William Dauchya598b502020-08-06 18:11:38 +0200583/* binary, returns a chain certificate in a binary chunk (der/raw).
584 * The 5th keyword char is used to support only peer cert
585 */
586static int
587smp_fetch_ssl_x_chain_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
588{
589 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
590 int conn_server = (kw[4] == 's') ? 1 : 0;
591 struct buffer *smp_trash;
592 struct buffer *tmp_trash = NULL;
593 struct connection *conn;
594 STACK_OF(X509) *certs = NULL;
595 X509 *crt = NULL;
596 SSL *ssl;
597 int ret = 0;
598 int num_certs;
599 int i;
600
601 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200602 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Dauchya598b502020-08-06 18:11:38 +0200603 else
604 conn = objt_conn(smp->sess->origin);
605
606 if (!conn)
607 return 0;
608
609 ssl = ssl_sock_get_ssl_object(conn);
610 if (!ssl)
611 return 0;
612
613 if (conn->flags & CO_FL_WAIT_XPRT) {
614 smp->flags |= SMP_F_MAY_CHANGE;
615 return 0;
616 }
617
618 if (!cert_peer)
619 return 0;
620
621 certs = SSL_get_peer_cert_chain(ssl);
622 if (!certs)
623 return 0;
624
625 num_certs = sk_X509_num(certs);
626 if (!num_certs)
627 goto out;
628 smp_trash = get_trash_chunk();
629 tmp_trash = alloc_trash_chunk();
630 if (!tmp_trash)
631 goto out;
632 for (i = 0; i < num_certs; i++) {
633 crt = sk_X509_value(certs, i);
634 if (ssl_sock_crt2der(crt, tmp_trash) <= 0)
635 goto out;
636 chunk_cat(smp_trash, tmp_trash);
637 }
638
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200639 smp->flags = SMP_F_VOL_SESS;
William Dauchya598b502020-08-06 18:11:38 +0200640 smp->data.u.str = *smp_trash;
641 smp->data.type = SMP_T_BIN;
642 ret = 1;
643out:
644 if (tmp_trash)
645 free_trash_chunk(tmp_trash);
William Dauchya598b502020-08-06 18:11:38 +0200646 return ret;
647}
648
William Lallemand15e16942020-05-15 00:25:08 +0200649/* binary, returns serial of certificate in a binary chunk.
650 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
651 * should be use.
652 */
653static int
654smp_fetch_ssl_x_serial(const struct arg *args, struct sample *smp, const char *kw, void *private)
655{
William Lallemandbfa3e812020-06-25 20:07:18 +0200656 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
657 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200658 X509 *crt = NULL;
659 int ret = 0;
660 struct buffer *smp_trash;
661 struct connection *conn;
662 SSL *ssl;
663
William Lallemandbfa3e812020-06-25 20:07:18 +0200664 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200665 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200666 else
667 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +0200668 ssl = ssl_sock_get_ssl_object(conn);
669 if (!ssl)
670 return 0;
671
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200672 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200673 smp->flags |= SMP_F_MAY_CHANGE;
674 return 0;
675 }
676
677 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200678 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200679 else
680 crt = SSL_get_certificate(ssl);
681
682 if (!crt)
683 goto out;
684
685 smp_trash = get_trash_chunk();
686 if (ssl_sock_get_serial(crt, smp_trash) <= 0)
687 goto out;
688
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200689 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200690 smp->data.u.str = *smp_trash;
691 smp->data.type = SMP_T_BIN;
692 ret = 1;
693out:
694 /* SSL_get_peer_certificate, it increase X509 * ref count */
695 if (cert_peer && crt)
696 X509_free(crt);
697 return ret;
698}
699
700/* binary, returns the client certificate's SHA-1 fingerprint (SHA-1 hash of DER-encoded certificate) in a binary chunk.
701 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
702 * should be use.
703 */
704static int
705smp_fetch_ssl_x_sha1(const struct arg *args, struct sample *smp, const char *kw, void *private)
706{
William Lallemandbfa3e812020-06-25 20:07:18 +0200707 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
708 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200709 X509 *crt = NULL;
710 const EVP_MD *digest;
711 int ret = 0;
712 unsigned int len = 0;
713 struct buffer *smp_trash;
714 struct connection *conn;
715 SSL *ssl;
716
William Lallemandbfa3e812020-06-25 20:07:18 +0200717 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200718 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200719 else
720 conn = objt_conn(smp->sess->origin);
721
William Lallemand15e16942020-05-15 00:25:08 +0200722 ssl = ssl_sock_get_ssl_object(conn);
723 if (!ssl)
724 return 0;
725
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200726 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200727 smp->flags |= SMP_F_MAY_CHANGE;
728 return 0;
729 }
730
731 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200732 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200733 else
734 crt = SSL_get_certificate(ssl);
735 if (!crt)
736 goto out;
737
738 smp_trash = get_trash_chunk();
739 digest = EVP_sha1();
740 X509_digest(crt, digest, (unsigned char *) smp_trash->area, &len);
741 smp_trash->data = len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200742 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200743 smp->data.u.str = *smp_trash;
744 smp->data.type = SMP_T_BIN;
745 ret = 1;
746out:
747 /* SSL_get_peer_certificate, it increase X509 * ref count */
748 if (cert_peer && crt)
749 X509_free(crt);
750 return ret;
751}
752
753/* string, returns certificate's notafter date in ASN1_UTCTIME format.
754 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
755 * should be use.
756 */
757static int
758smp_fetch_ssl_x_notafter(const struct arg *args, struct sample *smp, const char *kw, void *private)
759{
William Lallemandbfa3e812020-06-25 20:07:18 +0200760 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
761 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200762 X509 *crt = NULL;
763 int ret = 0;
764 struct buffer *smp_trash;
765 struct connection *conn;
766 SSL *ssl;
767
William Lallemandbfa3e812020-06-25 20:07:18 +0200768 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200769 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200770 else
771 conn = objt_conn(smp->sess->origin);
772
William Lallemand15e16942020-05-15 00:25:08 +0200773 ssl = ssl_sock_get_ssl_object(conn);
774 if (!ssl)
775 return 0;
776
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200777 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200778 smp->flags |= SMP_F_MAY_CHANGE;
779 return 0;
780 }
781
782 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200783 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200784 else
785 crt = SSL_get_certificate(ssl);
786 if (!crt)
787 goto out;
788
789 smp_trash = get_trash_chunk();
790 if (ssl_sock_get_time(X509_getm_notAfter(crt), smp_trash) <= 0)
791 goto out;
792
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200793 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200794 smp->data.u.str = *smp_trash;
795 smp->data.type = SMP_T_STR;
796 ret = 1;
797out:
798 /* SSL_get_peer_certificate, it increase X509 * ref count */
799 if (cert_peer && crt)
800 X509_free(crt);
801 return ret;
802}
803
804/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's issuer
805 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
806 * should be use.
807 */
808static int
809smp_fetch_ssl_x_i_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
810{
William Lallemandbfa3e812020-06-25 20:07:18 +0200811 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
812 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200813 X509 *crt = NULL;
814 X509_NAME *name;
815 int ret = 0;
816 struct buffer *smp_trash;
817 struct connection *conn;
818 SSL *ssl;
819
William Lallemandbfa3e812020-06-25 20:07:18 +0200820 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200821 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200822 else
823 conn = objt_conn(smp->sess->origin);
824
William Lallemand15e16942020-05-15 00:25:08 +0200825 ssl = ssl_sock_get_ssl_object(conn);
826 if (!ssl)
827 return 0;
828
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200829 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200830 smp->flags |= SMP_F_MAY_CHANGE;
831 return 0;
832 }
833
834 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200835 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200836 else
837 crt = SSL_get_certificate(ssl);
838 if (!crt)
839 goto out;
840
841 name = X509_get_issuer_name(crt);
842 if (!name)
843 goto out;
844
845 smp_trash = get_trash_chunk();
Christopher Faulet3702f782021-01-29 11:30:37 +0100846 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200847 int pos = 1;
848
849 if (args[1].type == ARGT_SINT)
850 pos = args[1].data.sint;
851
852 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
853 goto out;
854 }
Christopher Faulet3702f782021-01-29 11:30:37 +0100855 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200856 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
857 goto out;
858 }
859 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
860 goto out;
861
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200862 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200863 smp->data.type = SMP_T_STR;
864 smp->data.u.str = *smp_trash;
865 ret = 1;
866out:
867 /* SSL_get_peer_certificate, it increase X509 * ref count */
868 if (cert_peer && crt)
869 X509_free(crt);
870 return ret;
871}
872
873/* string, returns notbefore date in ASN1_UTCTIME format.
874 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
875 * should be use.
876 */
877static int
878smp_fetch_ssl_x_notbefore(const struct arg *args, struct sample *smp, const char *kw, void *private)
879{
William Lallemandbfa3e812020-06-25 20:07:18 +0200880 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
881 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200882 X509 *crt = NULL;
883 int ret = 0;
884 struct buffer *smp_trash;
885 struct connection *conn;
886 SSL *ssl;
887
William Lallemandbfa3e812020-06-25 20:07:18 +0200888 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200889 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200890 else
891 conn = objt_conn(smp->sess->origin);
892
William Lallemand15e16942020-05-15 00:25:08 +0200893 ssl = ssl_sock_get_ssl_object(conn);
894 if (!ssl)
895 return 0;
896
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200897 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200898 smp->flags |= SMP_F_MAY_CHANGE;
899 return 0;
900 }
901
902 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200903 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200904 else
905 crt = SSL_get_certificate(ssl);
906 if (!crt)
907 goto out;
908
909 smp_trash = get_trash_chunk();
910 if (ssl_sock_get_time(X509_getm_notBefore(crt), smp_trash) <= 0)
911 goto out;
912
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200913 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200914 smp->data.u.str = *smp_trash;
915 smp->data.type = SMP_T_STR;
916 ret = 1;
917out:
918 /* SSL_get_peer_certificate, it increase X509 * ref count */
919 if (cert_peer && crt)
920 X509_free(crt);
921 return ret;
922}
923
924/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's subject
925 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
926 * should be use.
927 */
928static int
929smp_fetch_ssl_x_s_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
930{
William Lallemandbfa3e812020-06-25 20:07:18 +0200931 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
932 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200933 X509 *crt = NULL;
934 X509_NAME *name;
935 int ret = 0;
936 struct buffer *smp_trash;
937 struct connection *conn;
938 SSL *ssl;
939
William Lallemandbfa3e812020-06-25 20:07:18 +0200940 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200941 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200942 else
943 conn = objt_conn(smp->sess->origin);
944
William Lallemand15e16942020-05-15 00:25:08 +0200945 ssl = ssl_sock_get_ssl_object(conn);
946 if (!ssl)
947 return 0;
948
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200949 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200950 smp->flags |= SMP_F_MAY_CHANGE;
951 return 0;
952 }
953
954 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200955 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200956 else
957 crt = SSL_get_certificate(ssl);
958 if (!crt)
959 goto out;
960
961 name = X509_get_subject_name(crt);
962 if (!name)
963 goto out;
964
965 smp_trash = get_trash_chunk();
Christopher Faulet3702f782021-01-29 11:30:37 +0100966 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200967 int pos = 1;
968
969 if (args[1].type == ARGT_SINT)
970 pos = args[1].data.sint;
971
972 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
973 goto out;
974 }
Christopher Faulet3702f782021-01-29 11:30:37 +0100975 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200976 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
977 goto out;
978 }
979 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
980 goto out;
981
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200982 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200983 smp->data.type = SMP_T_STR;
984 smp->data.u.str = *smp_trash;
985 ret = 1;
986out:
987 /* SSL_get_peer_certificate, it increase X509 * ref count */
988 if (cert_peer && crt)
989 X509_free(crt);
990 return ret;
991}
992
993/* integer, returns true if current session use a client certificate */
994static int
995smp_fetch_ssl_c_used(const struct arg *args, struct sample *smp, const char *kw, void *private)
996{
997 X509 *crt;
998 struct connection *conn;
999 SSL *ssl;
1000
1001 conn = objt_conn(smp->sess->origin);
1002 ssl = ssl_sock_get_ssl_object(conn);
1003 if (!ssl)
1004 return 0;
1005
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001006 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001007 smp->flags |= SMP_F_MAY_CHANGE;
1008 return 0;
1009 }
1010
1011 /* SSL_get_peer_certificate returns a ptr on allocated X509 struct */
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001012 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001013 if (crt) {
1014 X509_free(crt);
1015 }
1016
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001017 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001018 smp->data.type = SMP_T_BOOL;
1019 smp->data.u.sint = (crt != NULL);
1020 return 1;
1021}
1022
1023/* integer, returns the certificate version
1024 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1025 * should be use.
1026 */
1027static int
1028smp_fetch_ssl_x_version(const struct arg *args, struct sample *smp, const char *kw, void *private)
1029{
William Lallemandbfa3e812020-06-25 20:07:18 +02001030 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1031 int conn_server = (kw[4] == 's') ? 1 : 0;
1032
William Lallemand15e16942020-05-15 00:25:08 +02001033 X509 *crt;
1034 struct connection *conn;
1035 SSL *ssl;
1036
William Lallemandbfa3e812020-06-25 20:07:18 +02001037 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001038 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001039 else
1040 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +02001041 ssl = ssl_sock_get_ssl_object(conn);
1042 if (!ssl)
1043 return 0;
1044
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001045 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001046 smp->flags |= SMP_F_MAY_CHANGE;
1047 return 0;
1048 }
1049
1050 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001051 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001052 else
1053 crt = SSL_get_certificate(ssl);
1054 if (!crt)
1055 return 0;
1056
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001057 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001058 smp->data.u.sint = (unsigned int)(1 + X509_get_version(crt));
1059 /* SSL_get_peer_certificate increase X509 * ref count */
1060 if (cert_peer)
1061 X509_free(crt);
1062 smp->data.type = SMP_T_SINT;
1063
1064 return 1;
1065}
1066
1067/* string, returns the certificate's signature algorithm.
1068 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1069 * should be use.
1070 */
1071static int
1072smp_fetch_ssl_x_sig_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
1073{
William Lallemandbfa3e812020-06-25 20:07:18 +02001074 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1075 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +02001076 X509 *crt;
1077 __OPENSSL_110_CONST__ ASN1_OBJECT *algorithm;
1078 int nid;
1079 struct connection *conn;
1080 SSL *ssl;
1081
William Lallemandbfa3e812020-06-25 20:07:18 +02001082 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001083 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001084 else
1085 conn = objt_conn(smp->sess->origin);
1086
William Lallemand15e16942020-05-15 00:25:08 +02001087 ssl = ssl_sock_get_ssl_object(conn);
1088 if (!ssl)
1089 return 0;
1090
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001091 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001092 smp->flags |= SMP_F_MAY_CHANGE;
1093 return 0;
1094 }
1095
1096 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001097 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001098 else
1099 crt = SSL_get_certificate(ssl);
1100 if (!crt)
1101 return 0;
1102
1103 X509_ALGOR_get0(&algorithm, NULL, NULL, X509_get0_tbs_sigalg(crt));
1104 nid = OBJ_obj2nid(algorithm);
1105
1106 smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
1107 if (!smp->data.u.str.area) {
1108 /* SSL_get_peer_certificate increase X509 * ref count */
1109 if (cert_peer)
1110 X509_free(crt);
1111 return 0;
1112 }
1113
1114 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001115 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001116 smp->data.u.str.data = strlen(smp->data.u.str.area);
1117 /* SSL_get_peer_certificate increase X509 * ref count */
1118 if (cert_peer)
1119 X509_free(crt);
1120
1121 return 1;
1122}
1123
1124/* string, returns the certificate's key algorithm.
1125 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1126 * should be use.
1127 */
1128static int
1129smp_fetch_ssl_x_key_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
1130{
William Lallemandbfa3e812020-06-25 20:07:18 +02001131 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1132 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +02001133 X509 *crt;
1134 ASN1_OBJECT *algorithm;
1135 int nid;
1136 struct connection *conn;
1137 SSL *ssl;
1138
William Lallemandbfa3e812020-06-25 20:07:18 +02001139 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001140 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001141 else
1142 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +02001143 ssl = ssl_sock_get_ssl_object(conn);
1144 if (!ssl)
1145 return 0;
1146
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001147 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001148 smp->flags |= SMP_F_MAY_CHANGE;
1149 return 0;
1150 }
1151
1152 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001153 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001154 else
1155 crt = SSL_get_certificate(ssl);
1156 if (!crt)
1157 return 0;
1158
1159 X509_PUBKEY_get0_param(&algorithm, NULL, NULL, NULL, X509_get_X509_PUBKEY(crt));
1160 nid = OBJ_obj2nid(algorithm);
1161
1162 smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
1163 if (!smp->data.u.str.area) {
1164 /* SSL_get_peer_certificate increase X509 * ref count */
1165 if (cert_peer)
1166 X509_free(crt);
1167 return 0;
1168 }
1169
1170 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001171 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001172 smp->data.u.str.data = strlen(smp->data.u.str.area);
1173 if (cert_peer)
1174 X509_free(crt);
1175
1176 return 1;
1177}
1178
1179/* boolean, returns true if front conn. transport layer is SSL.
1180 * This function is also usable on backend conn if the fetch keyword 5th
1181 * char is 'b'.
1182 */
1183static int
1184smp_fetch_ssl_fc(const struct arg *args, struct sample *smp, const char *kw, void *private)
1185{
1186 struct connection *conn;
1187
1188 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001189 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001190 else
1191 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001192 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001193
1194 smp->data.type = SMP_T_BOOL;
Willy Tarreau939b0bf2022-04-11 11:29:11 +02001195 smp->data.u.sint = conn_is_ssl(conn);
William Lallemand15e16942020-05-15 00:25:08 +02001196 return 1;
1197}
1198
1199/* boolean, returns true if client present a SNI */
1200static int
1201smp_fetch_ssl_fc_has_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
1202{
1203#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1204 struct connection *conn = objt_conn(smp->sess->origin);
1205 SSL *ssl = ssl_sock_get_ssl_object(conn);
1206
1207 smp->data.type = SMP_T_BOOL;
1208 smp->data.u.sint = ssl && SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name) != NULL;
1209 return 1;
1210#else
1211 return 0;
1212#endif
1213}
1214
1215/* boolean, returns true if client session has been resumed.
1216 * This function is also usable on backend conn if the fetch keyword 5th
1217 * char is 'b'.
1218 */
1219static int
1220smp_fetch_ssl_fc_is_resumed(const struct arg *args, struct sample *smp, const char *kw, void *private)
1221{
1222 struct connection *conn;
1223 SSL *ssl;
1224
1225 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001226 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001227 else
1228 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001229 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001230
1231 ssl = ssl_sock_get_ssl_object(conn);
1232
1233 smp->data.type = SMP_T_BOOL;
1234 smp->data.u.sint = ssl && SSL_session_reused(ssl);
1235 return 1;
1236}
1237
1238/* string, returns the used cipher if front conn. transport layer is SSL.
1239 * This function is also usable on backend conn if the fetch keyword 5th
1240 * char is 'b'.
1241 */
1242static int
1243smp_fetch_ssl_fc_cipher(const struct arg *args, struct sample *smp, const char *kw, void *private)
1244{
1245 struct connection *conn;
1246 SSL *ssl;
1247
1248 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001249 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001250 else
1251 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001252 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001253
1254 smp->flags = 0;
1255 ssl = ssl_sock_get_ssl_object(conn);
1256 if (!ssl)
1257 return 0;
1258
1259 smp->data.u.str.area = (char *)SSL_get_cipher_name(ssl);
1260 if (!smp->data.u.str.area)
1261 return 0;
1262
1263 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001264 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001265 smp->data.u.str.data = strlen(smp->data.u.str.area);
1266
1267 return 1;
1268}
1269
1270/* integer, returns the algoritm's keysize if front conn. transport layer
1271 * is SSL.
1272 * This function is also usable on backend conn if the fetch keyword 5th
1273 * char is 'b'.
1274 */
1275static int
1276smp_fetch_ssl_fc_alg_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
1277{
1278 struct connection *conn;
1279 SSL *ssl;
1280 int sint;
1281
1282 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001283 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001284 else
1285 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001286 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001287
1288 smp->flags = 0;
1289 ssl = ssl_sock_get_ssl_object(conn);
1290 if (!ssl)
1291 return 0;
1292
1293 if (!SSL_get_cipher_bits(ssl, &sint))
1294 return 0;
1295
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001296 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001297 smp->data.u.sint = sint;
1298 smp->data.type = SMP_T_SINT;
1299
1300 return 1;
1301}
1302
1303/* integer, returns the used keysize if front conn. transport layer is SSL.
1304 * This function is also usable on backend conn if the fetch keyword 5th
1305 * char is 'b'.
1306 */
1307static int
1308smp_fetch_ssl_fc_use_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
1309{
1310 struct connection *conn;
1311 SSL *ssl;
1312
1313 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001314 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001315 else
1316 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001317 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001318
1319 smp->flags = 0;
1320 ssl = ssl_sock_get_ssl_object(conn);
1321 if (!ssl)
1322 return 0;
1323
1324 smp->data.u.sint = (unsigned int)SSL_get_cipher_bits(ssl, NULL);
1325 if (!smp->data.u.sint)
1326 return 0;
1327
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001328 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001329 smp->data.type = SMP_T_SINT;
1330
1331 return 1;
1332}
1333
1334#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
1335static int
1336smp_fetch_ssl_fc_npn(const struct arg *args, struct sample *smp, const char *kw, void *private)
1337{
1338 struct connection *conn;
1339 SSL *ssl;
1340 unsigned int len = 0;
1341
1342 smp->flags = SMP_F_CONST;
1343 smp->data.type = SMP_T_STR;
1344
1345 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001346 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001347 else
1348 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001349 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001350
1351 ssl = ssl_sock_get_ssl_object(conn);
1352 if (!ssl)
1353 return 0;
1354
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001355 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001356 smp->data.u.str.area = NULL;
1357 SSL_get0_next_proto_negotiated(ssl,
1358 (const unsigned char **)&smp->data.u.str.area,
1359 &len);
1360
1361 if (!smp->data.u.str.area)
1362 return 0;
1363
1364 smp->data.u.str.data = len;
1365 return 1;
1366}
1367#endif
1368
1369#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1370static int
1371smp_fetch_ssl_fc_alpn(const struct arg *args, struct sample *smp, const char *kw, void *private)
1372{
1373 struct connection *conn;
1374 SSL *ssl;
1375 unsigned int len = 0;
1376
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001377 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001378 smp->data.type = SMP_T_STR;
1379
1380 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001381 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001382 else
1383 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001384 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001385
1386 ssl = ssl_sock_get_ssl_object(conn);
1387 if (!ssl)
1388 return 0;
1389
1390 smp->data.u.str.area = NULL;
1391 SSL_get0_alpn_selected(ssl,
1392 (const unsigned char **)&smp->data.u.str.area,
1393 &len);
1394
1395 if (!smp->data.u.str.area)
1396 return 0;
1397
1398 smp->data.u.str.data = len;
1399 return 1;
1400}
1401#endif
1402
1403/* string, returns the used protocol if front conn. transport layer is SSL.
1404 * This function is also usable on backend conn if the fetch keyword 5th
1405 * char is 'b'.
1406 */
1407static int
1408smp_fetch_ssl_fc_protocol(const struct arg *args, struct sample *smp, const char *kw, void *private)
1409{
1410 struct connection *conn;
1411 SSL *ssl;
1412
1413 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001414 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001415 else
1416 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001417 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001418
1419 smp->flags = 0;
1420 ssl = ssl_sock_get_ssl_object(conn);
1421 if (!ssl)
1422 return 0;
1423
1424 smp->data.u.str.area = (char *)SSL_get_version(ssl);
1425 if (!smp->data.u.str.area)
1426 return 0;
1427
1428 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001429 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001430 smp->data.u.str.data = strlen(smp->data.u.str.area);
1431
1432 return 1;
1433}
1434
1435/* binary, returns the SSL stream id if front conn. transport layer is SSL.
1436 * This function is also usable on backend conn if the fetch keyword 5th
1437 * char is 'b'.
1438 */
1439#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1440static int
1441smp_fetch_ssl_fc_session_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1442{
1443 struct connection *conn;
1444 SSL_SESSION *ssl_sess;
1445 SSL *ssl;
1446 unsigned int len = 0;
1447
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001448 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001449 smp->data.type = SMP_T_BIN;
1450
1451 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001452 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001453 else
1454 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001455 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001456
1457 ssl = ssl_sock_get_ssl_object(conn);
1458 if (!ssl)
1459 return 0;
1460
1461 ssl_sess = SSL_get_session(ssl);
1462 if (!ssl_sess)
1463 return 0;
1464
1465 smp->data.u.str.area = (char *)SSL_SESSION_get_id(ssl_sess, &len);
1466 if (!smp->data.u.str.area || !len)
1467 return 0;
1468
1469 smp->data.u.str.data = len;
1470 return 1;
1471}
1472#endif
1473
1474
Ilya Shipitsindf627942021-03-25 00:41:41 +05001475#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02001476static int
1477smp_fetch_ssl_fc_random(const struct arg *args, struct sample *smp, const char *kw, void *private)
1478{
1479 struct connection *conn;
1480 struct buffer *data;
1481 SSL *ssl;
1482
1483 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001484 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001485 else
1486 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001487 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001488
1489 ssl = ssl_sock_get_ssl_object(conn);
1490 if (!ssl)
1491 return 0;
1492
1493 data = get_trash_chunk();
1494 if (kw[7] == 'c')
1495 data->data = SSL_get_client_random(ssl,
1496 (unsigned char *) data->area,
1497 data->size);
1498 else
1499 data->data = SSL_get_server_random(ssl,
1500 (unsigned char *) data->area,
1501 data->size);
1502 if (!data->data)
1503 return 0;
1504
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001505 smp->flags = SMP_F_VOL_TEST;
William Lallemand15e16942020-05-15 00:25:08 +02001506 smp->data.type = SMP_T_BIN;
1507 smp->data.u.str = *data;
1508
1509 return 1;
1510}
1511
1512static int
1513smp_fetch_ssl_fc_session_key(const struct arg *args, struct sample *smp, const char *kw, void *private)
1514{
1515 struct connection *conn;
1516 SSL_SESSION *ssl_sess;
1517 struct buffer *data;
1518 SSL *ssl;
1519
1520 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001521 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001522 else
1523 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001524 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001525
1526 ssl = ssl_sock_get_ssl_object(conn);
1527 if (!ssl)
1528 return 0;
1529
1530 ssl_sess = SSL_get_session(ssl);
1531 if (!ssl_sess)
1532 return 0;
1533
1534 data = get_trash_chunk();
1535 data->data = SSL_SESSION_get_master_key(ssl_sess,
1536 (unsigned char *) data->area,
1537 data->size);
1538 if (!data->data)
1539 return 0;
1540
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001541 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001542 smp->data.type = SMP_T_BIN;
1543 smp->data.u.str = *data;
1544
1545 return 1;
1546}
1547#endif
1548
William Lallemand15e16942020-05-15 00:25:08 +02001549static int
1550smp_fetch_ssl_fc_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
1551{
Willy Tarreau579259d2021-11-05 19:12:54 +01001552#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
William Lallemand15e16942020-05-15 00:25:08 +02001553 struct connection *conn;
1554 SSL *ssl;
1555
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001556 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001557 smp->data.type = SMP_T_STR;
1558
1559 conn = objt_conn(smp->sess->origin);
1560 ssl = ssl_sock_get_ssl_object(conn);
1561 if (!ssl)
1562 return 0;
1563
1564 smp->data.u.str.area = (char *)SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
Remi Tricot-Le Bretona9967632022-01-07 17:12:01 +01001565 if (!smp->data.u.str.area) {
1566 /* We might have stored the SNI ourselves, look for it in the
1567 * context's ex_data.
1568 */
1569 smp->data.u.str.area = SSL_get_ex_data(ssl, ssl_client_sni_index);
1570
1571 if (!smp->data.u.str.area)
1572 return 0;
1573 }
William Lallemand15e16942020-05-15 00:25:08 +02001574
1575 smp->data.u.str.data = strlen(smp->data.u.str.area);
Remi Tricot-Le Bretona9967632022-01-07 17:12:01 +01001576
William Lallemand15e16942020-05-15 00:25:08 +02001577 return 1;
Willy Tarreau579259d2021-11-05 19:12:54 +01001578#else
1579 /* SNI not supported */
1580 return 0;
William Lallemand15e16942020-05-15 00:25:08 +02001581#endif
Willy Tarreau579259d2021-11-05 19:12:54 +01001582}
William Lallemand15e16942020-05-15 00:25:08 +02001583
Marcin Deranek959a48c2021-07-13 15:14:21 +02001584/* binary, returns tls client hello cipher list.
1585 * Arguments: filter_option (0,1)
1586 */
William Lallemand15e16942020-05-15 00:25:08 +02001587static int
1588smp_fetch_ssl_fc_cl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1589{
Marcin Deranek959a48c2021-07-13 15:14:21 +02001590 struct buffer *smp_trash;
William Lallemand15e16942020-05-15 00:25:08 +02001591 struct connection *conn;
1592 struct ssl_capture *capture;
1593 SSL *ssl;
1594
1595 conn = objt_conn(smp->sess->origin);
1596 ssl = ssl_sock_get_ssl_object(conn);
1597 if (!ssl)
1598 return 0;
1599
1600 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1601 if (!capture)
1602 return 0;
1603
Marcin Deranek959a48c2021-07-13 15:14:21 +02001604 if (args[0].data.sint) {
1605 smp_trash = get_trash_chunk();
1606 exclude_tls_grease(capture->data + capture->ciphersuite_offset, capture->ciphersuite_len, smp_trash);
1607 smp->data.u.str.area = smp_trash->area;
1608 smp->data.u.str.data = smp_trash->data;
1609 smp->flags = SMP_F_VOL_SESS;
1610 }
1611 else {
1612 smp->data.u.str.area = capture->data + capture->ciphersuite_offset;
1613 smp->data.u.str.data = capture->ciphersuite_len;
1614 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1615 }
1616
William Lallemand15e16942020-05-15 00:25:08 +02001617 smp->data.type = SMP_T_BIN;
William Lallemand15e16942020-05-15 00:25:08 +02001618 return 1;
1619}
1620
Marcin Deranek959a48c2021-07-13 15:14:21 +02001621/* binary, returns tls client hello cipher list as hexadecimal string.
1622 * Arguments: filter_option (0,1)
1623 */
William Lallemand15e16942020-05-15 00:25:08 +02001624static int
1625smp_fetch_ssl_fc_cl_hex(const struct arg *args, struct sample *smp, const char *kw, void *private)
1626{
1627 struct buffer *data;
1628
1629 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1630 return 0;
1631
1632 data = get_trash_chunk();
1633 dump_binary(data, smp->data.u.str.area, smp->data.u.str.data);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001634 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001635 smp->data.type = SMP_T_BIN;
1636 smp->data.u.str = *data;
1637 return 1;
1638}
1639
Marcin Deranek959a48c2021-07-13 15:14:21 +02001640/* integer, returns xxh64 hash of tls client hello cipher list. */
William Lallemand15e16942020-05-15 00:25:08 +02001641static int
1642smp_fetch_ssl_fc_cl_xxh64(const struct arg *args, struct sample *smp, const char *kw, void *private)
1643{
1644 struct connection *conn;
1645 struct ssl_capture *capture;
1646 SSL *ssl;
1647
1648 conn = objt_conn(smp->sess->origin);
1649 ssl = ssl_sock_get_ssl_object(conn);
1650 if (!ssl)
1651 return 0;
1652
1653 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1654 if (!capture)
1655 return 0;
1656
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001657 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001658 smp->data.type = SMP_T_SINT;
1659 smp->data.u.sint = capture->xxh64;
1660 return 1;
1661}
1662
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001663static int
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001664smp_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 +02001665{
1666 struct connection *conn;
1667 struct ssl_sock_ctx *ctx;
1668
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001669 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001670 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001671 else
1672 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001673 smp->strm ? sc_conn(smp->strm->scb) : NULL;
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001674
Willy Tarreauce7a5e02022-04-12 07:40:42 +02001675 if (!conn)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001676 return 0;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001677
1678 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1679 smp->flags = SMP_F_MAY_CHANGE;
1680 return 0;
1681 }
1682
Willy Tarreauce7a5e02022-04-12 07:40:42 +02001683 ctx = conn_get_ssl_sock_ctx(conn);
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001684 if (!ctx)
1685 return 0;
1686
1687 smp->flags = SMP_F_VOL_SESS;
1688 smp->data.type = SMP_T_SINT;
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001689 smp->data.u.sint = ctx->error_code;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001690 return 1;
1691}
1692
1693static int
Marcin Deranek959a48c2021-07-13 15:14:21 +02001694smp_fetch_ssl_fc_protocol_hello_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1695{
1696 struct connection *conn;
1697 struct ssl_capture *capture;
1698 SSL *ssl;
1699
1700 conn = objt_conn(smp->sess->origin);
1701 ssl = ssl_sock_get_ssl_object(conn);
1702 if (!ssl)
1703 return 0;
1704
1705 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1706 if (!capture)
1707 return 0;
1708
1709 smp->flags = SMP_F_VOL_SESS;
1710 smp->data.type = SMP_T_SINT;
1711 smp->data.u.sint = capture->protocol_version;
1712 return 1;
1713}
1714
1715static int
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001716smp_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 +02001717{
1718 struct connection *conn;
1719 struct ssl_sock_ctx *ctx;
1720 const char *err_code_str;
1721
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001722 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001723 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001724 else
1725 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001726 smp->strm ? sc_conn(smp->strm->scb) : NULL;
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001727
Willy Tarreauce7a5e02022-04-12 07:40:42 +02001728 if (!conn)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001729 return 0;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001730
1731 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1732 smp->flags = SMP_F_MAY_CHANGE;
1733 return 0;
1734 }
1735
Willy Tarreauce7a5e02022-04-12 07:40:42 +02001736 ctx = conn_get_ssl_sock_ctx(conn);
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001737 if (!ctx || !ctx->error_code)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001738 return 0;
1739
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001740 err_code_str = ERR_error_string(ctx->error_code, NULL);
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001741
1742 smp->flags = SMP_F_VOL_SESS;
1743 smp->data.type = SMP_T_STR;
1744 smp->data.u.str.area = (char*)err_code_str;
1745 smp->data.u.str.data = strlen(err_code_str);
1746
Marcin Deranek959a48c2021-07-13 15:14:21 +02001747 return 1;
1748}
1749
1750/* binary, returns tls client hello extensions list.
1751 * Arguments: filter_option (0,1)
1752 */
1753static int
1754smp_fetch_ssl_fc_ext_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1755{
1756 struct buffer *smp_trash;
1757 struct connection *conn;
1758 struct ssl_capture *capture;
1759 SSL *ssl;
1760
1761 conn = objt_conn(smp->sess->origin);
1762 ssl = ssl_sock_get_ssl_object(conn);
1763 if (!ssl)
1764 return 0;
1765
1766 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1767 if (!capture)
1768 return 0;
1769
1770 if (args[0].data.sint) {
1771 smp_trash = get_trash_chunk();
1772 exclude_tls_grease(capture->data + capture->extensions_offset, capture->extensions_len, smp_trash);
1773 smp->data.u.str.area = smp_trash->area;
1774 smp->data.u.str.data = smp_trash->data;
1775 smp->flags = SMP_F_VOL_SESS;
1776 }
1777 else {
1778 smp->data.u.str.area = capture->data + capture->extensions_offset;
1779 smp->data.u.str.data = capture->extensions_len;
1780 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1781 }
1782
1783 smp->data.type = SMP_T_BIN;
1784 return 1;
1785}
1786
1787/* binary, returns tls client hello supported elliptic curves.
1788 * Arguments: filter_option (0,1)
1789 */
1790static int
1791smp_fetch_ssl_fc_ecl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1792{
1793 struct buffer *smp_trash;
1794 struct connection *conn;
1795 struct ssl_capture *capture;
1796 SSL *ssl;
1797
1798 conn = objt_conn(smp->sess->origin);
1799 ssl = ssl_sock_get_ssl_object(conn);
1800 if (!ssl)
1801 return 0;
1802
1803 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1804 if (!capture)
1805 return 0;
1806
1807 if (args[0].data.sint) {
1808 smp_trash = get_trash_chunk();
1809 exclude_tls_grease(capture->data + capture->ec_offset, capture->ec_len, smp_trash);
1810 smp->data.u.str.area = smp_trash->area;
1811 smp->data.u.str.data = smp_trash->data;
1812 smp->flags = SMP_F_VOL_SESS;
1813 }
1814 else {
1815 smp->data.u.str.area = capture->data + capture->ec_offset;
1816 smp->data.u.str.data = capture->ec_len;
1817 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1818 }
1819
1820 smp->data.type = SMP_T_BIN;
1821 return 1;
1822}
1823
1824/* binary, returns tls client hello supported elliptic curve point formats */
1825static int
1826smp_fetch_ssl_fc_ecf_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1827{
1828 struct connection *conn;
1829 struct ssl_capture *capture;
1830 SSL *ssl;
1831
1832 conn = objt_conn(smp->sess->origin);
1833 ssl = ssl_sock_get_ssl_object(conn);
1834 if (!ssl)
1835 return 0;
1836
1837 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1838 if (!capture)
1839 return 0;
1840
1841 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1842 smp->data.type = SMP_T_BIN;
1843 smp->data.u.str.area = capture->data + capture->ec_formats_offset;
1844 smp->data.u.str.data = capture->ec_formats_len;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001845 return 1;
1846}
1847
William Lallemand7d42ef52020-07-06 11:41:30 +02001848/* Dump the SSL keylog, it only works with "tune.ssl.keylog 1" */
William Lallemand722180a2021-06-09 16:46:12 +02001849#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02001850static int smp_fetch_ssl_x_keylog(const struct arg *args, struct sample *smp, const char *kw, void *private)
1851{
1852 struct connection *conn;
1853 struct ssl_keylog *keylog;
1854 SSL *ssl;
1855 char *src = NULL;
1856 const char *sfx;
1857
1858 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001859 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand7d42ef52020-07-06 11:41:30 +02001860
William Lallemandeec1d452020-07-07 10:48:13 +02001861 if (!conn)
1862 return 0;
1863
William Lallemand7d42ef52020-07-06 11:41:30 +02001864 if (conn->flags & CO_FL_WAIT_XPRT) {
1865 smp->flags |= SMP_F_MAY_CHANGE;
1866 return 0;
1867 }
1868
1869 ssl = ssl_sock_get_ssl_object(conn);
1870 if (!ssl)
1871 return 0;
1872
1873 keylog = SSL_get_ex_data(ssl, ssl_keylog_index);
1874 if (!keylog)
1875 return 0;
1876
1877 sfx = kw + strlen("ssl_xx_");
1878
1879 if (strcmp(sfx, "client_early_traffic_secret") == 0) {
1880 src = keylog->client_early_traffic_secret;
1881 } else if (strcmp(sfx, "client_handshake_traffic_secret") == 0) {
1882 src = keylog->client_handshake_traffic_secret;
1883 } else if (strcmp(sfx, "server_handshake_traffic_secret") == 0) {
1884 src = keylog->server_handshake_traffic_secret;
1885 } else if (strcmp(sfx, "client_traffic_secret_0") == 0) {
1886 src = keylog->client_traffic_secret_0;
1887 } else if (strcmp(sfx, "server_traffic_secret_0") == 0) {
1888 src = keylog->server_traffic_secret_0;
1889 } else if (strcmp(sfx, "exporter_secret") == 0) {
1890 src = keylog->exporter_secret;
1891 } else if (strcmp(sfx, "early_exporter_secret") == 0) {
1892 src = keylog->early_exporter_secret;
1893 }
1894
1895 if (!src || !*src)
1896 return 0;
1897
1898 smp->data.u.str.area = src;
1899 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001900 smp->flags |= SMP_F_VOL_TEST | SMP_F_CONST;
William Lallemand7d42ef52020-07-06 11:41:30 +02001901 smp->data.u.str.data = strlen(smp->data.u.str.area);
1902 return 1;
William Lallemand7d42ef52020-07-06 11:41:30 +02001903}
1904#endif
1905
William Lallemand15e16942020-05-15 00:25:08 +02001906static int
1907smp_fetch_ssl_fc_cl_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
1908{
Ilya Shipitsinc9dfee42020-10-31 02:10:02 +05001909#if defined(OPENSSL_IS_BORINGSSL) || defined(SSL_CTRL_GET_RAW_CIPHERLIST)
William Lallemand15e16942020-05-15 00:25:08 +02001910 struct buffer *data;
1911 int i;
1912
1913 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1914 return 0;
1915
1916 data = get_trash_chunk();
1917 for (i = 0; i + 1 < smp->data.u.str.data; i += 2) {
1918 const char *str;
1919 const SSL_CIPHER *cipher;
1920 const unsigned char *bin = (const unsigned char *) smp->data.u.str.area + i;
1921 uint16_t id = (bin[0] << 8) | bin[1];
1922#if defined(OPENSSL_IS_BORINGSSL)
1923 cipher = SSL_get_cipher_by_value(id);
1924#else
1925 struct connection *conn = __objt_conn(smp->sess->origin);
1926 SSL *ssl = ssl_sock_get_ssl_object(conn);
1927 cipher = SSL_CIPHER_find(ssl, bin);
1928#endif
1929 str = SSL_CIPHER_get_name(cipher);
1930 if (!str || strcmp(str, "(NONE)") == 0)
1931 chunk_appendf(data, "%sUNKNOWN(%04x)", i == 0 ? "" : ",", id);
1932 else
1933 chunk_appendf(data, "%s%s", i == 0 ? "" : ",", str);
1934 }
1935 smp->data.type = SMP_T_STR;
1936 smp->data.u.str = *data;
1937 return 1;
1938#else
1939 return smp_fetch_ssl_fc_cl_xxh64(args, smp, kw, private);
1940#endif
1941}
1942
1943#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1944static int
1945smp_fetch_ssl_fc_unique_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1946{
1947 struct connection *conn;
1948 int finished_len;
1949 struct buffer *finished_trash;
1950 SSL *ssl;
1951
1952 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001953 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001954 else
1955 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001956 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001957
1958 smp->flags = 0;
1959 ssl = ssl_sock_get_ssl_object(conn);
1960 if (!ssl)
1961 return 0;
1962
1963 if (conn->flags & CO_FL_WAIT_XPRT) {
1964 smp->flags |= SMP_F_MAY_CHANGE;
1965 return 0;
1966 }
1967
1968 finished_trash = get_trash_chunk();
1969 if (!SSL_session_reused(ssl))
1970 finished_len = SSL_get_peer_finished(ssl,
1971 finished_trash->area,
1972 finished_trash->size);
1973 else
1974 finished_len = SSL_get_finished(ssl,
1975 finished_trash->area,
1976 finished_trash->size);
1977
1978 if (!finished_len)
1979 return 0;
1980
1981 finished_trash->data = finished_len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001982 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001983 smp->data.u.str = *finished_trash;
1984 smp->data.type = SMP_T_BIN;
1985
1986 return 1;
1987}
1988#endif
1989
1990/* integer, returns the first verify error in CA chain of client certificate chain. */
1991static int
1992smp_fetch_ssl_c_ca_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
1993{
Willy Tarreau939b0bf2022-04-11 11:29:11 +02001994 struct connection *conn = objt_conn(smp->sess->origin);
1995 struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
William Lallemand15e16942020-05-15 00:25:08 +02001996
Willy Tarreau939b0bf2022-04-11 11:29:11 +02001997 if (conn && conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001998 smp->flags = SMP_F_MAY_CHANGE;
1999 return 0;
2000 }
2001
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002002 if (!ctx)
2003 return 0;
2004
William Lallemand15e16942020-05-15 00:25:08 +02002005 smp->data.type = SMP_T_SINT;
2006 smp->data.u.sint = (unsigned long long int)SSL_SOCK_ST_TO_CA_ERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002007 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002008
2009 return 1;
2010}
2011
2012/* integer, returns the depth of the first verify error in CA chain of client certificate chain. */
2013static int
2014smp_fetch_ssl_c_ca_err_depth(const struct arg *args, struct sample *smp, const char *kw, void *private)
2015{
Willy Tarreau939b0bf2022-04-11 11:29:11 +02002016 struct connection *conn = objt_conn(smp->sess->origin);
2017 struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
William Lallemand15e16942020-05-15 00:25:08 +02002018
Willy Tarreau939b0bf2022-04-11 11:29:11 +02002019 if (conn && conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02002020 smp->flags = SMP_F_MAY_CHANGE;
2021 return 0;
2022 }
William Lallemand15e16942020-05-15 00:25:08 +02002023
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002024 if (!ctx)
2025 return 0;
2026
William Lallemand15e16942020-05-15 00:25:08 +02002027 smp->data.type = SMP_T_SINT;
2028 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CAEDEPTH(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002029 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002030
2031 return 1;
2032}
2033
2034/* integer, returns the first verify error on client certificate */
2035static int
2036smp_fetch_ssl_c_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
2037{
Willy Tarreau939b0bf2022-04-11 11:29:11 +02002038 struct connection *conn = objt_conn(smp->sess->origin);
2039 struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
William Lallemand15e16942020-05-15 00:25:08 +02002040
Willy Tarreau939b0bf2022-04-11 11:29:11 +02002041 if (conn && conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02002042 smp->flags = SMP_F_MAY_CHANGE;
2043 return 0;
2044 }
2045
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002046 if (!ctx)
2047 return 0;
2048
William Lallemand15e16942020-05-15 00:25:08 +02002049 smp->data.type = SMP_T_SINT;
2050 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CRTERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002051 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002052
2053 return 1;
2054}
2055
2056/* integer, returns the verify result on client cert */
2057static int
2058smp_fetch_ssl_c_verify(const struct arg *args, struct sample *smp, const char *kw, void *private)
2059{
2060 struct connection *conn;
2061 SSL *ssl;
2062
2063 conn = objt_conn(smp->sess->origin);
2064 ssl = ssl_sock_get_ssl_object(conn);
2065 if (!ssl)
2066 return 0;
2067
2068 if (conn->flags & CO_FL_WAIT_XPRT) {
2069 smp->flags = SMP_F_MAY_CHANGE;
2070 return 0;
2071 }
2072
2073 smp->data.type = SMP_T_SINT;
2074 smp->data.u.sint = (long long int)SSL_get_verify_result(ssl);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002075 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002076
2077 return 1;
2078}
2079
2080/* Argument validation functions */
2081
2082/* This function is used to validate the arguments passed to any "x_dn" ssl
2083 * keywords. These keywords support specifying a third parameter that must be
2084 * either empty or the value "rfc2253". Returns 0 on error, non-zero if OK.
2085 */
2086int val_dnfmt(struct arg *arg, char **err_msg)
2087{
2088 if (arg && arg[2].type == ARGT_STR && arg[2].data.str.data > 0 && (strcmp(arg[2].data.str.area, "rfc2253") != 0)) {
2089 memprintf(err_msg, "only rfc2253 or a blank value are currently supported as the format argument.");
2090 return 0;
2091 }
2092 return 1;
2093}
2094
2095/* Note: must not be declared <const> as its list will be overwritten.
2096 * Please take care of keeping this list alphabetically sorted.
2097 */
2098static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
2099 { "ssl_bc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
2100 { "ssl_bc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2101#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2102 { "ssl_bc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2103#endif
2104 { "ssl_bc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2105#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2106 { "ssl_bc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2107#endif
2108 { "ssl_bc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
2109 { "ssl_bc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2110 { "ssl_bc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2111 { "ssl_bc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2112#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2113 { "ssl_bc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2114#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05002115#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02002116 { "ssl_bc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2117 { "ssl_bc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2118 { "ssl_bc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2119#endif
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02002120 { "ssl_bc_err", smp_fetch_ssl_fc_err, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2121 { "ssl_bc_err_str", smp_fetch_ssl_fc_err_str, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
William Lallemand15e16942020-05-15 00:25:08 +02002122 { "ssl_c_ca_err", smp_fetch_ssl_c_ca_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2123 { "ssl_c_ca_err_depth", smp_fetch_ssl_c_ca_err_depth, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2124 { "ssl_c_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02002125 { "ssl_c_chain_der", smp_fetch_ssl_x_chain_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Lallemand15e16942020-05-15 00:25:08 +02002126 { "ssl_c_err", smp_fetch_ssl_c_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2127 { "ssl_c_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2128 { "ssl_c_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2129 { "ssl_c_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2130 { "ssl_c_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2131 { "ssl_c_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2132 { "ssl_c_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2133 { "ssl_c_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2134 { "ssl_c_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2135 { "ssl_c_used", smp_fetch_ssl_c_used, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2136 { "ssl_c_verify", smp_fetch_ssl_c_verify, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2137 { "ssl_c_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2138 { "ssl_f_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2139 { "ssl_f_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2140 { "ssl_f_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2141 { "ssl_f_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2142 { "ssl_f_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2143 { "ssl_f_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2144 { "ssl_f_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2145 { "ssl_f_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2146 { "ssl_f_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2147 { "ssl_f_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2148 { "ssl_fc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2149 { "ssl_fc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2150 { "ssl_fc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2151 { "ssl_fc_has_crt", smp_fetch_ssl_fc_has_crt, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2152 { "ssl_fc_has_early", smp_fetch_ssl_fc_has_early, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2153 { "ssl_fc_has_sni", smp_fetch_ssl_fc_has_sni, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2154 { "ssl_fc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2155#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2156 { "ssl_fc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2157#endif
2158#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2159 { "ssl_fc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2160#endif
2161 { "ssl_fc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2162#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2163 { "ssl_fc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2164#endif
2165 { "ssl_fc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2166#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2167 { "ssl_fc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2168#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05002169#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02002170 { "ssl_fc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2171 { "ssl_fc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2172 { "ssl_fc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2173#endif
William Lallemand7d42ef52020-07-06 11:41:30 +02002174
William Lallemand722180a2021-06-09 16:46:12 +02002175#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02002176 { "ssl_fc_client_early_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2177 { "ssl_fc_client_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2178 { "ssl_fc_server_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2179 { "ssl_fc_client_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2180 { "ssl_fc_server_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2181 { "ssl_fc_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2182 { "ssl_fc_early_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2183#endif
2184
William Lallemand15e16942020-05-15 00:25:08 +02002185 { "ssl_fc_sni", smp_fetch_ssl_fc_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
Marcin Deranek959a48c2021-07-13 15:14:21 +02002186 { "ssl_fc_cipherlist_bin", smp_fetch_ssl_fc_cl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2187 { "ssl_fc_cipherlist_hex", smp_fetch_ssl_fc_cl_hex, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_USE_L5CLI },
2188 { "ssl_fc_cipherlist_str", smp_fetch_ssl_fc_cl_str, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
William Lallemand15e16942020-05-15 00:25:08 +02002189 { "ssl_fc_cipherlist_xxh", smp_fetch_ssl_fc_cl_xxh64, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02002190 { "ssl_fc_err", smp_fetch_ssl_fc_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2191 { "ssl_fc_err_str", smp_fetch_ssl_fc_err_str, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
Marcin Deranek959a48c2021-07-13 15:14:21 +02002192 { "ssl_fc_protocol_hello_id",smp_fetch_ssl_fc_protocol_hello_id,0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2193 { "ssl_fc_extlist_bin", smp_fetch_ssl_fc_ext_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2194 { "ssl_fc_eclist_bin", smp_fetch_ssl_fc_ecl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2195 { "ssl_fc_ecformats_bin", smp_fetch_ssl_fc_ecf_bin, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
William Lallemandbfa3e812020-06-25 20:07:18 +02002196
2197/* SSL server certificate fetches */
2198 { "ssl_s_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02002199 { "ssl_s_chain_der", smp_fetch_ssl_x_chain_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Lallemandbfa3e812020-06-25 20:07:18 +02002200 { "ssl_s_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2201 { "ssl_s_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2202 { "ssl_s_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2203 { "ssl_s_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2204 { "ssl_s_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2205 { "ssl_s_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2206 { "ssl_s_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2207 { "ssl_s_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2208 { "ssl_s_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
William Lallemand15e16942020-05-15 00:25:08 +02002209 { NULL, NULL, 0, 0, 0 },
2210}};
2211
2212INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
2213
Willy Tarreau99ea1882021-10-06 15:37:17 +02002214/* Note: must not be declared <const> as its list will be overwritten */
2215static struct sample_conv_kw_list sample_conv_kws = {ILH, {
2216 { "sha2", sample_conv_sha2, ARG1(0, SINT), smp_check_sha2, SMP_T_BIN, SMP_T_BIN },
2217#ifdef EVP_CIPH_GCM_MODE
2218 { "aes_gcm_dec", sample_conv_aes_gcm_dec, ARG4(4,SINT,STR,STR,STR), check_aes_gcm, SMP_T_BIN, SMP_T_BIN },
2219#endif
William Lallemand9fbc84e2022-11-03 18:56:37 +01002220 { "x509_v_err_str", sample_conv_x509_v_err, 0, NULL, SMP_T_SINT, SMP_T_STR },
Willy Tarreau99ea1882021-10-06 15:37:17 +02002221 { "digest", sample_conv_crypto_digest, ARG1(1,STR), check_crypto_digest, SMP_T_BIN, SMP_T_BIN },
2222 { "hmac", sample_conv_crypto_hmac, ARG2(2,STR,STR), check_crypto_hmac, SMP_T_BIN, SMP_T_BIN },
2223#if defined(HAVE_CRYPTO_memcmp)
2224 { "secure_memcmp", sample_conv_secure_memcmp, ARG1(1,STR), smp_check_secure_memcmp, SMP_T_BIN, SMP_T_BOOL },
2225#endif
2226 { NULL, NULL, 0, 0, 0 },
2227}};
2228
2229INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
2230
2231
William Lallemand15e16942020-05-15 00:25:08 +02002232/* Note: must not be declared <const> as its list will be overwritten.
2233 * Please take care of keeping this list alphabetically sorted.
2234 */
2235static struct acl_kw_list acl_kws = {ILH, {
2236 { "ssl_fc_sni_end", "ssl_fc_sni", PAT_MATCH_END },
2237 { "ssl_fc_sni_reg", "ssl_fc_sni", PAT_MATCH_REG },
2238 { /* END */ },
2239}};
2240
2241INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);