Implement PKCS#11 certificate support in ssh-agent#865
Open
VSSOtt wants to merge 8 commits into
Open
Conversation
Bring the Windows agent implementation in line with upstream support for associated-certs-v00@openssh.com. Match supplied certificates to PKCS#11-backed RSA and ECDSA keys, persist and reload certificate identities, and support certificate-only loading. Enable the existing -C option in the Windows ssh-add argument parser. Persist certificate identities separately from their underlying keys and reconstruct their PKCS#11 signing state after an agent restart. Allow individual certificate deletion while preserving provider-wide removal behavior. Keep the existing provider allowlist, remote-provider restrictions, and encrypted PIN storage intact. Reject malformed, duplicate, truncated, and oversized certificate constraints. Add Windows unit and Pester coverage for RSA and ECDSA certificates, certificate-only loading, unmatched certificates, deletion, provider removal, and service restart.
Treat repeated provider additions as additive and idempotent because the Windows service persists providers and identities across client and service lifetimes. Unlike the in-memory Unix agent, this allows certificates to be added in separate requests without replacing earlier identities. Roll back only identities created by the failed request and preserve all previously persisted state.
Try the regular fingerprint-backed Registry entry before falling back to the PKCS#11 certificate identity name. This preserves individual removal for both software-backed and token-backed certificates when PKCS#11 support is enabled. Add Windows regression coverage for RSA and ECDSA software certificates.
Continue past persisted providers that cannot be loaded while rebuilding the transient PKCS#11 key set for a sign request. The requested identity still fails when its backing key is unavailable, while software keys and identities from other providers remain usable. Cover signing with a stale provider record in the Windows PKCS#11 E2E tests.
Persist the PKCS#11 provider association separately from the user-visible identity comment and use the label returned by the provider. Empty labels continue to fall back to the canonical provider path. Keep legacy Registry entries readable and removable, migrate their metadata on a repeated add, and preserve labels across merged certificate additions and service restarts.
Skip persisted provider records with invalid or oversized Registry metadata while rebuilding the transient signing key set. This keeps corrupt records from causing unbounded allocations or blocking unrelated identities. Free Windows PKCS#11 provider list entries during termination and extend the stale-provider regression to cover oversized encrypted PIN data.
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
Author
|
@microsoft-github-policy-service agree |
Author
|
/azp run |
|
Commenter does not have sufficient privileges for PR 865 in repo PowerShell/openssh-portable |
There was a problem hiding this comment.
Pull request overview
This PR adds Windows ssh-agent support for OpenSSH certificates backed by PKCS#11 token keys (via associated-certs-v00@openssh.com), aligning behavior with upstream semantics while preserving the Windows agent’s registry-backed persistence model.
Changes:
- Add Windows support code for constructing PKCS#11-backed certificate identities and persisting/loading them across agent restarts.
- Extend the Windows agent request handling to support PKCS#11 certificate add/list/delete flows and more robust signing behavior with stale providers.
- Add Windows unit tests + Pester E2E coverage and wire new Win32 PKCS#11 cert helper code into the build.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
ssh-pkcs11-client.c |
Fix provider lifecycle memory handling; add Windows implementation for PKCS#11-backed cert private keys. |
ssh-add.c |
Enable -C parsing on Windows to support certificate-only PKCS#11 adds. |
regress/unittests/win32compat/tests.h |
Declare new PKCS#11 cert test entry point. |
regress/unittests/win32compat/tests.c |
Register PKCS#11 cert unit tests in the Windows test runner. |
regress/unittests/win32compat/pkcs11_cert_tests.c |
Add unit tests for PKCS#11 cert constraint parsing and identity naming/comment behavior. |
regress/pesterTests/README.md |
Document required environment variables for PKCS#11 certificate E2E tests. |
regress/pesterTests/KeyUtils.Tests.ps1 |
Add Pester E2E scenarios for PKCS#11 certificate add/sign/restart/delete flows and stale-provider isolation. |
regress/pesterTests/CommonUtils.psm1 |
Make askpass environment setup more robust across PowerShell/Windows environments. |
contrib/win32/win32compat/ssh-agent/keyagent-request.c |
Implement persisted PKCS#11 cert identities + provider/identity registry management and signing behavior updates. |
contrib/win32/win32compat/pkcs11-cert.h |
Add Win32 helper API for cert constraints and identity naming/comment logic. |
contrib/win32/win32compat/pkcs11-cert.c |
Implement constraint parsing and PKCS#11 cert identity naming/comment helpers. |
contrib/win32/openssh/unittest-win32compat.vcxproj |
Add the new helper + unit test compilation units to the Win32 test project. |
contrib/win32/openssh/ssh-agent.vcxproj |
Add the new helper compilation unit/include to the Windows ssh-agent project. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Keep SECURITY_ATTRIBUTES.nLength stable when converting Registry security descriptors by using a separate descriptor-size variable. Also wipe the full encrypted PIN allocation during provider reload cleanup.
Set SSHKEY_FLAG_EXT in the Windows wrap_key() path, matching the non-Windows helper and keeping the runtime flag with the private-operation redirection. Move the flag assignment there for consistency, so wrapped keys are marked external at their creation point instead of only in the certificate path. Remove the now-redundant certificate-specific assignment.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR Summary
Implement Windows
ssh-agentsupport for OpenSSH certificates backed byPKCS#11 token keys via
associated-certs-v00@openssh.com.The implementation covers RSA and ECDSA token keys and includes:
ssh-add -s provider -C cert.pubseparate requests without dropping existing persisted identities
PR Context
The Windows
ssh-addhelp text already advertised the PKCS#11 certificateflow, but the Windows agent did not handle certificate identities
from
associated-certs-v00@openssh.com. As a result, adding certificatesappeared to succeed without making them usable as agent identities.
Upstream OpenSSH already defines how certificates are associated with
PKCS#11-backed keys. The main Windows-specific difference is persistence:
unlike the usual Unix agent model, the Windows agent stores PKCS#11 providers
and identities in the registry and reloads them after the service restarts.
Because of that persistent model, repeated provider adds merge with existing
stored identities instead of replacing them. This allows certificates for the
same token provider to be added in separate requests while preserving
certificates and plain token-key identities that were already stored.
This PR intentionally does not change the existing Windows PKCS#11 constraint
semantics. Constraints such as confirm, lifetime, and destination restrictions
may be accepted for PKCS#11 provider additions, but they are still not enforced
for persisted Windows PKCS#11 identities. In particular,
ssh-add -c -s ...,ssh-add -t ... -s ..., and destination-constrained PKCS#11 additions shouldnot be treated as protected by those constraints.
This implementation keeps these existing security boundaries intact:
Validation
Windows x64 Debug/Release and x86 Release builds, Windows unit tests, Pester
tests, bash regressions, and non-Windows regression coverage pass.
Real-token validation was performed with a YubiKey 5 using RSA 2048 and ECDSA
NIST P-256. It covered: