Skip to content

feat(tbor): implement HKDF and single-step (X9.63 / SP 800-56A) KDF derivation - #589

Open
vsonims wants to merge 1 commit into
tbor/ecc-cryptofrom
tbor/kdf-crypto
Open

feat(tbor): implement HKDF and single-step (X9.63 / SP 800-56A) KDF derivation#589
vsonims wants to merge 1 commit into
tbor/ecc-cryptofrom
tbor/kdf-crypto

Conversation

@vsonims

@vsonims vsonims commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds two in-session TBOR KDF commands that derive key material from a caller-held masked ECDH shared secret (from EcdhDerive 0x19) and return the derived key masked under the requested scope — the KDF analogues of the ECC crypto commands, re-masking the output instead of vaulting it.

Opcode Command KDF
0x1C HkdfDerive HKDF (RFC 5869), salt + info
0x1D ConcatKdfDerive single-step: ANSI X9.63 or NIST SP 800-56A one-step (selected by kdf_alg), single info

Both derive AES (128/192/256) or HMAC (fixed SHA-256/384/512, or variable-length) keys.

Design

  • Unmask-on-use: the ECDH secret is unmasked in place in the request buffer, checked to be an ECDH-secret kind carrying derive, run through the KDF into scratch, and the output masked under the target scope. The recovered secret and derived scratch are scrubbed on every path.
  • Shared KdfKeyType output-type enum lives in key_props (used by both commands).
  • Cross-platform single-step KDF in azihsm_crypto: X9.63 and SP 800-56A are Hash-only, so one generic ConcatKdfAlgo over the shared Hasher serves both OpenSSL (Linux) and CNG (Windows) — no per-backend code. The std PAL x963_kdf / sp800_56a_kdf hooks (previously todo!() stubs) now delegate to it via StdKdf::concat_kdf; the Uno PAL already implemented them.

Changes

  • azihsm_crypto: ConcatKdfAlgo + ConcatKdfMode {X963, Sp800_56a} (crates/crypto/src/kdf/concat.rs), 3 CryptoError variants, known-answer tests (kdf/tests/concat_tests.rs).
  • std PAL: StdKdf::concat_kdf + wired both PAL methods; HsmError::ConcatKdfError.
  • TBOR: wire schemas (fw + host mirror), handlers, dispatch + 3 classifiers + op.rs for 0x1C / 0x1D.
  • Tests: emu coverage for every output key type under each KDF (and each X9.63 / SP 800-56A variant), all hashes/scopes, optional salt/info, and rejects (unknown hash / KDF variant / key type, var-HMAC missing / out-of-range length, non-ECDH-secret IKM).
  • Docs: hkdf_derive.md, concat_kdf_derive.md, README rows.

Testing

  • azihsm_crypto: 501 lib tests pass (incl. X9.63 / SP 800-56A KATs vs. independently computed vectors).
  • Full TBOR emu suite: 146 pass (19 new).
  • cargo check fw core (host + Uno no_std) + Uno PAL ✅ · clippy (crypto / std-PAL / fw / host) ✅ · nightly fmt ✅ · copyright ✅.

Notes

  • Based on feat(tbor): implement ECC keygen, sign, and ECDH derive #585 (tbor/ecc-crypto) for the ECDH shared-secret input. Uses opcodes 0x1C / 0x1D after the sibling AES / ECC / RSA / Hash crypto branches (0x15..0x1B).
  • ConcatKdfDerive is TBOR-only (no MBOR analogue). The concat KDFs' byte-level correctness is proven by the azihsm_crypto KATs; the emu tests verify command plumbing (the derived key is only observable masked).

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

…erivation

Add two in-session TBOR KDF commands that derive key material from a
caller-held masked ECDH shared secret (from EcdhDerive) and return the
derived key masked under the requested scope — the KDF analogues of the
ECC crypto commands, re-masking the output instead of vaulting it:

- HkdfDerive (0x1C): HKDF (RFC 5869) with optional salt + info.
- ConcatKdfDerive (0x1D): single-step "concatenation" KDF, selecting
  ANSI X9.63 (SEC 1 §3.6.1) or NIST SP 800-56A r3 one-step (§5.8.2.1)
  via a kdf_alg discriminant; both take a single info octet string.

Both handlers unmask the ECDH secret in place, verify it is an ECDH
shared-secret kind carrying `derive`, run the KDF into scratch, mask the
output (AES / fixed- or variable-length HMAC) under the target scope, and
scrub the recovered secret and derived scratch on every path. The shared
KdfKeyType output-type enum moves to key_props (used by both commands).

Single-step KDF primitive (azihsm_crypto): the X9.63 and SP 800-56A
concatenation KDFs are implemented once, generically, over the shared
Hasher — they need nothing but a hash, so a single platform-agnostic
ConcatKdfAlgo serves both the OpenSSL (Linux) and CNG (Windows) backends
(unlike HKDF, which is per-backend). Known-answer tests validate both
variants against independently computed vectors (SHA-256/384/512, single-
and multi-block, absent info). The std PAL x963_kdf / sp800_56a_kdf hooks
(previously todo!() stubs) now delegate to it via a new StdKdf::concat_kdf;
the Uno PAL already implemented them. Adds HsmError::ConcatKdfError and
three CryptoError variants.

Wire schemas (fw + host mirror), dispatch / classifier / op.rs wiring
(in-session, session-id cross-checked, default-PSK gated) for both
opcodes. Emu tests cover every output key type under each KDF (and each
X9.63 / SP 800-56A variant), all hashes and scopes, optional salt/info,
and rejection of unknown hash / KDF variant / key type, variable-length
HMAC without / out-of-range length, and a non-ECDH-secret IKM. Per-command
docs added.

Based on tbor/ecc-crypto for the ECDH shared-secret input (EcdhDerive);
uses opcodes 0x1C / 0x1D after the sibling AES / ECC / RSA / Hash crypto
branches (0x15..0x1B).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0b09e50a-a9be-4bae-b347-d42dc775a258
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant