Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/gunnar

assets/test/vetra-test-pki/README.md

Vetra Test PKI

A three-link certificate chain for development and tests only. Generated 2026-08-14 on the desktop.

Vetra Test Root CA        CA:TRUE pathlen:1   5 years   keyCertSign, cRLSign
  └─ Vetra Test Issuing CA  CA:TRUE pathlen:0   3 years   keyCertSign, cRLSign
                                                          EKU: codeSigning, emailProtection
       └─ Vetra Test Signer   CA:FALSE           3 years   digitalSignature, contentCommitment
                                                          EKU: codeSigning, emailProtection

Verified with the chain, not asserted:

$ openssl verify -CAfile root-ca-cert.pem -untrusted issuing-ca-cert.pem signer-cert.pem
signer-cert.pem: OK

Why these attributes

What is here

Each artefact ships twice: PEM, and the same bytes base64-encoded (.pem.b64) for anywhere a single line is easier to carry than a file.

root-ca-cert     root-ca-key
issuing-ca-cert  issuing-ca-key
signer-cert      signer-key
chain-signer-to-root       leaf, issuing CA, root — in verification order

These keys are public and worthless — and they are the ONLY ones

cargo xtask key-census reads every file git ls-files reports and fails the build on any private key outside this directory. Base64 too: every artefact here ships twice, and the .pem.b64 copies carry the same keys straight past a scan that greps for BEGIN PRIVATE KEY, so the census decodes as well as reads. Three keys, six files, named one by one in xtask/src/key_census.rs rather than excused by directory — a fourth cannot join them by being dropped in beside them.

The repository went public on 2026-09-08, and a published private key trips every scanner ever pointed at a git remote whether or not it is worthless. The argument below is why these three stay; the census is why they stay three.

Every private key in this directory is committed in the clear and is a throwaway minted by the generator below. That is the point: a test fixture nobody has to fetch from a secret store, and a key nobody can mistake for a real one. Nothing here may ever become a production identity. The production signing key's custody is a project decision, its private half never enters a repo, an image or a kernel command line, and no code changes when it is swapped in — the paths are the same.

Regenerating

The certificates are DECLARED, not folklore — generator/ is the program that made them and re-running it reproduces the shape (with fresh keys and dates):

cd generator && cargo run --release -- ../

Pure Rust: rcgen 0.13 on the ring backend, the same crate Skidbladnir, edda's nornir-flight and holger's bench-scenarios already use. No openssl, no shell-out, per the suite's pure-Rust law. The openssl invocations above are for inspection only and are not part of producing anything.

One measured gap, for whoever wires CMS

The leaf carries no Subject Key Identifier. rcgen puts SKI on the CA certificates and not on the leaf, which is RFC 5280's own split — SKI is mandatory for a CA, optional for an end entity.

That matters because a CMS SignerIdentifier is either issuerAndSerialNumber or subjectKeyIdentifier. This chain supports the first out of the box; a verifier configured for the second will not find the leaf. It is also exactly the field znippy-common/src/sign.rs:1168 asks about (Profile::Leaf { include_subject_key_identifier }), so decide it there and here together rather than separately.