Skip to content
1 change: 1 addition & 0 deletions include/fluent-bit/flb_input.h
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ struct flb_input_instance {
char *tls_crt_file; /* Certificate */
char *tls_key_file; /* Cert Key */
char *tls_key_passwd; /* Cert Key Password */
char *tls_crl_file; /* Certificate Revocation List */
char *tls_min_version; /* Minimum protocol version of TLS */
char *tls_max_version; /* Maximum protocol version of TLS */
char *tls_ciphers; /* TLS ciphers */
Expand Down
1 change: 1 addition & 0 deletions include/fluent-bit/flb_output.h
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ struct flb_output_instance {
char *tls_crt_file; /* Certificate */
char *tls_key_file; /* Cert Key */
char *tls_key_passwd; /* Cert Key Password */
char *tls_crl_file; /* Certificate Revocation List */
char *tls_min_version; /* Minimum protocol version of TLS */
char *tls_max_version; /* Maximum protocol version of TLS */
char *tls_ciphers; /* TLS ciphers */
Expand Down
2 changes: 2 additions & 0 deletions include/fluent-bit/tls/flb_tls.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ struct flb_tls_backend {
/* Additional settings */
int (*context_alpn_set) (void *, const char *);
int (*context_set_verify_client) (void *, int);
int (*context_set_crl_file) (void *, const char *);

/* TLS Protocol version */
int (*set_minmax_proto) (struct flb_tls *tls, const char *, const char *);
Expand Down Expand Up @@ -170,6 +171,7 @@ int flb_tls_reload_if_needed(struct flb_tls *tls);

int flb_tls_set_alpn(struct flb_tls *tls, const char *alpn);
int flb_tls_set_verify_client(struct flb_tls *tls, int verify_client);
int flb_tls_set_crl_file(struct flb_tls *tls, const char *crl_file);

int flb_tls_set_verify_hostname(struct flb_tls *tls, int verify_hostname);
#if defined(FLB_SYSTEM_WINDOWS)
Expand Down
18 changes: 18 additions & 0 deletions src/flb_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,7 @@ struct flb_input_instance *flb_input_new(struct flb_config *config,
instance->tls_crt_file = NULL;
instance->tls_key_file = NULL;
instance->tls_key_passwd = NULL;
instance->tls_crl_file = NULL;
#endif

/* Plugin requires a co-routine context ? */
Expand Down Expand Up @@ -885,6 +886,9 @@ int flb_input_set_property(struct flb_input_instance *ins,
else if (prop_key_check("tls.key_passwd", k, len) == 0) {
flb_utils_set_plugin_string_property("tls.key_passwd", &ins->tls_key_passwd, tmp);
}
else if (prop_key_check("tls.crl_file", k, len) == 0) {
flb_utils_set_plugin_string_property("tls.crl_file", &ins->tls_crl_file, tmp);
}
else if (prop_key_check("tls.min_version", k, len) == 0) {
flb_utils_set_plugin_string_property("tls.min_version", &ins->tls_min_version, tmp);
}
Expand Down Expand Up @@ -1073,6 +1077,10 @@ void flb_input_instance_destroy(struct flb_input_instance *ins)
flb_sds_destroy(ins->tls_key_file);
}

if (ins->tls_crl_file) {
flb_sds_destroy(ins->tls_crl_file);
}

if (ins->tls_key_passwd) {
flb_sds_destroy(ins->tls_key_passwd);
}
Expand Down Expand Up @@ -1719,6 +1727,16 @@ int flb_input_instance_init(struct flb_input_instance *ins,
return -1;
}
}

if (ins->tls_crl_file != NULL) {
ret = flb_tls_set_crl_file(ins->tls, ins->tls_crl_file);
if (ret != 0) {
flb_error("[input %s] error setting up TLS CRL file",
ins->name);

return -1;
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

struct flb_config_map *m;
Expand Down
17 changes: 17 additions & 0 deletions src/flb_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ static void flb_output_free_properties(struct flb_output_instance *ins)
if (ins->tls_key_passwd) {
flb_sds_destroy(ins->tls_key_passwd);
}
if (ins->tls_crl_file) {
flb_sds_destroy(ins->tls_crl_file);
}
if (ins->tls_min_version) {
flb_sds_destroy(ins->tls_min_version);
}
Expand Down Expand Up @@ -844,6 +847,7 @@ struct flb_output_instance *flb_output_new(struct flb_config *config,
instance->tls_crt_file = NULL;
instance->tls_key_file = NULL;
instance->tls_key_passwd = NULL;
instance->tls_crl_file = NULL;
# if defined(FLB_SYSTEM_WINDOWS)
instance->tls_win_certstore_name = NULL;
instance->tls_win_use_enterprise_certstore = FLB_FALSE;
Expand Down Expand Up @@ -1105,6 +1109,9 @@ int flb_output_set_property(struct flb_output_instance *ins,
else if (prop_key_check("tls.key_passwd", k, len) == 0) {
flb_utils_set_plugin_string_property("tls.key_passwd", &ins->tls_key_passwd, tmp);
}
else if (prop_key_check("tls.crl_file", k, len) == 0) {
flb_utils_set_plugin_string_property("tls.crl_file", &ins->tls_crl_file, tmp);
}
else if (prop_key_check("tls.min_version", k, len) == 0) {
flb_utils_set_plugin_string_property("tls.min_version", &ins->tls_min_version, tmp);
}
Expand Down Expand Up @@ -1637,6 +1644,16 @@ int flb_output_init_all(struct flb_config *config)
}
}

if (ins->tls_crl_file != NULL) {
ret = flb_tls_set_crl_file(ins->tls, ins->tls_crl_file);
Comment thread
egershonNvidia marked this conversation as resolved.
if (ret != 0) {
flb_error("[output %s] error setting up TLS CRL file",
ins->name);
flb_output_instance_destroy(ins);
return -1;
}
}

# if defined (FLB_SYSTEM_WINDOWS)
if (ins->tls_win_use_enterprise_certstore) {
ret = flb_tls_set_use_enterprise_store(ins->tls, ins->tls_win_use_enterprise_certstore);
Expand Down
19 changes: 19 additions & 0 deletions src/tls/flb_tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ struct flb_config_map tls_configmap[] = {
"Optional password for tls.key_file file"
},

{
FLB_CONFIG_MAP_STR, "tls.crl_file", NULL,
0, FLB_FALSE, 0,
"Absolute path to a Certificate Revocation List (CRL) file in PEM format"
},

{
FLB_CONFIG_MAP_STR, "tls.vhost", NULL,
0, FLB_FALSE, 0,
Expand Down Expand Up @@ -590,6 +596,19 @@ int flb_tls_set_verify_client(struct flb_tls *tls, int verify_client)
return 0;
}

int flb_tls_set_crl_file(struct flb_tls *tls, const char *crl_file)
{
if (!tls) {
return -1;
}

if (tls->ctx && tls->api->context_set_crl_file) {
return tls->api->context_set_crl_file(tls->ctx, crl_file);
}

return 0;
}

Comment thread
coderabbitai[bot] marked this conversation as resolved.
int flb_tls_set_verify_hostname(struct flb_tls *tls, int verify_hostname)
{
if (!tls) {
Expand Down
67 changes: 65 additions & 2 deletions src/tls/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <openssl/err.h>
#include <openssl/opensslv.h>
#include <openssl/x509v3.h>
#include <openssl/pem.h>

#ifdef FLB_SYSTEM_MACOS
#include <Security/Security.h>
Expand Down Expand Up @@ -455,6 +456,67 @@ static int tls_context_set_verify_client(void *ctx_backend, int verify_client)
return 0;
}

static int tls_context_set_crl_file(void *ctx_backend, const char *crl_file)
{
struct tls_context *ctx = ctx_backend;
X509_STORE *store;
X509_CRL *crl;
BIO *bio;
char err_buf[256];
int loaded = 0;

if (crl_file == NULL) {
return 0;
}

pthread_mutex_lock(&ctx->mutex);

store = SSL_CTX_get_cert_store(ctx->ctx);
if (store == NULL) {
flb_error("[tls] could not retrieve certificate store for CRL");
pthread_mutex_unlock(&ctx->mutex);
return -1;
}

bio = BIO_new_file(crl_file, "r");
if (bio == NULL) {
ERR_error_string_n(ERR_get_error(), err_buf, sizeof(err_buf) - 1);
flb_error("[tls] crl_file '%s': %s", crl_file, err_buf);
pthread_mutex_unlock(&ctx->mutex);
return -1;
}

while ((crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL)) != NULL) {
if (X509_STORE_add_crl(store, crl) != 1) {
ERR_error_string_n(ERR_get_error(), err_buf, sizeof(err_buf) - 1);
flb_warn("[tls] could not add CRL from '%s': %s", crl_file, err_buf);
}
else {
loaded++;
}
X509_CRL_free(crl);
}
BIO_free(bio);

// PEM_read_bio_X509_CRL leaves a benign EOF error on the stack
ERR_clear_error();

if (loaded == 0) {
flb_error("[tls] no CRL entries loaded from '%s'", crl_file);
pthread_mutex_unlock(&ctx->mutex);
return -1;
}

X509_STORE_set_flags(store,
X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);

pthread_mutex_unlock(&ctx->mutex);

flb_debug("[tls] loaded %i CRL entrie(s) from '%s'", loaded, crl_file);

return 0;
}

#ifdef _MSC_VER
/* Parse certstore_name prefix like
*
Expand Down Expand Up @@ -715,7 +777,7 @@ static int windows_load_system_certificates(struct tls_context *ctx)
return -1;
}

flb_debug("[tls] successfully loaded certificates from windows system %s store.",
flb_debug("[tls] successfully loaded certificates from windows system %s store.",
configured_name);
return 0;
}
Expand Down Expand Up @@ -1250,7 +1312,7 @@ static unsigned char *hex_to_bytes(const char *hex, size_t *out_len) {
return buf;
}

static int windows_set_allowed_thumbprints(struct tls_context *ctx, const char *thumbprints)
static int windows_set_allowed_thumbprints(struct tls_context *ctx, const char *thumbprints)
{
char *token_ctx = NULL, *tok = NULL;
size_t cap = 4, count = 0;
Expand Down Expand Up @@ -1926,6 +1988,7 @@ static struct flb_tls_backend tls_openssl = {
.context_destroy = tls_context_destroy,
.context_alpn_set = tls_context_alpn_set,
.context_set_verify_client = tls_context_set_verify_client,
.context_set_crl_file = tls_context_set_crl_file,
.session_alpn_get = tls_session_alpn_get,
.set_minmax_proto = tls_set_minmax_proto,
.set_ciphers = tls_set_ciphers,
Expand Down
81 changes: 81 additions & 0 deletions tests/internal/upstream_tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,83 @@ void test_tls_reload_does_not_hide_concurrent_file_change(void)
flb_free(dst_key);
}

/*
* CRL (tls.crl_file) dispatch. These use a mock TLS backend (same approach as
* the session tests above) to exercise the flb_tls_set_crl_file() wrapper
* without any real OpenSSL context, certificates or network I/O.
*/
struct crl_mock_ctx {
int calls;
int ret; /* value the mock returns */
};

static const char *crl_mock_last_path;

static int crl_mock_set_crl_file(void *ctx_backend, const char *crl_file)
{
struct crl_mock_ctx *m = ctx_backend;

m->calls++;
crl_mock_last_path = crl_file; /* wrapper forwards the pointer as-is */

return m->ret;
}

/* A NULL tls context must be rejected */
void test_crl_set_null_tls(void)
{
TEST_CHECK(flb_tls_set_crl_file(NULL, "x.pem") == -1);
}

/* The wrapper forwards ctx + path to the backend and propagates success */
void test_crl_dispatch_success(void)
{
struct crl_mock_ctx mock = {0};
struct flb_tls_backend api = {0};
struct flb_tls tls = {0};
const char *path = "/etc/crl.pem";

mock.ret = 0;
api.context_set_crl_file = crl_mock_set_crl_file;
tls.api = &api;
tls.ctx = &mock;
crl_mock_last_path = NULL;

TEST_CHECK(flb_tls_set_crl_file(&tls, path) == 0);
TEST_CHECK(mock.calls == 1);
TEST_CHECK(crl_mock_last_path == path);
}

/* The wrapper propagates a backend failure */
void test_crl_dispatch_error(void)
{
struct crl_mock_ctx mock = {0};
struct flb_tls_backend api = {0};
struct flb_tls tls = {0};

mock.ret = -1;
api.context_set_crl_file = crl_mock_set_crl_file;
tls.api = &api;
tls.ctx = &mock;

TEST_CHECK(flb_tls_set_crl_file(&tls, "/bad.pem") == -1);
TEST_CHECK(mock.calls == 1);
}

/* A backend without CRL support is a graceful no-op (backend not called) */
void test_crl_dispatch_unsupported(void)
{
struct crl_mock_ctx mock = {0};
struct flb_tls_backend api = {0}; /* context_set_crl_file stays NULL */
struct flb_tls tls = {0};

tls.api = &api;
tls.ctx = &mock;

TEST_CHECK(flb_tls_set_crl_file(&tls, "/whatever.pem") == 0);
TEST_CHECK(mock.calls == 0);
}

#endif

TEST_LIST = {
Expand All @@ -403,6 +480,10 @@ TEST_LIST = {
#endif
{"tls_reload_does_not_hide_concurrent_file_change",
test_tls_reload_does_not_hide_concurrent_file_change},
{"crl_set_null_tls", test_crl_set_null_tls},
{"crl_dispatch_success", test_crl_dispatch_success},
{"crl_dispatch_error", test_crl_dispatch_error},
{"crl_dispatch_unsupported", test_crl_dispatch_unsupported},
#endif
{0}
};
30 changes: 30 additions & 0 deletions tests/runtime/data/tls/ca_certificate.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
-----BEGIN CERTIFICATE-----
MIIFDTCCAvWgAwIBAgIUObKqIDoYgf674IVD15cdfdGaVHcwDQYJKoZIhvcNAQEL
BQAwFjEUMBIGA1UEAwwLTk1YLW1UTFMtQ0EwHhcNMjYwNjE1MDc1MTIwWhcNMjcw
NjE1MDc1MTIwWjAWMRQwEgYDVQQDDAtOTVgtbVRMUy1DQTCCAiIwDQYJKoZIhvcN
AQEBBQADggIPADCCAgoCggIBAK0ysr/tjivpac4laAYBAQpXj2lVUS8l2sqni/LZ
NEwDJ76K4OLyG9t1eAEkdLG230cn8+MC5y+oj3i1+Vu7QjO1o2K2nvktXxpLJtNA
qGeqFZDpAH1HPHVPyJ7vKcC49gRFsvgbzAbiAL5SVobVF9En2HMTapPQRKdD6OhB
gjRqZaYZnK5ECWLgDNv0Rz6M3CO3rWDY+znshdUHQIpX6SxjcabVRNS02pfC0SVB
XD77ysJE+SCPrui3hT0sweCgpHX0aE2hzSXVVXgrKVISGYy4swHW1YK5hkRY8+Kt
wPTqBU4G8l7GnEokYtrY1tym9sIdYm5rrFAvqG1Y+/pmanqoVUB2Xv2nX6jPOipy
9R6jnfhZ9O+GA71E1w2U1/6bKtS+Fy4ZLDamAjEz9IojWnX/jeWvlhAF1UVAE5c2
lYyELSarrQhoKdhkVI1mTzVw+Rvx5dGDL9u4fxOagMMvuk0OH4j1nUliBJ1gj+Kf
VUTb1BCukti5TIOPwH1PkmpI6QVneRGjXpPEjBsvObJ0J/qEkf6+am9x7obijGDw
CFz4//fpjwqAjqc7RAODiNogqkpDsyb2099ddRiVdw44JRHEmJrPI2cTMK4b2IUO
6hn1Vu6nUZhnizb4SF1dYEMTrGFadH6T9G3hc4bjB+yPsJuuaiv/30uTV/ngReew
HXP7AgMBAAGjUzBRMB0GA1UdDgQWBBQGn+YITFaRNj6VoDQQ9aiHlD8s/TAfBgNV
HSMEGDAWgBQGn+YITFaRNj6VoDQQ9aiHlD8s/TAPBgNVHRMBAf8EBTADAQH/MA0G
CSqGSIb3DQEBCwUAA4ICAQAbpLlqLqVRAP1et/gP+RGD4/CIPtaWZwI71FHHrgdE
gfSQOphN6cjfmaYqsV00vwoLHfB6p0k+O1fcTXX2sWldgxXbiCBuKqeB05Qls0+C
RFO7NQPGjMHn3wyltEimKOOCPM2v4HrFqZWMIMU8iJ4o0mSzvHcuz7IsVUYlFd3J
/vHYiULXQMrYQ88+xL5RSdYhSV0yfffIWVY1xto/i7aU/y+cE3Sppk5ZRa6wrnXL
YGcGe37yIKxe0yWo/jHd1qU6wNwm0Ewf7x1og04FiIyAsYhRAV63AeOU88fMtTm/
PLx3j3KHev08pD+r7cl+r8F6i2o4n4PpuBNBG9zO7KgrKj/XWi0RiG+BnY5+hjRp
HU40GaBAHFR8+yaCM/b2FeBPRsFeFbMMqKHhO4vMAtDcDjawZveqa+b2R0l5EsGG
lTZQLzvB4vSXbGspH+pxcwr4D0tAdleUl49DX1IIAzFgVbXHfAmEmTSn4p6U7WDl
Z8N0qbQns24GgbwKIu22ay//CxkXqXZbrdSqWqx58i+RxC94yKPvwa0Nhgv4LHjm
K5nIGAK3jRK96iia5QprIlRV3GNUW6MlsmOBLxLcfuDLtJXKVf43KJQGFtBNNjIn
NzaeTyrLsp36BwlFcQacJf17zpthrLCileU8K7S+JMIbPbuNkUEKyjTpV+Zm9Up0
0A==
-----END CERTIFICATE-----
Loading