Skip to content

Use of Windows certificate store for authentication - #900

Open
JacobBarthelmeh wants to merge 9 commits into
wolfSSL:masterfrom
JacobBarthelmeh:winSysCerts
Open

Use of Windows certificate store for authentication#900
JacobBarthelmeh wants to merge 9 commits into
wolfSSL:masterfrom
JacobBarthelmeh:winSysCerts

Conversation

@JacobBarthelmeh

Copy link
Copy Markdown
Contributor

No description provided.

@JacobBarthelmeh JacobBarthelmeh self-assigned this Mar 25, 2026
Copilot AI review requested due to automatic review settings March 25, 2026 12:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds Windows Certificate Store integration to wolfSSH so host keys and client authentication keys can be sourced from the Windows cert store (including CI coverage on Windows).

Changes:

  • Add a Windows-only API to load a private key by locating a certificate in the Windows Certificate Store, and use CNG to sign during SSH handshakes/auth.
  • Extend cert manager plumbing and wolfsshd configuration to support system/user CA loading and cert-store-based host keys.
  • Update Windows build projects and add a GitHub Actions workflow to exercise file-vs-store interop permutations.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
wolfssh/test.h Prefer wolfCrypt Base16 when available; otherwise keep local Base16 decode helper.
wolfssh/ssh.h Add wolfSSH_CTX_UsePrivateKey_fromStore() Windows-only public API.
wolfssh/internal.h Add CTX private-key metadata for cert-store backed keys and internal helper prototypes.
wolfssh/certman.h Expose cert-manager setter and Windows cert-store spec parser API.
src/ssh.c Implement loading a CTX private key from the Windows Certificate Store.
src/internal.c Add cert-store signing path (CNG) and cert-derived RSA public-key extraction for KEX/auth flows.
src/certman.c Implement wolfSSH_SetCertManager() and wolfSSH_ParseCertStoreSpec().
ide/winvs/wolfsshd/wolfsshd.vcxproj Link against crypt32/ncrypt for cert-store features.
ide/winvs/wolfssh/wolfssh.vcxproj Link against crypt32/ncrypt for cert-store features.
ide/winvs/wolfsftp-client/wolfsftp-client.vcxproj Link against crypt32/ncrypt for cert-store features.
ide/winvs/unit-test/unit-test.vcxproj Link against crypt32/ncrypt for cert-store features; normalize XML header.
ide/winvs/echoserver/echoserver.vcxproj Link against crypt32/ncrypt for cert-store features.
ide/winvs/client/client.vcxproj Link against crypt32/ncrypt for cert-store features.
ide/winvs/api-test/api-test.vcxproj Link against crypt32/ncrypt for cert-store features; normalize XML header.
examples/sftpclient/sftpclient.c Add -W store:subject:flags support for client key from Windows cert store.
examples/echoserver/echoserver.c Add -W support for server host key from Windows cert store; skip key-file root search when using store.
examples/client/common.h Declare helper functions for cert-store key loading/auth setup.
examples/client/common.c Implement cert-store key loading wrapper + auth globals setup for x509v3 publickey auth.
apps/wolfsshd/wolfsshd.c Add host-key-from-store support and optional system/user CA store loading into wolfSSH cert manager.
apps/wolfsshd/configuration.h Add config getters for host-key store and Windows user-CA store options.
apps/wolfsshd/configuration.c Add parsing/storage for new config directives and defaults.
.github/workflows/windows-cert-store-test.yml Add Windows CI workflow to validate store/file combinations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/internal.c Outdated
Comment thread src/certman.c Outdated
Comment thread src/certman.c Outdated
Comment thread wolfssh/internal.h Outdated
Comment thread src/ssh.c Outdated
Comment thread src/ssh.c Outdated
Comment thread src/ssh.c Outdated
Comment thread src/internal.c
Copilot AI review requested due to automatic review settings April 14, 2026 03:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 22 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread wolfssh/certman.h
Comment thread src/ssh.c Outdated
Comment thread src/ssh.c
Comment thread apps/wolfsshd/wolfsshd.c Outdated
Comment thread apps/wolfsshd/configuration.c

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 23 changed files in this pull request and generated 9 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread wolfssh/ssh.h Outdated
Comment thread wolfssh/internal.h Outdated
Comment thread src/ssh.c Outdated
Comment thread src/internal.c Outdated
Comment thread src/internal.c Outdated
Comment thread apps/wolfsshd/wolfsshd.c Outdated
Comment thread configure.ac Outdated
Comment thread .github/workflows/windows-cert-store-test.yml Outdated
Comment thread src/internal.c Outdated

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #900

Scan targets checked: wolfssh-bugs, wolfssh-src

Findings: 2
2 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 23 changed files in this pull request and generated 8 comments.

Comment thread src/internal.c Outdated
Comment thread src/ssh.c Outdated
Comment thread src/ssh.c
Comment thread wolfssh/internal.h Outdated
Comment thread src/internal.c
Comment thread src/internal.c
Comment thread src/internal.c Outdated
Comment thread src/internal.c Outdated

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #900

Scan targets checked: wolfssh-bugs, wolfssh-src

Findings: 1
1 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

@JacobBarthelmeh
JacobBarthelmeh marked this pull request as ready for review July 2, 2026 22:27
Comment thread src/internal.c Outdated
Comment thread src/internal.c Outdated
@JacobBarthelmeh
JacobBarthelmeh marked this pull request as draft July 7, 2026 05:11
JacobBarthelmeh and others added 7 commits September 2, 2026 11:26
add Windows cert store test case

make windows cert feature default disabled and simplify macro guard

additional unit tests, advertise x509 and pubkey, use CN to match username, build check for WOLFSSL_SYS_CA_CERTS, fix for CM ref count

additional build test, uniform enum name, fail on unkown cert store ecc curve, tie in of loading whole cert store for sys CA's
…nged default from MY to required to be set

enable SHA1 with windows cert store test case

expand test cases, adjust to authorized key file, minor dead code adjustments

add more documentation, refactor duplicate code sections, clean up test cases, more adjustments to logging spamming protections

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It introduces and wires up a new Windows credential-loading path across core auth, daemon config, examples, and build systems, which is high-impact and warrants final human review despite only one concrete nit found here.

Review details
  • Files reviewed: 36/36 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread wolfssh/test.h

@aidangarske aidangarske left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skoll Multi-Scan Review

Modes: review + review-security

Overall recommendation: REQUEST_CHANGES
Findings: 5 total — 5 posted, 0 skipped
5 finding(s) posted as inline comments (see file-level comments below)

Posted findings

  • [High] [review-security] Default Windows builds accept certificates restricted to non-SSH purposesapps/wolfsshd/wolfsshd.c:696-702
  • [Medium] [review] Parse -W as an option before skipping the root searchexamples/echoserver/echoserver.c:3178-3182
  • [Medium] [review] Exercise the non-FPKI Windows CN-binding pathapps/wolfsshd/auth.c:2836-2856
  • [Medium] [review] Do not turn arbitrary certificate-parser failures into skipstests/unit.c:18409-18416
  • [Medium] [review] Distinguish certificate-store enumeration failure from end of storeapps/wolfsshd/wolfsshd.c:739-744

Review generated by Skoll

Comment thread apps/wolfsshd/wolfsshd.c
"[SSHD] LOCAL_MACHINE is the safer location for trust anchors.");
}

#ifdef WOLFSSH_NO_FPKI

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default Windows builds accept certificates restricted to non-SSH purposes · Security

BEFORE this PR, wolfsshd had no Windows user-CA-store trust-source path. AFTER, LoadUserCACertsFromStore() imports CA certificates from the configured store and explicitly permits authentication without FPKI, merely warning that TLS-server, S/MIME, or code-signing certificates may be accepted. An attacker-supplied chain reaches wolfSSH_CERTMAN_VerifyCerts_buffer(), while the WOLFSSH_NO_FPKI path omits application-purpose, EKU, and key-usage enforcement. The new Windows authentication branch then checks only that the leaf subject CN matches the requested username before creating the user's token. Consequently, anyone holding a valid certificate and private key issued by a configured CA can authenticate as the matching Windows account even when that certificate is explicitly restricted to serverAuth, S/MIME, code signing, or lacks digitalSignature usage. This affects the supplied Visual Studio configuration, which defines WOLFSSH_NO_FPKI. Existing tests use a certificate without an explicit incompatible EKU and therefore do not cover this bypass (RFC 6187 section 2.2 requires digitalSignature when KeyUsage is present and restricts EKU-bearing certificates to their indicated purposes).

Fix: Enforce SSH-appropriate leaf usage independently of FPKI: require digitalSignature whenever KeyUsage is present and, whenever EKU is present, require id-kp-secureShellClient or an explicitly configured equivalent. Retain FPKI as an additional profile check. Add Windows integration tests proving that valid matching-CN chains containing serverAuth-only or codeSigning-only leaves are rejected.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that this issue is pre-existing in wolfSSH master branch. The fix widens the scope some of this PR (will add more lines to it) but it is a good fix to have for all code paths making use of X509 certs without FPKI enabled.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wolfSSL PR (wolfSSL/wolfssl#11361) adds some of the EKU logic needed for a cleaner bit check instead of the added manual parsing of the ASN1 syntax used for now. Later wolfSSH will be able to conditionally remove the parsing based on version of wolfSSL linked with.

Comment thread examples/echoserver/echoserver.c Outdated
int i;
const char* spec;

for (i = 1; i < argc; i++) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parse -W as an option before skipping the root search · bug

The PR's preliminary scan treats every argument beginning with -W as the certificate-store option. This includes values consumed by preceding options and tokens following --. For example, a valid option value such as -a -WolfCA.pem makes EchoserverUsingCertStore() return true even though getopt will not process a -W option. wolfSSH_Echoserver() consequently skips ChangeToWolfSshRoot(), after which relative certificate and default host-key paths are resolved from an unexpected directory. The SFTP client avoids this ambiguity by using mygetopt() for its preliminary scan.

Fix: Use the same option string as the main parser, scan with mygetopt(), and restore myoptind afterward. Add coverage for an argument value beginning with -W and for --.

@JacobBarthelmeh JacobBarthelmeh Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had seen this previously, was trying to avoid having the options set as a macro. It seemed a bit clunky in the examples to do it that way and changing the location of ChangeToWolfSshRoot() teases out a Mac OS / clang bug that leads to a segfault. I'll update the echoserver though to have the macro set for options.

Comment thread apps/wolfsshd/auth.c
if (upnRealmUnchecked) {
wolfSSH_Log(WS_LOG_WARN, "[SSHD] AuthorizedUPNDomains "
"not set; certificate UPN domain is not checked");
#else

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exercise the non-FPKI Windows CN-binding path · test

The PR adds a distinct authentication path that binds certificates to Windows accounts through the subject CN when WOLFSSL_FPKI is absent. The new Windows workflow enables OPENSSL_ALL, which enables FPKI, and explicitly notes that only the UPN branch is exercised. Consequently, the newly introduced CN extraction, length comparison, and case-insensitive account matching can regress without any functional test detecting it.

Fix: Add a Windows build configuration without OPENSSL_ALL/WOLFSSL_FPKI and test a matching CN, a case-differing matching account name, and a mismatched CN.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will expand the test coverage.

Comment thread tests/unit.c
/* matching curve accepted; a failure here means the chain itself did
* not verify under this build's profile, so skip the curve vectors
* rather than fail on unrelated policy */
if (result == 0) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not turn arbitrary certificate-parser failures into skips · test

The new control vector converts every failure from the matching P-256 ParseECCPubKeyCert() path into a positive skip result. The test harness then ignores all positive results. A regression in the newly changed certificate-chain parser, curve binding, or root verification can therefore make this test print SKIPPED while CI remains green, preventing the subsequent mismatch vector from running as well.

Fix: Skip only for an explicitly identified unsupported build profile or unavailable fixture. Treat unexpected parser and verification errors as test failures, or provide a fixture valid under every profile in which the test is compiled.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now only WS_CERT_PROFILE_E should skip.

Comment thread apps/wolfsshd/wolfsshd.c Outdated
return WS_FATAL_ERROR;
}

/* Passing the previous context frees it and advances the enumeration. */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Distinguish certificate-store enumeration failure from end of store · bug

The PR's new loader treats any NULL result from CertEnumCertificatesInStore() as successful completion. Microsoft's API contract requires checking GetLastError() because NULL represents both normal exhaustion and enumeration errors. If an error occurs after at least one CA was loaded, loaded > 0 makes this function return success and report the partial trust-store load as complete, silently omitting the remaining configured authorities.

Fix: Capture GetLastError() immediately after enumeration returns NULL. Accept only the documented end-of-enumeration statuses such as CRYPT_E_NOT_FOUND and, where applicable, ERROR_NO_MORE_FILES; otherwise fail the load and avoid reporting partial success.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed to check GetLastError()

…tEnumCertificatesInStore, add extended key usage type check if present, fix for EKU checks with X509 use and add test case
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants