feat(rust): read the client identity from a PKCS#12 bundle - #730
Draft
wkirschenmann wants to merge 1 commit into
Draft
wkirschenmann wants to merge 1 commit into
wkirschenmann wants to merge 1 commit into
Conversation
☂️ Python Coverage
Overall Coverage
New FilesNo new covered files... Modified FilesNo covered modified files...
|
wkirschenmann
force-pushed
the
wk/feat/rust-pkcs12-v2
branch
from
August 8, 2026 14:23
4f2f993 to
f418ee4
Compare
wkirschenmann
marked this pull request as ready for review
August 8, 2026 18:55
wkirschenmann
force-pushed
the
wk/feat/rust-pkcs12-v2
branch
from
August 9, 2026 08:37
f418ee4 to
37ce70a
Compare
wkirschenmann
force-pushed
the
wk/feat/rust-pkcs12-v2
branch
from
August 9, 2026 09:28
37ce70a to
6493367
Compare
`CertP12` names a certificate and its key bundled together, the form
Windows and most certificate authorities hand out, optionally protected
by `CertP12Password`. It is an alternative to `CertPem`/`KeyPem`, not an
addition: setting both spellings is refused while the configuration is
read, as is a password naming no bundle. Errors name the file, never the
password, which is a `SecretString` throughout.
The bundle is loaded through `p12-keystore` (pure Rust, so no OpenSSL
joins the build) under `Pkcs12ImportPolicy::Strict`, and its whole chain
is kept leaf first, re-encoded into the DER shapes the PEM pair already
produces, so a server that trusts only the root can still build its path
and nothing past `Identity` sees two identity formats.
`RawIdentity` gains a `Pkcs12` shape, first so it wins over the PEM one.
Every shape carries every identity option and differs only in which it
requires: that is what lets `load` see both spellings at once, and what
keeps a PEM pair readable next to a `CertP12` that is present but empty.
The generated schema spells the same distinction, as an `anyOf` whose
branches differ by `required`.
ArmoniK's C# client reads `CertP12` with no password counterpart
(`GrpcClient.cs` declares the option, `GrpcChannelFactory.cs` opens the
file with `new X509Certificate2(path)`), so `CertP12Password` is a name
only this client knows.
cargo test -p armonik-transport --all-features
test result: ok. 69 passed (lib)
test result: ok. 13 passed (proxy)
test result: ok. 5 passed (schema)
test result: ok. 6 passed (timeout)
cargo clippy -p armonik-transport --all-features --all-targets
Finished `dev` profile, 0 warnings
cargo clippy -p armonik --all-features --all-targets
Finished `dev` profile, 0 warnings
cargo check -p armonik-transport --no-default-features
Finished `dev` profile, 0 warnings
cargo fmt --check
clean
cargo run -p armonik-transport --features schema --example generate_schema
the identity `anyOf` now carries a branch requiring `CertP12` and
declaring `CertP12Password`
The 13 new tests are the PKCS#12 material (a bundle round-tripping, a
CA-signed chain keeping its intermediates leaf first, an unprotected
bundle opening without a password, a wrong password naming the path and
not itself, an identity-less bundle, a file that is not PKCS#12, a path
that leads nowhere, and the option reading the file it names) and the
option rules (mutual exclusion in all three combinations, an orphan
password not echoed, empty options reading as unset, an empty `CertP12`
leaving the PEM pair alone, a bundle path that leads nowhere).
`tests/schema.rs` pins both new option names and the bundle branch of
the identity `anyOf`, in place of the assertion that `CertP12` is absent.
wkirschenmann
force-pushed
the
wk/feat/rust-pkcs12-v2
branch
from
August 9, 2026 10:40
6493367 to
3ea509e
Compare
|
wkirschenmann
marked this pull request as draft
August 13, 2026 18:51
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.



Lets the client's mTLS identity come from a PKCS#12 bundle instead of a PEM certificate/key pair.
CertP12names a certificate and its key bundled together, the form Windows and most certificateauthorities hand out, optionally protected by
CertP12Password. It is an alternative toCertPem/KeyPem, not an addition: setting both spellings is refused while the configuration isread, as is a password naming no bundle.
How it works
The bundle is loaded through
p12-keystore(pure Rust, so no OpenSSL joins the build) underPkcs12ImportPolicy::Strict, and its whole chain is kept leaf first, re-encoded into the DERshapes the PEM pair already produces, so a server that trusts only the root can still build its
path and nothing past
Identitysees two identity formats. Loading happens while the configurationis read, like every other file-naming option, so a mistyped path fails where the error can name the
option rather than surfacing later as a refused handshake.
CertP12Passwordis aSecretString: redacted byDebug, zeroized on drop, and never echoed inan error. It deserialises through a
secret_textreader added toconfig_utils, naming no optionof its own. The proxy-options PR adds the same reader; whichever lands second drops its copy.
RawIdentitygains aPkcs12shape, first so it wins over the PEM one and ahead ofBare, whichrequires nothing and so stays last. Every shape carries every identity option and differs only in
which it requires: that is what lets
loadsee both spellings at once, and what keeps a PEM pairreadable next to a
CertP12that is present but empty. The generated schema spells the samedistinction, as an
anyOfwhose branches differ byrequired;tests/schema.rspins both newoption names and the bundle branch, in place of the assertion that
CertP12is absent.C# parity
Worth knowing before this merges: the C# client declares
CertP12(
packages/csharp/ArmoniK.Api.Client/Options/GrpcClient.cs:62) but has noCertP12Password-GrpcChannelFactory.cs:536opens the file withnew X509Certificate2(path), and no spelling of ap12 password exists anywhere under
packages/csharp/. SoCertP12Passwordis a name only the Rustclient knows, and a password-protected bundle is not portable to C#. The alternative is to refuse
password-protected bundles instead, keeping the vocabularies identical; this PR takes the first
road and documents the divergence in
armonik-transport/README.md.Tests
13 new tests. The PKCS#12 material: a bundle round-tripping into the same identity a PEM pair
produces, a CA-signed chain keeping its intermediates leaf first, an unprotected bundle opening
without a password, a wrong password naming the path and not itself, an identity-less bundle, a
file that is not PKCS#12, a path that leads nowhere, and the
CertP12option reading the file itnames. The option rules: mutual exclusion in all three combinations, an orphan password not echoed,
empty options reading as unset, an empty
CertP12leaving the PEM pair alone, and a bundle paththat leads nowhere failing while the configuration is read. Fixtures are generated with
rcgenrather than committed, so nothing can expire, and because
p12-keystorerebuilds a bundle's chainby issuer, proving the intermediates survive needs material that really signed the leaf.
Gates
From
packages/rust, all green: