Repository navigation
Releases: smallstep/crypto
Releases · smallstep/crypto
Release list
Release v0.91.1
Merge pull request #1151 from smallstep/mariano/signeropts Support nil signer options in KMS and TPM signers
Release v0.91.0
What's Changed
- Use go tools by @maraino in #1131
- Add support for creating signers with (just)
hashon MacKMS by @hslatman in #1134
Dependencies
- chore(deps): Bump github.com/aws/aws-sdk-go-v2/config from 1.33.1 to 1.33.3 by @dependabot[bot] in #1124
- chore(deps): Bump github.com/aws/aws-sdk-go-v2/service/kms from 1.57.1 to 1.60.0 by @dependabot[bot] in #1133
- chore(deps): Bump github.com/aws/aws-sdk-go-v2/config from 1.33.3 to 1.33.4 by @dependabot[bot] in #1132
- chore(deps): Bump modernc.org/sqlite from 1.57.0 to 1.58.0 by @dependabot[bot] in #1128
- chore(deps): Bump github.com/googleapis/gax-go/v2 from 2.24.0 to 2.24.1 by @dependabot[bot] in #1125
- chore(deps): Bump google.golang.org/api from 0.293.0 to 0.297.0 by @dependabot[bot] in #1126
Full Changelog: v0.90.0...v0.91.0
Release v0.90.0
What's Changed
- Let applications contribute template functions by @joshdrake in #1117
- Add support for ML-DSA algorithms by @maraino in #1098
- Complete mldsa package by @maraino in #1123
Dependencies
- chore(deps): Bump github.com/stretchr/testify from 1.11.1 to 1.12.0 by @dependabot[bot] in #1109
- chore(deps): Bump google.golang.org/protobuf from 1.36.11 to 1.36.12 by @dependabot[bot] in #1108
- chore(deps): Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.22.0 to 1.23.0 by @dependabot[bot] in #1107
- chore(deps): Bump google.golang.org/api from 0.292.0 to 0.293.0 by @dependabot[bot] in #1105
- chore(deps): Bump golang.org/x/crypto from 0.54.0 to 0.55.0 by @dependabot[bot] in #1106
- chore(deps): Bump golang.org/x/net from 0.57.0 to 0.58.0 by @dependabot[bot] in #1110
- chore(deps): Bump google.golang.org/grpc from 1.83.0 to 1.83.1 by @dependabot[bot] in #1113
- chore(deps): Bump github.com/googleapis/gax-go/v2 from 2.23.0 to 2.24.0 by @dependabot[bot] in #1114
- chore(deps): Bump modernc.org/sqlite from 1.56.0 to 1.57.0 by @dependabot[bot] in #1111
- chore(deps): Bump github.com/stretchr/testify from 1.12.0 to 1.12.1 by @dependabot[bot] in #1112
- chore(deps): Bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.14.0 to 1.14.1 by @dependabot[bot] in #1122
- chore(deps): Bump google.golang.org/grpc from 1.83.1 to 1.83.2 by @dependabot[bot] in #1121
- chore(deps): Bump github.com/aws/aws-sdk-go-v2/config from 1.32.35 to 1.33.1 by @dependabot[bot] in #1119
- chore(deps): Bump github.com/aws/aws-sdk-go-v2/service/kms from 1.55.4 to 1.57.1 by @dependabot[bot] in #1118
Full Changelog: v0.89.0...v0.90.0
Release v0.90.0-rc2
Merge pull request #1123 from smallstep/mariano/mldsa-stub-fix Complete mldsa package
Release v0.90.0-rc1
Merge pull request #1098 from smallstep/mariano/pq-cloudkms Add support for ML-DSA algorithms
Release v0.89.0
What's Changed
- Recertify a TPM key with new qualifying data by @tedmalone in #1092
New Contributors
- @tedmalone made their first contribution in #1092
Full Changelog: v0.88.0...v0.89.0
Release v0.88.0
What's Changed
- Fix pkcs11 tests on macOS by @maraino in #1104
- Add support for subject DN components in MacKMS certificate URIs by @joshdrake in #1073
Dependencies
- chore(deps): Bump google.golang.org/api from 0.290.0 to 0.291.0 by @dependabot[bot] in #1093
- chore(deps): Bump github.com/aws/aws-sdk-go-v2/config from 1.32.31 to 1.32.34 by @dependabot[bot] in #1094
- chore(deps): Bump modernc.org/sqlite from 1.54.0 to 1.55.0 by @dependabot[bot] in #1097
- chore(deps): Bump github.com/aws/aws-sdk-go-v2/service/kms from 1.55.0 to 1.55.3 by @dependabot[bot] in #1095
- chore(deps): Bump google.golang.org/grpc from 1.82.1 to 1.83.0 by @dependabot[bot] in #1096
- chore(deps): Bump google.golang.org/api from 0.291.0 to 0.292.0 by @dependabot[bot] in #1100
- chore(deps): Bump modernc.org/sqlite from 1.55.0 to 1.56.0 by @dependabot[bot] in #1101
- chore(deps): Bump github.com/aws/aws-sdk-go-v2/service/kms from 1.55.3 to 1.55.4 by @dependabot[bot] in #1102
- chore(deps): Bump github.com/aws/aws-sdk-go-v2/config from 1.32.34 to 1.32.35 by @dependabot[bot] in #1103
Full Changelog: v0.87.0...v0.88.0
Release v0.87.0
Add experimental certificate search to the KMS layer (#1089)
* Add experimental CertificateSearcher KMS interface
An optional interface for KMS implementations that can enumerate a
certificate store's contents together with each certificate's private-key
association. The key-container name is reported from certificate metadata
rather than by opening the key, so callers can identify which certificates
belong to which keys — including certificates whose private key no longer
exists.
Change-Type: feature
Release-Note: no
Audience: developer
Impact: low
Breaking: false
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Fix cryptFindCertificateKeyContainerName to actually read the property
The second CertGetCertificateContextProperty call passed a nil,
never-allocated buffer, and the function unconditionally returned an
empty name. Nothing called it, so no existing behavior depended on the
broken result.
Replace the body with the two-call size-then-data protocol the sibling
property helpers use, distinguishing a certificate with no key
association (CRYPT_E_NOT_FOUND, empty name) from genuine read failures.
Change-Type: fix
Release-Note: no
Audience: developer
Impact: low
Breaking: false
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Implement SearchCertificates for the CAPI KMS
Enumerates the certificate store selected by the request URI's
store-location and store attributes and returns each certificate
together with its key-container name, read from the CERT_KEY_PROV_INFO
property rather than by opening the key — so certificates whose key no
longer exists are still reported. A mid-enumeration failure returns the
certificates gathered so far alongside the error, and a certificate
whose DER cannot be parsed or whose properties cannot be read is
skipped rather than failing the search.
Change-Type: feature
Release-Note: no
Audience: developer
Impact: low
Breaking: false
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Copy certificate DER out of store contexts and close the search's store handle
x509.ParseCertificate aliases its input, so certContextToX509 handed out
certificates whose Raw, RawSubject, and related fields pointed into
store-owned memory — freed by the next enumeration advance, or kept
alive only by store handles that were never closed. Clone the DER before
parsing; every caller of the helper gets certificates backed by
Go-owned memory.
SearchCertificates now closes its store handle. It runs on every
certificate issuance in long-running callers, where an unclosed handle
per call accumulates without bound.
Change-Type: fix
Release-Note: no
Audience: developer
Impact: low
Breaking: false
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Expose SearchCertificates through the platform KMS
Delegates to backends implementing CertificateSearcher, applying the
same request-URI translation CleanupCredentials uses so callers can
address the platform scheme uniformly. Platforms whose backend lacks
the interface report NotImplementedError.
Change-Type: feature
Release-Note: no
Audience: developer
Impact: low
Breaking: false
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Harden the certificate search and document its partial-results contract
Keep the property buffer alive across the UTF-16 walk in
cryptFindCertificateKeyContainerName: the container name is an interior
pointer into a buffer the garbage collector treats as pointer-free, so
without runtime.KeepAlive the buffer could be collected mid-read.
Document at the interface and the platform wrapper that a failed search
may still return the certificates enumerated before the failure, and
assert the recorded container name in the delegation test so the
property read is verified against a known value. Also: singular
SearchCertificateResult to match the SearchKeys family, experimental
notices on the payload types, unsafe.Slice in place of the deprecated
reflect.SliceHeader, and test cleanup registered via t.Cleanup
immediately after the store write.
Change-Type: fix
Release-Note: no
Audience: developer
Impact: low
Breaking: false
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Implement SearchCertificates for the TPM KMS
The platform KMS selects the TPMKMS backend for default \"kms:\" URIs on
Windows (kms_windows.go's newKMS routes PlatformKMS, DefaultKMS, and TPMKMS
alike to newTPMKMS), not CAPIKMS. TPMKMS had no SearchCertificates method, so
the platform wrapper's apiv1.CertificateSearcher type assertion failed and
returned apiv1.NotImplementedError{} for the exact configuration production
consumers use. On real hardware this made a certificate sweep built on
SearchCertificates a silent no-op: superseded certificates were never found,
so they were never deleted.
Add TPMKMS.SearchCertificates, mirroring CleanupCredentials: it requires the
Windows certificate store to be configured, reads store-location/store
overrides from the request URI (falling back to the instance's configured
store), and delegates to the same windowsCertificateManager (capi.CAPIKMS on
Windows) used by CleanupCredentials, LoadCertificateChain, and
StoreCertificateChain. The response is returned unmodified so the
partial-results contract (a non-nil response alongside a non-nil error on a
mid-enumeration failure) flows through untouched.
Extend the capiCertificateManager interface with SearchCertificates; the only
test fake implementing it (fakeWindowsCertificateManager, gated behind the
tpmsimulator build tag) gets a no-op implementation to keep compiling.
Tests: a host-runnable tpmkms test asserts a TPMKMS not configured for the
Windows certificate store (the only possible state off Windows) returns
NotImplementedError. A new Windows test in kms/platform constructs the
platform KMS the same way the production consumer does - a default \"kms:\"
URI with no backend argument - confirms it resolves to TPMKMS, and exercises
store/search/delete end to end; it requires a TPM with the Windows Platform
Crypto Provider and skips via the file's existing SkipTests() guard when none
is available.
Change-Type: fix
Release-Note: no
Audience: developer
Impact: low
Breaking: false
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Pin the TPM KMS search delegation with host-runnable tests
Review follow-up on the SearchCertificates fix: the only test reaching
TPMKMS.SearchCertificates's delegation body was Windows+TPM-gated, so it runs
on zero CI runners. The downstream capi URI construction (store-location and
store attribute spellings) is exactly where a typo would silently search the
wrong certificate store, reproducing the original symptom, and nothing
caught that on ubuntu CI.
Add TestTPMKMS_SearchCertificates_delegation (tpmkms_search_test.go), a
host-runnable test using a recording capiCertificateManager fake, no TPM or
Windows required. It asserts the request Name TPMKMS hands its Windows
certificate manager parses to store-location=machine;store=My when the
caller's URI carries those overrides (mirroring what the platform wrapper's
transformToTPMKMS produces for "kms:store-location=machine;store=My"), and
that it falls back to the instance's configured defaults when the caller's
URI carries none. This pins hop 8 of the delegation on every CI run.
Fix fakeWindowsCertificateManager.SearchCertificates (tpmkms_simulator_test.go,
gated behind the tpmsimulator build tag): it previously returned (nil, nil),
the exact shape the original bug produced, so a future test written against
it could assert nothing and still pass. It now records the request it
received and returns a canned non-nil response with one result, unless a
test configures searchResp/searchErr explicitly.
TestKMS_SearchCertificates_platform (kms_windows_test.go) is left using the
user/My defaults rather than store-location=machine;store=My: writing to the
machine store needs administrator privileges, which the TPM-equipped test
runner isn't guaranteed to have, and store/search/delete need to agree with
each other. The override branch (tpmkms.go's SearchCertificates,
location/store fallback) is covered instead by the new host-runnable
delegation test above, which runs unconditionally on ubuntu CI rather than
only on a TPM-equipped Windows box.
Also note in TPMKMS.SearchCertificates's doc comment that the platform
wrapper's URI transform unconditionally injects
skip-find-certificate-key=true into every Windows request, including
searches; it's parsed but unused on this path since it only matters for
certificate-to-key association during store.
Change-Type: fix
Release-Note: no
Audience: developer
Impact: low
Breaking: false
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Follow-ups to the certificate searcher: bounds-checked property reads, store handle leaks (#1091)
* capi: read the key container name out of the property buffer
cryptFindCertificateKeyContainerName followed the pwszContainerName
pointer CryptoAPI wrote into the property buffer, walking UTF-16 until a
NUL with no relation to the size the API reported, and pinned the buffer
with runtime.KeepAlive.
The KeepAlive was a no-op: Go's garbage collector retains an object when
any pointer into it is live, and both info and info.pwszContainerName are
interior pointers into buf. Noscan means the collector does not scan
inside buf for outgoing pointers; it says nothing about incoming
references. The comment justifying the KeepAlive stated the opposite, and
would have been copied to somewhere it mattered.
The hazard that was real is the unbounded read. Decode the string out of
buf instead, so every read is bounds-checked against the reported size and
a short or malformed property yields an error rather than reading past the
buffer.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* capi: report certificates with unreadable key metadata
SearchCertificates dropped a certificate whenever its CERT_KEY_PROV_INFO
could not be read. A certificate with no private-key association already
reads back as ("", nil) via CRYPT_E_NOT_FOUND, so the only certificates
reaching that path were ones whose association exists but is corrupt --
exactly the population this API was added to find. Silently omitting them
inverts the purpose of the search.
Return the certificate with the read failure recorded on the new
SearchCertificateResult.Err field, which also lets a caller tell "no key
association at all" apart from "association present but unreadable". A
certificate whose DER cannot be parsed is still skipped: there is no
certificate to report.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* capi: cover the key container name reader on Windows
The existing capi test stores with skip-find-certificate-key=true and
asserts the container name comes back empty, so it passes just as happily
against the reader this branch's parent replaced -- one that returned ""
unconditionally. The only assertion of a real container name lives in a
test needing both a TPM and Windows.
Add a capi-level test that pins the name. StoreCertificate's "key" branch
records the association without checking that the container exists, so the
test needs no key, no TPM and no administrative rights, and it sets up
precisely the state SearchCertificates exists to detect: a certificate
naming a key container that is not there.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* capi: close certificate store handles
Six functions opened a system certificate store with the same twenty lines
of location switch, CertOpenStore and error wrap, and five of them never
closed the handle. SearchCertificates, added on the parent branch, was the
only one that did, on the grounds that a search invites frequent calls;
but FindCertificatesByIssuer and CleanupCredentials are called just as
often by the same long-running sweeps, and every LoadCertificate,
CreateSigner and GetPublicKey leaks one through getCertContext.
Extract openCertStore and close the handle at all six sites. Closing with
no flags only drops a reference -- a certificate context obtained from a
store holds its own -- so getCertContext can close with a defer while
still handing a live context back to its caller. CERT_CLOSE_STORE_FORCE_FLAG
would not be safe there and is deliberately not used.
Consolidating also fixes a latent GC hazard the six copies shared: the
store name was converted to uintptr inside the call, leaving no Go pointer
to it, so it could be reclaimed while CertOpenStore ran. The compiler's
special case for that pattern covers only conversions written inside a
syscall.Syscall call, which this is not, so the string is now held in a
variable and kept alive across the call.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* capi: centralize the CRYPT_E_NOT_FOUND check, drop a dead branch
Five places distinguished "not there" from "failed to look" with a bare
err.(windows.Errno) type assertion, which silently stops working the day
the error arrives wrapped. Replace them with an isNotFound helper built on
errors.As.
Also remove the certHandle == nil branch in SearchCertificates. x/sys sets
err whenever CertEnumCertificatesInStore returns a nil context -- errnoErr
maps a zero errno to EINVAL rather than nil -- so the branch was
unreachable, and having it there implied the two conditions were
independent.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* platform: reject a nil SearchCertificates request
The wrapper dereferenced req in clone(req) before any validation, so a nil
request panicked where both backends that implement the interface return
an error. Validate at the wrapper, which is the entry point most callers
reach the KMS through; capi and tpmkms keep their own checks, since both
are exported backends used directly as well.
platform.CleanupCredentials has the same gap, left alone here.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Rename SearchCertificateResult.KeyContainerName to KeyName
Review feedback (maraino): KeyContainerName spelled a CAPI implementation
detail into a cross-KMS interface. The value it carries is the key's name in
the KMS's own namespace — for capi specifically, capi.go's ContainerNameArg
is "key", and parseURI populates uriAttributes.keyContainerName from that
attribute, so the returned name is exactly what a caller feeds back into
"capi:key=<name>" to address the key.
Rename the field to KeyName and restructure its doc comment: the generic
meaning (the value a KMS URI's key attribute takes) leads, and the CNG/CAPI
key-container specifics — including that it is read from the certificate's
key-provider properties rather than by opening the key, so it survives the
key's deletion — move to a capi-specific paragraph.
Keep it a bare name rather than a full KMS URI, which is where the
SearchKeys precedent sits (SearchKeyResult is a CreateKeyResponse, whose
Name is a URI). A bare name is what the motivating caller wants — it
compares the value against the set of key names it manages — and keeping it
URI-free is what lets the platform wrapper return the response unmodified,
as its doc comment states.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Rename CertificateSearcher to SearchableCertificateManager
Review feedback (joshdrake): the interface broke from the naming convention
its neighbours follow. apiv1 splits two ways — bare single-method interfaces
take an -er name (KeyDeleter, CertificateDeleter, CredentialsCleaner,
Attester), while interfaces that embed a manager and extend it take a
Manager name (SearchableKeyManager is KeyManager plus SearchKeys).
CertificateSearcher sat in the second group structurally but wore a first-
group name.
Rename it to SearchableCertificateManager, the exact parallel of
SearchableKeyManager, and switch the embedded interface from KeyManager to
CertificateManager so the name describes what the type actually is. That
also makes the embed the useful one: a caller enumerating a store to find
broken credentials reaches for LoadCertificate and StoreCertificate, not
CreateKey and CreateSigner. All three implementers — CAPIKMS, TPMKMS, and
platform.KMS — already satisfy CertificateManager, and platform's runtime
assertion is against a backend whose extendedKeyManager constraint requires
it, so nothing narrows in practice.
Move the declaration to sit directly below CertificateManager, matching how
SearchableKeyManager sits below KeyManager, so the embedded interface is
declared before the interface extending it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Diego Fronza <darkfronza@gmail.com>
Release v0.86.0
What's Changed
- fipsutil: report which module is linked, not just the mode by @joshdrake in #1090
- Fix issues on gotip by @hslatman in #1072
Dependencies
- chore(deps): Bump github.com/googleapis/gax-go/v2 from 2.22.0 to 2.23.0 by @dependabot[bot] in #1081
- chore(deps): Bump golang.org/x/term from 0.44.0 to 0.45.0 by @dependabot[bot] in #1080
- chore(deps): Bump golang.org/x/crypto from 0.53.0 to 0.54.0 by @dependabot[bot] in #1077
- chore(deps): Bump golang.org/x/net from 0.56.0 to 0.57.0 by @dependabot[bot] in #1079
- chore(deps): Bump google.golang.org/grpc from 1.82.0 to 1.82.1 by @dependabot[bot] in #1082
- chore(deps): Bump cloud.google.com/go/kms from 1.31.0 to 1.32.0 by @dependabot[bot] in #1078
Full Changelog: v0.85.0...v0.86.0
Release v0.85.0
What's Changed
- Make TPM dirstore cache size configurable by @darkfronza in #1070
Dependencies
- chore(deps): Bump google.golang.org/api from 0.286.0 to 0.288.0 by @dependabot[bot] in #1068
- chore(deps): Bump github.com/aws/aws-sdk-go-v2/service/kms from 1.53.5 to 1.54.1 by @dependabot[bot] in #1065
- chore(deps): Bump github.com/aws/aws-sdk-go-v2/config from 1.32.26 to 1.32.30 by @dependabot[bot] in #1067
- chore(deps): Bump github.com/aws/aws-sdk-go-v2/service/kms from 1.53.4 to 1.53.5 by @dependabot[bot] in #1064
- chore(deps): Bump github.com/aws/aws-sdk-go-v2/config from 1.32.25 to 1.32.26 by @dependabot[bot] in #1063
- chore(deps): Bump github.com/ThalesGroup/crypto11 from 1.6.0 to 1.6.2 by @dependabot[bot] in #1069
- chore(deps): Bump google.golang.org/grpc from 1.81.1 to 1.82.0 by @dependabot[bot] in #1066
Full Changelog: v0.84.1...v0.85.0