2020-05-14 18:25:08 -04:00
|
|
|
/*
|
|
|
|
|
* This file contains the sample fetches related to the SSL
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2012 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
|
|
|
|
|
* Copyright (C) 2020 HAProxy Technologies, William Lallemand <wlallemand@haproxy.com>
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
|
* 2 of the License, or (at your option) any later version.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <dirent.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
2020-06-04 13:11:43 -04:00
|
|
|
#include <haproxy/acl.h>
|
2020-05-27 06:58:42 -04:00
|
|
|
#include <haproxy/api.h>
|
2020-06-09 03:07:15 -04:00
|
|
|
#include <haproxy/arg.h>
|
2021-10-06 09:37:17 -04:00
|
|
|
#include <haproxy/base64.h>
|
2020-06-02 05:28:02 -04:00
|
|
|
#include <haproxy/buf-t.h>
|
2022-04-11 05:29:11 -04:00
|
|
|
#include <haproxy/connection.h>
|
2020-06-04 05:29:21 -04:00
|
|
|
#include <haproxy/obj_type.h>
|
2020-05-27 10:26:00 -04:00
|
|
|
#include <haproxy/openssl-compat.h>
|
2020-06-04 09:33:47 -04:00
|
|
|
#include <haproxy/sample.h>
|
2020-06-04 14:30:20 -04:00
|
|
|
#include <haproxy/ssl_sock.h>
|
2020-06-04 08:21:22 -04:00
|
|
|
#include <haproxy/ssl_utils.h>
|
2022-05-27 03:47:12 -04:00
|
|
|
#include <haproxy/stconn.h>
|
2020-06-03 12:09:46 -04:00
|
|
|
#include <haproxy/tools.h>
|
2021-10-06 09:37:17 -04:00
|
|
|
#include <haproxy/vars.h>
|
2025-09-26 17:17:13 -04:00
|
|
|
#ifdef USE_ECH
|
|
|
|
|
#include <haproxy/ech.h>
|
|
|
|
|
#endif
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/***** Below are some sample fetching functions for ACL/patterns *****/
|
|
|
|
|
|
2021-10-06 09:37:17 -04:00
|
|
|
#if defined(HAVE_CRYPTO_memcmp)
|
|
|
|
|
/* Compares bytestring with a variable containing a bytestring. Return value
|
|
|
|
|
* is `true` if both bytestrings are bytewise identical and `false` otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Comparison will be performed in constant time if both bytestrings are of
|
|
|
|
|
* the same length. If the lengths differ execution time will not be constant.
|
|
|
|
|
*/
|
|
|
|
|
static int sample_conv_secure_memcmp(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct sample tmp;
|
|
|
|
|
int result;
|
|
|
|
|
|
|
|
|
|
smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
|
|
|
|
|
if (arg_p[0].type != ARGT_VAR)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (!sample_conv_var2smp(&arg_p[0].data.var, &tmp, SMP_T_BIN))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (smp->data.u.str.data != tmp.data.u.str.data) {
|
|
|
|
|
smp->data.u.sint = 0;
|
|
|
|
|
smp->data.type = SMP_T_BOOL;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The following comparison is performed in constant time. */
|
|
|
|
|
result = CRYPTO_memcmp(smp->data.u.str.area, tmp.data.u.str.area, smp->data.u.str.data);
|
|
|
|
|
|
|
|
|
|
smp->data.u.sint = result == 0;
|
|
|
|
|
smp->data.type = SMP_T_BOOL;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This function checks the "secure_memcmp" converter's arguments and extracts the
|
|
|
|
|
* variable name and its scope.
|
|
|
|
|
*/
|
|
|
|
|
static int smp_check_secure_memcmp(struct arg *args, struct sample_conv *conv,
|
|
|
|
|
const char *file, int line, char **err)
|
|
|
|
|
{
|
|
|
|
|
if (!args[0].data.str.data) {
|
|
|
|
|
memprintf(err, "missing variable name");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Try to decode a variable. */
|
|
|
|
|
if (vars_check_arg(&args[0], NULL))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
memprintf(err, "failed to register variable name '%s'",
|
|
|
|
|
args[0].data.str.area);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#endif // HAVE_secure_memcmp()
|
|
|
|
|
|
|
|
|
|
static int smp_check_sha2(struct arg *args, struct sample_conv *conv,
|
|
|
|
|
const char *file, int line, char **err)
|
|
|
|
|
{
|
|
|
|
|
if (args[0].type == ARGT_STOP)
|
|
|
|
|
return 1;
|
|
|
|
|
if (args[0].type != ARGT_SINT) {
|
|
|
|
|
memprintf(err, "Invalid type '%s'", arg_type_names[args[0].type]);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (args[0].data.sint) {
|
|
|
|
|
case 224:
|
|
|
|
|
case 256:
|
|
|
|
|
case 384:
|
|
|
|
|
case 512:
|
|
|
|
|
/* this is okay */
|
|
|
|
|
return 1;
|
|
|
|
|
default:
|
|
|
|
|
memprintf(err, "Unsupported number of bits: '%lld'", args[0].data.sint);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int sample_conv_sha2(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct buffer *trash = get_trash_chunk();
|
|
|
|
|
int bits = 256;
|
2022-02-08 11:45:53 -05:00
|
|
|
EVP_MD_CTX *mdctx;
|
|
|
|
|
const EVP_MD *evp = NULL;
|
|
|
|
|
unsigned int digest_length = 0;
|
2021-10-06 09:37:17 -04:00
|
|
|
if (arg_p->data.sint)
|
|
|
|
|
bits = arg_p->data.sint;
|
|
|
|
|
|
|
|
|
|
switch (bits) {
|
2022-02-08 11:45:53 -05:00
|
|
|
case 224:
|
|
|
|
|
evp = EVP_sha224();
|
2021-10-06 09:37:17 -04:00
|
|
|
break;
|
2022-02-08 11:45:53 -05:00
|
|
|
case 256:
|
|
|
|
|
evp = EVP_sha256();
|
2021-10-06 09:37:17 -04:00
|
|
|
break;
|
2022-02-08 11:45:53 -05:00
|
|
|
case 384:
|
|
|
|
|
evp = EVP_sha384();
|
2021-10-06 09:37:17 -04:00
|
|
|
break;
|
2022-02-08 11:45:53 -05:00
|
|
|
case 512:
|
|
|
|
|
evp = EVP_sha512();
|
2021-10-06 09:37:17 -04:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-08 11:45:53 -05:00
|
|
|
mdctx = EVP_MD_CTX_new();
|
|
|
|
|
if (!mdctx)
|
|
|
|
|
return 0;
|
2026-03-06 02:59:01 -05:00
|
|
|
|
|
|
|
|
if (!EVP_DigestInit_ex(mdctx, evp, NULL) ||
|
|
|
|
|
!EVP_DigestUpdate(mdctx, smp->data.u.str.area, smp->data.u.str.data) ||
|
|
|
|
|
!EVP_DigestFinal_ex(mdctx, (unsigned char*)trash->area, &digest_length)) {
|
|
|
|
|
EVP_MD_CTX_free(mdctx);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-08 11:45:53 -05:00
|
|
|
trash->data = digest_length;
|
|
|
|
|
|
|
|
|
|
EVP_MD_CTX_free(mdctx);
|
|
|
|
|
|
2021-10-06 09:37:17 -04:00
|
|
|
smp->data.u.str = *trash;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
smp->flags &= ~SMP_F_CONST;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This function checks an <arg> and fills it with a variable type if the
|
|
|
|
|
* <arg> string contains a valid variable name. If failed, the function
|
|
|
|
|
* tries to perform a base64 decode operation on the same string, and
|
|
|
|
|
* fills the <arg> with the decoded content.
|
|
|
|
|
*
|
|
|
|
|
* Validation is skipped if the <arg> string is empty.
|
|
|
|
|
*
|
|
|
|
|
* This function returns 0 if the variable lookup fails and the specified
|
|
|
|
|
* <arg> string is not a valid base64 encoded string, as well if
|
|
|
|
|
* unexpected argument type is specified or memory allocation error
|
|
|
|
|
* occurs. Otherwise it returns 1.
|
|
|
|
|
*/
|
2026-01-13 05:50:56 -05:00
|
|
|
int sample_check_arg_base64(struct arg *arg, char **err)
|
2021-10-06 09:37:17 -04:00
|
|
|
{
|
|
|
|
|
char *dec = NULL;
|
|
|
|
|
int dec_size;
|
|
|
|
|
|
|
|
|
|
if (arg->type != ARGT_STR) {
|
|
|
|
|
memprintf(err, "unexpected argument type");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arg->data.str.data == 0) /* empty */
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (vars_check_arg(arg, NULL))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (arg->data.str.data % 4) {
|
|
|
|
|
memprintf(err, "argument needs to be base64 encoded, and "
|
|
|
|
|
"can either be a string or a variable");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dec_size = (arg->data.str.data / 4 * 3)
|
|
|
|
|
- (arg->data.str.area[arg->data.str.data-1] == '=' ? 1 : 0)
|
|
|
|
|
- (arg->data.str.area[arg->data.str.data-2] == '=' ? 1 : 0);
|
|
|
|
|
|
|
|
|
|
if ((dec = malloc(dec_size)) == NULL) {
|
|
|
|
|
memprintf(err, "memory allocation error");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dec_size = base64dec(arg->data.str.area, arg->data.str.data, dec, dec_size);
|
|
|
|
|
if (dec_size < 0) {
|
|
|
|
|
memprintf(err, "argument needs to be base64 encoded, and "
|
|
|
|
|
"can either be a string or a variable");
|
|
|
|
|
free(dec);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* base64 decoded */
|
|
|
|
|
chunk_destroy(&arg->data.str);
|
|
|
|
|
arg->data.str.area = dec;
|
|
|
|
|
arg->data.str.data = dec_size;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 05:50:54 -05:00
|
|
|
#if defined(EVP_CIPH_GCM_MODE) || defined(EVP_CIPH_CBC_MODE)
|
|
|
|
|
|
|
|
|
|
#define AES_FLG_ENC (1 << 0)
|
|
|
|
|
#define AES_FLG_DEC (1 << 1)
|
|
|
|
|
#define AES_FLG_GCM (1 << 2)
|
|
|
|
|
#define AES_FLG_CBC (1 << 3)
|
|
|
|
|
|
|
|
|
|
static int check_aes(struct arg *args, struct sample_conv *conv,
|
|
|
|
|
const char *file, int line, char **err)
|
2021-10-06 09:37:17 -04:00
|
|
|
{
|
2026-01-13 05:50:54 -05:00
|
|
|
int last_arg_idx = 3;
|
|
|
|
|
|
2024-03-05 07:03:51 -05:00
|
|
|
if (conv->kw[8] == 'd')
|
|
|
|
|
/* flag it as "aes_gcm_dec" */
|
2026-01-13 05:50:54 -05:00
|
|
|
args[0].type_flags |= AES_FLG_DEC;
|
|
|
|
|
else
|
|
|
|
|
args[0].type_flags |= AES_FLG_ENC;
|
|
|
|
|
|
|
|
|
|
if (conv->kw[4] == 'g')
|
|
|
|
|
/* aes_gcm */
|
|
|
|
|
args[0].type_flags |= AES_FLG_GCM;
|
|
|
|
|
else
|
|
|
|
|
/* aes_cbc */
|
|
|
|
|
args[0].type_flags |= AES_FLG_CBC;
|
2024-03-05 07:03:51 -05:00
|
|
|
|
2021-10-06 09:37:17 -04:00
|
|
|
switch(args[0].data.sint) {
|
|
|
|
|
case 128:
|
|
|
|
|
case 192:
|
|
|
|
|
case 256:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
memprintf(err, "key size must be 128, 192 or 256 (bits).");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Try to decode variables. */
|
|
|
|
|
if (!sample_check_arg_base64(&args[1], err)) {
|
|
|
|
|
memprintf(err, "failed to parse nonce : %s", *err);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!sample_check_arg_base64(&args[2], err)) {
|
|
|
|
|
memprintf(err, "failed to parse key : %s", *err);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2026-01-13 05:50:54 -05:00
|
|
|
|
|
|
|
|
if (args[0].type_flags & AES_FLG_GCM) {
|
|
|
|
|
/* GCM converters have a mandatory AEAD argument, AES in CBC mode
|
|
|
|
|
* don't support this but still might have some AAD parameter. */
|
|
|
|
|
++last_arg_idx;
|
|
|
|
|
if (((args[0].type_flags & AES_FLG_DEC) && !sample_check_arg_base64(&args[3], err)) ||
|
|
|
|
|
(!(args[0].type_flags & AES_FLG_DEC) && !vars_check_arg(&args[3], err))) {
|
|
|
|
|
memprintf(err, "failed to parse aead_tag : %s", *err);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2021-10-06 09:37:17 -04:00
|
|
|
}
|
2026-01-13 05:50:54 -05:00
|
|
|
if (args[last_arg_idx].type) {
|
|
|
|
|
if (!sample_check_arg_base64(&args[last_arg_idx], err)) {
|
2025-10-30 14:02:13 -04:00
|
|
|
memprintf(err, "failed to parse aad : %s", *err);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-06 09:37:17 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 05:50:54 -05:00
|
|
|
#define sample_conv_aes_init(a, b, c, d, e, f) \
|
2024-03-05 07:03:51 -05:00
|
|
|
({ \
|
|
|
|
|
int _ret = (a) ? \
|
|
|
|
|
EVP_DecryptInit_ex(b, c, d, e, f) : \
|
|
|
|
|
EVP_EncryptInit_ex(b, c, d, e, f); \
|
|
|
|
|
_ret; \
|
|
|
|
|
})
|
|
|
|
|
|
2026-01-13 05:50:54 -05:00
|
|
|
#define sample_conv_aes_update(a, b, c, d, e, f) \
|
2024-03-05 07:03:51 -05:00
|
|
|
({ \
|
|
|
|
|
int _ret = (a) ? \
|
|
|
|
|
EVP_DecryptUpdate(b, c, d, e, f) : \
|
|
|
|
|
EVP_EncryptUpdate(b, c, d, e, f); \
|
|
|
|
|
_ret; \
|
|
|
|
|
})
|
|
|
|
|
|
2026-01-13 05:50:54 -05:00
|
|
|
#define sample_conv_aes_final(a, b, c, d) \
|
2024-03-05 07:03:51 -05:00
|
|
|
({ \
|
|
|
|
|
int _ret = (a) ? \
|
|
|
|
|
EVP_DecryptFinal_ex(b, c, d) : \
|
|
|
|
|
EVP_EncryptFinal_ex(b, c, d); \
|
|
|
|
|
_ret; \
|
|
|
|
|
})
|
|
|
|
|
|
2026-01-13 05:50:53 -05:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Encrypt or decrypt <data> alongside additional data <aad> using AES algorithm
|
2026-01-13 05:50:54 -05:00
|
|
|
* in GCM or CBC mode (depending on <gcm> parameter) thanks to <key> of size
|
|
|
|
|
* <key_size> using <nonce> as initialization vector.
|
|
|
|
|
* When GCM mode is used, the authentication tag <aead_tag> is validated as well
|
|
|
|
|
* (in case of decryption) or constructed in case of encryption.
|
|
|
|
|
* CBC does not support AEAD signature mechanism.
|
2026-01-13 05:50:53 -05:00
|
|
|
* Returns -1 in case of error, either during the authentication or
|
|
|
|
|
* encryption/decryption process, or the <out> buffer size in case of success.
|
|
|
|
|
*/
|
2026-01-13 05:50:56 -05:00
|
|
|
int aes_process(struct buffer *data, struct buffer *nonce, struct buffer *key, int key_size,
|
2026-01-13 05:50:54 -05:00
|
|
|
struct buffer *aead_tag, struct buffer *aad, struct buffer *out, int decrypt, int gcm)
|
2026-01-13 05:50:53 -05:00
|
|
|
{
|
|
|
|
|
EVP_CIPHER_CTX *ctx = NULL;
|
|
|
|
|
int size;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
ctx = EVP_CIPHER_CTX_new();
|
|
|
|
|
|
|
|
|
|
if (!ctx)
|
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
switch(key_size) {
|
|
|
|
|
case 128:
|
2026-01-13 05:50:54 -05:00
|
|
|
sample_conv_aes_init(decrypt, ctx, (gcm ? EVP_aes_128_gcm() : EVP_aes_128_cbc()),
|
|
|
|
|
NULL, NULL, NULL);
|
2026-01-13 05:50:53 -05:00
|
|
|
break;
|
|
|
|
|
case 192:
|
2026-01-13 05:50:54 -05:00
|
|
|
sample_conv_aes_init(decrypt, ctx, (gcm ? EVP_aes_192_gcm() : EVP_aes_192_cbc()),
|
|
|
|
|
NULL, NULL, NULL);
|
2026-01-13 05:50:53 -05:00
|
|
|
break;
|
|
|
|
|
case 256:
|
2026-01-13 05:50:54 -05:00
|
|
|
sample_conv_aes_init(decrypt, ctx, (gcm ? EVP_aes_256_gcm() : EVP_aes_256_cbc()),
|
|
|
|
|
NULL, NULL, NULL);
|
2026-01-13 05:50:53 -05:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 05:50:54 -05:00
|
|
|
if (gcm) {
|
|
|
|
|
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, b_data(nonce), NULL))
|
|
|
|
|
goto err;
|
|
|
|
|
} else {
|
|
|
|
|
/* CBC mode uses a fixed size (16B) Initialization Vector */
|
|
|
|
|
#define AES_CBC_IV_LEN 16
|
|
|
|
|
if (b_data(nonce) < AES_CBC_IV_LEN) {
|
|
|
|
|
if (b_size(nonce) < AES_CBC_IV_LEN) {
|
|
|
|
|
struct buffer *tmp = get_trash_chunk();
|
|
|
|
|
if (b_size(tmp) < AES_CBC_IV_LEN)
|
|
|
|
|
goto err;
|
|
|
|
|
chunk_memcpy(tmp, b_orig(nonce), b_data(nonce));
|
|
|
|
|
nonce = tmp;
|
|
|
|
|
}
|
|
|
|
|
/* Pad provided nonce with zeroes */
|
|
|
|
|
while (b_data(nonce) != AES_CBC_IV_LEN)
|
|
|
|
|
b_putchr(nonce, '\0');
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-01-13 05:50:53 -05:00
|
|
|
|
|
|
|
|
/* Initialise IV and key */
|
2026-01-13 05:50:54 -05:00
|
|
|
if(!sample_conv_aes_init(decrypt, ctx, NULL, NULL, (unsigned char*)b_orig(key),
|
|
|
|
|
(unsigned char*)b_orig(nonce)))
|
2026-01-13 05:50:53 -05:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
if (aad && b_data(aad)) {
|
2026-01-13 05:50:54 -05:00
|
|
|
if (!sample_conv_aes_update(decrypt, ctx, NULL, (int*)&out->data,
|
|
|
|
|
(unsigned char*)b_orig(aad), (int)b_data(aad)))
|
2026-01-13 05:50:53 -05:00
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 05:50:54 -05:00
|
|
|
if (!sample_conv_aes_update(decrypt, ctx, (unsigned char*)b_orig(out),
|
|
|
|
|
(int*)&out->data, (unsigned char*)b_orig(data), (int)b_data(data)))
|
2026-01-13 05:50:53 -05:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
size = out->data;
|
|
|
|
|
|
2026-01-13 05:50:54 -05:00
|
|
|
if (decrypt && gcm) {
|
2026-01-13 05:50:53 -05:00
|
|
|
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, b_data(aead_tag), b_orig(aead_tag)))
|
|
|
|
|
goto err;
|
2026-01-13 05:50:54 -05:00
|
|
|
}
|
2026-01-13 05:50:53 -05:00
|
|
|
|
2026-01-13 05:50:54 -05:00
|
|
|
ret = sample_conv_aes_final(decrypt, ctx, (unsigned char*)out->area + out->data,
|
|
|
|
|
(int *)&out->data);
|
2026-01-13 05:50:53 -05:00
|
|
|
if (ret <= 0)
|
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
out->data += size;
|
|
|
|
|
|
2026-01-13 05:50:54 -05:00
|
|
|
if (!decrypt && gcm) {
|
2026-01-13 05:50:53 -05:00
|
|
|
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, b_orig(aead_tag)))
|
|
|
|
|
goto err;
|
|
|
|
|
aead_tag->data = 16;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
|
|
|
return b_data(out);
|
|
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-10-06 09:37:17 -04:00
|
|
|
/* Arguments: AES size in bits, nonce, key, tag. The last three arguments are base64 encoded */
|
2026-01-13 05:50:54 -05:00
|
|
|
static int sample_conv_aes(const struct arg *arg_p, struct sample *smp, void *private)
|
2021-10-06 09:37:17 -04:00
|
|
|
{
|
2025-10-30 14:02:13 -04:00
|
|
|
struct sample nonce, key, aead_tag, aad;
|
|
|
|
|
struct buffer *smp_trash = NULL, *smp_trash_alloc = NULL, *aad_trash = NULL;
|
2026-01-13 05:50:53 -05:00
|
|
|
struct buffer *nonce_trash = NULL, *key_trash = NULL, *aead_tag_trash = NULL;
|
2026-01-13 05:50:54 -05:00
|
|
|
int size, ret, dec, gcm;
|
2026-01-13 05:50:53 -05:00
|
|
|
int retval = 0;
|
2021-10-06 09:37:17 -04:00
|
|
|
|
2026-01-13 05:50:54 -05:00
|
|
|
int aad_arg_idx = 0;
|
|
|
|
|
|
2021-10-06 09:37:17 -04:00
|
|
|
smp_trash_alloc = alloc_trash_chunk();
|
|
|
|
|
if (!smp_trash_alloc)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* smp copy */
|
|
|
|
|
smp_trash_alloc->data = smp->data.u.str.data;
|
|
|
|
|
if (unlikely(smp_trash_alloc->data > smp_trash_alloc->size))
|
|
|
|
|
smp_trash_alloc->data = smp_trash_alloc->size;
|
|
|
|
|
memcpy(smp_trash_alloc->area, smp->data.u.str.area, smp_trash_alloc->data);
|
|
|
|
|
|
|
|
|
|
smp_trash = alloc_trash_chunk();
|
|
|
|
|
if (!smp_trash)
|
2026-01-13 05:50:53 -05:00
|
|
|
goto end;
|
2021-10-06 09:37:17 -04:00
|
|
|
|
|
|
|
|
smp_set_owner(&nonce, smp->px, smp->sess, smp->strm, smp->opt);
|
|
|
|
|
if (!sample_conv_var2smp_str(&arg_p[1], &nonce))
|
2026-01-13 05:50:53 -05:00
|
|
|
goto end;
|
2021-10-06 09:37:17 -04:00
|
|
|
|
|
|
|
|
if (arg_p[1].type == ARGT_VAR) {
|
2026-01-13 05:50:53 -05:00
|
|
|
nonce_trash = alloc_trash_chunk();
|
|
|
|
|
if (!nonce_trash)
|
|
|
|
|
goto end;
|
|
|
|
|
size = base64dec(nonce.data.u.str.area, nonce.data.u.str.data, nonce_trash->area, nonce_trash->size);
|
2024-03-05 07:03:51 -05:00
|
|
|
if (size < 0)
|
2026-01-13 05:50:53 -05:00
|
|
|
goto end;
|
|
|
|
|
nonce_trash->data = size;
|
|
|
|
|
nonce.data.u.str = *nonce_trash;
|
2021-10-06 09:37:17 -04:00
|
|
|
}
|
|
|
|
|
|
2024-03-05 07:03:51 -05:00
|
|
|
/* encrypt (0) or decrypt (1) */
|
2026-01-13 05:50:54 -05:00
|
|
|
dec = (arg_p[0].type_flags & AES_FLG_DEC);
|
|
|
|
|
gcm = (arg_p[0].type_flags & AES_FLG_GCM);
|
2024-03-05 07:03:51 -05:00
|
|
|
|
2021-10-06 09:37:17 -04:00
|
|
|
smp_set_owner(&key, smp->px, smp->sess, smp->strm, smp->opt);
|
|
|
|
|
if (!sample_conv_var2smp_str(&arg_p[2], &key))
|
2026-01-13 05:50:53 -05:00
|
|
|
goto end;
|
2021-10-06 09:37:17 -04:00
|
|
|
|
|
|
|
|
if (arg_p[2].type == ARGT_VAR) {
|
2026-01-13 05:50:53 -05:00
|
|
|
key_trash = alloc_trash_chunk();
|
|
|
|
|
if (!key_trash)
|
|
|
|
|
goto end;
|
|
|
|
|
size = base64dec(key.data.u.str.area, key.data.u.str.data, key_trash->area, key_trash->size);
|
2024-03-05 07:03:51 -05:00
|
|
|
if (size < 0)
|
2026-01-13 05:50:53 -05:00
|
|
|
goto end;
|
|
|
|
|
key_trash->data = size;
|
|
|
|
|
key.data.u.str = *key_trash;
|
2021-10-06 09:37:17 -04:00
|
|
|
}
|
|
|
|
|
|
2026-01-13 05:50:54 -05:00
|
|
|
if (gcm)
|
|
|
|
|
aad_arg_idx = 4;
|
|
|
|
|
else
|
|
|
|
|
aad_arg_idx = 3;
|
|
|
|
|
|
2025-10-30 14:02:13 -04:00
|
|
|
/* if there's an AAD parameter */
|
2026-01-13 05:50:54 -05:00
|
|
|
if (arg_p[aad_arg_idx].type) {
|
2025-10-30 14:02:13 -04:00
|
|
|
smp_set_owner(&aad, smp->px, smp->sess, smp->strm, smp->opt);
|
|
|
|
|
|
2026-01-13 05:50:54 -05:00
|
|
|
if (!sample_conv_var2smp_str(&arg_p[aad_arg_idx], &aad))
|
2026-01-13 05:50:53 -05:00
|
|
|
goto end;
|
2026-01-13 05:50:54 -05:00
|
|
|
/* if stored in a variable, the base64 decode was not done in check_aes() */
|
|
|
|
|
if (arg_p[aad_arg_idx].type == ARGT_VAR) {
|
2025-10-30 14:02:13 -04:00
|
|
|
int aad_len;
|
|
|
|
|
|
|
|
|
|
aad_trash = alloc_trash_chunk();
|
|
|
|
|
if (!aad_trash)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
aad_len = base64dec(aad.data.u.str.area, aad.data.u.str.data, aad_trash->area, aad_trash->size);
|
|
|
|
|
if (aad_len < 0)
|
2026-01-13 05:50:53 -05:00
|
|
|
goto end;
|
2025-10-30 14:02:13 -04:00
|
|
|
aad_trash->data = aad_len;
|
|
|
|
|
aad.data.u.str = *aad_trash;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 05:50:54 -05:00
|
|
|
if (gcm) {
|
|
|
|
|
smp_set_owner(&aead_tag, smp->px, smp->sess, smp->strm, smp->opt);
|
|
|
|
|
if (dec) {
|
|
|
|
|
if (!sample_conv_var2smp_str(&arg_p[3], &aead_tag))
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
if (arg_p[3].type == ARGT_VAR) {
|
2021-10-06 09:37:17 -04:00
|
|
|
|
2026-01-13 05:50:54 -05:00
|
|
|
aead_tag_trash = alloc_trash_chunk();
|
|
|
|
|
if (!aead_tag_trash)
|
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
size = base64dec(aead_tag.data.u.str.area, aead_tag.data.u.str.data, aead_tag_trash->area,
|
|
|
|
|
aead_tag_trash->size);
|
|
|
|
|
if (size < 0)
|
|
|
|
|
goto end;
|
|
|
|
|
aead_tag_trash->data = size;
|
|
|
|
|
aead_tag.data.u.str = *aead_tag_trash;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2026-01-13 05:50:53 -05:00
|
|
|
aead_tag_trash = alloc_trash_chunk();
|
|
|
|
|
if (!aead_tag_trash)
|
|
|
|
|
goto end;
|
2024-03-05 07:03:51 -05:00
|
|
|
}
|
|
|
|
|
}
|
2021-10-06 09:37:17 -04:00
|
|
|
|
2026-01-13 05:50:53 -05:00
|
|
|
size = aes_process(smp_trash_alloc, &nonce.data.u.str, &key.data.u.str, arg_p[0].data.sint,
|
2026-01-13 05:50:54 -05:00
|
|
|
(gcm && dec) ? &aead_tag.data.u.str : aead_tag_trash,
|
|
|
|
|
arg_p[4].type ? &aad.data.u.str : NULL, smp_trash, dec, gcm);
|
|
|
|
|
|
2026-01-13 05:50:53 -05:00
|
|
|
if (size < 0)
|
|
|
|
|
goto end;
|
2021-10-06 09:37:17 -04:00
|
|
|
|
2026-01-13 05:50:54 -05:00
|
|
|
if (!dec && gcm) {
|
2024-03-05 07:03:51 -05:00
|
|
|
struct buffer *trash = get_trash_chunk();
|
|
|
|
|
|
2026-01-13 05:50:53 -05:00
|
|
|
chunk_memcpy(trash, b_orig(aead_tag_trash), b_data(aead_tag_trash));
|
2024-03-05 07:03:51 -05:00
|
|
|
|
|
|
|
|
aead_tag.data.u.str = *smp_trash_alloc;
|
|
|
|
|
ret = a2base64(trash->area, 16, aead_tag.data.u.str.area, aead_tag.data.u.str.size);
|
|
|
|
|
if (ret < 0)
|
2026-01-13 05:50:53 -05:00
|
|
|
goto end;
|
2024-03-05 07:03:51 -05:00
|
|
|
|
|
|
|
|
aead_tag.data.u.str.data = ret;
|
|
|
|
|
aead_tag.data.type = SMP_T_STR;
|
|
|
|
|
|
2024-07-17 10:38:13 -04:00
|
|
|
if (!var_set(&arg_p[3].data.var, &aead_tag,
|
2024-03-05 07:03:51 -05:00
|
|
|
(arg_p[3].data.var.scope == SCOPE_PROC) ? VF_COND_IFEXISTS : 0)) {
|
2026-01-13 05:50:53 -05:00
|
|
|
goto end;
|
2024-03-05 07:03:51 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 05:50:53 -05:00
|
|
|
smp->data.u.str.data = smp_trash->data;
|
2021-10-06 09:37:17 -04:00
|
|
|
smp->data.u.str.area = smp_trash->area;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
smp_dup(smp);
|
|
|
|
|
|
2026-01-13 05:50:53 -05:00
|
|
|
retval = 1;
|
|
|
|
|
|
|
|
|
|
end:
|
2021-10-06 09:37:17 -04:00
|
|
|
free_trash_chunk(smp_trash_alloc);
|
|
|
|
|
free_trash_chunk(smp_trash);
|
2025-10-30 14:02:13 -04:00
|
|
|
free_trash_chunk(aad_trash);
|
2026-01-13 05:50:53 -05:00
|
|
|
free_trash_chunk(nonce_trash);
|
|
|
|
|
free_trash_chunk(key_trash);
|
|
|
|
|
free_trash_chunk(aead_tag_trash);
|
|
|
|
|
return retval;
|
2021-10-06 09:37:17 -04:00
|
|
|
}
|
2026-01-13 05:50:54 -05:00
|
|
|
#endif /* defined(EVP_CIPH_GCM_MODE) || defined(EVP_CIPH_CBC_MODE) */
|
2021-10-06 09:37:17 -04:00
|
|
|
|
|
|
|
|
static int check_crypto_digest(struct arg *args, struct sample_conv *conv,
|
|
|
|
|
const char *file, int line, char **err)
|
|
|
|
|
{
|
|
|
|
|
const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
|
|
|
|
|
|
|
|
|
|
if (evp)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
memprintf(err, "algorithm must be a valid OpenSSL message digest name.");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int sample_conv_crypto_digest(const struct arg *args, struct sample *smp, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct buffer *trash = get_trash_chunk();
|
|
|
|
|
unsigned char *md = (unsigned char*) trash->area;
|
|
|
|
|
unsigned int md_len = trash->size;
|
|
|
|
|
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
|
|
|
|
|
const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
|
|
|
|
|
|
|
|
|
|
if (!ctx)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (!EVP_DigestInit_ex(ctx, evp, NULL) ||
|
|
|
|
|
!EVP_DigestUpdate(ctx, smp->data.u.str.area, smp->data.u.str.data) ||
|
|
|
|
|
!EVP_DigestFinal_ex(ctx, md, &md_len)) {
|
|
|
|
|
EVP_MD_CTX_free(ctx);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EVP_MD_CTX_free(ctx);
|
|
|
|
|
|
|
|
|
|
trash->data = md_len;
|
|
|
|
|
smp->data.u.str = *trash;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
smp->flags &= ~SMP_F_CONST;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-03 13:56:37 -04:00
|
|
|
/* Take a numerical X509_V_ERR and return its constant name */
|
|
|
|
|
static int sample_conv_x509_v_err(const struct arg *arg_p, struct sample *smp, void *private)
|
|
|
|
|
{
|
|
|
|
|
const char *res = x509_v_err_int_to_str(smp->data.u.sint);
|
|
|
|
|
|
|
|
|
|
/* if the value was found return its string */
|
|
|
|
|
if (res) {
|
|
|
|
|
smp->data.u.str.area = (char *)res;
|
|
|
|
|
smp->data.u.str.data = strlen(res);
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
smp->flags |= SMP_F_CONST;
|
|
|
|
|
|
2023-05-03 09:13:10 -04:00
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
struct buffer *smp_trash = get_trash_chunk();
|
|
|
|
|
|
|
|
|
|
/* if the conversion failed, output the numbers as string */
|
|
|
|
|
chunk_printf(smp_trash, "%llu", smp->data.u.sint);
|
|
|
|
|
|
|
|
|
|
smp->data.u.str = *smp_trash;
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
smp->flags &= ~SMP_F_CONST;
|
|
|
|
|
|
2022-11-03 13:56:37 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-06 09:37:17 -04:00
|
|
|
static int check_crypto_hmac(struct arg *args, struct sample_conv *conv,
|
|
|
|
|
const char *file, int line, char **err)
|
|
|
|
|
{
|
|
|
|
|
if (!check_crypto_digest(args, conv, file, line, err))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (!sample_check_arg_base64(&args[1], err)) {
|
|
|
|
|
memprintf(err, "failed to parse key : %s", *err);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int sample_conv_crypto_hmac(const struct arg *args, struct sample *smp, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct sample key;
|
|
|
|
|
struct buffer *trash = NULL, *key_trash = NULL;
|
|
|
|
|
unsigned char *md;
|
|
|
|
|
unsigned int md_len;
|
|
|
|
|
const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.area);
|
|
|
|
|
int dec_size;
|
|
|
|
|
|
|
|
|
|
smp_set_owner(&key, smp->px, smp->sess, smp->strm, smp->opt);
|
|
|
|
|
if (!sample_conv_var2smp_str(&args[1], &key))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (args[1].type == ARGT_VAR) {
|
|
|
|
|
key_trash = alloc_trash_chunk();
|
|
|
|
|
if (!key_trash)
|
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
dec_size = base64dec(key.data.u.str.area, key.data.u.str.data, key_trash->area, key_trash->size);
|
|
|
|
|
if (dec_size < 0)
|
|
|
|
|
goto err;
|
|
|
|
|
key_trash->data = dec_size;
|
|
|
|
|
key.data.u.str = *key_trash;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trash = alloc_trash_chunk();
|
|
|
|
|
if (!trash)
|
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
md = (unsigned char*) trash->area;
|
|
|
|
|
md_len = trash->size;
|
|
|
|
|
if (!HMAC(evp, key.data.u.str.area, key.data.u.str.data, (const unsigned char*) smp->data.u.str.area,
|
|
|
|
|
smp->data.u.str.data, md, &md_len))
|
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
free_trash_chunk(key_trash);
|
|
|
|
|
|
|
|
|
|
trash->data = md_len;
|
|
|
|
|
smp->data.u.str = *trash;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
smp_dup(smp);
|
|
|
|
|
free_trash_chunk(trash);
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
free_trash_chunk(key_trash);
|
|
|
|
|
free_trash_chunk(trash);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_has_early(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->flags = 0;
|
|
|
|
|
smp->data.type = SMP_T_BOOL;
|
|
|
|
|
#ifdef OPENSSL_IS_BORINGSSL
|
|
|
|
|
{
|
|
|
|
|
smp->data.u.sint = (SSL_in_early_data(ssl) &&
|
|
|
|
|
SSL_early_data_accepted(ssl));
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
smp->data.u.sint = ((conn->flags & CO_FL_EARLY_DATA) &&
|
|
|
|
|
(conn->flags & (CO_FL_EARLY_SSL_HS | CO_FL_SSL_WAIT_HS))) ? 1 : 0;
|
|
|
|
|
#endif
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-29 03:03:01 -04:00
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_early_rcvd(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->flags = 0;
|
|
|
|
|
smp->data.type = SMP_T_BOOL;
|
|
|
|
|
#ifdef OPENSSL_IS_BORINGSSL
|
|
|
|
|
smp->data.u.sint = SSL_early_data_accepted(ssl);
|
|
|
|
|
#else
|
|
|
|
|
smp->data.u.sint = !!(conn->flags & CO_FL_EARLY_DATA);
|
|
|
|
|
#endif
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
/* boolean, returns true if client cert was present */
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_has_crt(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2022-04-11 05:29:11 -04:00
|
|
|
struct connection *conn = objt_conn(smp->sess->origin);
|
|
|
|
|
struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
|
2020-05-14 18:25:08 -04:00
|
|
|
|
2022-04-11 05:29:11 -04:00
|
|
|
if (!ctx)
|
2020-05-14 18:25:08 -04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT) {
|
|
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.type = SMP_T_BOOL;
|
|
|
|
|
smp->data.u.sint = SSL_SOCK_ST_FL_VERIFY_DONE & ctx->xprt_st ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-13 23:04:45 -04:00
|
|
|
/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of the
|
|
|
|
|
* client certificate's root CA.
|
|
|
|
|
*/
|
2023-05-15 06:05:55 -04:00
|
|
|
#ifdef HAVE_SSL_get0_verified_chain
|
2023-05-13 23:04:45 -04:00
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_r_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
X509 *crt = NULL;
|
BUILD: ssl: make X509_NAME usage OpenSSL 4.0 ready
Starting with OpenSSL 4.0, X509_get_subject_name(), X509_get_issuer_name(),
and X509_CRL_get_issuer() return a const-qualified X509_NAME pointer.
Similarly, X509_NAME_get_entry() returns a const X509_NAME_ENTRY *, and
X509_NAME_ENTRY_get_data() returns a const ASN1_STRING *.
Introduce the __X509_NAME_CONST__ macro (defined to 'const' for OpenSSL
>= 4.0.0, empty for WolfSSL and older OpenSSL version which lacks const
on these APIs) and use it to qualify X509_NAME * variables and the
parameters of the three DN helper functions ssl_sock_get_dn_entry(),
ssl_sock_get_dn_formatted(), and ssl_sock_get_dn_oneline(). This avoids
both const-qualifier warnings on OpenSSL 4.0 and discarded-qualifier
warnings on WolfSSL, without needing explicit casts at call sites.
In ssl_sock.c (ssl_get_client_ca_file) and ssl_gencert.c
(ssl_sock_do_create_cert), a __X509_NAME_CONST__ X509_NAME * variable was
being reused to store the result of X509_NAME_dup() and then passed to
mutating functions (X509_NAME_add_entry_by_txt, X509_NAME_free). Introduce
separate X509_NAME * variables (xn_dup, subject) to hold the mutable
duplicate.
Original patch from Alexandr Nedvedicky <sashan@openssl.org>:
https://www.mail-archive.com/haproxy@formilux.org/msg46696.html
2026-03-11 10:03:36 -04:00
|
|
|
__X509_NAME_CONST__ X509_NAME *name;
|
2023-05-13 23:04:45 -04:00
|
|
|
int ret = 0;
|
|
|
|
|
struct buffer *smp_trash;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
|
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
crt = ssl_sock_get_verified_chain_root(ssl);
|
|
|
|
|
if (!crt)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
name = X509_get_subject_name(crt);
|
|
|
|
|
if (!name)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
smp_trash = get_trash_chunk();
|
|
|
|
|
if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
|
|
|
|
|
int pos = 1;
|
|
|
|
|
|
|
|
|
|
if (args[1].type == ARGT_SINT)
|
|
|
|
|
pos = args[1].data.sint;
|
|
|
|
|
|
|
|
|
|
if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
|
|
|
|
|
if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
smp->data.u.str = *smp_trash;
|
|
|
|
|
ret = 1;
|
|
|
|
|
out:
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2023-05-15 06:05:55 -04:00
|
|
|
#endif
|
2023-05-13 23:04:45 -04:00
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
/* binary, returns a certificate in a binary chunk (der/raw).
|
|
|
|
|
* The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
|
|
|
|
|
* should be use.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_x_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2020-06-25 14:07:18 -04:00
|
|
|
int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
|
|
|
|
|
int conn_server = (kw[4] == 's') ? 1 : 0;
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
X509 *crt = NULL;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
struct buffer *smp_trash;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
2020-06-25 14:07:18 -04:00
|
|
|
if (conn_server)
|
2022-05-18 10:23:22 -04:00
|
|
|
conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-06-25 14:07:18 -04:00
|
|
|
else
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-08-19 12:06:30 -04:00
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cert_peer)
|
2021-08-19 12:06:30 -04:00
|
|
|
crt = ssl_sock_get_peer_certificate(ssl);
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
crt = SSL_get_certificate(ssl);
|
|
|
|
|
|
|
|
|
|
if (!crt)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
smp_trash = get_trash_chunk();
|
|
|
|
|
if (ssl_sock_crt2der(crt, smp_trash) <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.u.str = *smp_trash;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
ret = 1;
|
|
|
|
|
out:
|
|
|
|
|
/* SSL_get_peer_certificate, it increase X509 * ref count */
|
|
|
|
|
if (cert_peer && crt)
|
|
|
|
|
X509_free(crt);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-06 12:11:38 -04:00
|
|
|
/* binary, returns a chain certificate in a binary chunk (der/raw).
|
|
|
|
|
* The 5th keyword char is used to support only peer cert
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_x_chain_der(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
|
|
|
|
|
int conn_server = (kw[4] == 's') ? 1 : 0;
|
|
|
|
|
struct buffer *smp_trash;
|
|
|
|
|
struct buffer *tmp_trash = NULL;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
STACK_OF(X509) *certs = NULL;
|
|
|
|
|
X509 *crt = NULL;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
int num_certs;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (conn_server)
|
2022-05-18 10:23:22 -04:00
|
|
|
conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-08-06 12:11:38 -04:00
|
|
|
else
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
|
|
|
|
|
if (!conn)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT) {
|
|
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!cert_peer)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
certs = SSL_get_peer_cert_chain(ssl);
|
|
|
|
|
if (!certs)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
num_certs = sk_X509_num(certs);
|
|
|
|
|
if (!num_certs)
|
|
|
|
|
goto out;
|
|
|
|
|
smp_trash = get_trash_chunk();
|
|
|
|
|
tmp_trash = alloc_trash_chunk();
|
|
|
|
|
if (!tmp_trash)
|
|
|
|
|
goto out;
|
|
|
|
|
for (i = 0; i < num_certs; i++) {
|
|
|
|
|
crt = sk_X509_value(certs, i);
|
|
|
|
|
if (ssl_sock_crt2der(crt, tmp_trash) <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
chunk_cat(smp_trash, tmp_trash);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-08-06 12:11:38 -04:00
|
|
|
smp->data.u.str = *smp_trash;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
ret = 1;
|
|
|
|
|
out:
|
|
|
|
|
if (tmp_trash)
|
|
|
|
|
free_trash_chunk(tmp_trash);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
/* binary, returns serial of certificate in a binary chunk.
|
|
|
|
|
* The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
|
|
|
|
|
* should be use.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_x_serial(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2020-06-25 14:07:18 -04:00
|
|
|
int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
|
|
|
|
|
int conn_server = (kw[4] == 's') ? 1 : 0;
|
2020-05-14 18:25:08 -04:00
|
|
|
X509 *crt = NULL;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
struct buffer *smp_trash;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
2020-06-25 14:07:18 -04:00
|
|
|
if (conn_server)
|
2022-05-18 10:23:22 -04:00
|
|
|
conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-06-25 14:07:18 -04:00
|
|
|
else
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
2020-05-14 18:25:08 -04:00
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-08-19 12:06:30 -04:00
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cert_peer)
|
2021-08-19 12:06:30 -04:00
|
|
|
crt = ssl_sock_get_peer_certificate(ssl);
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
crt = SSL_get_certificate(ssl);
|
|
|
|
|
|
|
|
|
|
if (!crt)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
smp_trash = get_trash_chunk();
|
|
|
|
|
if (ssl_sock_get_serial(crt, smp_trash) <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.u.str = *smp_trash;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
ret = 1;
|
|
|
|
|
out:
|
|
|
|
|
/* SSL_get_peer_certificate, it increase X509 * ref count */
|
|
|
|
|
if (cert_peer && crt)
|
|
|
|
|
X509_free(crt);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* binary, returns the client certificate's SHA-1 fingerprint (SHA-1 hash of DER-encoded certificate) in a binary chunk.
|
|
|
|
|
* The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
|
|
|
|
|
* should be use.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_x_sha1(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2020-06-25 14:07:18 -04:00
|
|
|
int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
|
|
|
|
|
int conn_server = (kw[4] == 's') ? 1 : 0;
|
2020-05-14 18:25:08 -04:00
|
|
|
X509 *crt = NULL;
|
|
|
|
|
const EVP_MD *digest;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
unsigned int len = 0;
|
|
|
|
|
struct buffer *smp_trash;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
2020-06-25 14:07:18 -04:00
|
|
|
if (conn_server)
|
2022-05-18 10:23:22 -04:00
|
|
|
conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-06-25 14:07:18 -04:00
|
|
|
else
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-08-19 12:06:30 -04:00
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cert_peer)
|
2021-08-19 12:06:30 -04:00
|
|
|
crt = ssl_sock_get_peer_certificate(ssl);
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
crt = SSL_get_certificate(ssl);
|
|
|
|
|
if (!crt)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
smp_trash = get_trash_chunk();
|
|
|
|
|
digest = EVP_sha1();
|
|
|
|
|
X509_digest(crt, digest, (unsigned char *) smp_trash->area, &len);
|
|
|
|
|
smp_trash->data = len;
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.u.str = *smp_trash;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
ret = 1;
|
|
|
|
|
out:
|
|
|
|
|
/* SSL_get_peer_certificate, it increase X509 * ref count */
|
|
|
|
|
if (cert_peer && crt)
|
|
|
|
|
X509_free(crt);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* string, returns certificate's notafter date in ASN1_UTCTIME format.
|
|
|
|
|
* The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
|
|
|
|
|
* should be use.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_x_notafter(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2020-06-25 14:07:18 -04:00
|
|
|
int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
|
|
|
|
|
int conn_server = (kw[4] == 's') ? 1 : 0;
|
2020-05-14 18:25:08 -04:00
|
|
|
X509 *crt = NULL;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
struct buffer *smp_trash;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
2020-06-25 14:07:18 -04:00
|
|
|
if (conn_server)
|
2022-05-18 10:23:22 -04:00
|
|
|
conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-06-25 14:07:18 -04:00
|
|
|
else
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-08-19 12:06:30 -04:00
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cert_peer)
|
2021-08-19 12:06:30 -04:00
|
|
|
crt = ssl_sock_get_peer_certificate(ssl);
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
crt = SSL_get_certificate(ssl);
|
|
|
|
|
if (!crt)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
smp_trash = get_trash_chunk();
|
|
|
|
|
if (ssl_sock_get_time(X509_getm_notAfter(crt), smp_trash) <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.u.str = *smp_trash;
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
ret = 1;
|
|
|
|
|
out:
|
|
|
|
|
/* SSL_get_peer_certificate, it increase X509 * ref count */
|
|
|
|
|
if (cert_peer && crt)
|
|
|
|
|
X509_free(crt);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's issuer
|
|
|
|
|
* The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
|
|
|
|
|
* should be use.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_x_i_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2020-06-25 14:07:18 -04:00
|
|
|
int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
|
|
|
|
|
int conn_server = (kw[4] == 's') ? 1 : 0;
|
2020-05-14 18:25:08 -04:00
|
|
|
X509 *crt = NULL;
|
BUILD: ssl: make X509_NAME usage OpenSSL 4.0 ready
Starting with OpenSSL 4.0, X509_get_subject_name(), X509_get_issuer_name(),
and X509_CRL_get_issuer() return a const-qualified X509_NAME pointer.
Similarly, X509_NAME_get_entry() returns a const X509_NAME_ENTRY *, and
X509_NAME_ENTRY_get_data() returns a const ASN1_STRING *.
Introduce the __X509_NAME_CONST__ macro (defined to 'const' for OpenSSL
>= 4.0.0, empty for WolfSSL and older OpenSSL version which lacks const
on these APIs) and use it to qualify X509_NAME * variables and the
parameters of the three DN helper functions ssl_sock_get_dn_entry(),
ssl_sock_get_dn_formatted(), and ssl_sock_get_dn_oneline(). This avoids
both const-qualifier warnings on OpenSSL 4.0 and discarded-qualifier
warnings on WolfSSL, without needing explicit casts at call sites.
In ssl_sock.c (ssl_get_client_ca_file) and ssl_gencert.c
(ssl_sock_do_create_cert), a __X509_NAME_CONST__ X509_NAME * variable was
being reused to store the result of X509_NAME_dup() and then passed to
mutating functions (X509_NAME_add_entry_by_txt, X509_NAME_free). Introduce
separate X509_NAME * variables (xn_dup, subject) to hold the mutable
duplicate.
Original patch from Alexandr Nedvedicky <sashan@openssl.org>:
https://www.mail-archive.com/haproxy@formilux.org/msg46696.html
2026-03-11 10:03:36 -04:00
|
|
|
__X509_NAME_CONST__ X509_NAME *name;
|
2020-05-14 18:25:08 -04:00
|
|
|
int ret = 0;
|
|
|
|
|
struct buffer *smp_trash;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
2020-06-25 14:07:18 -04:00
|
|
|
if (conn_server)
|
2022-05-18 10:23:22 -04:00
|
|
|
conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-06-25 14:07:18 -04:00
|
|
|
else
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-08-19 12:06:30 -04:00
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cert_peer)
|
2021-08-19 12:06:30 -04:00
|
|
|
crt = ssl_sock_get_peer_certificate(ssl);
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
crt = SSL_get_certificate(ssl);
|
|
|
|
|
if (!crt)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
name = X509_get_issuer_name(crt);
|
|
|
|
|
if (!name)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
smp_trash = get_trash_chunk();
|
2021-01-29 05:30:37 -05:00
|
|
|
if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
|
2020-05-14 18:25:08 -04:00
|
|
|
int pos = 1;
|
|
|
|
|
|
|
|
|
|
if (args[1].type == ARGT_SINT)
|
|
|
|
|
pos = args[1].data.sint;
|
|
|
|
|
|
|
|
|
|
if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2021-01-29 05:30:37 -05:00
|
|
|
else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
|
2020-05-14 18:25:08 -04:00
|
|
|
if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
smp->data.u.str = *smp_trash;
|
|
|
|
|
ret = 1;
|
|
|
|
|
out:
|
|
|
|
|
/* SSL_get_peer_certificate, it increase X509 * ref count */
|
|
|
|
|
if (cert_peer && crt)
|
|
|
|
|
X509_free(crt);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-27 16:16:06 -05:00
|
|
|
/*
|
|
|
|
|
* returns a string of comma separated SAN in a client certificate, Use "GENERAL_NAME_print"
|
|
|
|
|
* Example: "IP Address:127.0.0.1, IP Address:127.0.0.2, IP Address:127.0.0.3, URI:http://docs.haproxy.org/2.7/, DNS:ca.tests.haproxy.com"
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_x_san(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
|
|
|
|
|
int conn_server = (kw[4] == 's') ? 1 : 0;
|
|
|
|
|
STACK_OF(GENERAL_NAME) *names;
|
|
|
|
|
X509 *crt = NULL;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
struct buffer *smp_trash;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
int i, read;
|
|
|
|
|
BIO *bio = NULL;
|
|
|
|
|
|
|
|
|
|
if (conn_server)
|
|
|
|
|
conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
|
|
|
|
else
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
|
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cert_peer)
|
|
|
|
|
crt = ssl_sock_get_peer_certificate(ssl);
|
|
|
|
|
else
|
|
|
|
|
crt = SSL_get_certificate(ssl);
|
|
|
|
|
if (!crt)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
names = X509_get_ext_d2i(crt, NID_subject_alt_name, NULL, NULL);
|
|
|
|
|
if (!names)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
smp_trash = get_trash_chunk();
|
|
|
|
|
|
|
|
|
|
bio = BIO_new(BIO_s_mem());
|
|
|
|
|
if (!bio)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < sk_GENERAL_NAME_num(names); i++) {
|
|
|
|
|
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
|
|
|
|
|
if (i != 0)
|
|
|
|
|
BIO_puts(bio, ", ");
|
|
|
|
|
GENERAL_NAME_print(bio, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
|
|
|
|
|
|
|
|
|
|
read = BIO_read(bio, smp_trash->area, smp_trash->size-1);
|
|
|
|
|
if (read <= 0) /* nothing to read, prevent negative array index */
|
|
|
|
|
goto out;
|
|
|
|
|
smp_trash->area[read] = '\0';
|
|
|
|
|
smp_trash->data = read;
|
|
|
|
|
|
|
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
smp->data.u.str = *smp_trash;
|
|
|
|
|
ret = 1;
|
|
|
|
|
out:
|
|
|
|
|
/* SSL_get_peer_certificate, it increase X509 * ref count */
|
|
|
|
|
if (cert_peer && crt)
|
|
|
|
|
X509_free(crt);
|
|
|
|
|
BIO_free(bio);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
/* string, returns notbefore date in ASN1_UTCTIME format.
|
|
|
|
|
* The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
|
|
|
|
|
* should be use.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_x_notbefore(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2020-06-25 14:07:18 -04:00
|
|
|
int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
|
|
|
|
|
int conn_server = (kw[4] == 's') ? 1 : 0;
|
2020-05-14 18:25:08 -04:00
|
|
|
X509 *crt = NULL;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
struct buffer *smp_trash;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
2020-06-25 14:07:18 -04:00
|
|
|
if (conn_server)
|
2022-05-18 10:23:22 -04:00
|
|
|
conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-06-25 14:07:18 -04:00
|
|
|
else
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-08-19 12:06:30 -04:00
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cert_peer)
|
2021-08-19 12:06:30 -04:00
|
|
|
crt = ssl_sock_get_peer_certificate(ssl);
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
crt = SSL_get_certificate(ssl);
|
|
|
|
|
if (!crt)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
smp_trash = get_trash_chunk();
|
|
|
|
|
if (ssl_sock_get_time(X509_getm_notBefore(crt), smp_trash) <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.u.str = *smp_trash;
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
ret = 1;
|
|
|
|
|
out:
|
|
|
|
|
/* SSL_get_peer_certificate, it increase X509 * ref count */
|
|
|
|
|
if (cert_peer && crt)
|
|
|
|
|
X509_free(crt);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's subject
|
|
|
|
|
* The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
|
|
|
|
|
* should be use.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_x_s_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2020-06-25 14:07:18 -04:00
|
|
|
int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
|
|
|
|
|
int conn_server = (kw[4] == 's') ? 1 : 0;
|
2020-05-14 18:25:08 -04:00
|
|
|
X509 *crt = NULL;
|
BUILD: ssl: make X509_NAME usage OpenSSL 4.0 ready
Starting with OpenSSL 4.0, X509_get_subject_name(), X509_get_issuer_name(),
and X509_CRL_get_issuer() return a const-qualified X509_NAME pointer.
Similarly, X509_NAME_get_entry() returns a const X509_NAME_ENTRY *, and
X509_NAME_ENTRY_get_data() returns a const ASN1_STRING *.
Introduce the __X509_NAME_CONST__ macro (defined to 'const' for OpenSSL
>= 4.0.0, empty for WolfSSL and older OpenSSL version which lacks const
on these APIs) and use it to qualify X509_NAME * variables and the
parameters of the three DN helper functions ssl_sock_get_dn_entry(),
ssl_sock_get_dn_formatted(), and ssl_sock_get_dn_oneline(). This avoids
both const-qualifier warnings on OpenSSL 4.0 and discarded-qualifier
warnings on WolfSSL, without needing explicit casts at call sites.
In ssl_sock.c (ssl_get_client_ca_file) and ssl_gencert.c
(ssl_sock_do_create_cert), a __X509_NAME_CONST__ X509_NAME * variable was
being reused to store the result of X509_NAME_dup() and then passed to
mutating functions (X509_NAME_add_entry_by_txt, X509_NAME_free). Introduce
separate X509_NAME * variables (xn_dup, subject) to hold the mutable
duplicate.
Original patch from Alexandr Nedvedicky <sashan@openssl.org>:
https://www.mail-archive.com/haproxy@formilux.org/msg46696.html
2026-03-11 10:03:36 -04:00
|
|
|
__X509_NAME_CONST__ X509_NAME *name;
|
2020-05-14 18:25:08 -04:00
|
|
|
int ret = 0;
|
|
|
|
|
struct buffer *smp_trash;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
2020-06-25 14:07:18 -04:00
|
|
|
if (conn_server)
|
2022-05-18 10:23:22 -04:00
|
|
|
conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-06-25 14:07:18 -04:00
|
|
|
else
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-08-19 12:06:30 -04:00
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cert_peer)
|
2021-08-19 12:06:30 -04:00
|
|
|
crt = ssl_sock_get_peer_certificate(ssl);
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
crt = SSL_get_certificate(ssl);
|
|
|
|
|
if (!crt)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
name = X509_get_subject_name(crt);
|
|
|
|
|
if (!name)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
smp_trash = get_trash_chunk();
|
2021-01-29 05:30:37 -05:00
|
|
|
if (args[0].type == ARGT_STR && args[0].data.str.data > 0) {
|
2020-05-14 18:25:08 -04:00
|
|
|
int pos = 1;
|
|
|
|
|
|
|
|
|
|
if (args[1].type == ARGT_SINT)
|
|
|
|
|
pos = args[1].data.sint;
|
|
|
|
|
|
|
|
|
|
if (ssl_sock_get_dn_entry(name, &args[0].data.str, pos, smp_trash) <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2021-01-29 05:30:37 -05:00
|
|
|
else if (args[2].type == ARGT_STR && args[2].data.str.data > 0) {
|
2020-05-14 18:25:08 -04:00
|
|
|
if (ssl_sock_get_dn_formatted(name, &args[2].data.str, smp_trash) <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
else if (ssl_sock_get_dn_oneline(name, smp_trash) <= 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
smp->data.u.str = *smp_trash;
|
|
|
|
|
ret = 1;
|
|
|
|
|
out:
|
|
|
|
|
/* SSL_get_peer_certificate, it increase X509 * ref count */
|
|
|
|
|
if (cert_peer && crt)
|
|
|
|
|
X509_free(crt);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* integer, returns true if current session use a client certificate */
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_c_used(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
X509 *crt;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-08-19 12:06:30 -04:00
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* SSL_get_peer_certificate returns a ptr on allocated X509 struct */
|
2021-08-19 12:06:30 -04:00
|
|
|
crt = ssl_sock_get_peer_certificate(ssl);
|
2020-05-14 18:25:08 -04:00
|
|
|
if (crt) {
|
|
|
|
|
X509_free(crt);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.type = SMP_T_BOOL;
|
|
|
|
|
smp->data.u.sint = (crt != NULL);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* integer, returns the certificate version
|
|
|
|
|
* The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
|
|
|
|
|
* should be use.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_x_version(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2020-06-25 14:07:18 -04:00
|
|
|
int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
|
|
|
|
|
int conn_server = (kw[4] == 's') ? 1 : 0;
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
X509 *crt;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
2020-06-25 14:07:18 -04:00
|
|
|
if (conn_server)
|
2022-05-18 10:23:22 -04:00
|
|
|
conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-06-25 14:07:18 -04:00
|
|
|
else
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
2020-05-14 18:25:08 -04:00
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-08-19 12:06:30 -04:00
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cert_peer)
|
2021-08-19 12:06:30 -04:00
|
|
|
crt = ssl_sock_get_peer_certificate(ssl);
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
crt = SSL_get_certificate(ssl);
|
|
|
|
|
if (!crt)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.u.sint = (unsigned int)(1 + X509_get_version(crt));
|
|
|
|
|
/* SSL_get_peer_certificate increase X509 * ref count */
|
|
|
|
|
if (cert_peer)
|
|
|
|
|
X509_free(crt);
|
|
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* string, returns the certificate's signature algorithm.
|
|
|
|
|
* The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
|
|
|
|
|
* should be use.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_x_sig_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2020-06-25 14:07:18 -04:00
|
|
|
int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
|
|
|
|
|
int conn_server = (kw[4] == 's') ? 1 : 0;
|
2020-05-14 18:25:08 -04:00
|
|
|
X509 *crt;
|
|
|
|
|
__OPENSSL_110_CONST__ ASN1_OBJECT *algorithm;
|
|
|
|
|
int nid;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
2020-06-25 14:07:18 -04:00
|
|
|
if (conn_server)
|
2022-05-18 10:23:22 -04:00
|
|
|
conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-06-25 14:07:18 -04:00
|
|
|
else
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-08-19 12:06:30 -04:00
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cert_peer)
|
2021-08-19 12:06:30 -04:00
|
|
|
crt = ssl_sock_get_peer_certificate(ssl);
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
crt = SSL_get_certificate(ssl);
|
|
|
|
|
if (!crt)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
X509_ALGOR_get0(&algorithm, NULL, NULL, X509_get0_tbs_sigalg(crt));
|
|
|
|
|
nid = OBJ_obj2nid(algorithm);
|
|
|
|
|
|
|
|
|
|
smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
|
|
|
|
|
if (!smp->data.u.str.area) {
|
|
|
|
|
/* SSL_get_peer_certificate increase X509 * ref count */
|
|
|
|
|
if (cert_peer)
|
|
|
|
|
X509_free(crt);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.u.str.data = strlen(smp->data.u.str.area);
|
|
|
|
|
/* SSL_get_peer_certificate increase X509 * ref count */
|
|
|
|
|
if (cert_peer)
|
|
|
|
|
X509_free(crt);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* string, returns the certificate's key algorithm.
|
|
|
|
|
* The 5th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
|
|
|
|
|
* should be use.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_x_key_alg(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2020-06-25 14:07:18 -04:00
|
|
|
int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
|
|
|
|
|
int conn_server = (kw[4] == 's') ? 1 : 0;
|
2020-05-14 18:25:08 -04:00
|
|
|
X509 *crt;
|
|
|
|
|
ASN1_OBJECT *algorithm;
|
|
|
|
|
int nid;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
2020-06-25 14:07:18 -04:00
|
|
|
if (conn_server)
|
2022-05-18 10:23:22 -04:00
|
|
|
conn = smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-06-25 14:07:18 -04:00
|
|
|
else
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
2020-05-14 18:25:08 -04:00
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-08-19 12:06:30 -04:00
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cert_peer)
|
2021-08-19 12:06:30 -04:00
|
|
|
crt = ssl_sock_get_peer_certificate(ssl);
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
crt = SSL_get_certificate(ssl);
|
|
|
|
|
if (!crt)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
X509_PUBKEY_get0_param(&algorithm, NULL, NULL, NULL, X509_get_X509_PUBKEY(crt));
|
|
|
|
|
nid = OBJ_obj2nid(algorithm);
|
|
|
|
|
|
|
|
|
|
smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
|
|
|
|
|
if (!smp->data.u.str.area) {
|
|
|
|
|
/* SSL_get_peer_certificate increase X509 * ref count */
|
|
|
|
|
if (cert_peer)
|
|
|
|
|
X509_free(crt);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.u.str.data = strlen(smp->data.u.str.area);
|
|
|
|
|
if (cert_peer)
|
|
|
|
|
X509_free(crt);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* boolean, returns true if front conn. transport layer is SSL.
|
|
|
|
|
* This function is also usable on backend conn if the fetch keyword 5th
|
|
|
|
|
* char is 'b'.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
|
|
|
|
|
if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
|
2022-05-27 04:04:04 -04:00
|
|
|
conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
2022-05-18 10:23:22 -04:00
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
smp->data.type = SMP_T_BOOL;
|
2022-04-11 05:29:11 -04:00
|
|
|
smp->data.u.sint = conn_is_ssl(conn);
|
2020-05-14 18:25:08 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* boolean, returns true if client present a SNI */
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_has_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
|
|
|
|
struct connection *conn = objt_conn(smp->sess->origin);
|
|
|
|
|
SSL *ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
|
|
|
|
|
smp->data.type = SMP_T_BOOL;
|
|
|
|
|
smp->data.u.sint = ssl && SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name) != NULL;
|
|
|
|
|
return 1;
|
|
|
|
|
#else
|
|
|
|
|
return 0;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* boolean, returns true if client session has been resumed.
|
|
|
|
|
* This function is also usable on backend conn if the fetch keyword 5th
|
|
|
|
|
* char is 'b'.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_is_resumed(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
|
2022-05-27 04:04:04 -04:00
|
|
|
conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
2022-05-18 10:23:22 -04:00
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
|
|
|
|
|
smp->data.type = SMP_T_BOOL;
|
|
|
|
|
smp->data.u.sint = ssl && SSL_session_reused(ssl);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 09:22:59 -04:00
|
|
|
/*
|
|
|
|
|
* string, returns the EC curve used for key agreement on the
|
|
|
|
|
* front and backend connection.
|
|
|
|
|
*
|
|
|
|
|
* The function to get the curve name (SSL_get_negotiated_group) is only available
|
2025-11-13 10:39:58 -05:00
|
|
|
* in OpenSSLv3 onwards and not for previous versions, and in AWS-LC >= 1.57.0.
|
2023-07-17 09:22:59 -04:00
|
|
|
*/
|
2025-11-13 10:39:58 -05:00
|
|
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x3000000fL) || (defined(OPENSSL_IS_AWSLC) && AWSLC_API_VERSION >= 35)
|
2023-07-17 09:22:59 -04:00
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_ec(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2024-01-09 05:42:51 -05:00
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
int __maybe_unused nid;
|
|
|
|
|
char *curve_name;
|
|
|
|
|
|
|
|
|
|
if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
|
|
|
|
|
conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
|
|
|
|
|
else
|
|
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
|
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
|
|
|
|
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* SSL_get0_group_name is a function to get the curve name and is available from
|
|
|
|
|
* OpenSSL v3.2 onwards. For OpenSSL >=3.0 and <3.2, we will continue to use
|
|
|
|
|
* SSL_get_negotiated_group to get the curve name.
|
|
|
|
|
*/
|
|
|
|
|
# if (HA_OPENSSL_VERSION_NUMBER >= 0x3020000fL)
|
|
|
|
|
curve_name = (char *)SSL_get0_group_name(ssl);
|
|
|
|
|
if (curve_name == NULL) {
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
2024-01-09 09:24:29 -05:00
|
|
|
/*
|
|
|
|
|
* The curve name returned by SSL_get0_group_name is in lowercase whereas the curve
|
|
|
|
|
* name returned when we use `SSL_get_negotiated_group` and `OBJ_nid2sn` is the
|
|
|
|
|
* short name and is in upper case. To make the return value consistent across the
|
|
|
|
|
* different functional calls and to make it consistent while upgrading OpenSSL versions,
|
|
|
|
|
* will convert the curve name returned by SSL_get0_group_name to upper case.
|
|
|
|
|
*/
|
2024-03-25 16:21:47 -04:00
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; curve_name[i]; i++)
|
2024-07-18 07:20:04 -04:00
|
|
|
curve_name[i] = toupper((unsigned char)curve_name[i]);
|
2024-01-09 09:24:29 -05:00
|
|
|
}
|
|
|
|
|
# else
|
|
|
|
|
nid = SSL_get_negotiated_group(ssl);
|
|
|
|
|
if (!nid)
|
|
|
|
|
return 0;
|
|
|
|
|
curve_name = (char *)OBJ_nid2sn(nid);
|
|
|
|
|
if (curve_name == NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
# endif
|
|
|
|
|
|
|
|
|
|
smp->data.u.str.area = curve_name;
|
|
|
|
|
if (!smp->data.u.str.area)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
|
|
|
|
|
smp->data.u.str.data = strlen(smp->data.u.str.area);
|
|
|
|
|
|
|
|
|
|
return 1;
|
2023-07-17 09:22:59 -04:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
/* string, returns the used cipher if front conn. transport layer is SSL.
|
|
|
|
|
* This function is also usable on backend conn if the fetch keyword 5th
|
|
|
|
|
* char is 'b'.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_cipher(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
|
2022-05-27 04:04:04 -04:00
|
|
|
conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
2022-05-18 10:23:22 -04:00
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
smp->flags = 0;
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->data.u.str.area = (char *)SSL_get_cipher_name(ssl);
|
|
|
|
|
if (!smp->data.u.str.area)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.u.str.data = strlen(smp->data.u.str.area);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* integer, returns the algoritm's keysize if front conn. transport layer
|
|
|
|
|
* is SSL.
|
|
|
|
|
* This function is also usable on backend conn if the fetch keyword 5th
|
|
|
|
|
* char is 'b'.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_alg_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
int sint;
|
|
|
|
|
|
|
|
|
|
if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
|
2022-05-27 04:04:04 -04:00
|
|
|
conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
2022-05-18 10:23:22 -04:00
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
smp->flags = 0;
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (!SSL_get_cipher_bits(ssl, &sint))
|
|
|
|
|
return 0;
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.u.sint = sint;
|
|
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* integer, returns the used keysize if front conn. transport layer is SSL.
|
|
|
|
|
* This function is also usable on backend conn if the fetch keyword 5th
|
|
|
|
|
* char is 'b'.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_use_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
|
2022-05-27 04:04:04 -04:00
|
|
|
conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
2022-05-18 10:23:22 -04:00
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
smp->flags = 0;
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->data.u.sint = (unsigned int)SSL_get_cipher_bits(ssl, NULL);
|
|
|
|
|
if (!smp->data.u.sint)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_npn(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
unsigned int len = 0;
|
|
|
|
|
|
|
|
|
|
smp->flags = SMP_F_CONST;
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
|
|
|
|
|
if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
|
2022-05-27 04:04:04 -04:00
|
|
|
conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
2022-05-18 10:23:22 -04:00
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.u.str.area = NULL;
|
|
|
|
|
SSL_get0_next_proto_negotiated(ssl,
|
|
|
|
|
(const unsigned char **)&smp->data.u.str.area,
|
|
|
|
|
&len);
|
|
|
|
|
|
|
|
|
|
if (!smp->data.u.str.area)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->data.u.str.data = len;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_alpn(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
unsigned int len = 0;
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
|
|
|
|
|
if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
|
2022-05-27 04:04:04 -04:00
|
|
|
conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
2022-05-18 10:23:22 -04:00
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->data.u.str.area = NULL;
|
|
|
|
|
SSL_get0_alpn_selected(ssl,
|
|
|
|
|
(const unsigned char **)&smp->data.u.str.area,
|
|
|
|
|
&len);
|
|
|
|
|
|
|
|
|
|
if (!smp->data.u.str.area)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->data.u.str.data = len;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* string, returns the used protocol if front conn. transport layer is SSL.
|
|
|
|
|
* This function is also usable on backend conn if the fetch keyword 5th
|
|
|
|
|
* char is 'b'.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_protocol(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
|
2022-05-27 04:04:04 -04:00
|
|
|
conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
2022-05-18 10:23:22 -04:00
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
smp->flags = 0;
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->data.u.str.area = (char *)SSL_get_version(ssl);
|
|
|
|
|
if (!smp->data.u.str.area)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.u.str.data = strlen(smp->data.u.str.area);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* binary, returns the SSL stream id if front conn. transport layer is SSL.
|
|
|
|
|
* This function is also usable on backend conn if the fetch keyword 5th
|
|
|
|
|
* char is 'b'.
|
|
|
|
|
*/
|
|
|
|
|
#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_session_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL_SESSION *ssl_sess;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
unsigned int len = 0;
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
|
|
|
|
|
if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
|
2022-05-27 04:04:04 -04:00
|
|
|
conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
2022-05-18 10:23:22 -04:00
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
ssl_sess = SSL_get_session(ssl);
|
|
|
|
|
if (!ssl_sess)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->data.u.str.area = (char *)SSL_SESSION_get_id(ssl_sess, &len);
|
|
|
|
|
if (!smp->data.u.str.area || !len)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->data.u.str.data = len;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
2021-03-24 15:41:41 -04:00
|
|
|
#ifdef HAVE_SSL_EXTRACT_RANDOM
|
2020-05-14 18:25:08 -04:00
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_random(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
struct buffer *data;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
|
2022-05-27 04:04:04 -04:00
|
|
|
conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
2022-05-18 10:23:22 -04:00
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
data = get_trash_chunk();
|
|
|
|
|
if (kw[7] == 'c')
|
|
|
|
|
data->data = SSL_get_client_random(ssl,
|
|
|
|
|
(unsigned char *) data->area,
|
|
|
|
|
data->size);
|
|
|
|
|
else
|
|
|
|
|
data->data = SSL_get_server_random(ssl,
|
|
|
|
|
(unsigned char *) data->area,
|
|
|
|
|
data->size);
|
|
|
|
|
if (!data->data)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_TEST;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
smp->data.u.str = *data;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_session_key(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL_SESSION *ssl_sess;
|
|
|
|
|
struct buffer *data;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
|
2022-05-27 04:04:04 -04:00
|
|
|
conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
2022-05-18 10:23:22 -04:00
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
ssl_sess = SSL_get_session(ssl);
|
|
|
|
|
if (!ssl_sess)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
data = get_trash_chunk();
|
|
|
|
|
data->data = SSL_SESSION_get_master_key(ssl_sess,
|
|
|
|
|
(unsigned char *) data->area,
|
|
|
|
|
data->size);
|
|
|
|
|
if (!data->data)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
smp->data.u.str = *data;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-09-29 07:30:12 -04:00
|
|
|
/* ssl_fc_sni and ssl_bc_sni */
|
2020-05-14 18:25:08 -04:00
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_sni(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2021-11-05 14:12:54 -04:00
|
|
|
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
2020-05-14 18:25:08 -04:00
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
|
2025-09-29 07:30:12 -04:00
|
|
|
if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
|
|
|
|
|
conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
|
|
|
|
|
else
|
|
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
|
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->data.u.str.area = (char *)SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
2022-01-07 11:12:01 -05:00
|
|
|
if (!smp->data.u.str.area) {
|
|
|
|
|
/* We might have stored the SNI ourselves, look for it in the
|
|
|
|
|
* context's ex_data.
|
|
|
|
|
*/
|
|
|
|
|
smp->data.u.str.area = SSL_get_ex_data(ssl, ssl_client_sni_index);
|
|
|
|
|
|
|
|
|
|
if (!smp->data.u.str.area)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
smp->data.u.str.data = strlen(smp->data.u.str.area);
|
2022-01-07 11:12:01 -05:00
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
return 1;
|
2021-11-05 14:12:54 -04:00
|
|
|
#else
|
|
|
|
|
/* SNI not supported */
|
|
|
|
|
return 0;
|
2020-05-14 18:25:08 -04:00
|
|
|
#endif
|
2021-11-05 14:12:54 -04:00
|
|
|
}
|
2020-05-14 18:25:08 -04:00
|
|
|
|
2025-09-26 17:17:13 -04:00
|
|
|
#ifdef USE_ECH
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_ech_status(const struct arg *args, struct sample *smp,
|
|
|
|
|
const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct buffer *smp_trash;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
|
|
|
|
|
smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
if (!conn)
|
|
|
|
|
return 0;
|
|
|
|
|
smp_trash = get_trash_chunk();
|
|
|
|
|
if (conn_get_ech_status(conn, smp_trash) == 1) {
|
|
|
|
|
smp->data.u.str.area = smp_trash->area;
|
|
|
|
|
smp->data.u.str.data = smp_trash->data;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_ech_outer_sni(const struct arg *args, struct sample *smp,
|
|
|
|
|
const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct buffer *smp_trash;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
|
|
|
|
|
smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
if (!conn)
|
|
|
|
|
return 0;
|
|
|
|
|
smp_trash = get_trash_chunk();
|
|
|
|
|
if (conn_get_ech_outer_sni(conn, smp_trash) == 1) {
|
|
|
|
|
smp->data.u.str.area = smp_trash->area;
|
|
|
|
|
smp->data.u.str.data = smp_trash->data;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-07-13 09:14:21 -04:00
|
|
|
/* binary, returns tls client hello cipher list.
|
|
|
|
|
* Arguments: filter_option (0,1)
|
|
|
|
|
*/
|
2020-05-14 18:25:08 -04:00
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_cl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2021-07-13 09:14:21 -04:00
|
|
|
struct buffer *smp_trash;
|
2020-05-14 18:25:08 -04:00
|
|
|
struct connection *conn;
|
|
|
|
|
struct ssl_capture *capture;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
|
|
|
|
|
if (!capture)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-07-13 09:14:21 -04:00
|
|
|
if (args[0].data.sint) {
|
|
|
|
|
smp_trash = get_trash_chunk();
|
|
|
|
|
exclude_tls_grease(capture->data + capture->ciphersuite_offset, capture->ciphersuite_len, smp_trash);
|
|
|
|
|
smp->data.u.str.area = smp_trash->area;
|
|
|
|
|
smp->data.u.str.data = smp_trash->data;
|
|
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
smp->data.u.str.area = capture->data + capture->ciphersuite_offset;
|
|
|
|
|
smp->data.u.str.data = capture->ciphersuite_len;
|
|
|
|
|
smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-13 09:14:21 -04:00
|
|
|
/* binary, returns tls client hello cipher list as hexadecimal string.
|
|
|
|
|
* Arguments: filter_option (0,1)
|
|
|
|
|
*/
|
2020-05-14 18:25:08 -04:00
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_cl_hex(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct buffer *data;
|
|
|
|
|
|
|
|
|
|
if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
data = get_trash_chunk();
|
|
|
|
|
dump_binary(data, smp->data.u.str.area, smp->data.u.str.data);
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
smp->data.u.str = *data;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-13 09:14:21 -04:00
|
|
|
/* integer, returns xxh64 hash of tls client hello cipher list. */
|
2020-05-14 18:25:08 -04:00
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_cl_xxh64(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
struct ssl_capture *capture;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
|
|
|
|
|
if (!capture)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
smp->data.u.sint = capture->xxh64;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-29 03:45:51 -04:00
|
|
|
static int
|
2021-09-29 12:56:52 -04:00
|
|
|
smp_fetch_ssl_fc_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
2021-07-29 03:45:51 -04:00
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
struct ssl_sock_ctx *ctx;
|
|
|
|
|
|
2021-09-01 09:52:14 -04:00
|
|
|
if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
|
2022-05-27 04:04:04 -04:00
|
|
|
conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
|
2021-09-01 09:52:14 -04:00
|
|
|
else
|
|
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
2022-05-18 10:23:22 -04:00
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2021-09-01 09:52:14 -04:00
|
|
|
|
2022-04-12 01:40:42 -04:00
|
|
|
if (!conn)
|
2021-07-29 03:45:51 -04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
|
|
|
|
smp->flags = SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-12 01:40:42 -04:00
|
|
|
ctx = conn_get_ssl_sock_ctx(conn);
|
2021-07-29 03:45:51 -04:00
|
|
|
if (!ctx)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
|
|
|
|
smp->data.type = SMP_T_SINT;
|
2021-09-29 12:56:52 -04:00
|
|
|
smp->data.u.sint = ctx->error_code;
|
2021-07-29 03:45:51 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-13 09:14:21 -04:00
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_protocol_hello_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
struct ssl_capture *capture;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
|
|
|
|
|
if (!capture)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
|
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
smp->data.u.sint = capture->protocol_version;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-23 12:15:52 -04:00
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_supver_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct buffer *smp_trash;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
struct ssl_capture *capture;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
|
|
|
|
|
if (!capture)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (args[0].data.sint) {
|
|
|
|
|
smp_trash = get_trash_chunk();
|
|
|
|
|
exclude_tls_grease(capture->data + capture->supver_offset, capture->supver_len, smp_trash);
|
|
|
|
|
smp->data.u.str.area = smp_trash->area;
|
|
|
|
|
smp->data.u.str.data = smp_trash->data;
|
|
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
} else {
|
|
|
|
|
smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
smp->data.u.str.area = capture->data + capture->supver_offset;
|
|
|
|
|
smp->data.u.str.data = capture->supver_len;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-23 14:53:24 -04:00
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_sigalgs_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct buffer *smp_trash;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
struct ssl_capture *capture;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
|
|
|
|
|
if (!capture)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (args[0].data.sint) {
|
|
|
|
|
smp_trash = get_trash_chunk();
|
|
|
|
|
exclude_tls_grease(capture->data + capture->sigalgs_offset, capture->sigalgs_len, smp_trash);
|
|
|
|
|
smp->data.u.str.area = smp_trash->area;
|
|
|
|
|
smp->data.u.str.data = smp_trash->data;
|
|
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
} else {
|
|
|
|
|
smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
smp->data.u.str.area = capture->data + capture->sigalgs_offset;
|
|
|
|
|
smp->data.u.str.data = capture->sigalgs_len;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2024-08-23 12:15:52 -04:00
|
|
|
|
2021-07-29 03:45:51 -04:00
|
|
|
static int
|
2021-09-29 12:56:52 -04:00
|
|
|
smp_fetch_ssl_fc_err_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
2021-07-29 03:45:51 -04:00
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
struct ssl_sock_ctx *ctx;
|
|
|
|
|
const char *err_code_str;
|
|
|
|
|
|
2021-09-01 09:52:14 -04:00
|
|
|
if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
|
2022-05-27 04:04:04 -04:00
|
|
|
conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
|
2021-09-01 09:52:14 -04:00
|
|
|
else
|
|
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
2022-05-18 10:23:22 -04:00
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2021-09-01 09:52:14 -04:00
|
|
|
|
2022-04-12 01:40:42 -04:00
|
|
|
if (!conn)
|
2021-07-29 03:45:51 -04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
|
|
|
|
smp->flags = SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-12 01:40:42 -04:00
|
|
|
ctx = conn_get_ssl_sock_ctx(conn);
|
2021-09-29 12:56:52 -04:00
|
|
|
if (!ctx || !ctx->error_code)
|
2021-07-29 03:45:51 -04:00
|
|
|
return 0;
|
|
|
|
|
|
2021-09-29 12:56:52 -04:00
|
|
|
err_code_str = ERR_error_string(ctx->error_code, NULL);
|
2021-07-29 03:45:51 -04:00
|
|
|
|
|
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
smp->data.u.str.area = (char*)err_code_str;
|
|
|
|
|
smp->data.u.str.data = strlen(err_code_str);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-13 09:14:21 -04:00
|
|
|
/* binary, returns tls client hello extensions list.
|
|
|
|
|
* Arguments: filter_option (0,1)
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_ext_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct buffer *smp_trash;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
struct ssl_capture *capture;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
|
|
|
|
|
if (!capture)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (args[0].data.sint) {
|
|
|
|
|
smp_trash = get_trash_chunk();
|
|
|
|
|
exclude_tls_grease(capture->data + capture->extensions_offset, capture->extensions_len, smp_trash);
|
|
|
|
|
smp->data.u.str.area = smp_trash->area;
|
|
|
|
|
smp->data.u.str.data = smp_trash->data;
|
|
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
smp->data.u.str.area = capture->data + capture->extensions_offset;
|
|
|
|
|
smp->data.u.str.data = capture->extensions_len;
|
|
|
|
|
smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* binary, returns tls client hello supported elliptic curves.
|
|
|
|
|
* Arguments: filter_option (0,1)
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_ecl_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct buffer *smp_trash;
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
struct ssl_capture *capture;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
|
|
|
|
|
if (!capture)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (args[0].data.sint) {
|
|
|
|
|
smp_trash = get_trash_chunk();
|
|
|
|
|
exclude_tls_grease(capture->data + capture->ec_offset, capture->ec_len, smp_trash);
|
|
|
|
|
smp->data.u.str.area = smp_trash->area;
|
|
|
|
|
smp->data.u.str.data = smp_trash->data;
|
|
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
smp->data.u.str.area = capture->data + capture->ec_offset;
|
|
|
|
|
smp->data.u.str.data = capture->ec_len;
|
|
|
|
|
smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* binary, returns tls client hello supported elliptic curve point formats */
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_ecf_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
struct ssl_capture *capture;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
capture = SSL_get_ex_data(ssl, ssl_capture_ptr_index);
|
|
|
|
|
if (!capture)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->flags = SMP_F_VOL_TEST | SMP_F_CONST;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
smp->data.u.str.area = capture->data + capture->ec_formats_offset;
|
|
|
|
|
smp->data.u.str.data = capture->ec_formats_len;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
WIP/MINOR: ssl: add sample fetches for keylog in frontend
OpenSSL 1.1.1 provides a callback registering function
SSL_CTX_set_keylog_callback, which allows one to receive a string
containing the keys to deciphers TLSv1.3.
Unfortunately it is not possible to store this data in binary form and
we can only get this information using the callback. Which means that we
need to store it until the connection is closed.
This patches add 2 pools, the first one, pool_head_ssl_keylog is used to
store a struct ssl_keylog which will be inserted as a ex_data in a SSL *.
The second one is pool_head_ssl_keylog_str which will be used to store
the hexadecimal strings.
To enable the capture of the keys, you need to set "tune.ssl.keylog on"
in your configuration.
The following fetches were implemented:
ssl_fc_client_early_traffic_secret,
ssl_fc_client_handshake_traffic_secret,
ssl_fc_server_handshake_traffic_secret,
ssl_fc_client_traffic_secret_0,
ssl_fc_server_traffic_secret_0,
ssl_fc_exporter_secret,
ssl_fc_early_exporter_secret
2020-07-06 05:41:30 -04:00
|
|
|
/* Dump the SSL keylog, it only works with "tune.ssl.keylog 1" */
|
2021-06-09 10:46:12 -04:00
|
|
|
#ifdef HAVE_SSL_KEYLOG
|
WIP/MINOR: ssl: add sample fetches for keylog in frontend
OpenSSL 1.1.1 provides a callback registering function
SSL_CTX_set_keylog_callback, which allows one to receive a string
containing the keys to deciphers TLSv1.3.
Unfortunately it is not possible to store this data in binary form and
we can only get this information using the callback. Which means that we
need to store it until the connection is closed.
This patches add 2 pools, the first one, pool_head_ssl_keylog is used to
store a struct ssl_keylog which will be inserted as a ex_data in a SSL *.
The second one is pool_head_ssl_keylog_str which will be used to store
the hexadecimal strings.
To enable the capture of the keys, you need to set "tune.ssl.keylog on"
in your configuration.
The following fetches were implemented:
ssl_fc_client_early_traffic_secret,
ssl_fc_client_handshake_traffic_secret,
ssl_fc_server_handshake_traffic_secret,
ssl_fc_client_traffic_secret_0,
ssl_fc_server_traffic_secret_0,
ssl_fc_exporter_secret,
ssl_fc_early_exporter_secret
2020-07-06 05:41:30 -04:00
|
|
|
static int smp_fetch_ssl_x_keylog(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
struct ssl_keylog *keylog;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
char *src = NULL;
|
|
|
|
|
const char *sfx;
|
|
|
|
|
|
2022-11-18 09:00:15 -05:00
|
|
|
if (global_ssl.keylog <= 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
WIP/MINOR: ssl: add sample fetches for keylog in frontend
OpenSSL 1.1.1 provides a callback registering function
SSL_CTX_set_keylog_callback, which allows one to receive a string
containing the keys to deciphers TLSv1.3.
Unfortunately it is not possible to store this data in binary form and
we can only get this information using the callback. Which means that we
need to store it until the connection is closed.
This patches add 2 pools, the first one, pool_head_ssl_keylog is used to
store a struct ssl_keylog which will be inserted as a ex_data in a SSL *.
The second one is pool_head_ssl_keylog_str which will be used to store
the hexadecimal strings.
To enable the capture of the keys, you need to set "tune.ssl.keylog on"
in your configuration.
The following fetches were implemented:
ssl_fc_client_early_traffic_secret,
ssl_fc_client_handshake_traffic_secret,
ssl_fc_server_handshake_traffic_secret,
ssl_fc_client_traffic_secret_0,
ssl_fc_server_traffic_secret_0,
ssl_fc_exporter_secret,
ssl_fc_early_exporter_secret
2020-07-06 05:41:30 -04:00
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
2022-05-18 10:23:22 -04:00
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
WIP/MINOR: ssl: add sample fetches for keylog in frontend
OpenSSL 1.1.1 provides a callback registering function
SSL_CTX_set_keylog_callback, which allows one to receive a string
containing the keys to deciphers TLSv1.3.
Unfortunately it is not possible to store this data in binary form and
we can only get this information using the callback. Which means that we
need to store it until the connection is closed.
This patches add 2 pools, the first one, pool_head_ssl_keylog is used to
store a struct ssl_keylog which will be inserted as a ex_data in a SSL *.
The second one is pool_head_ssl_keylog_str which will be used to store
the hexadecimal strings.
To enable the capture of the keys, you need to set "tune.ssl.keylog on"
in your configuration.
The following fetches were implemented:
ssl_fc_client_early_traffic_secret,
ssl_fc_client_handshake_traffic_secret,
ssl_fc_server_handshake_traffic_secret,
ssl_fc_client_traffic_secret_0,
ssl_fc_server_traffic_secret_0,
ssl_fc_exporter_secret,
ssl_fc_early_exporter_secret
2020-07-06 05:41:30 -04:00
|
|
|
|
2020-07-07 04:48:13 -04:00
|
|
|
if (!conn)
|
|
|
|
|
return 0;
|
|
|
|
|
|
WIP/MINOR: ssl: add sample fetches for keylog in frontend
OpenSSL 1.1.1 provides a callback registering function
SSL_CTX_set_keylog_callback, which allows one to receive a string
containing the keys to deciphers TLSv1.3.
Unfortunately it is not possible to store this data in binary form and
we can only get this information using the callback. Which means that we
need to store it until the connection is closed.
This patches add 2 pools, the first one, pool_head_ssl_keylog is used to
store a struct ssl_keylog which will be inserted as a ex_data in a SSL *.
The second one is pool_head_ssl_keylog_str which will be used to store
the hexadecimal strings.
To enable the capture of the keys, you need to set "tune.ssl.keylog on"
in your configuration.
The following fetches were implemented:
ssl_fc_client_early_traffic_secret,
ssl_fc_client_handshake_traffic_secret,
ssl_fc_server_handshake_traffic_secret,
ssl_fc_client_traffic_secret_0,
ssl_fc_server_traffic_secret_0,
ssl_fc_exporter_secret,
ssl_fc_early_exporter_secret
2020-07-06 05:41:30 -04:00
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT) {
|
|
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
keylog = SSL_get_ex_data(ssl, ssl_keylog_index);
|
|
|
|
|
if (!keylog)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
sfx = kw + strlen("ssl_xx_");
|
|
|
|
|
|
|
|
|
|
if (strcmp(sfx, "client_early_traffic_secret") == 0) {
|
|
|
|
|
src = keylog->client_early_traffic_secret;
|
|
|
|
|
} else if (strcmp(sfx, "client_handshake_traffic_secret") == 0) {
|
|
|
|
|
src = keylog->client_handshake_traffic_secret;
|
|
|
|
|
} else if (strcmp(sfx, "server_handshake_traffic_secret") == 0) {
|
|
|
|
|
src = keylog->server_handshake_traffic_secret;
|
|
|
|
|
} else if (strcmp(sfx, "client_traffic_secret_0") == 0) {
|
|
|
|
|
src = keylog->client_traffic_secret_0;
|
|
|
|
|
} else if (strcmp(sfx, "server_traffic_secret_0") == 0) {
|
|
|
|
|
src = keylog->server_traffic_secret_0;
|
|
|
|
|
} else if (strcmp(sfx, "exporter_secret") == 0) {
|
|
|
|
|
src = keylog->exporter_secret;
|
|
|
|
|
} else if (strcmp(sfx, "early_exporter_secret") == 0) {
|
|
|
|
|
src = keylog->early_exporter_secret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!src || !*src)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
smp->data.u.str.area = src;
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags |= SMP_F_VOL_TEST | SMP_F_CONST;
|
WIP/MINOR: ssl: add sample fetches for keylog in frontend
OpenSSL 1.1.1 provides a callback registering function
SSL_CTX_set_keylog_callback, which allows one to receive a string
containing the keys to deciphers TLSv1.3.
Unfortunately it is not possible to store this data in binary form and
we can only get this information using the callback. Which means that we
need to store it until the connection is closed.
This patches add 2 pools, the first one, pool_head_ssl_keylog is used to
store a struct ssl_keylog which will be inserted as a ex_data in a SSL *.
The second one is pool_head_ssl_keylog_str which will be used to store
the hexadecimal strings.
To enable the capture of the keys, you need to set "tune.ssl.keylog on"
in your configuration.
The following fetches were implemented:
ssl_fc_client_early_traffic_secret,
ssl_fc_client_handshake_traffic_secret,
ssl_fc_server_handshake_traffic_secret,
ssl_fc_client_traffic_secret_0,
ssl_fc_server_traffic_secret_0,
ssl_fc_exporter_secret,
ssl_fc_early_exporter_secret
2020-07-06 05:41:30 -04:00
|
|
|
smp->data.u.str.data = strlen(smp->data.u.str.area);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_cl_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2020-10-30 17:10:02 -04:00
|
|
|
#if defined(OPENSSL_IS_BORINGSSL) || defined(SSL_CTRL_GET_RAW_CIPHERLIST)
|
2020-05-14 18:25:08 -04:00
|
|
|
struct buffer *data;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (!smp_fetch_ssl_fc_cl_bin(args, smp, kw, private))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
data = get_trash_chunk();
|
|
|
|
|
for (i = 0; i + 1 < smp->data.u.str.data; i += 2) {
|
|
|
|
|
const char *str;
|
|
|
|
|
const SSL_CIPHER *cipher;
|
|
|
|
|
const unsigned char *bin = (const unsigned char *) smp->data.u.str.area + i;
|
|
|
|
|
uint16_t id = (bin[0] << 8) | bin[1];
|
|
|
|
|
#if defined(OPENSSL_IS_BORINGSSL)
|
|
|
|
|
cipher = SSL_get_cipher_by_value(id);
|
|
|
|
|
#else
|
|
|
|
|
struct connection *conn = __objt_conn(smp->sess->origin);
|
|
|
|
|
SSL *ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
cipher = SSL_CIPHER_find(ssl, bin);
|
|
|
|
|
#endif
|
|
|
|
|
str = SSL_CIPHER_get_name(cipher);
|
|
|
|
|
if (!str || strcmp(str, "(NONE)") == 0)
|
|
|
|
|
chunk_appendf(data, "%sUNKNOWN(%04x)", i == 0 ? "" : ",", id);
|
|
|
|
|
else
|
|
|
|
|
chunk_appendf(data, "%s%s", i == 0 ? "" : ",", str);
|
|
|
|
|
}
|
|
|
|
|
smp->data.type = SMP_T_STR;
|
|
|
|
|
smp->data.u.str = *data;
|
|
|
|
|
return 1;
|
|
|
|
|
#else
|
|
|
|
|
return smp_fetch_ssl_fc_cl_xxh64(args, smp, kw, private);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_fc_unique_id(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
int finished_len;
|
|
|
|
|
struct buffer *finished_trash;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
|
2022-05-27 04:04:04 -04:00
|
|
|
conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
else
|
|
|
|
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
2022-05-18 10:23:22 -04:00
|
|
|
smp->strm ? sc_conn(smp->strm->scb) : NULL;
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
smp->flags = 0;
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT) {
|
|
|
|
|
smp->flags |= SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
finished_trash = get_trash_chunk();
|
|
|
|
|
if (!SSL_session_reused(ssl))
|
|
|
|
|
finished_len = SSL_get_peer_finished(ssl,
|
|
|
|
|
finished_trash->area,
|
|
|
|
|
finished_trash->size);
|
|
|
|
|
else
|
|
|
|
|
finished_len = SSL_get_finished(ssl,
|
|
|
|
|
finished_trash->area,
|
|
|
|
|
finished_trash->size);
|
|
|
|
|
|
|
|
|
|
if (!finished_len)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
finished_trash->data = finished_len;
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.u.str = *finished_trash;
|
|
|
|
|
smp->data.type = SMP_T_BIN;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* integer, returns the first verify error in CA chain of client certificate chain. */
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_c_ca_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2022-04-11 05:29:11 -04:00
|
|
|
struct connection *conn = objt_conn(smp->sess->origin);
|
|
|
|
|
struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
|
2020-05-14 18:25:08 -04:00
|
|
|
|
2022-04-11 05:29:11 -04:00
|
|
|
if (conn && conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->flags = SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-29 03:45:50 -04:00
|
|
|
if (!ctx)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
smp->data.u.sint = (unsigned long long int)SSL_SOCK_ST_TO_CA_ERROR(ctx->xprt_st);
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* integer, returns the depth of the first verify error in CA chain of client certificate chain. */
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_c_ca_err_depth(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2022-04-11 05:29:11 -04:00
|
|
|
struct connection *conn = objt_conn(smp->sess->origin);
|
|
|
|
|
struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
|
2020-05-14 18:25:08 -04:00
|
|
|
|
2022-04-11 05:29:11 -04:00
|
|
|
if (conn && conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->flags = SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-29 03:45:50 -04:00
|
|
|
if (!ctx)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CAEDEPTH(ctx->xprt_st);
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* integer, returns the first verify error on client certificate */
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_c_err(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
2022-04-11 05:29:11 -04:00
|
|
|
struct connection *conn = objt_conn(smp->sess->origin);
|
|
|
|
|
struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
|
2020-05-14 18:25:08 -04:00
|
|
|
|
2022-04-11 05:29:11 -04:00
|
|
|
if (conn && conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) {
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->flags = SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-29 03:45:50 -04:00
|
|
|
if (!ctx)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
smp->data.u.sint = (long long int)SSL_SOCK_ST_TO_CRTERROR(ctx->xprt_st);
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* integer, returns the verify result on client cert */
|
|
|
|
|
static int
|
|
|
|
|
smp_fetch_ssl_c_verify(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
|
|
|
|
{
|
|
|
|
|
struct connection *conn;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
|
|
|
|
|
conn = objt_conn(smp->sess->origin);
|
|
|
|
|
ssl = ssl_sock_get_ssl_object(conn);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (conn->flags & CO_FL_WAIT_XPRT) {
|
|
|
|
|
smp->flags = SMP_F_MAY_CHANGE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
smp->data.type = SMP_T_SINT;
|
|
|
|
|
smp->data.u.sint = (long long int)SSL_get_verify_result(ssl);
|
2020-10-15 10:41:08 -04:00
|
|
|
smp->flags = SMP_F_VOL_SESS;
|
2020-05-14 18:25:08 -04:00
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Argument validation functions */
|
|
|
|
|
|
|
|
|
|
/* This function is used to validate the arguments passed to any "x_dn" ssl
|
|
|
|
|
* keywords. These keywords support specifying a third parameter that must be
|
|
|
|
|
* either empty or the value "rfc2253". Returns 0 on error, non-zero if OK.
|
|
|
|
|
*/
|
|
|
|
|
int val_dnfmt(struct arg *arg, char **err_msg)
|
|
|
|
|
{
|
|
|
|
|
if (arg && arg[2].type == ARGT_STR && arg[2].data.str.data > 0 && (strcmp(arg[2].data.str.area, "rfc2253") != 0)) {
|
|
|
|
|
memprintf(err_msg, "only rfc2253 or a blank value are currently supported as the format argument.");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Note: must not be declared <const> as its list will be overwritten.
|
|
|
|
|
* Please take care of keeping this list alphabetically sorted.
|
|
|
|
|
*/
|
|
|
|
|
static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
|
|
|
|
|
{ "ssl_bc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
|
|
|
|
|
{ "ssl_bc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
|
|
|
|
|
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
|
|
|
|
|
{ "ssl_bc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
|
|
|
|
|
#endif
|
|
|
|
|
{ "ssl_bc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
|
2025-11-13 10:39:58 -05:00
|
|
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x3000000fL) || (defined(OPENSSL_IS_AWSLC) && AWSLC_API_VERSION >= 35)
|
2023-07-17 09:22:59 -04:00
|
|
|
{ "ssl_bc_curve", smp_fetch_ssl_fc_ec, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
|
|
|
|
|
#endif
|
2020-05-14 18:25:08 -04:00
|
|
|
#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
|
|
|
|
|
{ "ssl_bc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
|
|
|
|
|
#endif
|
|
|
|
|
{ "ssl_bc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5SRV },
|
|
|
|
|
{ "ssl_bc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
|
|
|
|
|
{ "ssl_bc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
|
|
|
|
|
{ "ssl_bc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
|
|
|
|
|
#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
|
|
|
|
|
{ "ssl_bc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
|
|
|
|
|
#endif
|
2021-03-24 15:41:41 -04:00
|
|
|
#ifdef HAVE_SSL_EXTRACT_RANDOM
|
2020-05-14 18:25:08 -04:00
|
|
|
{ "ssl_bc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
|
|
|
|
|
{ "ssl_bc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
|
|
|
|
|
{ "ssl_bc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5SRV },
|
2024-04-19 08:29:05 -04:00
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_SSL_KEYLOG
|
|
|
|
|
{ "ssl_bc_client_early_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_bc_client_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_bc_server_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_bc_client_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_bc_server_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_bc_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_bc_early_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
2020-05-14 18:25:08 -04:00
|
|
|
#endif
|
2021-09-29 12:56:52 -04:00
|
|
|
{ "ssl_bc_err", smp_fetch_ssl_fc_err, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
|
|
|
|
|
{ "ssl_bc_err_str", smp_fetch_ssl_fc_err_str, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
|
2025-09-29 07:30:12 -04:00
|
|
|
{ "ssl_bc_sni", smp_fetch_ssl_fc_sni, 0, NULL, SMP_T_STR, SMP_USE_L5SRV },
|
2020-05-14 18:25:08 -04:00
|
|
|
{ "ssl_c_ca_err", smp_fetch_ssl_c_ca_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_c_ca_err_depth", smp_fetch_ssl_c_ca_err_depth, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_c_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
2020-08-06 12:11:38 -04:00
|
|
|
{ "ssl_c_chain_der", smp_fetch_ssl_x_chain_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
2020-05-14 18:25:08 -04:00
|
|
|
{ "ssl_c_err", smp_fetch_ssl_c_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_c_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_c_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_c_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_c_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
2023-05-15 06:05:55 -04:00
|
|
|
#ifdef HAVE_SSL_get0_verified_chain
|
2023-05-13 23:04:45 -04:00
|
|
|
{ "ssl_c_r_dn", smp_fetch_ssl_r_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
|
2023-05-15 06:05:55 -04:00
|
|
|
#endif
|
2020-05-14 18:25:08 -04:00
|
|
|
{ "ssl_c_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
2023-02-27 16:16:06 -05:00
|
|
|
{ "ssl_c_san", smp_fetch_ssl_x_san, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
2020-05-14 18:25:08 -04:00
|
|
|
{ "ssl_c_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_c_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_c_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_c_used", smp_fetch_ssl_c_used, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_c_verify", smp_fetch_ssl_c_verify, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_c_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_f_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_f_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_f_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_f_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_f_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_f_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_f_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_f_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_f_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_f_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc", smp_fetch_ssl_fc, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_alg_keysize", smp_fetch_ssl_fc_alg_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_cipher", smp_fetch_ssl_fc_cipher, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
2025-11-13 10:39:58 -05:00
|
|
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x3000000fL) || (defined(OPENSSL_IS_AWSLC) && AWSLC_API_VERSION >= 35)
|
2023-07-17 09:22:59 -04:00
|
|
|
{ "ssl_fc_curve", smp_fetch_ssl_fc_ec, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
#endif
|
2025-10-29 03:03:01 -04:00
|
|
|
{ "ssl_fc_early_rcvd", smp_fetch_ssl_fc_early_rcvd, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
|
2020-05-14 18:25:08 -04:00
|
|
|
{ "ssl_fc_has_crt", smp_fetch_ssl_fc_has_crt, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_has_early", smp_fetch_ssl_fc_has_early, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_has_sni", smp_fetch_ssl_fc_has_sni, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_is_resumed", smp_fetch_ssl_fc_is_resumed, 0, NULL, SMP_T_BOOL, SMP_USE_L5CLI },
|
|
|
|
|
#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
|
|
|
|
|
{ "ssl_fc_npn", smp_fetch_ssl_fc_npn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
|
|
|
|
|
{ "ssl_fc_alpn", smp_fetch_ssl_fc_alpn, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
#endif
|
|
|
|
|
{ "ssl_fc_protocol", smp_fetch_ssl_fc_protocol, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
|
|
|
|
|
{ "ssl_fc_unique_id", smp_fetch_ssl_fc_unique_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
|
|
|
|
#endif
|
|
|
|
|
{ "ssl_fc_use_keysize", smp_fetch_ssl_fc_use_keysize, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
|
|
|
|
|
#if HA_OPENSSL_VERSION_NUMBER > 0x0090800fL
|
|
|
|
|
{ "ssl_fc_session_id", smp_fetch_ssl_fc_session_id, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
|
|
|
|
#endif
|
2021-03-24 15:41:41 -04:00
|
|
|
#ifdef HAVE_SSL_EXTRACT_RANDOM
|
2020-05-14 18:25:08 -04:00
|
|
|
{ "ssl_fc_client_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
|
|
|
|
#endif
|
WIP/MINOR: ssl: add sample fetches for keylog in frontend
OpenSSL 1.1.1 provides a callback registering function
SSL_CTX_set_keylog_callback, which allows one to receive a string
containing the keys to deciphers TLSv1.3.
Unfortunately it is not possible to store this data in binary form and
we can only get this information using the callback. Which means that we
need to store it until the connection is closed.
This patches add 2 pools, the first one, pool_head_ssl_keylog is used to
store a struct ssl_keylog which will be inserted as a ex_data in a SSL *.
The second one is pool_head_ssl_keylog_str which will be used to store
the hexadecimal strings.
To enable the capture of the keys, you need to set "tune.ssl.keylog on"
in your configuration.
The following fetches were implemented:
ssl_fc_client_early_traffic_secret,
ssl_fc_client_handshake_traffic_secret,
ssl_fc_server_handshake_traffic_secret,
ssl_fc_client_traffic_secret_0,
ssl_fc_server_traffic_secret_0,
ssl_fc_exporter_secret,
ssl_fc_early_exporter_secret
2020-07-06 05:41:30 -04:00
|
|
|
|
2021-06-09 10:46:12 -04:00
|
|
|
#ifdef HAVE_SSL_KEYLOG
|
WIP/MINOR: ssl: add sample fetches for keylog in frontend
OpenSSL 1.1.1 provides a callback registering function
SSL_CTX_set_keylog_callback, which allows one to receive a string
containing the keys to deciphers TLSv1.3.
Unfortunately it is not possible to store this data in binary form and
we can only get this information using the callback. Which means that we
need to store it until the connection is closed.
This patches add 2 pools, the first one, pool_head_ssl_keylog is used to
store a struct ssl_keylog which will be inserted as a ex_data in a SSL *.
The second one is pool_head_ssl_keylog_str which will be used to store
the hexadecimal strings.
To enable the capture of the keys, you need to set "tune.ssl.keylog on"
in your configuration.
The following fetches were implemented:
ssl_fc_client_early_traffic_secret,
ssl_fc_client_handshake_traffic_secret,
ssl_fc_server_handshake_traffic_secret,
ssl_fc_client_traffic_secret_0,
ssl_fc_server_traffic_secret_0,
ssl_fc_exporter_secret,
ssl_fc_early_exporter_secret
2020-07-06 05:41:30 -04:00
|
|
|
{ "ssl_fc_client_early_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_client_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_server_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_client_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_server_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_early_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
{ "ssl_fc_sni", smp_fetch_ssl_fc_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
2025-09-26 17:17:13 -04:00
|
|
|
#ifdef USE_ECH
|
|
|
|
|
{ "ssl_fc_ech_status", smp_fetch_ssl_fc_ech_status, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_ech_outer_sni", smp_fetch_ssl_fc_ech_outer_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
#endif
|
2021-07-13 09:14:21 -04:00
|
|
|
{ "ssl_fc_cipherlist_bin", smp_fetch_ssl_fc_cl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_cipherlist_hex", smp_fetch_ssl_fc_cl_hex, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_cipherlist_str", smp_fetch_ssl_fc_cl_str, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
|
2020-05-14 18:25:08 -04:00
|
|
|
{ "ssl_fc_cipherlist_xxh", smp_fetch_ssl_fc_cl_xxh64, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
|
2021-09-29 12:56:52 -04:00
|
|
|
{ "ssl_fc_err", smp_fetch_ssl_fc_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_err_str", smp_fetch_ssl_fc_err_str, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
2021-07-13 09:14:21 -04:00
|
|
|
{ "ssl_fc_protocol_hello_id",smp_fetch_ssl_fc_protocol_hello_id,0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_extlist_bin", smp_fetch_ssl_fc_ext_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_eclist_bin", smp_fetch_ssl_fc_ecl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_fc_ecformats_bin", smp_fetch_ssl_fc_ecf_bin, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
2024-08-23 12:15:52 -04:00
|
|
|
{ "ssl_fc_supported_versions_bin", smp_fetch_ssl_fc_supver_bin, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
2024-08-23 14:53:24 -04:00
|
|
|
{ "ssl_fc_sigalgs_bin", smp_fetch_ssl_fc_sigalgs_bin, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
2020-06-25 14:07:18 -04:00
|
|
|
|
|
|
|
|
/* SSL server certificate fetches */
|
|
|
|
|
{ "ssl_s_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
2020-08-06 12:11:38 -04:00
|
|
|
{ "ssl_s_chain_der", smp_fetch_ssl_x_chain_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
2020-06-25 14:07:18 -04:00
|
|
|
{ "ssl_s_key_alg", smp_fetch_ssl_x_key_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_s_notafter", smp_fetch_ssl_x_notafter, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_s_notbefore", smp_fetch_ssl_x_notbefore, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_s_sig_alg", smp_fetch_ssl_x_sig_alg, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_s_s_dn", smp_fetch_ssl_x_s_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_s_i_dn", smp_fetch_ssl_x_i_dn, ARG3(0,STR,SINT,STR),val_dnfmt, SMP_T_STR, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_s_serial", smp_fetch_ssl_x_serial, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_s_sha1", smp_fetch_ssl_x_sha1, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
|
|
|
|
{ "ssl_s_version", smp_fetch_ssl_x_version, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
|
2020-05-14 18:25:08 -04:00
|
|
|
{ NULL, NULL, 0, 0, 0 },
|
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
|
|
|
|
|
|
2021-10-06 09:37:17 -04:00
|
|
|
/* Note: must not be declared <const> as its list will be overwritten */
|
|
|
|
|
static struct sample_conv_kw_list sample_conv_kws = {ILH, {
|
|
|
|
|
{ "sha2", sample_conv_sha2, ARG1(0, SINT), smp_check_sha2, SMP_T_BIN, SMP_T_BIN },
|
|
|
|
|
#ifdef EVP_CIPH_GCM_MODE
|
2026-01-13 05:50:54 -05:00
|
|
|
{ "aes_gcm_enc", sample_conv_aes, ARG5(4,SINT,STR,STR,STR,STR), check_aes, SMP_T_BIN, SMP_T_BIN },
|
|
|
|
|
{ "aes_gcm_dec", sample_conv_aes, ARG5(4,SINT,STR,STR,STR,STR), check_aes, SMP_T_BIN, SMP_T_BIN },
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef EVP_CIPH_CBC_MODE
|
|
|
|
|
{ "aes_cbc_enc", sample_conv_aes, ARG4(3,SINT,STR,STR,STR), check_aes, SMP_T_BIN, SMP_T_BIN },
|
|
|
|
|
{ "aes_cbc_dec", sample_conv_aes, ARG4(3,SINT,STR,STR,STR), check_aes, SMP_T_BIN, SMP_T_BIN },
|
2021-10-06 09:37:17 -04:00
|
|
|
#endif
|
2022-11-03 13:56:37 -04:00
|
|
|
{ "x509_v_err_str", sample_conv_x509_v_err, 0, NULL, SMP_T_SINT, SMP_T_STR },
|
2021-10-06 09:37:17 -04:00
|
|
|
{ "digest", sample_conv_crypto_digest, ARG1(1,STR), check_crypto_digest, SMP_T_BIN, SMP_T_BIN },
|
|
|
|
|
{ "hmac", sample_conv_crypto_hmac, ARG2(2,STR,STR), check_crypto_hmac, SMP_T_BIN, SMP_T_BIN },
|
|
|
|
|
#if defined(HAVE_CRYPTO_memcmp)
|
|
|
|
|
{ "secure_memcmp", sample_conv_secure_memcmp, ARG1(1,STR), smp_check_secure_memcmp, SMP_T_BIN, SMP_T_BOOL },
|
|
|
|
|
#endif
|
|
|
|
|
{ NULL, NULL, 0, 0, 0 },
|
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
|
|
|
|
|
|
|
|
|
|
|
2020-05-14 18:25:08 -04:00
|
|
|
/* Note: must not be declared <const> as its list will be overwritten.
|
|
|
|
|
* Please take care of keeping this list alphabetically sorted.
|
|
|
|
|
*/
|
|
|
|
|
static struct acl_kw_list acl_kws = {ILH, {
|
|
|
|
|
{ "ssl_fc_sni_end", "ssl_fc_sni", PAT_MATCH_END },
|
|
|
|
|
{ "ssl_fc_sni_reg", "ssl_fc_sni", PAT_MATCH_REG },
|
|
|
|
|
{ /* END */ },
|
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
|