@@ -302,6 +302,100 @@ int tls_context_alpn_set(void *ctx_backend, const char *alpn)
302302}
303303
304304#ifdef _MSC_VER
305+ /* Parse certstore_name prefix like
306+ *
307+ * "My" -> no prefix, leave location untouched
308+ * "CurrentUser\\My" -> CERT_SYSTEM_STORE_CURRENT_USER, "My"
309+ * "HKCU\\My" -> CERT_SYSTEM_STORE_CURRENT_USER, "My"
310+ * "LocalMachine\\My" -> CERT_SYSTEM_STORE_LOCAL_MACHINE, "My"
311+ * "HKLM\\My" -> CERT_SYSTEM_STORE_LOCAL_MACHINE, "My"
312+ * "LocalMachineEnterprise\\My"-> CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, "My"
313+ * "HKLME\\My" -> CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, "My"
314+ *
315+ * Also accepts '/' as separator.
316+ *
317+ * If no known prefix is found, *store_name_out is left as-is and *location_flags
318+ * is not modified (so legacy behavior is preserved).
319+ */
320+ static void windows_resolve_certstore_location (const char * configured_name ,
321+ DWORD * location_flags ,
322+ const char * * store_name_out )
323+ {
324+ const char * name ;
325+ const char * sep ;
326+ size_t prefix_len ;
327+ char prefix_buf [32 ];
328+ size_t i ;
329+ size_t len = 0 ;
330+
331+ if (!configured_name || !* configured_name ) {
332+ return ;
333+ }
334+
335+ name = configured_name ;
336+ len = strlen (name );
337+
338+ /* Optional "Cert:\" prefix (PowerShell style) */
339+ if (len >= 6 &&
340+ strncasecmp (name , "cert:" , 5 ) == 0 &&
341+ (name [5 ] == '\\' || name [5 ] == '/' )) {
342+ name += 6 ;
343+ }
344+
345+ /* Find first '\' or '/' separator */
346+ sep = name ;
347+ while (* sep != '\0' && * sep != '\\' && * sep != '/' ) {
348+ sep ++ ;
349+ }
350+
351+ if (* sep == '\0' ) {
352+ /* No prefix, only store name (e.g. "My" or "Root")
353+ * -> keep legacy behavior (location_flags unchanged).
354+ */
355+ * store_name_out = name ;
356+ return ;
357+ }
358+
359+ /* Copy and lowercase prefix into buffer */
360+ prefix_len = (size_t )(sep - name );
361+ if (prefix_len >= sizeof (prefix_buf )) {
362+ prefix_len = sizeof (prefix_buf ) - 1 ;
363+ }
364+
365+ for (i = 0 ; i < prefix_len ; i ++ ) {
366+ char c = (char ) name [i ];
367+
368+ if (c >= 'A' && c <= 'Z' ) {
369+ c = (char ) (c - 'A' + 'a' );
370+ }
371+ prefix_buf [i ] = c ;
372+ }
373+ prefix_buf [prefix_len ] = '\0' ;
374+
375+ /* Default: keep *location_flags as-is */
376+ if (strncasecmp (prefix_buf , "currentuser" , 11 ) == 0 ||
377+ strncasecmp (prefix_buf , "hkcu" , 4 ) == 0 ) {
378+ * location_flags = CERT_SYSTEM_STORE_CURRENT_USER ;
379+ }
380+ else if (strncasecmp (prefix_buf , "localmachine" , 12 ) == 0 ||
381+ strncasecmp (prefix_buf , "hklm" , 4 ) == 0 ) {
382+ * location_flags = CERT_SYSTEM_STORE_LOCAL_MACHINE ;
383+ }
384+ else if (strncasecmp (prefix_buf , "localmachineenterprise" , 22 ) == 0 ||
385+ strncasecmp (prefix_buf , "hklme" , 5 ) == 0 ) {
386+ * location_flags = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE ;
387+ }
388+ else {
389+ /* Unknown prefix -> treat entire string as store name */
390+ * store_name_out = configured_name ;
391+
392+ return ;
393+ }
394+
395+ /* Store name part after the separator "\" or "/" */
396+ * store_name_out = sep + 1 ;
397+ }
398+
305399static int windows_load_system_certificates (struct tls_context * ctx )
306400{
307401 int ret ;
@@ -311,7 +405,9 @@ static int windows_load_system_certificates(struct tls_context *ctx)
311405 const unsigned char * win_cert_data ;
312406 X509_STORE * ossl_store = SSL_CTX_get_cert_store (ctx -> ctx );
313407 X509 * ossl_cert ;
314- char * certstore_name = "Root" ;
408+ char * configured_name = "Root" ;
409+ const char * store_name = "Root" ;
410+ DWORD store_location = CERT_SYSTEM_STORE_CURRENT_USER ;
315411
316412 /* Check if OpenSSL certificate store is available */
317413 if (!ossl_store ) {
@@ -320,20 +416,36 @@ static int windows_load_system_certificates(struct tls_context *ctx)
320416 }
321417
322418 if (ctx -> certstore_name ) {
323- certstore_name = ctx -> certstore_name ;
419+ configured_name = ctx -> certstore_name ;
420+ store_name = ctx -> certstore_name ;
421+ }
422+
423+ /* First, resolve explicit prefix if present */
424+ windows_resolve_certstore_location (configured_name ,
425+ & store_location ,
426+ & store_name );
427+
428+ /* Backward compatibility:
429+ * If no prefix was given (store_name == configured_name) and
430+ * use_enterprise_store is set, override location accordingly.
431+ */
432+ if (store_name == configured_name && ctx -> use_enterprise_store ) {
433+ store_location = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE ;
324434 }
325435
326- if (ctx -> use_enterprise_store ) {
327- /* Open the Windows system enterprise certificate store */
436+ /* Open the Windows certificate store for the resolved location */
437+ if (store_location == CERT_SYSTEM_STORE_CURRENT_USER ) {
438+ /* Keep using CertOpenSystemStoreA for current user to avoid
439+ * changing existing behavior.
440+ */
441+ win_store = CertOpenSystemStoreA (0 , store_name );
442+ }
443+ else {
328444 win_store = CertOpenStore (CERT_STORE_PROV_SYSTEM ,
329445 0 ,
330446 0 ,
331- CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE ,
332- certstore_name );
333- }
334- else {
335- /* Open the Windows system certificate store */
336- win_store = CertOpenSystemStoreA (0 , certstore_name );
447+ store_location ,
448+ store_name );
337449 }
338450
339451 if (win_store == NULL ) {
@@ -389,10 +501,10 @@ static int windows_load_system_certificates(struct tls_context *ctx)
389501 }
390502
391503 if (loaded == 0 ) {
392- flb_warn ("[tls] no certificates loaded by thumbprint from '%s'." , certstore_name );
504+ flb_warn ("[tls] no certificates loaded by thumbprint from '%s'." , configured_name );
393505 }
394506 else {
395- flb_debug ("[tls] loaded %zu certificate(s) by thumbprint from '%s'." , loaded , certstore_name );
507+ flb_debug ("[tls] loaded %zu certificate(s) by thumbprint from '%s'." , loaded , configured_name );
396508 }
397509 return 0 ;
398510 }
@@ -445,7 +557,7 @@ static int windows_load_system_certificates(struct tls_context *ctx)
445557 }
446558
447559 flb_debug ("[tls] successfully loaded certificates from windows system %s store." ,
448- certstore_name );
560+ configured_name );
449561 return 0 ;
450562}
451563#endif
0 commit comments