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
8171043static 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