Skip to content

Commit baae91e

Browse files
committed
tls: openssl: Implement certificates" thumbprint handlings
Signed-off-by: Hiroshi Hatake <[email protected]>
1 parent 2af2017 commit baae91e

File tree

3 files changed

+236
-0
lines changed

3 files changed

+236
-0
lines changed

include/fluent-bit/tls/flb_tls.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ struct flb_tls_backend {
9797
#if defined(FLB_SYSTEM_WINDOWS)
9898
int (*set_certstore_name)(struct flb_tls *tls, const char *certstore_name);
9999
int (*set_use_enterprise_store)(struct flb_tls *tls, int use_enterprise);
100+
int (*set_client_thumbprints)(struct flb_tls *tls, const char *thumbprints);
100101
#endif
101102
};
102103

@@ -135,6 +136,7 @@ int flb_tls_set_verify_hostname(struct flb_tls *tls, int verify_hostname);
135136
#if defined(FLB_SYSTEM_WINDOWS)
136137
int flb_tls_set_certstore_name(struct flb_tls *tls, const char *certstore_name);
137138
int flb_tls_set_use_enterprise_store(struct flb_tls *tls, int use_enterprise);
139+
int flb_tls_set_client_thumbprints(struct flb_tls *tls, const char *thumbprints);
138140
#endif
139141

140142
int flb_tls_load_system_certificates(struct flb_tls *tls);

src/tls/flb_tls.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,13 @@ int flb_tls_set_use_enterprise_store(struct flb_tls *tls, int use_enterprise)
314314

315315
return 0;
316316
}
317+
318+
int flb_tls_set_client_thumbprints(struct flb_tls *tls, const char *thumbprints) {
319+
if (tls && tls->api->set_client_thumbprints) {
320+
return tls->api->set_client_thumbprints(tls, thumbprints);
321+
}
322+
return -1;
323+
}
317324
#endif
318325

319326
int flb_tls_net_read(struct flb_tls_session *session, void *buf, size_t len)

src/tls/openssl.c

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@
4040
#ifdef FLB_SYSTEM_WINDOWS
4141
#define strtok_r(str, delimiter, context) \
4242
strtok_s(str, delimiter, context)
43+
#include <wincrypt.h>
44+
#ifndef CERT_FIND_SHA256_HASH
45+
/* Older SDKs may not define this */
46+
#define CERT_FIND_SHA256_HASH 0x0001000d
47+
#endif
4348
#endif
4449

4550
/*
@@ -59,6 +64,8 @@ struct tls_context {
5964
#if defined(FLB_SYSTEM_WINDOWS)
6065
char *certstore_name;
6166
int use_enterprise_store;
67+
CRYPT_HASH_BLOB *allowed_thumbprints;
68+
size_t allowed_thumbprints_count;
6269
#endif
6370
pthread_mutex_t mutex;
6471
};
@@ -158,6 +165,17 @@ static void tls_context_destroy(void *ctx_backend)
158165

159166
ctx->certstore_name = NULL;
160167
}
168+
if (ctx->allowed_thumbprints) {
169+
/* We allocated each blob->pbData; free them too */
170+
for (size_t i = 0; i < ctx->allowed_thumbprints_count; i++) {
171+
if (ctx->allowed_thumbprints[i].pbData) {
172+
flb_free(ctx->allowed_thumbprints[i].pbData);
173+
}
174+
}
175+
flb_free(ctx->allowed_thumbprints);
176+
ctx->allowed_thumbprints = NULL;
177+
ctx->allowed_thumbprints_count = 0;
178+
}
161179
#endif
162180

163181
pthread_mutex_unlock(&ctx->mutex);
@@ -323,6 +341,62 @@ static int windows_load_system_certificates(struct tls_context *ctx)
323341
return -1;
324342
}
325343

344+
if (ctx->allowed_thumbprints_count > 0) {
345+
size_t loaded = 0;
346+
DWORD find_type = 0;
347+
size_t i;
348+
349+
for (i = 0; i < ctx->allowed_thumbprints_count; i++) {
350+
find_type = (ctx->allowed_thumbprints[i].cbData == 20)
351+
? CERT_FIND_SHA1_HASH
352+
: CERT_FIND_SHA256_HASH;
353+
354+
win_cert = NULL;
355+
while ((win_cert = CertFindCertificateInStore(win_store,
356+
X509_ASN_ENCODING,
357+
0,
358+
find_type,
359+
&ctx->allowed_thumbprints[i],
360+
win_cert)) != NULL) {
361+
362+
win_cert_data = win_cert->pbCertEncoded;
363+
ossl_cert = d2i_X509(NULL, &win_cert_data, win_cert->cbCertEncoded);
364+
if (!ossl_cert) {
365+
flb_debug("[tls] parse failed for matched certificate (thumbprint idx %zu)", i);
366+
continue;
367+
}
368+
369+
ret = X509_STORE_add_cert(ossl_store, ossl_cert);
370+
if (ret != 1) {
371+
unsigned long err = ERR_get_error();
372+
if (ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
373+
flb_debug("[tls] certificate already present (thumbprint idx %zu).", i);
374+
}
375+
else {
376+
flb_warn("[tls] add_cert failed: %s", ERR_error_string(err, NULL));
377+
}
378+
}
379+
else {
380+
loaded++;
381+
}
382+
X509_free(ossl_cert);
383+
}
384+
}
385+
386+
if (!CertCloseStore(win_store, 0)) {
387+
flb_error("[tls] cannot close windows certificate store: %lu", GetLastError());
388+
return -1;
389+
}
390+
391+
if (loaded == 0) {
392+
flb_warn("[tls] no certificates loaded by thumbprint from '%s'.", certstore_name);
393+
}
394+
else {
395+
flb_debug("[tls] loaded %zu certificate(s) by thumbprint from '%s'.", loaded, certstore_name);
396+
}
397+
return 0;
398+
}
399+
326400
/* Iterate over certificates in the store */
327401
while ((win_cert = CertEnumCertificatesInStore(win_store, win_cert)) != NULL) {
328402
/* Check if the certificate is encoded in ASN.1 DER format */
@@ -597,6 +671,12 @@ static void *tls_context_create(int verify,
597671
ctx->mode = mode;
598672
ctx->alpn = NULL;
599673
ctx->debug_level = debug;
674+
#if defined(FLB_SYSTEM_WINDOWS)
675+
ctx->certstore_name = NULL;
676+
ctx->use_enterprise_store = 0;
677+
ctx->allowed_thumbprints = NULL;
678+
ctx->allowed_thumbprints_count = 0;
679+
#endif
600680
pthread_mutex_init(&ctx->mutex, NULL);
601681

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

813893
return 0;
814894
}
895+
896+
static int hex_nibble(int c) {
897+
if (c >= '0' && c <= '9') {
898+
return c - '0';
899+
}
900+
else if (c >= 'a' && c <= 'f') {
901+
return c - 'a' + 10;
902+
}
903+
else if (c >= 'A' && c <= 'F') {
904+
return c - 'A' + 10;
905+
}
906+
return -1;
907+
}
908+
909+
static char *compact_hex(const char *s) {
910+
size_t n = 0;
911+
size_t i;
912+
char *out = flb_calloc(1, strlen(s) + 1);
913+
914+
if (!out) {
915+
return NULL;
916+
}
917+
918+
for (i = 0; s[i]; i++) {
919+
int c = s[i];
920+
if ((c >= '0' && c <= '9') ||
921+
(c >= 'a' && c <= 'f') ||
922+
(c >= 'A' && c <= 'F')) {
923+
out[n++] = (char)c;
924+
}
925+
}
926+
out[n] = '\0';
927+
return out;
928+
}
929+
930+
static unsigned char *hex_to_bytes(const char *hex, size_t *out_len) {
931+
unsigned char *buf = NULL;
932+
size_t i;
933+
size_t len = strlen(hex);
934+
if (len % 2 != 0) {
935+
return NULL;
936+
}
937+
938+
buf = flb_calloc(1, len / 2);
939+
if (!buf) {
940+
return NULL;
941+
}
942+
943+
for (i = 0; i < len; i += 2) {
944+
int hi = hex_nibble(hex[i]);
945+
int lo = hex_nibble(hex[i+1]);
946+
if (hi < 0 || lo < 0) {
947+
flb_free(buf);
948+
return NULL;
949+
}
950+
buf[i/2] = (unsigned char)((hi << 4) | lo);
951+
}
952+
*out_len = len / 2;
953+
return buf;
954+
}
955+
956+
static int windows_set_allowed_thumbprints(struct tls_context *ctx, const char *thumbprints)
957+
{
958+
char *token_ctx = NULL, *tok = NULL;
959+
size_t cap = 4, count = 0;
960+
char *hex = NULL;
961+
struct cfl_list *kvs;
962+
struct cfl_list *head;
963+
struct cfl_split_entry *cur;
964+
CRYPT_HASH_BLOB *arr;
965+
size_t bytes_len = 0;
966+
unsigned char *bytes = NULL;
967+
968+
if (!thumbprints || !*thumbprints) {
969+
return 0;
970+
}
971+
972+
arr = flb_calloc(cap, sizeof(*arr));
973+
if (!arr) {
974+
return -1;
975+
}
976+
977+
kvs = cfl_utils_split(thumbprints, ',', -1);
978+
cfl_list_foreach(head, kvs) {
979+
cur = cfl_list_entry(head, struct cfl_split_entry, _head);
980+
tok = cur->value;
981+
hex = compact_hex(tok);
982+
if (hex && *hex) {
983+
bytes = hex_to_bytes(hex, &bytes_len);
984+
if (bytes && (bytes_len == 20 || bytes_len == 32)) {
985+
if (count == cap) {
986+
cap *= 2;
987+
CRYPT_HASH_BLOB *tmp = flb_realloc(arr, cap * sizeof(*arr));
988+
if (!tmp) {
989+
flb_free(bytes);
990+
break;
991+
}
992+
arr = tmp;
993+
}
994+
arr[count].cbData = (DWORD)bytes_len;
995+
arr[count].pbData = bytes;
996+
count++;
997+
}
998+
else {
999+
flb_warn("[tls] ignoring thumbprint '%s' (length must be 40 or 64 hex chars after stripping).", tok);
1000+
if (bytes) {
1001+
flb_free(bytes);
1002+
}
1003+
}
1004+
}
1005+
if (hex) {
1006+
flb_free(hex);
1007+
}
1008+
}
1009+
cfl_utils_split_free(kvs);
1010+
1011+
if (count == 0) {
1012+
if (arr) {
1013+
flb_free(arr);
1014+
}
1015+
flb_warn("[tls] no valid thumbprints parsed.");
1016+
return -1;
1017+
}
1018+
1019+
ctx->allowed_thumbprints = arr;
1020+
ctx->allowed_thumbprints_count = count;
1021+
flb_debug("[tls] parsed %zu allowed thumbprint(s).", count);
1022+
1023+
return 0;
1024+
}
1025+
1026+
static int tls_set_client_thumbprints(struct flb_tls *tls, const char *thumbprints) {
1027+
struct tls_context *ctx = tls->ctx;
1028+
int rc = 0;
1029+
1030+
pthread_mutex_lock(&ctx->mutex);
1031+
1032+
if (ctx->allowed_thumbprints || ctx->allowed_thumbprints_count) {
1033+
pthread_mutex_unlock(&ctx->mutex);
1034+
return -1;
1035+
}
1036+
rc = windows_set_allowed_thumbprints(ctx, thumbprints);
1037+
pthread_mutex_unlock(&ctx->mutex);
1038+
return rc;
1039+
}
1040+
8151041
#endif
8161042

8171043
static void *tls_session_create(struct flb_tls *tls,
@@ -1243,5 +1469,6 @@ static struct flb_tls_backend tls_openssl = {
12431469
#if defined(FLB_SYSTEM_WINDOWS)
12441470
.set_certstore_name = tls_set_certstore_name,
12451471
.set_use_enterprise_store = tls_set_use_enterprise_store,
1472+
.set_client_thumbprints = tls_set_client_thumbprints,
12461473
#endif
12471474
};

0 commit comments

Comments
 (0)