uselesskey
Deterministic auth, TLS, webhook, token, and test fixtures with metadata-only audit receipts.
`uselesskey` is a **test-fixture factory**, not a crypto library. It generates deterministic auth, TLS, webhook, token, and test fixtures; keeps raw generated material out of git by default; audits what was generated; and makes the proof boundary explicit.
## Start Here
Pick the job first; the repo proof machinery is behind links when you need it.
| I need to... | Start with | Copy this |
| --- | --- | --- |
| write Rust tests | facade crate | `uselesskey = { version = "0.9.1", features = ["rsa"] }` |
| install CI fixtures | installed CLI bundle | `uselesskey bundle --profile scanner-safe --out target/uselesskey-bundle` |
| test negative verifier paths | contract packs | `uselesskey bundle --profile oidc --out target/uselesskey-oidc` |
| review bundle evidence | verify + inspect + audit | `uselesskey inspect-bundle target/uselesskey-webhook` |
| keep runtime material disposable | `target/` output | `uselesskey audit-bundle target/uselesskey-webhook --ci --out target/uselesskey-webhook-audit` |
| prove repo public claims from a checkout | repo verification pack | `cargo xtask verification-pack --out target/uselesskey-verification` |
Install the CLI when you want fixture bundles outside this workspace:
cargo install uselesskey-cli --version 0.9.1 --locked
uselesskey doctor
uselesskey profiles
uselesskey bundle --profile webhook --explain
Generate, verify, inspect, and audit a webhook bundle:
uselesskey bundle --profile webhook --out target/uselesskey-webhook
uselesskey verify-bundle target/uselesskey-webhook
uselesskey inspect-bundle target/uselesskey-webhook
uselesskey audit-bundle target/uselesskey-webhook --ci --out target/uselesskey-webhook-audit
Use `--ci --expect-profile
--policy strict --out ` when
the audit is part of a downstream CI gate:
uselesskey audit-bundle target/uselesskey-webhook --ci --expect-profile webhook --policy strict --out target/uselesskey-webhook-audit
Rust test authors start with the facade crate:
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa"] }
Then generate deterministic fixtures at runtime:
use uselesskey::{Factory, RsaFactoryExt, RsaSpec};
let fx = Factory::deterministic_from_str("test-seed");
let key = fx.rsa("issuer", RsaSpec::rs256());
let pkcs8_pem = key.private_key_pkcs8_pem();
Reviewer and maintainer proof is repo-local. From a checkout, public claims can
be packaged as a metadata-only proof bundle:
cargo xtask verification-pack --out target/uselesskey-verification
What this does not prove:
- production key generation, key custody, or secret management;
- production PKI, provider compatibility, or webhook delivery semantics;
- permission to commit generated secret-shaped payloads;
- downstream verifier correctness;
- repo public claims unless you run the repo-local proof commands.
Start with [docs/how-to/start-here.md](docs/how-to/start-here.md) for the task
router, [docs/how-to/verify-a-fixture-bundle.md](docs/how-to/verify-a-fixture-bundle.md)
for the verify/audit loop, or
[docs/status/PUBLIC_CLAIMS.md](docs/status/PUBLIC_CLAIMS.md) for the full proof
index.
For downstream-shaped clean projects, use the
[external examples index](examples/external/README.md).
## Why this exists
`uselesskey` is a **test-fixture layer**, not a runtime crypto service.
Use it when you need realistic cryptographic fixtures without committing PEM/DER/JWK files.
It exists to remove this test friction:
- scanners inspect every commit in a PR, not just the final diff
- fake-looking keys still trigger policy, push protection, and review friction
`uselesskey` replaces security exceptions + path ignores + fixture directories with one dev-dependency and runtime generation.
## What problem it solves
Without this layer, teams commonly end up with one of these:
| Approach | Problem |
|----------|----------|
| Commit PEM/DER files | Triggers scanners and push protection |
| Generate keys ad hoc in tests | Repeated boilerplate, slow RSA, no shared determinism |
| Use raw crypto crates directly | You still have to assemble PEM/DER/JWK/X.509 shapes yourself |
| Use `rcgen` or other runtime crates directly | Useful, but not centered on fixture ergonomics, determinism, or negative cases |
`uselesskey` is built specifically for **test artifacts**.
## What you get
### Fixture families
- RSA (2048, 3072, 4096)
- ECDSA (P-256, P-384)
- Ed25519
- HMAC (HS256, HS384, HS512)
- OpenPGP (RSA 2048/3072, Ed25519)
- Token fixtures (API key, bearer, OAuth access-token / JWT shape)
- X.509 self-signed certificates and certificate chains
### Output shapes
- PKCS#8 PEM/DER
- SPKI PEM/DER
- OpenPGP armored and binary keyblocks
- JWK / JWKS
- tempfiles for path-based APIs
- X.509 leaves and chains, and negative variants
### Negative artifacts
- corrupt PEM
- truncated DER
- mismatched keypairs
- expired / revoked / hostname-mismatch / unknown-CA certificates
## Pick The Lane First
Start with the cheapest lane that preserves the test's semantics.
| I need | Recommended lane | Why |
|----------|----------|----------|
| entropy / scanner-shape only | `uselesskey-entropy` or facade `features = ["entropy"]` | deterministic bytes without key-generation baggage |
| JWT / bearer / API-token shapes only | `uselesskey-token` or facade `features = ["token"]` | token-shaped fixtures without RSA/X.509 pull-in |
| valid runtime crypto semantics | leaf crates such as `uselesskey-rsa`, `uselesskey-x509`, `uselesskey-ssh` | real PKCS#8/JWK/X.509/SSH fixture behavior |
| build-time materialized fixtures | `uselesskey-cli materialize` + `verify` | clean shape-only `OUT_DIR` / `include_bytes!` workflow, with RSA materialization as an explicit opt-in |
| reproducible fixture bundles + handoff | `uselesskey-cli bundle` + `verify-bundle` + `inspect-bundle` + `export` | deterministic scanner-safe bundle of fixtures, manifest, and receipts; Kubernetes/Vault payload handoff without committing real secrets |
Start with [docs/how-to/choose-features.md](docs/how-to/choose-features.md) for feature selection.
Use [docs/how-to/choose-lane.md](docs/how-to/choose-lane.md) when deciding between entropy, token, semantic, and materialized fixture workflows.
See [docs/reference/dependency-economics.md](docs/reference/dependency-economics.md) and [docs/reference/audit-surface.md](docs/reference/audit-surface.md) for the current local-cost and advisory receipts.
## Choose the smallest feature set
The `uselesskey` facade has an empty default feature set. Enable only the fixture families you need.
Common starting points:
# Entropy-only fixtures
[dev-dependencies]
uselesskey = { version = "0.9.1", default-features = false, features = ["entropy"] }
# RSA fixtures
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa"] }
# Token-only fixtures, no RSA/X.509 pull-in
[dev-dependencies]
uselesskey = { version = "0.9.1", default-features = false, features = ["token"] }
# RSA + JWK/JWKS
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa", "jwk"] }
# X.509 fixtures
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["x509"] }
The following materialization commands are repo-checkout examples. Installed
CLI users can run the same subcommands as `uselesskey materialize ...` and
`uselesskey verify ...`.
# Build-time materialization, shape-only common lane
cargo run -p uselesskey-cli -- materialize --manifest crates/materialize-shape-buildrs-example/uselesskey-fixtures.toml --out-dir target/tmp-fixtures
cargo run -p uselesskey-cli -- verify --manifest crates/materialize-shape-buildrs-example/uselesskey-fixtures.toml --out-dir target/tmp-fixtures
For `build.rs` consumers:
# Common shape-only build-time path
[build-dependencies]
uselesskey-cli = { version = "0.9.1", default-features = false }
# Specialized RSA PKCS#8 build-time path
[build-dependencies]
uselesskey-cli = { version = "0.9.1", default-features = false, features = ["rsa-materialize"] }
Use the facade for convenience. Depend on leaf crates only when compile-time minimization matters enough to justify the sharper API.
If you are unsure which flags to start with, start from [docs/how-to/choose-features.md](docs/how-to/choose-features.md).
For downstream bot/reviewer policy, use [docs/how-to/downstream-fixture-policy.md](docs/how-to/downstream-fixture-policy.md).
For a crate-by-crate support contract (stable/incubating/experimental, audience, and publish status), see [docs/reference/support-matrix.md](docs/reference/support-matrix.md).
## Quick start
use uselesskey::{Factory, RsaFactoryExt, RsaSpec};
// Random mode: different keys every run
let fx = Factory::random();
// Deterministic mode: stable output for a seed string
let fx = Factory::deterministic_from_str("my-test-seed");
// Or use env-var seed with random fallback
let fx = Factory::deterministic_from_env("USELESSKEY_SEED")
.unwrap_or_else(|_| Factory::random());
let rsa = fx.rsa("issuer", RsaSpec::rs256());
let pkcs8_pem = rsa.private_key_pkcs8_pem();
let spki_der = rsa.public_key_spki_der();
The core shape is always:
(mode, domain, label, spec, variant) -> artifact
That keeps fixtures stable in deterministic mode and cacheable in both modes.
## Feature reminders for common snippets
- `rsa` for PEM/DER, tempfiles, and negative-key examples
- `rsa` + `jwk` for `public_jwk()` / `public_jwks()`
- `x509` for certificate, rustls, and tonic examples
- `token` for token-shaped fixtures only
- `pgp` for armored/binary OpenPGP fixtures
## Dependency Snippet Reminders
Dependency snippets:
- **Quick start (RSA)**
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa"] }
- **Token-only**
[dev-dependencies]
uselesskey = { version = "0.9.1", default-features = false, features = ["token"] }
- **JWT/JWK**
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa", "jwk"] }
- **X.509 + rustls**
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["x509"] }
uselesskey-rustls = { version = "0.9.1", features = ["tls-config", "rustls-ring"] }
- **jsonwebtoken adapter**
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa", "ecdsa", "ed25519", "hmac"] }
uselesskey-jsonwebtoken = { version = "0.9.1", features = ["all"] }
### JWK / JWKS
Requires `features = ["rsa", "jwk"]`.
use uselesskey::{Factory, RsaSpec, RsaFactoryExt};
let fx = Factory::random();
let rsa = fx.rsa("issuer", RsaSpec::rs256());
let jwk = rsa.public_jwk();
let jwks = rsa.public_jwks();
### Tempfiles
use uselesskey::{Factory, RsaSpec, RsaFactoryExt};
let fx = Factory::random();
let rsa = fx.rsa("server", RsaSpec::rs256());
let keyfile = rsa.write_private_key_pkcs8_pem().unwrap();
assert!(keyfile.path().exists());
### X.509 Certificates
Requires `features = ["x509"]`.
Self-signed certificates for simple TLS tests:
use uselesskey::{Factory, X509FactoryExt, X509Spec};
let fx = Factory::random();
let cert = fx.x509_self_signed("my-service", X509Spec::self_signed("test.example.com"));
let cert_pem = cert.cert_pem();
let key_pem = cert.private_key_pkcs8_pem();
Three-level chains (root intermediate leaf):
use uselesskey::{Factory, X509FactoryExt, ChainSpec};
let fx = Factory::random();
let chain = fx.x509_chain("my-service", ChainSpec::new("test.example.com"));
// Standard TLS server chain: leaf + intermediate, no root
let chain_pem = chain.chain_pem();
// Individual artifacts for custom setups
let root_pem = chain.root_cert_pem();
let leaf_key = chain.leaf_private_key_pkcs8_pem();
### X.509 negative fixtures
These are for error-path tests, not validation logic.
use uselesskey::{Factory, X509FactoryExt, ChainSpec};
let fx = Factory::random();
let chain = fx.x509_chain("my-service", ChainSpec::new("test.example.com"));
// Expired leaf certificate
let expired = chain.expired_leaf();
// Hostname mismatch (SAN doesn't match expected hostname)
let wrong_host = chain.hostname_mismatch("wrong.example.com");
// Signed by an unknown CA (not in your trust store)
let unknown = chain.unknown_ca();
// Revoked leaf with CRL signed by the intermediate CA
let revoked = chain.revoked_leaf();
let crl_pem = revoked.crl_pem().expect("CRL present for revoked variant");
### Negative fixtures (keys)
use uselesskey::{Factory, RsaSpec, RsaFactoryExt};
use uselesskey::negative::CorruptPem;
let fx = Factory::random();
let rsa = fx.rsa("issuer", RsaSpec::rs256());
let bad_pem = rsa.private_key_pkcs8_pem_corrupt(CorruptPem::BadBase64);
let truncated = rsa.private_key_pkcs8_der_truncated(32);
let mismatched_pub = rsa.mismatched_public_key_spki_der();
### Token fixtures
Token fixtures are **artifact shapes**, not an auth framework. They exist so tests can use realistic-looking token values without committing blobs.
use uselesskey::{Factory, TokenFactoryExt, TokenSpec};
let fx = Factory::random();
let api_key = fx.token("billing", TokenSpec::api_key());
let bearer = fx.token("gateway", TokenSpec::bearer());
let oauth = fx.token("issuer", TokenSpec::oauth_access_token());
assert!(api_key.value().starts_with("uk_test_"));
assert!(bearer.authorization_header().starts_with("Bearer "));
assert_eq!(oauth.value().split('.').count(), 3);
## Scanner-safe bundles and exports
The `uselesskey-cli` bundle workflow generates a deterministic directory of fixtures, a manifest, and per-artifact receipts that downstream tests can verify, inspect, and hand off to Kubernetes or Vault without committing real secret material.
# Generate a scanner-safe fixture bundle (default profile)
uselesskey bundle --profile scanner-safe --out target/uselesskey-bundle
# Verify the bundle against its recorded manifest and receipts
uselesskey verify-bundle target/uselesskey-bundle
# Print a human-readable summary without exposing fixture payloads
uselesskey inspect-bundle target/uselesskey-bundle
# Render Kubernetes / Vault payloads from the verified bundle
uselesskey export k8s \
--bundle-dir target/uselesskey-bundle \
--name uselesskey-fixtures \
--namespace tests \
--out target/uselesskey-bundle/secret.yaml
uselesskey export vault-kv-json \
--bundle-dir target/uselesskey-bundle \
--out target/uselesskey-bundle/kv-v2.json
The `oidc` profile emits an OIDC/JWKS contract pack with valid JWKS and JWT-shape fixtures plus duplicate-`kid`, missing-`kid`, `alg: none`, and bad-audience negatives:
uselesskey bundle --profile oidc --out target/uselesskey-oidc
For the reference manifest, receipts, and payload shapes see [`examples/scanner-safe-bundle/README.md`](examples/scanner-safe-bundle/README.md). For OIDC/JWT validator-test recipes see [`docs/how-to/test-oidc-jwks-validation.md`](docs/how-to/test-oidc-jwks-validation.md) and [`docs/how-to/test-jwt-negative-validation.md`](docs/how-to/test-jwt-negative-validation.md).
For a task-first list of scanner-safe, TLS, OIDC/JWKS, and webhook profiles,
see [`docs/contract-packs/README.md`](docs/contract-packs/README.md).
## Adapter crates
Adapter crates are separate packages, not facade features. That keeps integration versioning explicit and avoids coupling the facade to every downstream ecosystem type.
Use them when you want **native third-party library types** returned directly from fixture artifacts.
### TLS config builders (`uselesskey-rustls`)
With the `tls-config` feature, build rustls configs in one step:
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["x509"] }
uselesskey-rustls = { version = "0.9.1", features = ["tls-config", "rustls-ring"] }
use uselesskey::{ChainSpec, Factory, X509FactoryExt};
use uselesskey_rustls::{RustlsServerConfigExt, RustlsClientConfigExt};
let fx = Factory::random();
let chain = fx.x509_chain("my-service", ChainSpec::new("test.example.com"));
let server_config = chain.server_config_rustls();
let client_config = chain.client_config_rustls();
### ring signing keys (`uselesskey-ring`)
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa"] }
uselesskey-ring = { version = "0.9.1", features = ["all"] }
use uselesskey::{Factory, RsaFactoryExt, RsaSpec};
use uselesskey_ring::RingRsaKeyPairExt;
let fx = Factory::random();
let rsa = fx.rsa("signer", RsaSpec::rs256());
let ring_kp = rsa.rsa_key_pair_ring();
### RustCrypto types (`uselesskey-rustcrypto`)
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa"] }
uselesskey-rustcrypto = { version = "0.9.1", features = ["all"] }
use uselesskey::{Factory, RsaFactoryExt, RsaSpec};
use uselesskey_rustcrypto::RustCryptoRsaExt;
let fx = Factory::random();
let rsa = fx.rsa("signer", RsaSpec::rs256());
let rsa_pk = rsa.rsa_private_key();
### aws-lc-rs types (`uselesskey-aws-lc-rs`)
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa"] }
uselesskey-aws-lc-rs = { version = "0.9.1", features = ["native", "all"] }
use uselesskey::{Factory, RsaFactoryExt, RsaSpec};
use uselesskey_aws_lc_rs::AwsLcRsRsaKeyPairExt;
let fx = Factory::random();
let rsa = fx.rsa("signer", RsaSpec::rs256());
let lc_kp = rsa.rsa_key_pair_aws_lc_rs();
### gRPC TLS (`uselesskey-tonic`)
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["x509"] }
uselesskey-tonic = "0.9.1"
use uselesskey::{ChainSpec, Factory, X509FactoryExt};
use uselesskey_tonic::{TonicClientTlsExt, TonicServerTlsExt};
let fx = Factory::random();
let chain = fx.x509_chain("grpc", ChainSpec::new("test.example.com"));
let server_tls = chain.server_tls_config_tonic();
let client_tls = chain.client_tls_config_tonic("test.example.com");
## Runnable Examples
The [`crates/uselesskey/examples/`](crates/uselesskey/examples/) directory contains standalone programs. Because the facade default feature set is empty, run them with `cargo run -p uselesskey --example --features ""` using one working feature set below:
| Example | Feature(s) | Description |
|---------|------------|-------------|
| [adapter_jsonwebtoken](crates/uselesskey/examples/adapter_jsonwebtoken.rs) | `rsa,ecdsa,ed25519,hmac` | Sign and verify JWTs using `jsonwebtoken` crate integration |
| [adapter_rustls](crates/uselesskey/examples/adapter_rustls.rs) | `x509` | Convert X.509 fixtures into rustls `ServerConfig` / `ClientConfig` |
| [basic_ecdsa](crates/uselesskey/examples/basic_ecdsa.rs) | `ecdsa,jwk` | Generate ECDSA keypairs for P-256 and P-384 in PEM, DER, JWK |
| [basic_ed25519](crates/uselesskey/examples/basic_ed25519.rs) | `ed25519,jwk` | Generate Ed25519 keypairs in PEM, DER, and JWK formats |
| [basic_hmac](crates/uselesskey/examples/basic_hmac.rs) | `hmac,jwk` | Generate HMAC secrets for HS256, HS384, and HS512 |
| [basic_rsa](crates/uselesskey/examples/basic_rsa.rs) | `rsa,jwk` | Generate RSA keypairs in PEM, DER, and JWK formats |
| [basic_token](crates/uselesskey/examples/basic_token.rs) | `token` | Generate API key, bearer token, and OAuth access-token fixtures |
| [basic_usage](crates/uselesskey/examples/basic_usage.rs) | `ecdsa,ed25519,rsa,jwk` | All-in-one: RSA, ECDSA, and Ed25519 fixture generation |
| [deterministic](crates/uselesskey/examples/deterministic.rs) | `rsa` | Reproducible fixtures from seeds - same seed always yields the same key |
| [deterministic_mode](crates/uselesskey/examples/deterministic_mode.rs) | `rsa,ecdsa,ed25519` | Order-independent deterministic derivation guarantees |
| [jwk_generation](crates/uselesskey/examples/jwk_generation.rs) | `ecdsa,ed25519,hmac,rsa,jwk` | Build JWKs and JWKS with `JwksBuilder` across key types |
| [jwk_jwks](crates/uselesskey/examples/jwk_jwks.rs) | `ecdsa,ed25519,hmac,rsa,jwk` | JWK sets from multiple key types with metadata inspection |
| [jwks](crates/uselesskey/examples/jwks.rs) | `rsa,ecdsa,jwk` | Build a JWKS from RSA and ECDSA public keys |
| [jwks_server_mock](crates/uselesskey/examples/jwks_server_mock.rs) | `rsa,ecdsa,ed25519,jwk` | Generate a JWKS response body for a mock `/.well-known/jwks.json` endpoint |
| [jwt_rs256_jwks](crates/uselesskey/examples/jwt_rs256_jwks.rs) | `rsa,jwk` | RSA keypairs with JWK/JWKS extraction for JWT verification flows |
| [jwt_signing](crates/uselesskey/examples/jwt_signing.rs) | `rsa,jwk` | JWT signing with deterministic RSA, ECDSA, and HMAC keys (ECDSA/HMAC optional) |
| [negative_fixtures](crates/uselesskey/examples/negative_fixtures.rs) | `x509` | Intentionally invalid certificates and keys for error-path testing |
| [negative_payload_shapes](crates/uselesskey/examples/negative_payload_shapes.rs) | `rsa,jwk,token` | Scanner-safe negative JWK/JWKS and token shapes for validator tests |
| [tempfile_paths](crates/uselesskey/examples/tempfile_paths.rs) | `rsa,ed25519` | Write key fixtures to temporary files for path-based APIs |
| [tempfiles](crates/uselesskey/examples/tempfiles.rs) | `x509` | Write X.509 cert, key, and identity PEM to temp files |
| [tls_server](crates/uselesskey/examples/tls_server.rs) | `x509` | Certificate chain generation for TLS server testing |
| [token_generation](crates/uselesskey/examples/token_generation.rs) | `token` | Realistic API keys, bearer tokens, and OAuth tokens for tests |
| [x509_certificates](crates/uselesskey/examples/x509_certificates.rs) | `x509` | Self-signed certs, cert chains, and negative X.509 fixtures |
## Workspace Crates
`uselesskey` is a **facade crate** that re-exports from focused implementation crates.
Depend on the facade for convenience, or on individual crates to minimize compile time.
### Implementation Crates
| Crate | Description |
|-------|-------------|
| [`uselesskey`](https://crates.io/crates/uselesskey) | Public facade — re-exports all key types and traits behind feature flags |
| [`uselesskey-core`](https://crates.io/crates/uselesskey-core) | Factory, deterministic derivation, caching, and negative-fixture helpers |
| [`uselesskey-entropy`](https://crates.io/crates/uselesskey-entropy) | Deterministic high-entropy byte fixtures for scanner-safe and placeholder tests |
| [`uselesskey-rsa`](https://crates.io/crates/uselesskey-rsa) | RSA 2048/3072/4096 keypairs (PKCS#8, SPKI, PEM, DER) |
| [`uselesskey-ecdsa`](https://crates.io/crates/uselesskey-ecdsa) | ECDSA P-256 / P-384 keypairs |
| [`uselesskey-ed25519`](https://crates.io/crates/uselesskey-ed25519) | Ed25519 keypairs |
| [`uselesskey-hmac`](https://crates.io/crates/uselesskey-hmac) | HMAC HS256/HS384/HS512 secrets |
| [`uselesskey-ssh`](https://crates.io/crates/uselesskey-ssh) | Deterministic OpenSSH key and certificate fixtures |
| [`uselesskey-pgp`](https://crates.io/crates/uselesskey-pgp) | OpenPGP key fixtures (armored + binary keyblocks) |
| [`uselesskey-token`](https://crates.io/crates/uselesskey-token) | API key, bearer token, and OAuth access-token fixtures |
| [`uselesskey-webhook`](https://crates.io/crates/uselesskey-webhook) | Deterministic webhook fixtures for GitHub, Stripe, and Slack signature tests |
| [`uselesskey-jwk`](https://crates.io/crates/uselesskey-jwk) | Typed JWK/JWKS models and builders |
| [`uselesskey-x509`](https://crates.io/crates/uselesskey-x509) | X.509 self-signed certificates and certificate chains |
| [`uselesskey-cli`](https://crates.io/crates/uselesskey-cli) | Command-line fixture generation, bundling, and export helpers |
| [`uselesskey-test-server`](https://crates.io/crates/uselesskey-test-server) | Deterministic OIDC discovery and JWKS HTTP test server fixtures |
| [`uselesskey-pkcs11-mock`](https://crates.io/crates/uselesskey-pkcs11-mock) | PKCS#11 mock provider fixtures for HSM/provider integration tests |
| [`uselesskey-webauthn`](https://crates.io/crates/uselesskey-webauthn) | WebAuthn credential and assertion fixtures for passkey tests |
### Adapter Crates
| Crate | Description |
|-------|-------------|
| [`uselesskey-axum`](https://crates.io/crates/uselesskey-axum) | `axum` auth-test helpers with deterministic JWKS/OIDC routes |
| [`uselesskey-jsonwebtoken`](https://crates.io/crates/uselesskey-jsonwebtoken) | `jsonwebtoken` `EncodingKey` / `DecodingKey` |
| [`uselesskey-rustls`](https://crates.io/crates/uselesskey-rustls) | `rustls` `ServerConfig` / `ClientConfig` builders |
| [`uselesskey-tonic`](https://crates.io/crates/uselesskey-tonic) | `tonic::transport` TLS identity / config for gRPC |
| [`uselesskey-ring`](https://crates.io/crates/uselesskey-ring) | `ring` 0.17 native signing key types |
| [`uselesskey-rustcrypto`](https://crates.io/crates/uselesskey-rustcrypto) | RustCrypto native types (`rsa::RsaPrivateKey`, etc.) |
| [`uselesskey-aws-lc-rs`](https://crates.io/crates/uselesskey-aws-lc-rs) | `aws-lc-rs` native types |
## Feature Flags
The `uselesskey` facade defaults to no features.
Extension traits by feature:
- `rsa`: `RsaFactoryExt`
- `ecdsa`: `EcdsaFactoryExt`
- `ed25519`: `Ed25519FactoryExt`
- `hmac`: `HmacFactoryExt`
- `pgp`: `PgpFactoryExt`
- `token`: `TokenFactoryExt`
- `x509`: `X509FactoryExt`
For output-family coverage and dependency implications, use the matrix below.
## Feature matrix
### Facade features (`uselesskey` crate)
| Feature | Extension Trait | Algorithms / Outputs | Implies |
|---------|----------------|---------------------|---------|
| `rsa` | `RsaFactoryExt` | RSA 2048/3072/4096 — PKCS#8, SPKI, PEM, DER | — |
| `ecdsa` | `EcdsaFactoryExt` | P-256 (ES256), P-384 (ES384) — PKCS#8, SPKI | — |
| `ed25519` | `Ed25519FactoryExt` | Ed25519 — PKCS#8, SPKI | — |
| `hmac` | `HmacFactoryExt` | HS256, HS384, HS512 | — |
| `pgp` | `PgpFactoryExt` | OpenPGP RSA 2048/3072, Ed25519 — armored, binary | — |
| `token` | `TokenFactoryExt` | API key, bearer access token, and OAuth access token | — |
| `x509` | `X509FactoryExt` | Self-signed certs, cert chains, negative certs | `rsa` |
| `jwk` | — | JWK/JWKS output for all enabled key types | — |
| `all-keys` | — | (bundle) | `rsa` `ecdsa` `ed25519` `hmac` `pgp` |
| `full` | — | (everything) | `all-keys` `token` `x509` `jwk` |
## Why this crate
### Order-independent determinism
Fixtures derive from stable identity components:
seed + (domain, label, spec, variant) -> derived seed -> artifact
Adding new fixtures doesn't perturb existing ones. Test order doesn't matter.
### Cache-by-identity
RSA keygen is expensive. Per-factory caching by `(domain, label, spec, variant)` makes runtime generation cheap enough to replace committed fixtures.
### Shape-first outputs
Ask for shapes first: PKCS#8, SPKI, PEM, DER, JWK, JWKS, or tempfiles.
Consumers ask for artifact shapes; low-level crypto primitives are intentionally not the default output.
### Negative artifacts as first-class
Corrupt PEM, truncated DER, mismatched keys, expired certs, revoked leaves with CRLs: these are exactly the artifacts teams otherwise handcraft and commit.
`uselesskey` makes them deterministic, cheap, and disposable.
## When not to use this crate
- production key generation
- runtime certificate authority behavior
- certificate validation logic
- HSM / TPM / hardware-backed keys
- signing or verification APIs as the primary abstraction
For runtime certificate generation, reach for `rcgen` directly. For validation, use `rustls`, `x509-parser`, or the library actually responsible for verification.
## Ecosystem
Use `uselesskey` when you need **realistic test fixtures that should not live in git history**.
Reach for:
- `rcgen` when you need runtime certificate generation outside a fixture-centric workflow
- `rustls` when you need TLS runtime integration and validation
- `x509-parser` when you need parsing/inspection/validation work
## Stability and versioning
**Derivation stability**
Artifacts for a given `(seed, domain, label, spec, variant)` tuple are stable within the same `DerivationVersion`.
If derivation logic changes, a new derivation version is introduced instead of mutating the old one.
**Semver**
Breaking API changes bump the minor version until `1.0`, then the major version.
**MSRV**
The minimum supported Rust version is **1.95** (edition 2024).
## License
Licensed under either of:
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))
- MIT license ([LICENSE-MIT](LICENSE-MIT))
at your option.