blob: 5aec97fef18b61d8633499e8a5e2d68a3b163b0c [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;
William Lallemand117c7fd2023-05-03 15:13:10 +0200414 } else {
415 struct buffer *smp_trash = get_trash_chunk();
416
417 /* if the conversion failed, output the numbers as string */
418 chunk_printf(smp_trash, "%llu", smp->data.u.sint);
419
420 smp->data.u.str = *smp_trash;
421 smp->data.type = SMP_T_STR;
422 smp->flags &= ~SMP_F_CONST;
423
424 return 1;
William Lallemand9fbc84e2022-11-03 18:56:37 +0100425 }
426
427 return 0;
428}
429
Willy Tarreau99ea1882021-10-06 15:37:17 +0200430static int check_crypto_hmac(struct arg *args, struct sample_conv *conv,
431 const char *file, int line, char **err)
432{
433 if (!check_crypto_digest(args, conv, file, line, err))
434 return 0;
435
436 if (!sample_check_arg_base64(&args[1], err)) {
437 memprintf(err, "failed to parse key : %s", *err);
438 return 0;
439 }
440
441 return 1;
442}
443
444static int sample_conv_crypto_hmac(const struct arg *args, struct sample *smp, void *private)
445{
446 struct sample key;
447 struct buffer *trash = NULL, *key_trash = NULL;
448 unsigned char *md;
449 unsigned int md_len;
450 const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
451 int dec_size;
452
453 smp_set_owner(&key, smp->px, smp->sess, smp->strm, smp->opt);
454 if (!sample_conv_var2smp_str(&args[1], &key))
455 return 0;
456
457 if (args[1].type == ARGT_VAR) {
458 key_trash = alloc_trash_chunk();
459 if (!key_trash)
460 goto err;
461
462 dec_size = base64dec(key.data.u.str.area, key.data.u.str.data, key_trash->area, key_trash->size);
463 if (dec_size < 0)
464 goto err;
465 key_trash->data = dec_size;
466 key.data.u.str = *key_trash;
467 }
468
469 trash = alloc_trash_chunk();
470 if (!trash)
471 goto err;
472
473 md = (unsigned char*) trash->area;
474 md_len = trash->size;
475 if (!HMAC(evp, key.data.u.str.area, key.data.u.str.data, (const unsigned char*) smp->data.u.str.area,
476 smp->data.u.str.data, md, &md_len))
477 goto err;
478
479 free_trash_chunk(key_trash);
480
481 trash->data = md_len;
482 smp->data.u.str = *trash;
483 smp->data.type = SMP_T_BIN;
484 smp_dup(smp);
485 free_trash_chunk(trash);
486 return 1;
487
488err:
489 free_trash_chunk(key_trash);
490 free_trash_chunk(trash);
491 return 0;
492}
493
William Lallemand15e16942020-05-15 00:25:08 +0200494static int
495smp_fetch_ssl_fc_has_early(const struct arg *args, struct sample *smp, const char *kw, void *private)
496{
497 SSL *ssl;
498 struct connection *conn;
499
500 conn = objt_conn(smp->sess->origin);
501 ssl = ssl_sock_get_ssl_object(conn);
502 if (!ssl)
503 return 0;
504
505 smp->flags = 0;
506 smp->data.type = SMP_T_BOOL;
507#ifdef OPENSSL_IS_BORINGSSL
508 {
509 smp->data.u.sint = (SSL_in_early_data(ssl) &&
510 SSL_early_data_accepted(ssl));
511 }
512#else
513 smp->data.u.sint = ((conn->flags & CO_FL_EARLY_DATA) &&
514 (conn->flags & (CO_FL_EARLY_SSL_HS | CO_FL_SSL_WAIT_HS))) ? 1 : 0;
515#endif
516 return 1;
517}
518
519/* boolean, returns true if client cert was present */
520static int
521smp_fetch_ssl_fc_has_crt(const struct arg *args, struct sample *smp, const char *kw, void *private)
522{
Willy Tarreau939b0bf2022-04-11 11:29:11 +0200523 struct connection *conn = objt_conn(smp->sess->origin);
524 struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
William Lallemand15e16942020-05-15 00:25:08 +0200525
Willy Tarreau939b0bf2022-04-11 11:29:11 +0200526 if (!ctx)
William Lallemand15e16942020-05-15 00:25:08 +0200527 return 0;
528
William Lallemand15e16942020-05-15 00:25:08 +0200529 if (conn->flags & CO_FL_WAIT_XPRT) {
530 smp->flags |= SMP_F_MAY_CHANGE;
531 return 0;
532 }
533
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200534 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200535 smp->data.type = SMP_T_BOOL;
536 smp->data.u.sint = SSL_SOCK_ST_FL_VERIFY_DONE & ctx->xprt_st ? 1 : 0;
537
538 return 1;
539}
540
Abhijeet Rastogidf97f472023-05-13 20:04:45 -0700541/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of the
542 * client certificate's root CA.
543 */
William Lallemand6e0c39d2023-05-15 12:05:55 +0200544#ifdef HAVE_SSL_get0_verified_chain
Abhijeet Rastogidf97f472023-05-13 20:04:45 -0700545static int
546smp_fetch_ssl_r_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
547{
548 X509 *crt = NULL;
549 X509_NAME *name;
550 int ret = 0;
551 struct buffer *smp_trash;
552 struct connection *conn;
553 SSL *ssl;
554
555 conn = objt_conn(smp->sess->origin);
556 ssl = ssl_sock_get_ssl_object(conn);
557 if (!ssl)
558 return 0;
559
560 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
561 smp->flags |= SMP_F_MAY_CHANGE;
562 return 0;
563 }
564
565 crt = ssl_sock_get_verified_chain_root(ssl);
566 if (!crt)
567 goto out;
568
569 name = X509_get_subject_name(crt);
570 if (!name)
571 goto out;
572
573 smp_trash = get_trash_chunk();
574 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
575 int pos = 1;
576
577 if (args[1].type == ARGT_SINT)
578 pos = args[1].data.sint;
579
580 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
581 goto out;
582 }
583 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
584 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
585 goto out;
586 }
587 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
588 goto out;
589
590 smp->flags = SMP_F_VOL_SESS;
591 smp->data.type = SMP_T_STR;
592 smp->data.u.str = *smp_trash;
593 ret = 1;
594out:
595 return ret;
596}
William Lallemand6e0c39d2023-05-15 12:05:55 +0200597#endif
Abhijeet Rastogidf97f472023-05-13 20:04:45 -0700598
William Lallemand15e16942020-05-15 00:25:08 +0200599/* binary, returns a certificate in a binary chunk (der/raw).
600 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
601 * should be use.
602 */
603static int
604smp_fetch_ssl_x_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
605{
William Lallemandbfa3e812020-06-25 20:07:18 +0200606 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
607 int conn_server = (kw[4] == 's') ? 1 : 0;
608
William Lallemand15e16942020-05-15 00:25:08 +0200609 X509 *crt = NULL;
610 int ret = 0;
611 struct buffer *smp_trash;
612 struct connection *conn;
613 SSL *ssl;
614
William Lallemandbfa3e812020-06-25 20:07:18 +0200615 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200616 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200617 else
618 conn = objt_conn(smp->sess->origin);
619
William Lallemand15e16942020-05-15 00:25:08 +0200620 ssl = ssl_sock_get_ssl_object(conn);
621 if (!ssl)
622 return 0;
623
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200624 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200625 smp->flags |= SMP_F_MAY_CHANGE;
626 return 0;
627 }
628
629 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200630 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200631 else
632 crt = SSL_get_certificate(ssl);
633
634 if (!crt)
635 goto out;
636
637 smp_trash = get_trash_chunk();
638 if (ssl_sock_crt2der(crt, smp_trash) <= 0)
639 goto out;
640
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200641 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200642 smp->data.u.str = *smp_trash;
643 smp->data.type = SMP_T_BIN;
644 ret = 1;
645out:
646 /* SSL_get_peer_certificate, it increase X509 * ref count */
647 if (cert_peer && crt)
648 X509_free(crt);
649 return ret;
650}
651
William Dauchya598b502020-08-06 18:11:38 +0200652/* binary, returns a chain certificate in a binary chunk (der/raw).
653 * The 5th keyword char is used to support only peer cert
654 */
655static int
656smp_fetch_ssl_x_chain_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
657{
658 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
659 int conn_server = (kw[4] == 's') ? 1 : 0;
660 struct buffer *smp_trash;
661 struct buffer *tmp_trash = NULL;
662 struct connection *conn;
663 STACK_OF(X509) *certs = NULL;
664 X509 *crt = NULL;
665 SSL *ssl;
666 int ret = 0;
667 int num_certs;
668 int i;
669
670 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200671 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Dauchya598b502020-08-06 18:11:38 +0200672 else
673 conn = objt_conn(smp->sess->origin);
674
675 if (!conn)
676 return 0;
677
678 ssl = ssl_sock_get_ssl_object(conn);
679 if (!ssl)
680 return 0;
681
682 if (conn->flags & CO_FL_WAIT_XPRT) {
683 smp->flags |= SMP_F_MAY_CHANGE;
684 return 0;
685 }
686
687 if (!cert_peer)
688 return 0;
689
690 certs = SSL_get_peer_cert_chain(ssl);
691 if (!certs)
692 return 0;
693
694 num_certs = sk_X509_num(certs);
695 if (!num_certs)
696 goto out;
697 smp_trash = get_trash_chunk();
698 tmp_trash = alloc_trash_chunk();
699 if (!tmp_trash)
700 goto out;
701 for (i = 0; i < num_certs; i++) {
702 crt = sk_X509_value(certs, i);
703 if (ssl_sock_crt2der(crt, tmp_trash) <= 0)
704 goto out;
705 chunk_cat(smp_trash, tmp_trash);
706 }
707
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200708 smp->flags = SMP_F_VOL_SESS;
William Dauchya598b502020-08-06 18:11:38 +0200709 smp->data.u.str = *smp_trash;
710 smp->data.type = SMP_T_BIN;
711 ret = 1;
712out:
713 if (tmp_trash)
714 free_trash_chunk(tmp_trash);
William Dauchya598b502020-08-06 18:11:38 +0200715 return ret;
716}
717
William Lallemand15e16942020-05-15 00:25:08 +0200718/* binary, returns serial of certificate in a binary chunk.
719 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
720 * should be use.
721 */
722static int
723smp_fetch_ssl_x_serial(const struct arg *args, struct sample *smp, const char *kw, void *private)
724{
William Lallemandbfa3e812020-06-25 20:07:18 +0200725 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
726 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200727 X509 *crt = NULL;
728 int ret = 0;
729 struct buffer *smp_trash;
730 struct connection *conn;
731 SSL *ssl;
732
William Lallemandbfa3e812020-06-25 20:07:18 +0200733 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200734 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200735 else
736 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +0200737 ssl = ssl_sock_get_ssl_object(conn);
738 if (!ssl)
739 return 0;
740
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200741 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200742 smp->flags |= SMP_F_MAY_CHANGE;
743 return 0;
744 }
745
746 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200747 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200748 else
749 crt = SSL_get_certificate(ssl);
750
751 if (!crt)
752 goto out;
753
754 smp_trash = get_trash_chunk();
755 if (ssl_sock_get_serial(crt, smp_trash) <= 0)
756 goto out;
757
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200758 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200759 smp->data.u.str = *smp_trash;
760 smp->data.type = SMP_T_BIN;
761 ret = 1;
762out:
763 /* SSL_get_peer_certificate, it increase X509 * ref count */
764 if (cert_peer && crt)
765 X509_free(crt);
766 return ret;
767}
768
769/* binary, returns the client certificate's SHA-1 fingerprint (SHA-1 hash of DER-encoded certificate) in a binary chunk.
770 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
771 * should be use.
772 */
773static int
774smp_fetch_ssl_x_sha1(const struct arg *args, struct sample *smp, const char *kw, void *private)
775{
William Lallemandbfa3e812020-06-25 20:07:18 +0200776 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
777 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200778 X509 *crt = NULL;
779 const EVP_MD *digest;
780 int ret = 0;
781 unsigned int len = 0;
782 struct buffer *smp_trash;
783 struct connection *conn;
784 SSL *ssl;
785
William Lallemandbfa3e812020-06-25 20:07:18 +0200786 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200787 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200788 else
789 conn = objt_conn(smp->sess->origin);
790
William Lallemand15e16942020-05-15 00:25:08 +0200791 ssl = ssl_sock_get_ssl_object(conn);
792 if (!ssl)
793 return 0;
794
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200795 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200796 smp->flags |= SMP_F_MAY_CHANGE;
797 return 0;
798 }
799
800 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200801 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200802 else
803 crt = SSL_get_certificate(ssl);
804 if (!crt)
805 goto out;
806
807 smp_trash = get_trash_chunk();
808 digest = EVP_sha1();
809 X509_digest(crt, digest, (unsigned char *) smp_trash->area, &len);
810 smp_trash->data = len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200811 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200812 smp->data.u.str = *smp_trash;
813 smp->data.type = SMP_T_BIN;
814 ret = 1;
815out:
816 /* SSL_get_peer_certificate, it increase X509 * ref count */
817 if (cert_peer && crt)
818 X509_free(crt);
819 return ret;
820}
821
822/* string, returns certificate's notafter date in ASN1_UTCTIME format.
823 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
824 * should be use.
825 */
826static int
827smp_fetch_ssl_x_notafter(const struct arg *args, struct sample *smp, const char *kw, void *private)
828{
William Lallemandbfa3e812020-06-25 20:07:18 +0200829 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
830 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200831 X509 *crt = NULL;
832 int ret = 0;
833 struct buffer *smp_trash;
834 struct connection *conn;
835 SSL *ssl;
836
William Lallemandbfa3e812020-06-25 20:07:18 +0200837 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200838 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200839 else
840 conn = objt_conn(smp->sess->origin);
841
William Lallemand15e16942020-05-15 00:25:08 +0200842 ssl = ssl_sock_get_ssl_object(conn);
843 if (!ssl)
844 return 0;
845
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200846 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200847 smp->flags |= SMP_F_MAY_CHANGE;
848 return 0;
849 }
850
851 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200852 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200853 else
854 crt = SSL_get_certificate(ssl);
855 if (!crt)
856 goto out;
857
858 smp_trash = get_trash_chunk();
859 if (ssl_sock_get_time(X509_getm_notAfter(crt), 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.u.str = *smp_trash;
864 smp->data.type = SMP_T_STR;
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 a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's issuer
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_i_dn(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 X509_NAME *name;
884 int ret = 0;
885 struct buffer *smp_trash;
886 struct connection *conn;
887 SSL *ssl;
888
William Lallemandbfa3e812020-06-25 20:07:18 +0200889 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200890 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200891 else
892 conn = objt_conn(smp->sess->origin);
893
William Lallemand15e16942020-05-15 00:25:08 +0200894 ssl = ssl_sock_get_ssl_object(conn);
895 if (!ssl)
896 return 0;
897
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200898 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200899 smp->flags |= SMP_F_MAY_CHANGE;
900 return 0;
901 }
902
903 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200904 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200905 else
906 crt = SSL_get_certificate(ssl);
907 if (!crt)
908 goto out;
909
910 name = X509_get_issuer_name(crt);
911 if (!name)
912 goto out;
913
914 smp_trash = get_trash_chunk();
Christopher Faulet3702f782021-01-29 11:30:37 +0100915 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200916 int pos = 1;
917
918 if (args[1].type == ARGT_SINT)
919 pos = args[1].data.sint;
920
921 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
922 goto out;
923 }
Christopher Faulet3702f782021-01-29 11:30:37 +0100924 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +0200925 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
926 goto out;
927 }
928 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
929 goto out;
930
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +0200931 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +0200932 smp->data.type = SMP_T_STR;
933 smp->data.u.str = *smp_trash;
934 ret = 1;
935out:
936 /* SSL_get_peer_certificate, it increase X509 * ref count */
937 if (cert_peer && crt)
938 X509_free(crt);
939 return ret;
940}
941
942/* string, returns notbefore date in ASN1_UTCTIME format.
943 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
944 * should be use.
945 */
946static int
947smp_fetch_ssl_x_notbefore(const struct arg *args, struct sample *smp, const char *kw, void *private)
948{
William Lallemandbfa3e812020-06-25 20:07:18 +0200949 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
950 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +0200951 X509 *crt = NULL;
952 int ret = 0;
953 struct buffer *smp_trash;
954 struct connection *conn;
955 SSL *ssl;
956
William Lallemandbfa3e812020-06-25 20:07:18 +0200957 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200958 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +0200959 else
960 conn = objt_conn(smp->sess->origin);
961
William Lallemand15e16942020-05-15 00:25:08 +0200962 ssl = ssl_sock_get_ssl_object(conn);
963 if (!ssl)
964 return 0;
965
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200966 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +0200967 smp->flags |= SMP_F_MAY_CHANGE;
968 return 0;
969 }
970
971 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +0200972 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +0200973 else
974 crt = SSL_get_certificate(ssl);
975 if (!crt)
976 goto out;
977
978 smp_trash = get_trash_chunk();
979 if (ssl_sock_get_time(X509_getm_notBefore(crt), 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.u.str = *smp_trash;
984 smp->data.type = SMP_T_STR;
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/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's subject
994 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
995 * should be use.
996 */
997static int
998smp_fetch_ssl_x_s_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
999{
William Lallemandbfa3e812020-06-25 20:07:18 +02001000 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1001 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +02001002 X509 *crt = NULL;
1003 X509_NAME *name;
1004 int ret = 0;
1005 struct buffer *smp_trash;
1006 struct connection *conn;
1007 SSL *ssl;
1008
William Lallemandbfa3e812020-06-25 20:07:18 +02001009 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001010 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001011 else
1012 conn = objt_conn(smp->sess->origin);
1013
William Lallemand15e16942020-05-15 00:25:08 +02001014 ssl = ssl_sock_get_ssl_object(conn);
1015 if (!ssl)
1016 return 0;
1017
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001018 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001019 smp->flags |= SMP_F_MAY_CHANGE;
1020 return 0;
1021 }
1022
1023 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001024 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001025 else
1026 crt = SSL_get_certificate(ssl);
1027 if (!crt)
1028 goto out;
1029
1030 name = X509_get_subject_name(crt);
1031 if (!name)
1032 goto out;
1033
1034 smp_trash = get_trash_chunk();
Christopher Faulet3702f782021-01-29 11:30:37 +01001035 if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +02001036 int pos = 1;
1037
1038 if (args[1].type == ARGT_SINT)
1039 pos = args[1].data.sint;
1040
1041 if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
1042 goto out;
1043 }
Christopher Faulet3702f782021-01-29 11:30:37 +01001044 else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
William Lallemand15e16942020-05-15 00:25:08 +02001045 if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
1046 goto out;
1047 }
1048 else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
1049 goto out;
1050
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001051 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001052 smp->data.type = SMP_T_STR;
1053 smp->data.u.str = *smp_trash;
1054 ret = 1;
1055out:
1056 /* SSL_get_peer_certificate, it increase X509 * ref count */
1057 if (cert_peer && crt)
1058 X509_free(crt);
1059 return ret;
1060}
1061
1062/* integer, returns true if current session use a client certificate */
1063static int
1064smp_fetch_ssl_c_used(const struct arg *args, struct sample *smp, const char *kw, void *private)
1065{
1066 X509 *crt;
1067 struct connection *conn;
1068 SSL *ssl;
1069
1070 conn = objt_conn(smp->sess->origin);
1071 ssl = ssl_sock_get_ssl_object(conn);
1072 if (!ssl)
1073 return 0;
1074
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001075 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001076 smp->flags |= SMP_F_MAY_CHANGE;
1077 return 0;
1078 }
1079
1080 /* SSL_get_peer_certificate returns a ptr on allocated X509 struct */
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001081 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001082 if (crt) {
1083 X509_free(crt);
1084 }
1085
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001086 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001087 smp->data.type = SMP_T_BOOL;
1088 smp->data.u.sint = (crt != NULL);
1089 return 1;
1090}
1091
1092/* integer, returns the certificate version
1093 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1094 * should be use.
1095 */
1096static int
1097smp_fetch_ssl_x_version(const struct arg *args, struct sample *smp, const char *kw, void *private)
1098{
William Lallemandbfa3e812020-06-25 20:07:18 +02001099 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1100 int conn_server = (kw[4] == 's') ? 1 : 0;
1101
William Lallemand15e16942020-05-15 00:25:08 +02001102 X509 *crt;
1103 struct connection *conn;
1104 SSL *ssl;
1105
William Lallemandbfa3e812020-06-25 20:07:18 +02001106 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001107 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001108 else
1109 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +02001110 ssl = ssl_sock_get_ssl_object(conn);
1111 if (!ssl)
1112 return 0;
1113
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001114 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001115 smp->flags |= SMP_F_MAY_CHANGE;
1116 return 0;
1117 }
1118
1119 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001120 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001121 else
1122 crt = SSL_get_certificate(ssl);
1123 if (!crt)
1124 return 0;
1125
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001126 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001127 smp->data.u.sint = (unsigned int)(1 + X509_get_version(crt));
1128 /* SSL_get_peer_certificate increase X509 * ref count */
1129 if (cert_peer)
1130 X509_free(crt);
1131 smp->data.type = SMP_T_SINT;
1132
1133 return 1;
1134}
1135
1136/* string, returns the certificate's signature algorithm.
1137 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1138 * should be use.
1139 */
1140static int
1141smp_fetch_ssl_x_sig_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
1142{
William Lallemandbfa3e812020-06-25 20:07:18 +02001143 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1144 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +02001145 X509 *crt;
1146 __OPENSSL_110_CONST__ ASN1_OBJECT *algorithm;
1147 int nid;
1148 struct connection *conn;
1149 SSL *ssl;
1150
William Lallemandbfa3e812020-06-25 20:07:18 +02001151 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001152 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001153 else
1154 conn = objt_conn(smp->sess->origin);
1155
William Lallemand15e16942020-05-15 00:25:08 +02001156 ssl = ssl_sock_get_ssl_object(conn);
1157 if (!ssl)
1158 return 0;
1159
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001160 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001161 smp->flags |= SMP_F_MAY_CHANGE;
1162 return 0;
1163 }
1164
1165 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001166 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001167 else
1168 crt = SSL_get_certificate(ssl);
1169 if (!crt)
1170 return 0;
1171
1172 X509_ALGOR_get0(&algorithm, NULL, NULL, X509_get0_tbs_sigalg(crt));
1173 nid = OBJ_obj2nid(algorithm);
1174
1175 smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
1176 if (!smp->data.u.str.area) {
1177 /* SSL_get_peer_certificate increase X509 * ref count */
1178 if (cert_peer)
1179 X509_free(crt);
1180 return 0;
1181 }
1182
1183 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001184 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001185 smp->data.u.str.data = strlen(smp->data.u.str.area);
1186 /* SSL_get_peer_certificate increase X509 * ref count */
1187 if (cert_peer)
1188 X509_free(crt);
1189
1190 return 1;
1191}
1192
1193/* string, returns the certificate's key algorithm.
1194 * The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
1195 * should be use.
1196 */
1197static int
1198smp_fetch_ssl_x_key_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
1199{
William Lallemandbfa3e812020-06-25 20:07:18 +02001200 int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
1201 int conn_server = (kw[4] == 's') ? 1 : 0;
William Lallemand15e16942020-05-15 00:25:08 +02001202 X509 *crt;
1203 ASN1_OBJECT *algorithm;
1204 int nid;
1205 struct connection *conn;
1206 SSL *ssl;
1207
William Lallemandbfa3e812020-06-25 20:07:18 +02001208 if (conn_server)
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001209 conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemandbfa3e812020-06-25 20:07:18 +02001210 else
1211 conn = objt_conn(smp->sess->origin);
William Lallemand15e16942020-05-15 00:25:08 +02001212 ssl = ssl_sock_get_ssl_object(conn);
1213 if (!ssl)
1214 return 0;
1215
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001216 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02001217 smp->flags |= SMP_F_MAY_CHANGE;
1218 return 0;
1219 }
1220
1221 if (cert_peer)
Remi Tricot-Le Breton74f6ab62021-08-19 18:06:30 +02001222 crt = ssl_sock_get_peer_certificate(ssl);
William Lallemand15e16942020-05-15 00:25:08 +02001223 else
1224 crt = SSL_get_certificate(ssl);
1225 if (!crt)
1226 return 0;
1227
1228 X509_PUBKEY_get0_param(&algorithm, NULL, NULL, NULL, X509_get_X509_PUBKEY(crt));
1229 nid = OBJ_obj2nid(algorithm);
1230
1231 smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
1232 if (!smp->data.u.str.area) {
1233 /* SSL_get_peer_certificate increase X509 * ref count */
1234 if (cert_peer)
1235 X509_free(crt);
1236 return 0;
1237 }
1238
1239 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001240 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001241 smp->data.u.str.data = strlen(smp->data.u.str.area);
1242 if (cert_peer)
1243 X509_free(crt);
1244
1245 return 1;
1246}
1247
1248/* boolean, returns true if front conn. transport layer is SSL.
1249 * This function is also usable on backend conn if the fetch keyword 5th
1250 * char is 'b'.
1251 */
1252static int
1253smp_fetch_ssl_fc(const struct arg *args, struct sample *smp, const char *kw, void *private)
1254{
1255 struct connection *conn;
1256
1257 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001258 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001259 else
1260 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001261 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001262
1263 smp->data.type = SMP_T_BOOL;
Willy Tarreau939b0bf2022-04-11 11:29:11 +02001264 smp->data.u.sint = conn_is_ssl(conn);
William Lallemand15e16942020-05-15 00:25:08 +02001265 return 1;
1266}
1267
1268/* boolean, returns true if client present a SNI */
1269static int
1270smp_fetch_ssl_fc_has_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
1271{
1272#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1273 struct connection *conn = objt_conn(smp->sess->origin);
1274 SSL *ssl = ssl_sock_get_ssl_object(conn);
1275
1276 smp->data.type = SMP_T_BOOL;
1277 smp->data.u.sint = ssl && SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name) != NULL;
1278 return 1;
1279#else
1280 return 0;
1281#endif
1282}
1283
1284/* boolean, returns true if client session has been resumed.
1285 * This function is also usable on backend conn if the fetch keyword 5th
1286 * char is 'b'.
1287 */
1288static int
1289smp_fetch_ssl_fc_is_resumed(const struct arg *args, struct sample *smp, const char *kw, void *private)
1290{
1291 struct connection *conn;
1292 SSL *ssl;
1293
1294 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001295 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001296 else
1297 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001298 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001299
1300 ssl = ssl_sock_get_ssl_object(conn);
1301
1302 smp->data.type = SMP_T_BOOL;
1303 smp->data.u.sint = ssl && SSL_session_reused(ssl);
1304 return 1;
1305}
1306
1307/* string, returns the used cipher if front conn. transport layer is SSL.
1308 * This function is also usable on backend conn if the fetch keyword 5th
1309 * char is 'b'.
1310 */
1311static int
1312smp_fetch_ssl_fc_cipher(const struct arg *args, struct sample *smp, const char *kw, void *private)
1313{
1314 struct connection *conn;
1315 SSL *ssl;
1316
1317 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001318 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001319 else
1320 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001321 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001322
1323 smp->flags = 0;
1324 ssl = ssl_sock_get_ssl_object(conn);
1325 if (!ssl)
1326 return 0;
1327
1328 smp->data.u.str.area = (char *)SSL_get_cipher_name(ssl);
1329 if (!smp->data.u.str.area)
1330 return 0;
1331
1332 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001333 smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001334 smp->data.u.str.data = strlen(smp->data.u.str.area);
1335
1336 return 1;
1337}
1338
1339/* integer, returns the algoritm's keysize if front conn. transport layer
1340 * is SSL.
1341 * This function is also usable on backend conn if the fetch keyword 5th
1342 * char is 'b'.
1343 */
1344static int
1345smp_fetch_ssl_fc_alg_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
1346{
1347 struct connection *conn;
1348 SSL *ssl;
1349 int sint;
1350
1351 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001352 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001353 else
1354 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001355 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001356
1357 smp->flags = 0;
1358 ssl = ssl_sock_get_ssl_object(conn);
1359 if (!ssl)
1360 return 0;
1361
1362 if (!SSL_get_cipher_bits(ssl, &sint))
1363 return 0;
1364
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001365 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001366 smp->data.u.sint = sint;
1367 smp->data.type = SMP_T_SINT;
1368
1369 return 1;
1370}
1371
1372/* integer, returns the used keysize if front conn. transport layer is SSL.
1373 * This function is also usable on backend conn if the fetch keyword 5th
1374 * char is 'b'.
1375 */
1376static int
1377smp_fetch_ssl_fc_use_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
1378{
1379 struct connection *conn;
1380 SSL *ssl;
1381
1382 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001383 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001384 else
1385 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001386 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001387
1388 smp->flags = 0;
1389 ssl = ssl_sock_get_ssl_object(conn);
1390 if (!ssl)
1391 return 0;
1392
1393 smp->data.u.sint = (unsigned int)SSL_get_cipher_bits(ssl, NULL);
1394 if (!smp->data.u.sint)
1395 return 0;
1396
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001397 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001398 smp->data.type = SMP_T_SINT;
1399
1400 return 1;
1401}
1402
1403#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
1404static int
1405smp_fetch_ssl_fc_npn(const struct arg *args, struct sample *smp, const char *kw, void *private)
1406{
1407 struct connection *conn;
1408 SSL *ssl;
1409 unsigned int len = 0;
1410
1411 smp->flags = SMP_F_CONST;
1412 smp->data.type = SMP_T_STR;
1413
1414 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001415 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001416 else
1417 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001418 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001419
1420 ssl = ssl_sock_get_ssl_object(conn);
1421 if (!ssl)
1422 return 0;
1423
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001424 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001425 smp->data.u.str.area = NULL;
1426 SSL_get0_next_proto_negotiated(ssl,
1427 (const unsigned char **)&smp->data.u.str.area,
1428 &len);
1429
1430 if (!smp->data.u.str.area)
1431 return 0;
1432
1433 smp->data.u.str.data = len;
1434 return 1;
1435}
1436#endif
1437
1438#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1439static int
1440smp_fetch_ssl_fc_alpn(const struct arg *args, struct sample *smp, const char *kw, void *private)
1441{
1442 struct connection *conn;
1443 SSL *ssl;
1444 unsigned int len = 0;
1445
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001446 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001447 smp->data.type = SMP_T_STR;
1448
1449 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001450 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001451 else
1452 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001453 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001454
1455 ssl = ssl_sock_get_ssl_object(conn);
1456 if (!ssl)
1457 return 0;
1458
1459 smp->data.u.str.area = NULL;
1460 SSL_get0_alpn_selected(ssl,
1461 (const unsigned char **)&smp->data.u.str.area,
1462 &len);
1463
1464 if (!smp->data.u.str.area)
1465 return 0;
1466
1467 smp->data.u.str.data = len;
1468 return 1;
1469}
1470#endif
1471
1472/* string, returns the used protocol if front conn. transport layer is SSL.
1473 * This function is also usable on backend conn if the fetch keyword 5th
1474 * char is 'b'.
1475 */
1476static int
1477smp_fetch_ssl_fc_protocol(const struct arg *args, struct sample *smp, const char *kw, void *private)
1478{
1479 struct connection *conn;
1480 SSL *ssl;
1481
1482 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001483 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001484 else
1485 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001486 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001487
1488 smp->flags = 0;
1489 ssl = ssl_sock_get_ssl_object(conn);
1490 if (!ssl)
1491 return 0;
1492
1493 smp->data.u.str.area = (char *)SSL_get_version(ssl);
1494 if (!smp->data.u.str.area)
1495 return 0;
1496
1497 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001498 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001499 smp->data.u.str.data = strlen(smp->data.u.str.area);
1500
1501 return 1;
1502}
1503
1504/* binary, returns the SSL stream id if front conn. transport layer is SSL.
1505 * This function is also usable on backend conn if the fetch keyword 5th
1506 * char is 'b'.
1507 */
1508#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
1509static int
1510smp_fetch_ssl_fc_session_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1511{
1512 struct connection *conn;
1513 SSL_SESSION *ssl_sess;
1514 SSL *ssl;
1515 unsigned int len = 0;
1516
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001517 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001518 smp->data.type = SMP_T_BIN;
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 smp->data.u.str.area = (char *)SSL_SESSION_get_id(ssl_sess, &len);
1535 if (!smp->data.u.str.area || !len)
1536 return 0;
1537
1538 smp->data.u.str.data = len;
1539 return 1;
1540}
1541#endif
1542
1543
Ilya Shipitsindf627942021-03-25 00:41:41 +05001544#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02001545static int
1546smp_fetch_ssl_fc_random(const struct arg *args, struct sample *smp, const char *kw, void *private)
1547{
1548 struct connection *conn;
1549 struct buffer *data;
1550 SSL *ssl;
1551
1552 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001553 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001554 else
1555 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001556 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001557
1558 ssl = ssl_sock_get_ssl_object(conn);
1559 if (!ssl)
1560 return 0;
1561
1562 data = get_trash_chunk();
1563 if (kw[7] == 'c')
1564 data->data = SSL_get_client_random(ssl,
1565 (unsigned char *) data->area,
1566 data->size);
1567 else
1568 data->data = SSL_get_server_random(ssl,
1569 (unsigned char *) data->area,
1570 data->size);
1571 if (!data->data)
1572 return 0;
1573
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001574 smp->flags = SMP_F_VOL_TEST;
William Lallemand15e16942020-05-15 00:25:08 +02001575 smp->data.type = SMP_T_BIN;
1576 smp->data.u.str = *data;
1577
1578 return 1;
1579}
1580
1581static int
1582smp_fetch_ssl_fc_session_key(const struct arg *args, struct sample *smp, const char *kw, void *private)
1583{
1584 struct connection *conn;
1585 SSL_SESSION *ssl_sess;
1586 struct buffer *data;
1587 SSL *ssl;
1588
1589 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001590 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001591 else
1592 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001593 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02001594
1595 ssl = ssl_sock_get_ssl_object(conn);
1596 if (!ssl)
1597 return 0;
1598
1599 ssl_sess = SSL_get_session(ssl);
1600 if (!ssl_sess)
1601 return 0;
1602
1603 data = get_trash_chunk();
1604 data->data = SSL_SESSION_get_master_key(ssl_sess,
1605 (unsigned char *) data->area,
1606 data->size);
1607 if (!data->data)
1608 return 0;
1609
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001610 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001611 smp->data.type = SMP_T_BIN;
1612 smp->data.u.str = *data;
1613
1614 return 1;
1615}
1616#endif
1617
William Lallemand15e16942020-05-15 00:25:08 +02001618static int
1619smp_fetch_ssl_fc_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
1620{
Willy Tarreau579259d2021-11-05 19:12:54 +01001621#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
William Lallemand15e16942020-05-15 00:25:08 +02001622 struct connection *conn;
1623 SSL *ssl;
1624
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001625 smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
William Lallemand15e16942020-05-15 00:25:08 +02001626 smp->data.type = SMP_T_STR;
1627
1628 conn = objt_conn(smp->sess->origin);
1629 ssl = ssl_sock_get_ssl_object(conn);
1630 if (!ssl)
1631 return 0;
1632
1633 smp->data.u.str.area = (char *)SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
Remi Tricot-Le Bretona9967632022-01-07 17:12:01 +01001634 if (!smp->data.u.str.area) {
1635 /* We might have stored the SNI ourselves, look for it in the
1636 * context's ex_data.
1637 */
1638 smp->data.u.str.area = SSL_get_ex_data(ssl, ssl_client_sni_index);
1639
1640 if (!smp->data.u.str.area)
1641 return 0;
1642 }
William Lallemand15e16942020-05-15 00:25:08 +02001643
1644 smp->data.u.str.data = strlen(smp->data.u.str.area);
Remi Tricot-Le Bretona9967632022-01-07 17:12:01 +01001645
William Lallemand15e16942020-05-15 00:25:08 +02001646 return 1;
Willy Tarreau579259d2021-11-05 19:12:54 +01001647#else
1648 /* SNI not supported */
1649 return 0;
William Lallemand15e16942020-05-15 00:25:08 +02001650#endif
Willy Tarreau579259d2021-11-05 19:12:54 +01001651}
William Lallemand15e16942020-05-15 00:25:08 +02001652
Marcin Deranek959a48c2021-07-13 15:14:21 +02001653/* binary, returns tls client hello cipher list.
1654 * Arguments: filter_option (0,1)
1655 */
William Lallemand15e16942020-05-15 00:25:08 +02001656static int
1657smp_fetch_ssl_fc_cl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1658{
Marcin Deranek959a48c2021-07-13 15:14:21 +02001659 struct buffer *smp_trash;
William Lallemand15e16942020-05-15 00:25:08 +02001660 struct connection *conn;
1661 struct ssl_capture *capture;
1662 SSL *ssl;
1663
1664 conn = objt_conn(smp->sess->origin);
1665 ssl = ssl_sock_get_ssl_object(conn);
1666 if (!ssl)
1667 return 0;
1668
1669 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1670 if (!capture)
1671 return 0;
1672
Marcin Deranek959a48c2021-07-13 15:14:21 +02001673 if (args[0].data.sint) {
1674 smp_trash = get_trash_chunk();
1675 exclude_tls_grease(capture->data + capture->ciphersuite_offset, capture->ciphersuite_len, smp_trash);
1676 smp->data.u.str.area = smp_trash->area;
1677 smp->data.u.str.data = smp_trash->data;
1678 smp->flags = SMP_F_VOL_SESS;
1679 }
1680 else {
1681 smp->data.u.str.area = capture->data + capture->ciphersuite_offset;
1682 smp->data.u.str.data = capture->ciphersuite_len;
1683 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1684 }
1685
William Lallemand15e16942020-05-15 00:25:08 +02001686 smp->data.type = SMP_T_BIN;
William Lallemand15e16942020-05-15 00:25:08 +02001687 return 1;
1688}
1689
Marcin Deranek959a48c2021-07-13 15:14:21 +02001690/* binary, returns tls client hello cipher list as hexadecimal string.
1691 * Arguments: filter_option (0,1)
1692 */
William Lallemand15e16942020-05-15 00:25:08 +02001693static int
1694smp_fetch_ssl_fc_cl_hex(const struct arg *args, struct sample *smp, const char *kw, void *private)
1695{
1696 struct buffer *data;
1697
1698 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1699 return 0;
1700
1701 data = get_trash_chunk();
1702 dump_binary(data, smp->data.u.str.area, smp->data.u.str.data);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001703 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001704 smp->data.type = SMP_T_BIN;
1705 smp->data.u.str = *data;
1706 return 1;
1707}
1708
Marcin Deranek959a48c2021-07-13 15:14:21 +02001709/* integer, returns xxh64 hash of tls client hello cipher list. */
William Lallemand15e16942020-05-15 00:25:08 +02001710static int
1711smp_fetch_ssl_fc_cl_xxh64(const struct arg *args, struct sample *smp, const char *kw, void *private)
1712{
1713 struct connection *conn;
1714 struct ssl_capture *capture;
1715 SSL *ssl;
1716
1717 conn = objt_conn(smp->sess->origin);
1718 ssl = ssl_sock_get_ssl_object(conn);
1719 if (!ssl)
1720 return 0;
1721
1722 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1723 if (!capture)
1724 return 0;
1725
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001726 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02001727 smp->data.type = SMP_T_SINT;
1728 smp->data.u.sint = capture->xxh64;
1729 return 1;
1730}
1731
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001732static int
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001733smp_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 +02001734{
1735 struct connection *conn;
1736 struct ssl_sock_ctx *ctx;
1737
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001738 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001739 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001740 else
1741 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001742 smp->strm ? sc_conn(smp->strm->scb) : NULL;
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001743
Willy Tarreauce7a5e02022-04-12 07:40:42 +02001744 if (!conn)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001745 return 0;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001746
1747 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1748 smp->flags = SMP_F_MAY_CHANGE;
1749 return 0;
1750 }
1751
Willy Tarreauce7a5e02022-04-12 07:40:42 +02001752 ctx = conn_get_ssl_sock_ctx(conn);
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001753 if (!ctx)
1754 return 0;
1755
1756 smp->flags = SMP_F_VOL_SESS;
1757 smp->data.type = SMP_T_SINT;
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001758 smp->data.u.sint = ctx->error_code;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001759 return 1;
1760}
1761
1762static int
Marcin Deranek959a48c2021-07-13 15:14:21 +02001763smp_fetch_ssl_fc_protocol_hello_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
1764{
1765 struct connection *conn;
1766 struct ssl_capture *capture;
1767 SSL *ssl;
1768
1769 conn = objt_conn(smp->sess->origin);
1770 ssl = ssl_sock_get_ssl_object(conn);
1771 if (!ssl)
1772 return 0;
1773
1774 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1775 if (!capture)
1776 return 0;
1777
1778 smp->flags = SMP_F_VOL_SESS;
1779 smp->data.type = SMP_T_SINT;
1780 smp->data.u.sint = capture->protocol_version;
1781 return 1;
1782}
1783
1784static int
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001785smp_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 +02001786{
1787 struct connection *conn;
1788 struct ssl_sock_ctx *ctx;
1789 const char *err_code_str;
1790
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001791 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02001792 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001793 else
1794 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001795 smp->strm ? sc_conn(smp->strm->scb) : NULL;
Remi Tricot-Le Breton163cdeb2021-09-01 15:52:14 +02001796
Willy Tarreauce7a5e02022-04-12 07:40:42 +02001797 if (!conn)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001798 return 0;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001799
1800 if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
1801 smp->flags = SMP_F_MAY_CHANGE;
1802 return 0;
1803 }
1804
Willy Tarreauce7a5e02022-04-12 07:40:42 +02001805 ctx = conn_get_ssl_sock_ctx(conn);
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001806 if (!ctx || !ctx->error_code)
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001807 return 0;
1808
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02001809 err_code_str = ERR_error_string(ctx->error_code, NULL);
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001810
1811 smp->flags = SMP_F_VOL_SESS;
1812 smp->data.type = SMP_T_STR;
1813 smp->data.u.str.area = (char*)err_code_str;
1814 smp->data.u.str.data = strlen(err_code_str);
1815
Marcin Deranek959a48c2021-07-13 15:14:21 +02001816 return 1;
1817}
1818
1819/* binary, returns tls client hello extensions list.
1820 * Arguments: filter_option (0,1)
1821 */
1822static int
1823smp_fetch_ssl_fc_ext_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1824{
1825 struct buffer *smp_trash;
1826 struct connection *conn;
1827 struct ssl_capture *capture;
1828 SSL *ssl;
1829
1830 conn = objt_conn(smp->sess->origin);
1831 ssl = ssl_sock_get_ssl_object(conn);
1832 if (!ssl)
1833 return 0;
1834
1835 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1836 if (!capture)
1837 return 0;
1838
1839 if (args[0].data.sint) {
1840 smp_trash = get_trash_chunk();
1841 exclude_tls_grease(capture->data + capture->extensions_offset, capture->extensions_len, smp_trash);
1842 smp->data.u.str.area = smp_trash->area;
1843 smp->data.u.str.data = smp_trash->data;
1844 smp->flags = SMP_F_VOL_SESS;
1845 }
1846 else {
1847 smp->data.u.str.area = capture->data + capture->extensions_offset;
1848 smp->data.u.str.data = capture->extensions_len;
1849 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1850 }
1851
1852 smp->data.type = SMP_T_BIN;
1853 return 1;
1854}
1855
1856/* binary, returns tls client hello supported elliptic curves.
1857 * Arguments: filter_option (0,1)
1858 */
1859static int
1860smp_fetch_ssl_fc_ecl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1861{
1862 struct buffer *smp_trash;
1863 struct connection *conn;
1864 struct ssl_capture *capture;
1865 SSL *ssl;
1866
1867 conn = objt_conn(smp->sess->origin);
1868 ssl = ssl_sock_get_ssl_object(conn);
1869 if (!ssl)
1870 return 0;
1871
1872 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1873 if (!capture)
1874 return 0;
1875
1876 if (args[0].data.sint) {
1877 smp_trash = get_trash_chunk();
1878 exclude_tls_grease(capture->data + capture->ec_offset, capture->ec_len, smp_trash);
1879 smp->data.u.str.area = smp_trash->area;
1880 smp->data.u.str.data = smp_trash->data;
1881 smp->flags = SMP_F_VOL_SESS;
1882 }
1883 else {
1884 smp->data.u.str.area = capture->data + capture->ec_offset;
1885 smp->data.u.str.data = capture->ec_len;
1886 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1887 }
1888
1889 smp->data.type = SMP_T_BIN;
1890 return 1;
1891}
1892
1893/* binary, returns tls client hello supported elliptic curve point formats */
1894static int
1895smp_fetch_ssl_fc_ecf_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
1896{
1897 struct connection *conn;
1898 struct ssl_capture *capture;
1899 SSL *ssl;
1900
1901 conn = objt_conn(smp->sess->origin);
1902 ssl = ssl_sock_get_ssl_object(conn);
1903 if (!ssl)
1904 return 0;
1905
1906 capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
1907 if (!capture)
1908 return 0;
1909
1910 smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
1911 smp->data.type = SMP_T_BIN;
1912 smp->data.u.str.area = capture->data + capture->ec_formats_offset;
1913 smp->data.u.str.data = capture->ec_formats_len;
Remi Tricot-Le Breton7c6898e2021-07-29 09:45:51 +02001914 return 1;
1915}
1916
William Lallemand7d42ef52020-07-06 11:41:30 +02001917/* Dump the SSL keylog, it only works with "tune.ssl.keylog 1" */
William Lallemand722180a2021-06-09 16:46:12 +02001918#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02001919static int smp_fetch_ssl_x_keylog(const struct arg *args, struct sample *smp, const char *kw, void *private)
1920{
1921 struct connection *conn;
1922 struct ssl_keylog *keylog;
1923 SSL *ssl;
1924 char *src = NULL;
1925 const char *sfx;
1926
William Lallemandb60a77b2022-11-18 15:00:15 +01001927 if (global_ssl.keylog <= 0)
1928 return 0;
1929
William Lallemand7d42ef52020-07-06 11:41:30 +02001930 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02001931 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand7d42ef52020-07-06 11:41:30 +02001932
William Lallemandeec1d452020-07-07 10:48:13 +02001933 if (!conn)
1934 return 0;
1935
William Lallemand7d42ef52020-07-06 11:41:30 +02001936 if (conn->flags & CO_FL_WAIT_XPRT) {
1937 smp->flags |= SMP_F_MAY_CHANGE;
1938 return 0;
1939 }
1940
1941 ssl = ssl_sock_get_ssl_object(conn);
1942 if (!ssl)
1943 return 0;
1944
1945 keylog = SSL_get_ex_data(ssl, ssl_keylog_index);
1946 if (!keylog)
1947 return 0;
1948
1949 sfx = kw + strlen("ssl_xx_");
1950
1951 if (strcmp(sfx, "client_early_traffic_secret") == 0) {
1952 src = keylog->client_early_traffic_secret;
1953 } else if (strcmp(sfx, "client_handshake_traffic_secret") == 0) {
1954 src = keylog->client_handshake_traffic_secret;
1955 } else if (strcmp(sfx, "server_handshake_traffic_secret") == 0) {
1956 src = keylog->server_handshake_traffic_secret;
1957 } else if (strcmp(sfx, "client_traffic_secret_0") == 0) {
1958 src = keylog->client_traffic_secret_0;
1959 } else if (strcmp(sfx, "server_traffic_secret_0") == 0) {
1960 src = keylog->server_traffic_secret_0;
1961 } else if (strcmp(sfx, "exporter_secret") == 0) {
1962 src = keylog->exporter_secret;
1963 } else if (strcmp(sfx, "early_exporter_secret") == 0) {
1964 src = keylog->early_exporter_secret;
1965 }
1966
1967 if (!src || !*src)
1968 return 0;
1969
1970 smp->data.u.str.area = src;
1971 smp->data.type = SMP_T_STR;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02001972 smp->flags |= SMP_F_VOL_TEST | SMP_F_CONST;
William Lallemand7d42ef52020-07-06 11:41:30 +02001973 smp->data.u.str.data = strlen(smp->data.u.str.area);
1974 return 1;
William Lallemand7d42ef52020-07-06 11:41:30 +02001975}
1976#endif
1977
William Lallemand15e16942020-05-15 00:25:08 +02001978static int
1979smp_fetch_ssl_fc_cl_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
1980{
Ilya Shipitsinc9dfee42020-10-31 02:10:02 +05001981#if defined(OPENSSL_IS_BORINGSSL) || defined(SSL_CTRL_GET_RAW_CIPHERLIST)
William Lallemand15e16942020-05-15 00:25:08 +02001982 struct buffer *data;
1983 int i;
1984
1985 if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
1986 return 0;
1987
1988 data = get_trash_chunk();
1989 for (i = 0; i + 1 < smp->data.u.str.data; i += 2) {
1990 const char *str;
1991 const SSL_CIPHER *cipher;
1992 const unsigned char *bin = (const unsigned char *) smp->data.u.str.area + i;
1993 uint16_t id = (bin[0] << 8) | bin[1];
1994#if defined(OPENSSL_IS_BORINGSSL)
1995 cipher = SSL_get_cipher_by_value(id);
1996#else
1997 struct connection *conn = __objt_conn(smp->sess->origin);
1998 SSL *ssl = ssl_sock_get_ssl_object(conn);
1999 cipher = SSL_CIPHER_find(ssl, bin);
2000#endif
2001 str = SSL_CIPHER_get_name(cipher);
2002 if (!str || strcmp(str, "(NONE)") == 0)
2003 chunk_appendf(data, "%sUNKNOWN(%04x)", i == 0 ? "" : ",", id);
2004 else
2005 chunk_appendf(data, "%s%s", i == 0 ? "" : ",", str);
2006 }
2007 smp->data.type = SMP_T_STR;
2008 smp->data.u.str = *data;
2009 return 1;
2010#else
2011 return smp_fetch_ssl_fc_cl_xxh64(args, smp, kw, private);
2012#endif
2013}
2014
2015#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2016static int
2017smp_fetch_ssl_fc_unique_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
2018{
2019 struct connection *conn;
2020 int finished_len;
2021 struct buffer *finished_trash;
2022 SSL *ssl;
2023
2024 if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +02002025 conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02002026 else
2027 conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
Willy Tarreaufd9417b2022-05-18 16:23:22 +02002028 smp->strm ? sc_conn(smp->strm->scb) : NULL;
William Lallemand15e16942020-05-15 00:25:08 +02002029
2030 smp->flags = 0;
2031 ssl = ssl_sock_get_ssl_object(conn);
2032 if (!ssl)
2033 return 0;
2034
2035 if (conn->flags & CO_FL_WAIT_XPRT) {
2036 smp->flags |= SMP_F_MAY_CHANGE;
2037 return 0;
2038 }
2039
2040 finished_trash = get_trash_chunk();
2041 if (!SSL_session_reused(ssl))
2042 finished_len = SSL_get_peer_finished(ssl,
2043 finished_trash->area,
2044 finished_trash->size);
2045 else
2046 finished_len = SSL_get_finished(ssl,
2047 finished_trash->area,
2048 finished_trash->size);
2049
2050 if (!finished_len)
2051 return 0;
2052
2053 finished_trash->data = finished_len;
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002054 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002055 smp->data.u.str = *finished_trash;
2056 smp->data.type = SMP_T_BIN;
2057
2058 return 1;
2059}
2060#endif
2061
2062/* integer, returns the first verify error in CA chain of client certificate chain. */
2063static int
2064smp_fetch_ssl_c_ca_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
2065{
Willy Tarreau939b0bf2022-04-11 11:29:11 +02002066 struct connection *conn = objt_conn(smp->sess->origin);
2067 struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
William Lallemand15e16942020-05-15 00:25:08 +02002068
Willy Tarreau939b0bf2022-04-11 11:29:11 +02002069 if (conn && conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02002070 smp->flags = SMP_F_MAY_CHANGE;
2071 return 0;
2072 }
2073
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002074 if (!ctx)
2075 return 0;
2076
William Lallemand15e16942020-05-15 00:25:08 +02002077 smp->data.type = SMP_T_SINT;
2078 smp->data.u.sint = (unsigned long long int)SSL_SOCK_ST_TO_CA_ERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002079 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002080
2081 return 1;
2082}
2083
2084/* integer, returns the depth of the first verify error in CA chain of client certificate chain. */
2085static int
2086smp_fetch_ssl_c_ca_err_depth(const struct arg *args, struct sample *smp, const char *kw, void *private)
2087{
Willy Tarreau939b0bf2022-04-11 11:29:11 +02002088 struct connection *conn = objt_conn(smp->sess->origin);
2089 struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
William Lallemand15e16942020-05-15 00:25:08 +02002090
Willy Tarreau939b0bf2022-04-11 11:29:11 +02002091 if (conn && conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02002092 smp->flags = SMP_F_MAY_CHANGE;
2093 return 0;
2094 }
William Lallemand15e16942020-05-15 00:25:08 +02002095
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002096 if (!ctx)
2097 return 0;
2098
William Lallemand15e16942020-05-15 00:25:08 +02002099 smp->data.type = SMP_T_SINT;
2100 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CAEDEPTH(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002101 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002102
2103 return 1;
2104}
2105
2106/* integer, returns the first verify error on client certificate */
2107static int
2108smp_fetch_ssl_c_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
2109{
Willy Tarreau939b0bf2022-04-11 11:29:11 +02002110 struct connection *conn = objt_conn(smp->sess->origin);
2111 struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
William Lallemand15e16942020-05-15 00:25:08 +02002112
Willy Tarreau939b0bf2022-04-11 11:29:11 +02002113 if (conn && conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
William Lallemand15e16942020-05-15 00:25:08 +02002114 smp->flags = SMP_F_MAY_CHANGE;
2115 return 0;
2116 }
2117
Remi Tricot-Le Breton89b65cf2021-07-29 09:45:50 +02002118 if (!ctx)
2119 return 0;
2120
William Lallemand15e16942020-05-15 00:25:08 +02002121 smp->data.type = SMP_T_SINT;
2122 smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CRTERROR(ctx->xprt_st);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002123 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002124
2125 return 1;
2126}
2127
2128/* integer, returns the verify result on client cert */
2129static int
2130smp_fetch_ssl_c_verify(const struct arg *args, struct sample *smp, const char *kw, void *private)
2131{
2132 struct connection *conn;
2133 SSL *ssl;
2134
2135 conn = objt_conn(smp->sess->origin);
2136 ssl = ssl_sock_get_ssl_object(conn);
2137 if (!ssl)
2138 return 0;
2139
2140 if (conn->flags & CO_FL_WAIT_XPRT) {
2141 smp->flags = SMP_F_MAY_CHANGE;
2142 return 0;
2143 }
2144
2145 smp->data.type = SMP_T_SINT;
2146 smp->data.u.sint = (long long int)SSL_get_verify_result(ssl);
Amaury Denoyelle2f0a7972020-10-15 16:41:08 +02002147 smp->flags = SMP_F_VOL_SESS;
William Lallemand15e16942020-05-15 00:25:08 +02002148
2149 return 1;
2150}
2151
2152/* Argument validation functions */
2153
2154/* This function is used to validate the arguments passed to any "x_dn" ssl
2155 * keywords. These keywords support specifying a third parameter that must be
2156 * either empty or the value "rfc2253". Returns 0 on error, non-zero if OK.
2157 */
2158int val_dnfmt(struct arg *arg, char **err_msg)
2159{
2160 if (arg && arg[2].type == ARGT_STR && arg[2].data.str.data > 0 && (strcmp(arg[2].data.str.area, "rfc2253") != 0)) {
2161 memprintf(err_msg, "only rfc2253 or a blank value are currently supported as the format argument.");
2162 return 0;
2163 }
2164 return 1;
2165}
2166
2167/* Note: must not be declared <const> as its list will be overwritten.
2168 * Please take care of keeping this list alphabetically sorted.
2169 */
2170static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
2171 { "ssl_bc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
2172 { "ssl_bc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2173#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2174 { "ssl_bc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2175#endif
2176 { "ssl_bc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2177#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2178 { "ssl_bc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2179#endif
2180 { "ssl_bc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
2181 { "ssl_bc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
2182 { "ssl_bc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2183 { "ssl_bc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2184#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2185 { "ssl_bc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2186#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05002187#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02002188 { "ssl_bc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2189 { "ssl_bc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2190 { "ssl_bc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
2191#endif
Remi Tricot-Le Breton1fe0fad2021-09-29 18:56:52 +02002192 { "ssl_bc_err", smp_fetch_ssl_fc_err, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
2193 { "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 +02002194 { "ssl_c_ca_err", smp_fetch_ssl_c_ca_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2195 { "ssl_c_ca_err_depth", smp_fetch_ssl_c_ca_err_depth, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2196 { "ssl_c_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02002197 { "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 +02002198 { "ssl_c_err", smp_fetch_ssl_c_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2199 { "ssl_c_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2200 { "ssl_c_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2201 { "ssl_c_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2202 { "ssl_c_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
William Lallemand6e0c39d2023-05-15 12:05:55 +02002203#ifdef HAVE_SSL_get0_verified_chain
Abhijeet Rastogidf97f472023-05-13 20:04:45 -07002204 { "ssl_c_r_dn", smp_fetch_ssl_r_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
William Lallemand6e0c39d2023-05-15 12:05:55 +02002205#endif
William Lallemand15e16942020-05-15 00:25:08 +02002206 { "ssl_c_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2207 { "ssl_c_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2208 { "ssl_c_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2209 { "ssl_c_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2210 { "ssl_c_used", smp_fetch_ssl_c_used, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2211 { "ssl_c_verify", smp_fetch_ssl_c_verify, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2212 { "ssl_c_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2213 { "ssl_f_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2214 { "ssl_f_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2215 { "ssl_f_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2216 { "ssl_f_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2217 { "ssl_f_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2218 { "ssl_f_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2219 { "ssl_f_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2220 { "ssl_f_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2221 { "ssl_f_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2222 { "ssl_f_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2223 { "ssl_fc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2224 { "ssl_fc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2225 { "ssl_fc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2226 { "ssl_fc_has_crt", smp_fetch_ssl_fc_has_crt, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2227 { "ssl_fc_has_early", smp_fetch_ssl_fc_has_early, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2228 { "ssl_fc_has_sni", smp_fetch_ssl_fc_has_sni, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2229 { "ssl_fc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
2230#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2231 { "ssl_fc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2232#endif
2233#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2234 { "ssl_fc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2235#endif
2236 { "ssl_fc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2237#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2238 { "ssl_fc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2239#endif
2240 { "ssl_fc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2241#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
2242 { "ssl_fc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2243#endif
Ilya Shipitsindf627942021-03-25 00:41:41 +05002244#ifdef HAVE_SSL_EXTRACT_RANDOM
William Lallemand15e16942020-05-15 00:25:08 +02002245 { "ssl_fc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2246 { "ssl_fc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2247 { "ssl_fc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2248#endif
William Lallemand7d42ef52020-07-06 11:41:30 +02002249
William Lallemand722180a2021-06-09 16:46:12 +02002250#ifdef HAVE_SSL_KEYLOG
William Lallemand7d42ef52020-07-06 11:41:30 +02002251 { "ssl_fc_client_early_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2252 { "ssl_fc_client_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2253 { "ssl_fc_server_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2254 { "ssl_fc_client_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2255 { "ssl_fc_server_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2256 { "ssl_fc_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2257 { "ssl_fc_early_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2258#endif
2259
William Lallemand15e16942020-05-15 00:25:08 +02002260 { "ssl_fc_sni", smp_fetch_ssl_fc_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
Marcin Deranek959a48c2021-07-13 15:14:21 +02002261 { "ssl_fc_cipherlist_bin", smp_fetch_ssl_fc_cl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2262 { "ssl_fc_cipherlist_hex", smp_fetch_ssl_fc_cl_hex, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_USE_L5CLI },
2263 { "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 +02002264 { "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 +02002265 { "ssl_fc_err", smp_fetch_ssl_fc_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2266 { "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 +02002267 { "ssl_fc_protocol_hello_id",smp_fetch_ssl_fc_protocol_hello_id,0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
2268 { "ssl_fc_extlist_bin", smp_fetch_ssl_fc_ext_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2269 { "ssl_fc_eclist_bin", smp_fetch_ssl_fc_ecl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
2270 { "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 +02002271
2272/* SSL server certificate fetches */
2273 { "ssl_s_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
William Dauchya598b502020-08-06 18:11:38 +02002274 { "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 +02002275 { "ssl_s_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2276 { "ssl_s_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2277 { "ssl_s_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2278 { "ssl_s_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
2279 { "ssl_s_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2280 { "ssl_s_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
2281 { "ssl_s_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2282 { "ssl_s_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
2283 { "ssl_s_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
William Lallemand15e16942020-05-15 00:25:08 +02002284 { NULL, NULL, 0, 0, 0 },
2285}};
2286
2287INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
2288
Willy Tarreau99ea1882021-10-06 15:37:17 +02002289/* Note: must not be declared <const> as its list will be overwritten */
2290static struct sample_conv_kw_list sample_conv_kws = {ILH, {
2291 { "sha2", sample_conv_sha2, ARG1(0, SINT), smp_check_sha2, SMP_T_BIN, SMP_T_BIN },
2292#ifdef EVP_CIPH_GCM_MODE
2293 { "aes_gcm_dec", sample_conv_aes_gcm_dec, ARG4(4,SINT,STR,STR,STR), check_aes_gcm, SMP_T_BIN, SMP_T_BIN },
2294#endif
William Lallemand9fbc84e2022-11-03 18:56:37 +01002295 { "x509_v_err_str", sample_conv_x509_v_err, 0, NULL, SMP_T_SINT, SMP_T_STR },
Willy Tarreau99ea1882021-10-06 15:37:17 +02002296 { "digest", sample_conv_crypto_digest, ARG1(1,STR), check_crypto_digest, SMP_T_BIN, SMP_T_BIN },
2297 { "hmac", sample_conv_crypto_hmac, ARG2(2,STR,STR), check_crypto_hmac, SMP_T_BIN, SMP_T_BIN },
2298#if defined(HAVE_CRYPTO_memcmp)
2299 { "secure_memcmp", sample_conv_secure_memcmp, ARG1(1,STR), smp_check_secure_memcmp, SMP_T_BIN, SMP_T_BOOL },
2300#endif
2301 { NULL, NULL, 0, 0, 0 },
2302}};
2303
2304INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
2305
2306
William Lallemand15e16942020-05-15 00:25:08 +02002307/* Note: must not be declared <const> as its list will be overwritten.
2308 * Please take care of keeping this list alphabetically sorted.
2309 */
2310static struct acl_kw_list acl_kws = {ILH, {
2311 { "ssl_fc_sni_end", "ssl_fc_sni", PAT_MATCH_END },
2312 { "ssl_fc_sni_reg", "ssl_fc_sni", PAT_MATCH_REG },
2313 { /* END */ },
2314}};
2315
2316INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);