Skip to content

Commit ef3f075

Browse files
cosmo0920edsiper
authored andcommitted
tls: openssl: Implement flexible certstore loading on Windows
With this patch, we can load certificates from Windows CertStore as: * My -> no prefix, leave location untouched * CurrentUser\My -> CERT_SYSTEM_STORE_CURRENT_USER, "My" * HKCU\My -> CERT_SYSTEM_STORE_CURRENT_USER, "My" * LocalMachine\My -> CERT_SYSTEM_STORE_LOCAL_MACHINE, "My" * HKLM\My -> CERT_SYSTEM_STORE_LOCAL_MACHINE, "My" * LocalMachineEnterprise\My -> CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, "My" * HKLME\My -> CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, "My" Signed-off-by: Hiroshi Hatake <hiroshi@chronosphere.io>
1 parent ae14454 commit ef3f075

File tree

1 file changed

+125
-13
lines changed

1 file changed

+125
-13
lines changed

src/tls/openssl.c

Lines changed: 125 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
305399
static 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

Comments
 (0)