Repository navigation
Releases: mingulov/pkcs11-proxy-ng
Release list
pkcs11-proxy-ng v0.2.2
v0.2.2 is a testing candidate that follows the published v0.2.1
release. Its theme is client-blocker repair: three v0.2.1 regressions
reported against a real client project are fixed with failing-first
regression tests and A/B base-vs-patched validation. See the candidate
notes.
Fixed
- Daemon crash on
C_MessageEncryptInitwithCK_CHACHA20_PARAMS(#37):
unmodeled message-opaque parameter bytes are no longer forwarded
verbatim when the mechanism declares a pointer-struct shape. A strict
shape gate (message_opaque_admits_shape) admits only byte-buffer and
parameterless shapes and fails closed on unknown shapes; the shim
refuses locally withCKR_MECHANISM_PARAM_INVALID(zero RPC), and the
server backstop refuses opaque struct images at message-init, plain
encrypt/decrypt init, and authenticated-wrap validation. Flat-byte
opaque (e.g. CBC IV) and typed classic ChaCha20 paths are unchanged. - Private
CKO_DATAobjects lost across logout/login (#35): providers
that rotate private handles at logout no longer strand session-scoped
objects. Positively session-scoped (CKA_TOKEN=false) unmapped
handles are admitted when the session is the sole holder on the slot,
with post-scan re-verification; shared-slot handles stay hidden per
CROSS-PROC-001 isolation. CKO_CERTIFICATEobjects never found (#36): providers that omit
CKA_PRIVATEwhen unset (absent means public) are honored via the
mint-record fallback, which admits recorded-public objects and keeps
recorded-private, unrecorded, and foreign handles hidden.- Last-mile message-opaque backstop (review F-01): fresh message-init
construction re-checks admission against the request registry
snapshot carried by the validated mechanism — the same snapshot the
server gate used, so the two cannot disagree. Begin/Next/OneShot
byte-reuse splits into a separate documented constructor. - Cross-context destroy eviction (review F-02):
C_DestroyObject
now evicts the backend handle's mappings, privacy bits, and cached
metadata in every context, closing the daemon-mediated
handle-recycling ABA leg. Out-of-band provider mutation stays an
accepted residual (see notes).
Changed
- Version bookkeeping is single-sourced:
scripts/sync-versions.sh
mirrors the workspaceCargo.tomlversion into crate pins,
packaging files, and the README token (with a--checkmode wired
into the packaging smoke); docs prose and workflow examples are
version-free, so future bumps touch no documentation by hand.
Known limitations
- All v0.2.1 limits carry forward, including the single logical client in
one trusted security domain per daemon/provider instance. The v1
typed-presence wire is decode-side only at the Phase-2 gate where
noted; mixed shim/daemon versions are unsupported. Backend token
objects outlive the client's Finalize/Initialize cycle (#27);
stale-session message calls answer SHI by default and may differ
from args-first native providers (#23 defect 4). - Message-path mechanisms whose parameter shape is unmodeled are refused
withCKR_MECHANISM_PARAM_INVALIDinstead of forwarding caller bytes;
typed support for additional message parameter shapes is future work.
pkcs11-proxy-ng v0.2.1
v0.2.1 is a testing candidate that supersedes the unpublished v0.2.0
candidate. Its theme is shape truthfulness: caller-NULL versus empty
distinctions are now preserved exactly across the shim, wire, daemon, and
backend FFI, with machine-checkable mechanism-parameter shapes and
transport validation at every server site. See the candidate
notes.
Added
- Typed presence v1 wire schema (
Flat/Null, version 83) with a
machine-checkable mechanism-parameter manifest: shared shape
descriptors, resolver, fingerprints, and a Phase-2 gate. The shim emits
typed v1 readers with presence; the server validates transport shape
(PointerBytes,ValidatedMechanismParams) at every handler site; the
backend reconstructs Flat/Null at the FFI boundary with guarded backing.
Verbatim and completeness quality gates pin the behavior, and exotic-tail
envelopes cover the remaining input-pointer tail under decision D1(a). - End-to-end
C_GetAttributeValuetemplate presence (FIX-1): a
template_nullwire bit travels from the shim through the daemon to the
backend FFI, which materializes a real NULL for absent templates. The
daemon fail-closed rejects an absent marker with a non-empty payload.
Proven against a real Kryoptic backend, where NULL versus empty is
provider-observable. - Truthful 3.0 advertisement from slot provenance with 3.0 to 3.1 to 3.2
dispatch, plus discovery of explicit{3,1}interfaces. - Packed-32 (win32 ILP32) as a fourth v1 ABI, with
ParamAbi::native()for 32-bit Windows. - Shim regression nets: read-after-destroy canary (#26), NULL-shape
termination/parity net (#30, #31), blocking slot-wait refusal with
finalize regression (#25), async fixed-refusal 16-leg matrix (#24), and
post-restart stale-handle0x82regression (#32). - Assurance: cargo-fuzz harnesses with corrected seeds, expanded Miri
scope, Kani proofs adopted for the width-translation laws, a coverage
ratchet, and secret-boundary canaries with attribute classifier laws. - Performance instrumentation: T1 comparator with receipts, RSA/EC keygen
template parity gate, sign-pair latency bench receipts, degraded-
operation control qualification (T3), and direct-leg bench mode (T4). - macOS arm64 bundle packaging with smoke, CI lanes, and install doc.
- Release engineering: single-invocation workspace repackaging, tag
checkout with out-of-repo artifact staging, CI candidate resolution from
the green tag run, and cut-release dispatch fixes.
Fixed
- Message-path shape handling: request-shape validation before session
resolution (S1D4), residual auth-blocking gates hoisted above the
session lock (SDD T4), NULL/nonzero preservation onVerifyMessageNext
(S1D3), CK_ULONG-aligned provider-written query output (SDD T5), Raw
auth-input negative branch coverage (SDD T1), Raw message parameters
accepted at the backend FFI boundary, and D6(1)-gated operations
forwarded after a contended PIN login. - Verify-then-fix campaigns for independent review findings (F1-F6,
NF1-NF7) and the deferred-minor wave (R16/R18/R19/R21/R23). - Pre-existing i686/Windows test failures, win32
ParamAbi::native(),
and win32 manifest failures on CRLF checkouts. - Recorded decisions: RF-MC-ORDER option (a) — session arms stay
SHI-first with an arm-difference pin; S1D4 AB-beats-stale-session
scoped tosanitize_inputson with a spec-precedence pin (#23). - Solved decisions: memory token objects survive the client
Finalize/Initialize cycle by design, pinned by a restart-lifecycle
lock test (#27, known issue); #23 defect 4 solved as an accepted
limitation — default SHI-first per spec §5.1.7 with a sanitize-on
AB-first exception, native Kryoptic args-first order pinned as
provider evidence.
Known limitations
- All v0.2.0 limits carry forward, including the single logical client in
one trusted security domain per daemon/provider instance. The v1
typed-presence wire is decode-side only at the Phase-2 gate where
noted; mixed shim/daemon versions are unsupported. Backend token
objects outlive the client's Finalize/Initialize cycle (#27);
stale-session message calls answer SHI by default and may differ
from args-first native providers (#23 defect 4).
pkcs11-proxy-ng v0.2.0
v0.2.0 is a testing candidate for one logical client in one trusted security
domain per daemon/provider instance. Restart both before switching independent
clients or domains. Multi-client isolation and final platform/provider
validation remain open; see the candidate notes.
Added
- Optional authorization policies based on client certificate identity, with
object, class, mechanism, and extraction grants; per-principal rate and
session quotas; and per-slot failed-login limits. Unmatched identities are
denied when a policy is configured.allow_all_authenticatedis an explicit
override;anonymous_principalis an audit label and never grants access.
Policies and allow-all settings require authenticated listeners. - Tamper-evident audit logs with a hash chain and signed checkpoints. Records
contain operational metadata, never PINs, keys, or raw payloads. Data-plane
records can be dropped with gap reporting; fail-closed security records can
reject a request after a backend side effect. - Startup backend attestation using the module hash and library/token identity.
Configuration hashes and reconnect/hot-swap re-attestation are not included. - Backend object-population limits, authenticated local metrics, and optional
context-scoped attribute coalescing. [proxy] sanitize_inputs = trueto reject NULL data pointers with nonzero
lengths and NULL init mechanism pointers before calling the provider. It
defaults tofalse. Rejections returnCKR_ARGUMENTS_BADand leave the
active backend operation intact.- Server-managed mechanism registry, reloadable with SIGHUP and distributed
to shims throughGetBackendInterfaces. Operator exclusions hide mechanisms
from discovery and reject their use withCKR_MECHANISM_INVALID.
PKCS11_PROXY_DISABLE_SERVER_REGISTRY=1selects the local registry for testing. - Startup and shutdown timeouts (30 seconds by default), a configurable backend
health failure threshold, rejection of the shipped placeholder module path,
and a startup warning for explicitly enabled unauthenticated TCP. - Legacy
PKCS11_PROXY_SOCKET=tcp://host:portsupport.
PKCS11_PROXY_ENDPOINTtakes precedence when both are set.
LOG_FORMAT=plainselects readable logs; JSON remains the default. - Alpine 3.22/3.23 APK and Amazon Linux 2023 RPM builds in GitLab CI. Packages
are split into shim, daemon, and CLI, with an optional compatibility symlink
package. Carrier images expose packages at/apkor/rpm. - Windows x64/MSVC daemon and shim builds, a Windows ZIP release bundle, and
additional Linux cross-width, musl, and platform checks. Validation limits
are listed in the candidate notes. - Typed X3DH transport and backend FFI conversion. The shim still rejects
direct parameterized X3DH calls because their caller pointers lack bounded
lengths; see parameter support. - Mechanism parameter layouts for DES CFB/OFB, SSL3/TLS keygen and MAC,
CAMELLIA/ARIA/SEED encrypt-data derivation, BLAKE2B HMAC_GENERAL, and
ECDH-X/COF AES-wrap.
Changed
- Workspace MSRV is
1.88; Alpine 3.22 and Amazon Linux 2023 use a
rustup-managed toolchain because their stock Rust is older. Edition2024is
preserved. SeeAGENTS.mdrule 5 for the rationale. [profile.release]now setslto = "thin",strip = "symbols", and
codegen-units = 1. The shim cdylib and daemon binary shrink ~25-30%
at the cost of ~30s additional CI build time.- Shim's
MECHANISM_REGISTRYstorage changed from
OnceLock<MechanismRegistry>to
OnceLock<RwLock<Arc<MechanismRegistry>>>so the registry can be
atomically swapped on reprobe.state::mechanism_registry()now
returnsArc<MechanismRegistry>(cheap clone); callers never hold
the read lock across FFI/RPC calls. Pkcs11Client::get_backend_interfaces()now returns a
BackendProbe { interfaces, mechanism_registry }struct.
BackendProbeis re-exported from the client crate.Pkcs11ProxyService::new()gains aMechanismRegistrySource
argument; test helpers use the embedded default.- Split the shim's 6078-line
helpers.rsinto ahelpers/directory
module (no behavior change). - tonic features are now selected per-crate, so client-side artifacts
no longer pull in the server stack. - Workspace builds clippy-clean under
-D warnings. C_Loginon a slot held by another live context returns
CKR_USER_ALREADY_LOGGED_INfaithfully and mints no logical login; the
cached-PIN verifier is removed (ADR-0008 superseded by the ADR-0002
rewrite). One-login-holder-per-slot is the mandated trade-off, bounded by
the last-context-out and refcounted-teardown release paths. Login also
self-heals a holderless-but-logged-in backend (F-01 reconcile: one logout- single retry →
OK).
- single retry →
pkcs11-moduleis now consumed from crates.io (version 0.2, which also
provides thepkcs11-abilayout catalog) instead of the nested
crates/module; the nested crate is removed. The backend keeps using the same
pkcs11_module::{function_list, tables::{...}}API via the upstream
re-export, so runtime behavior is unchanged.pkcs11-proxy-ng-typesstays
nested: it carries proxy-specific exact-output contracts and registry
policy (effect validation, apply flags, operator exclusion, wiping secret
owners) that the generic upstreampkcs11-typesdoes not provide.- Secret-classified
Pkcs11Clientresults now return the wiping
SecretBytesowner instead ofVec<u8>(T13; pre-release API migration,
no compatibility shim):wrap_key,wrap_key_authenticated(both tuple
members),wrap_key_authenticated_typed(wrapped blob),
unwrap_key_authenticated(opaque parameter member),
get_operation_state,generate_random,async_complete(payload
member),async_join, the decrypt family (decrypt,decrypt_update,
decrypt_final, the three*_with_mechanism_outbyte members,
decrypt_digest_update,decrypt_verify_update),verify_recover,
and the message-API opaque members (encrypt_message,
encrypt_message_begin/next,decrypt_message,
decrypt_message_begin/nextbytes and recovered data,sign_message,
sign_message_begin/nextparameter members). Read bytes inside
SecretBytes::expose; exact-output result shapes are unchanged and
their buffers are now adopted without copying. Public outputs stay
plainVec<u8>: ciphertext, digests, signatures, KEM ciphertext, and
generated mechanism parameters (IVs).
Removed
state::init_mechanism_registry(the back-compat wrapper) — all
callers migrated toreplace_mechanism_registry.- The minimum Rust version is 1.88, with edition 2024. CI checks that version;
packaging uses rustup where the distribution compiler is older. - Release builds use thin LTO, symbol stripping, and one codegen unit.
Client artifacts no longer include the server's tonic features. - The shim replaces its mechanism registry atomically when reprobed.
state::mechanism_registry()now returnsArc<MechanismRegistry>;
replace_mechanism_registryreplacesinit_mechanism_registry. Pkcs11Client::get_backend_interfaces()returnsBackendProbe, containing
interfaces and the mechanism registry.Pkcs11ProxyService::new()takes a
MechanismRegistrySource.- Module loading and ABI layouts come from the published
pkcs11-components crates
on crates.io (version 0.2).
Proxy-specific types remain in this repository. - Admitted
C_LoginandC_LoginUsercalls reach the backend even when a
context already holds the slot login. Provider PIN errors andALREADY
results are preserved;ALREADYdoes not establish a logical login.
Reconciliation of a backend login with no logical holder still uses one
logout and one login retry. - Secret-classified
Pkcs11Clientresults returnSecretBytesinstead of
Vec<u8>. Read them throughSecretBytes::expose. This affects
wrap_key,wrap_key_authenticated(both tuple members),
wrap_key_authenticated_typed(wrapped blob),
unwrap_key_authenticated(opaque parameter),get_operation_state,
generate_random,async_complete(payload),async_join, the decrypt
family (including*_with_mechanism_out,decrypt_digest_update, and
decrypt_verify_update),verify_recover, and opaque or recovered-data
members of message encrypt/decrypt/sign results. Ciphertext, digests,
signatures, KEM ciphertext, and generated IVs remain plainVec<u8>.
Fixed
- NULL data pointers and NULL
C_VerifyInit/C_DigestInitmechanism pointers
reach the backend with their original lengths when sanitization is disabled.
The backend determines the return value and operation state. - Oversized or overflowing input lengths return
CKR_ARGUMENTS_BAD.
Embedded mechanism data is checked before reading; oversized parameters
returnCKR_MECHANISM_PARAM_INVALID. The 64 KiB struct limit no longer
rejects valid embedded data, which has a separate 512 MiB transport limit. - Native handles and mechanism IDs are range-checked before conversion to
narrowerCK_ULONGvalues, returningCKR_FUNCTION_FAILEDon overflow. - Native allocations remain owned while a provider may retain their pointers.
Finalization closes admission and drains active calls before native cleanup.
Failed initialization/finalization cannot recycle unsafe state. Unresolved
retention uses the platform-specific whole-process stop described in the
ownership contract. - Caller-NULL templates, empty GCM/CCM IV and AAD pointers, and OAEP source
pointers retain their NULL/present distinction in the covered conversion
paths. - Interface discovery rejects a backend interface older than the requested
version. - SSL3/TLS/WTLS and SP800-108 derived output handles are virtualized and
...
pkcs11-proxy-ng v0.1.0
Initial release of the Rust PKCS#11 remote proxy.
Added
pkcs11-proxy-ngdaemon: gRPC/protobuf server that forwards PKCS#11
operations from clients to backend tokens and HSMs.pkcs11-proxy-ng-cli: administrative and smoke-test command-line tool
for managing daemon configuration, auth policy, and provider backends.libpkcs11_proxy_ng_shim.so: loadable PKCS#11 v2.40 / v3.0 / v3.2 shim
library that consumers (NSS, OpenSC, GnuTLS, application code) link against
to talk to the daemon. 105 functions implemented across all three interface
versions.- mTLS-authenticated transport with configurable authorization policy and
identity-based access control. - Provider isolation: per-backend test state and capability matrix probes.
- Hardening passes covering session lifecycle, attribute-template validation,
wrap-handle return-value priority, NULL PIN pointer preservation, admin
entrypoint guards, and sensitive config debug redaction. - Concurrency stress, resource exhaustion, and config validation test suites.
- Protobuf contract drift checks ratcheted in CI.
- Provider-free release dry run (
scripts/release-dry-run.sh) producing
daemon, CLI, and shim artifacts under a staged install layout. - Consumer integration scripts for SoftHSM2, NSS, OpenSC/GnuTLS, Python,
and provider-backed end-to-end tests. - Clippy static gate, local CI parity gate, and nightly workflow.