Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/fluent-bit/flb_output.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ struct flb_output_instance {
# if defined(FLB_SYSTEM_WINDOWS)
char *tls_win_certstore_name; /* CertStore Name (Windows) */
int tls_win_use_enterprise_certstore; /* Use enterprise CertStore */
char *tls_win_thumbprints; /* CertStore Thumbprints (Windows) */
# endif
#endif

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 @@ -97,6 +97,7 @@ struct flb_tls_backend {
#if defined(FLB_SYSTEM_WINDOWS)
int (*set_certstore_name)(struct flb_tls *tls, const char *certstore_name);
int (*set_use_enterprise_store)(struct flb_tls *tls, int use_enterprise);
int (*set_ca_thumbprints)(struct flb_tls *tls, const char *thumbprints);
#endif
};

Expand Down Expand Up @@ -135,6 +136,7 @@ int flb_tls_set_verify_hostname(struct flb_tls *tls, int verify_hostname);
#if defined(FLB_SYSTEM_WINDOWS)
int flb_tls_set_certstore_name(struct flb_tls *tls, const char *certstore_name);
int flb_tls_set_use_enterprise_store(struct flb_tls *tls, int use_enterprise);
int flb_tls_set_ca_thumbprints(struct flb_tls *tls, const char *thumbprints);
#endif

int flb_tls_load_system_certificates(struct flb_tls *tls);
Expand Down
22 changes: 22 additions & 0 deletions src/flb_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ struct flb_config_map output_global_properties[] = {
0, FLB_FALSE, 0,
"Sets whether using enterprise certstore or not on an output (Windows)"
},
{
FLB_CONFIG_MAP_STR, "tls.windows.ca_thumbprints", NULL,
0, FLB_FALSE, 0,
"Comma-separated list of certificate thumbprints (SHA1/SHA256) to trust from the Windows store (Windows)"
},

{0}
};
Expand Down Expand Up @@ -193,6 +198,9 @@ static void flb_output_free_properties(struct flb_output_instance *ins)
if (ins->tls_win_certstore_name) {
flb_sds_destroy(ins->tls_win_certstore_name);
}
if (ins->tls_win_thumbprints) {
flb_sds_destroy(ins->tls_win_thumbprints);
}
# endif
#endif
}
Expand Down Expand Up @@ -774,6 +782,7 @@ struct flb_output_instance *flb_output_new(struct flb_config *config,
# if defined(FLB_SYSTEM_WINDOWS)
instance->tls_win_certstore_name = NULL;
instance->tls_win_use_enterprise_certstore = FLB_FALSE;
instance->tls_win_thumbprints = NULL;
# endif
#endif

Expand Down Expand Up @@ -1007,6 +1016,9 @@ int flb_output_set_property(struct flb_output_instance *ins,
ins->tls_win_use_enterprise_certstore = flb_utils_bool(tmp);
flb_sds_destroy(tmp);
}
else if (prop_key_check("tls.windows.ca_thumbprints", k, len) == 0 && tmp) {
flb_utils_set_plugin_string_property("tls.windows.ca_thumbprints", &ins->tls_win_thumbprints, tmp);
}
# endif
#endif
else if (prop_key_check("storage.total_limit_size", k, len) == 0 && tmp) {
Expand Down Expand Up @@ -1421,6 +1433,16 @@ int flb_output_init_all(struct flb_config *config)
}
}

if (ins->tls_win_thumbprints) {
ret = flb_tls_set_ca_thumbprints(ins->tls, ins->tls_win_thumbprints);
if (ret == -1) {
flb_error("[input %s] error set up to use thumbprints of certificates in TLS context",
ins->name);

return -1;
}
}

if (ins->tls_win_certstore_name) {
flb_debug("[output %s] starting to load %s certstore in TLS context",
ins->name, ins->tls_win_certstore_name);
Expand Down
7 changes: 7 additions & 0 deletions src/tls/flb_tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,13 @@ int flb_tls_set_use_enterprise_store(struct flb_tls *tls, int use_enterprise)

return 0;
}

int flb_tls_set_ca_thumbprints(struct flb_tls *tls, const char *thumbprints) {
if (tls && tls->api->set_ca_thumbprints) {
return tls->api->set_ca_thumbprints(tls, thumbprints);
}
return -1;
}
#endif

int flb_tls_net_read(struct flb_tls_session *session, void *buf, size_t len)
Expand Down
227 changes: 227 additions & 0 deletions src/tls/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@
#ifdef FLB_SYSTEM_WINDOWS
#define strtok_r(str, delimiter, context) \
strtok_s(str, delimiter, context)
#include <wincrypt.h>
#ifndef CERT_FIND_SHA256_HASH
/* Older SDKs may not define this */
#define CERT_FIND_SHA256_HASH 0x0001000d
#endif
#endif

/*
Expand All @@ -59,6 +64,8 @@ struct tls_context {
#if defined(FLB_SYSTEM_WINDOWS)
char *certstore_name;
int use_enterprise_store;
CRYPT_HASH_BLOB *allowed_thumbprints;
size_t allowed_thumbprints_count;
#endif
pthread_mutex_t mutex;
};
Expand Down Expand Up @@ -158,6 +165,17 @@ static void tls_context_destroy(void *ctx_backend)

ctx->certstore_name = NULL;
}
if (ctx->allowed_thumbprints) {
/* We allocated each blob->pbData; free them too */
for (size_t i = 0; i < ctx->allowed_thumbprints_count; i++) {
if (ctx->allowed_thumbprints[i].pbData) {
flb_free(ctx->allowed_thumbprints[i].pbData);
}
}
flb_free(ctx->allowed_thumbprints);
ctx->allowed_thumbprints = NULL;
ctx->allowed_thumbprints_count = 0;
}
#endif

pthread_mutex_unlock(&ctx->mutex);
Expand Down Expand Up @@ -323,6 +341,62 @@ static int windows_load_system_certificates(struct tls_context *ctx)
return -1;
}

if (ctx->allowed_thumbprints_count > 0) {
size_t loaded = 0;
DWORD find_type = 0;
size_t i;

for (i = 0; i < ctx->allowed_thumbprints_count; i++) {
find_type = (ctx->allowed_thumbprints[i].cbData == 20)
? CERT_FIND_SHA1_HASH
: CERT_FIND_SHA256_HASH;

win_cert = NULL;
while ((win_cert = CertFindCertificateInStore(win_store,
X509_ASN_ENCODING,
0,
find_type,
&ctx->allowed_thumbprints[i],
win_cert)) != NULL) {

win_cert_data = win_cert->pbCertEncoded;
ossl_cert = d2i_X509(NULL, &win_cert_data, win_cert->cbCertEncoded);
if (!ossl_cert) {
flb_debug("[tls] parse failed for matched certificate (thumbprint idx %zu)", i);
continue;
}

ret = X509_STORE_add_cert(ossl_store, ossl_cert);
if (ret != 1) {
unsigned long err = ERR_get_error();
if (ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
flb_debug("[tls] certificate already present (thumbprint idx %zu).", i);
}
else {
flb_warn("[tls] add_cert failed: %s", ERR_error_string(err, NULL));
}
}
else {
loaded++;
}
X509_free(ossl_cert);
}
}

if (!CertCloseStore(win_store, 0)) {
flb_error("[tls] cannot close windows certificate store: %lu", GetLastError());
return -1;
}

if (loaded == 0) {
flb_warn("[tls] no certificates loaded by thumbprint from '%s'.", certstore_name);
}
else {
flb_debug("[tls] loaded %zu certificate(s) by thumbprint from '%s'.", loaded, certstore_name);
}
return 0;
}

/* Iterate over certificates in the store */
while ((win_cert = CertEnumCertificatesInStore(win_store, win_cert)) != NULL) {
/* Check if the certificate is encoded in ASN.1 DER format */
Expand Down Expand Up @@ -597,6 +671,12 @@ static void *tls_context_create(int verify,
ctx->mode = mode;
ctx->alpn = NULL;
ctx->debug_level = debug;
#if defined(FLB_SYSTEM_WINDOWS)
ctx->certstore_name = NULL;
ctx->use_enterprise_store = 0;
ctx->allowed_thumbprints = NULL;
ctx->allowed_thumbprints_count = 0;
#endif
pthread_mutex_init(&ctx->mutex, NULL);

/* Verify peer: by default OpenSSL always verify peer */
Expand Down Expand Up @@ -812,6 +892,152 @@ static int tls_set_use_enterprise_store(struct flb_tls *tls, int use_enterprise)

return 0;
}

static int hex_nibble(int c) {
if (c >= '0' && c <= '9') {
return c - '0';
}
else if (c >= 'a' && c <= 'f') {
return c - 'a' + 10;
}
else if (c >= 'A' && c <= 'F') {
return c - 'A' + 10;
}
return -1;
}

static char *compact_hex(const char *s) {
size_t n = 0;
size_t i;
char *out = flb_calloc(1, strlen(s) + 1);

if (!out) {
return NULL;
}

for (i = 0; s[i]; i++) {
int c = s[i];
if ((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F')) {
out[n++] = (char)c;
}
}
out[n] = '\0';
return out;
}

static unsigned char *hex_to_bytes(const char *hex, size_t *out_len) {
unsigned char *buf = NULL;
size_t i;
size_t len = strlen(hex);
if (len % 2 != 0) {
return NULL;
}

buf = flb_calloc(1, len / 2);
if (!buf) {
return NULL;
}

for (i = 0; i < len; i += 2) {
int hi = hex_nibble(hex[i]);
int lo = hex_nibble(hex[i+1]);
if (hi < 0 || lo < 0) {
flb_free(buf);
return NULL;
}
buf[i/2] = (unsigned char)((hi << 4) | lo);
}
*out_len = len / 2;
return buf;
}

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;
char *hex = NULL;
struct cfl_list *kvs;
struct cfl_list *head;
struct cfl_split_entry *cur;
CRYPT_HASH_BLOB *arr;
size_t bytes_len = 0;
unsigned char *bytes = NULL;

if (!thumbprints || !*thumbprints) {
return 0;
}

arr = flb_calloc(cap, sizeof(*arr));
if (!arr) {
return -1;
}

kvs = cfl_utils_split(thumbprints, ',', -1);
cfl_list_foreach(head, kvs) {
cur = cfl_list_entry(head, struct cfl_split_entry, _head);
tok = cur->value;
hex = compact_hex(tok);
if (hex && *hex) {
bytes = hex_to_bytes(hex, &bytes_len);
if (bytes && (bytes_len == 20 || bytes_len == 32)) {
if (count == cap) {
cap *= 2;
CRYPT_HASH_BLOB *tmp = flb_realloc(arr, cap * sizeof(*arr));
if (!tmp) {
flb_free(bytes);
break;
}
arr = tmp;
}
arr[count].cbData = (DWORD)bytes_len;
arr[count].pbData = bytes;
count++;
}
else {
flb_warn("[tls] ignoring thumbprint '%s' (length must be 40 or 64 hex chars after stripping).", tok);
if (bytes) {
flb_free(bytes);
}
}
}
if (hex) {
flb_free(hex);
}
}
cfl_utils_split_free(kvs);

if (count == 0) {
if (arr) {
flb_free(arr);
}
flb_warn("[tls] no valid thumbprints parsed.");
return -1;
}

ctx->allowed_thumbprints = arr;
ctx->allowed_thumbprints_count = count;
flb_debug("[tls] parsed %zu allowed thumbprint(s).", count);

return 0;
}

static int tls_set_ca_thumbprints(struct flb_tls *tls, const char *thumbprints) {
struct tls_context *ctx = tls->ctx;
int rc = 0;

pthread_mutex_lock(&ctx->mutex);

if (ctx->allowed_thumbprints || ctx->allowed_thumbprints_count) {
pthread_mutex_unlock(&ctx->mutex);
return -1;
}
rc = windows_set_allowed_thumbprints(ctx, thumbprints);
pthread_mutex_unlock(&ctx->mutex);
return rc;
}

#endif

static void *tls_session_create(struct flb_tls *tls,
Expand Down Expand Up @@ -1243,5 +1469,6 @@ static struct flb_tls_backend tls_openssl = {
#if defined(FLB_SYSTEM_WINDOWS)
.set_certstore_name = tls_set_certstore_name,
.set_use_enterprise_store = tls_set_use_enterprise_store,
.set_ca_thumbprints = tls_set_ca_thumbprints,
#endif
};
Loading