Skip to content

fw(uno): add FIPS 140-3 key assurance - #789

Open
Kevin (kevhuo) wants to merge 2 commits into
Azure:mainfrom
kevhuo:kevinhuo/uno-fips-key-assurance
Open

Kevin (kevhuo) wants to merge 2 commits into
Azure:mainfrom
kevhuo:kevinhuo/uno-fips-key-assurance

Conversation

@kevhuo

@kevhuo Kevin (kevhuo) commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Adds FIPS 140-3 key assurance to the Uno firmware. The Uno PAL now runs pairwise consistency tests (PCTs) on generated keys, imported keys, and the partition's RSA unwrapping key, and it checks an imported ECC key's structure. A generated key or unwrapping key that fails its PCT puts the module in a new FIPS error state. An imported key that fails a check is rejected. Core only passes the PCT that a key's usage selects, and the std PAL runs none of the checks.

Firmware

  • Key generation: Core picks the PCT from the key's usage (ecc_pct_for in key-decode) and passes it to ecc_gen_keypair. Signing keys get the sign/verify PCT, and derive keys get the key-agreement PCT. HPKE's ephemeral keys get the key-agreement PCT, and the PTA derivation gets the sign/verify PCT. The Uno PAL runs each PCT with the new azihsm_fw_uno_pct crate.
  • Import: HsmEcc::ecc_priv_der_to_vault gains a pct parameter and becomes async, and HsmRsa::rsa_priv_der_to_vault gains a pct parameter. The Uno ECC conversion requires the key to carry an uncompressed public key, right after the private key, that matches the private key, and then runs the PCT. The Uno RSA conversion runs the PCT. A failed check rejects the import with KeyStructuralValidationFailed, PctValidationRsaUnwrapEccKeyFailed, or PctValidationRsaUnwrapRsaKeyFailed.
  • Unwrapping key: Before each host IO, the Uno app has the PAL certify a newly published key, which moves its slot to a PctPassed state. The first-use import takes only a certified key. vault_key_create runs the PCT on the key that EstablishCredential restores.
  • FIPS error state: azihsm_fw_uno_fault::enter_error_state sets Mailbox0's error bit for the SP and halts. This change adds the SYS_MBX registers for it.
  • RSA public operation: Uno's mod_exp_pub reorders the wire public key (n, e) into the PKA's exponent-first operand, which every RSA PCT needs.

Kevin (kevhuo) and others added 2 commits October 9, 2026 15:19
Runs pairwise consistency tests (PCTs) on generated keys, imported keys, and
the partition's RSA unwrapping key, and checks an imported ECC key's
structure. The checks live in the Uno PAL; core only passes the PCT that a
key's usage selects. The std PAL runs none of them.

- Key generation: core picks the PCT from the key's usage (ecc_pct_for in
  key-decode) for ecc_gen_keypair. HPKE's ephemeral keys get the
  key-agreement PCT, and the PTA derivation gets the sign/verify PCT. The Uno
  PAL runs it with the new PCT crate (fw/plat/uno/fw/crates/pct); a failing
  key pair enters the FIPS error state.
- Import: HsmEcc::ecc_priv_der_to_vault gains a pct parameter and becomes
  async, and HsmRsa::rsa_priv_der_to_vault gains a pct parameter. key-decode's
  decode takes the key's attributes and picks the PCT with ecc_pct_for and
  rsa_pct_for. The Uno ECC conversion requires the key to carry an
  uncompressed public key, right after the private key, that matches the
  private key, and then runs the PCT. The Uno RSA conversion runs the PCT. A
  failed check rejects the import with KeyStructuralValidationFailed,
  PctValidationRsaUnwrapEccKeyFailed, or PctValidationRsaUnwrapRsaKeyFailed.
- Unwrapping key: before each host IO, the Uno app has the PAL certify a
  newly SP-published key. Its slot gets a PctPassed state, and the first-use
  import takes only a certified key. vault_key_create runs the PCT on the key
  that EstablishCredential restores. A failure enters the FIPS error state.
- FIPS error state: azihsm_fw_uno_fault::enter_error_state sets Mailbox0's
  error bit for the SP and halts. The SYS_MBX registers are added for it.
- Uno's mod_exp_pub reorders the wire public key (n, e) into the PKA's
  exponent-first operand, which every RSA PCT needs.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7838f9e2-299a-4ebb-a5ac-300c9c931387
Imports valid and malformed ECC and RSA keys through MBOR RsaUnwrap and TBOR
UnwrapKey, and checks the exact status of each rejection. Only hardware
firmware runs the structure check and the pairwise consistency tests, so the
tests that need either are ignored under the emu, mock, and sock features.
The TBOR tests that need neither also run under emu: valid imports, key
generation, and ECC keys whose private value is 0 or the curve order, which
every firmware rejects with InvalidArg.

The key builders that both suites need (DER and PKCS#8 encoders, host ECC
and RSA keys, and the test curves) live in a new pkcs8 module in
azihsm_ddi_mbor_test_helpers, which both test crates already depend on.
TBOR's commands/common.rs now builds for every backend, so the
hardware-eligible key-assurance tests share helpers with the emu-only
command tests: the RSA-AES wrap, UnwrapKey import, byte-reversal, sign,
verify, derive, and mod-exp helpers, and the ECDSA and raw-RSA result
checks.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7838f9e2-299a-4ebb-a5ac-300c9c931387
Copilot AI balanced review requested due to automatic review settings October 9, 2026 22:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The cross-processor slot protocol lacks hardware memory barriers, allowing stale reads or replacement-key corruption.

1 open finding
What changed in this PR

Adds FIPS 140-3 key assurance to Uno firmware, covering generated, imported, and partition unwrapping keys.

Changes:

  • Adds ECC/RSA pairwise consistency tests and import validation.
  • Adds the FIPS error state and SP mailbox signaling.
  • Adds hardware-oriented TBOR/MBOR assurance tests and documentation.
File Description
fw/​plat/​uno/​rdl/​soc/​uno.rdl Maps the system mailbox.
fw/​plat/​uno/​rdl/​soc/​sys_mbx.rdl Defines mailbox registers.
fw/​plat/​uno/​fw/​reg/​soc/​src/​sys_mbx.rs Generates mailbox bindings.
fw/​plat/​uno/​fw/​reg/​soc/​src/​lib.rs Exports mailbox bindings.
fw/​plat/​uno/​fw/​pal/​src/​vault.rs Tests restored unwrapping keys.
fw/​plat/​uno/​fw/​pal/​src/​unwrapping_key.rs Certifies published unwrapping keys.
fw/​plat/​uno/​fw/​pal/​src/​test_hooks/​raw_key_import.rs Adapts test-hook slot handling.
fw/​plat/​uno/​fw/​pal/​src/​pct.rs Integrates RSA PCT execution.
fw/​plat/​uno/​fw/​pal/​src/​part.rs Gates unwrapping-key import on certification.
fw/​plat/​uno/​fw/​pal/​src/​pal.rs Adds per-partition PCT reservations.
fw/​plat/​uno/​fw/​pal/​src/​lib.rs Registers assurance modules.
fw/​plat/​uno/​fw/​pal/​src/​crypto/​rsa.rs Adds RSA import PCTs and public-key reordering.
fw/​plat/​uno/​fw/​pal/​src/​crypto/​ecc.rs Adds ECC generation/import assurance.
fw/​plat/​uno/​fw/​pal/​src/​asn1.rs Decodes embedded ECC public keys.
fw/​plat/​uno/​fw/​pal/​Cargo.toml Adds fault and PCT dependencies.
fw/​plat/​uno/​fw/​drivers/​part_store/​src/​part_store/​tests.rs Tests slot-state transitions.
fw/​plat/​uno/​fw/​drivers/​part_store/​src/​part_store.rs Implements unwrapping-key slot states.
fw/​plat/​uno/​fw/​drivers/​part_store/​src/​lib.rs Exports slot-state type.
fw/​plat/​uno/​fw/​crates/​pct/​src/​vectors.rs Adds fixed ECDH vectors.
fw/​plat/​uno/​fw/​crates/​pct/​src/​tests.rs Tests constant-time comparison behavior.
fw/​plat/​uno/​fw/​crates/​pct/​src/​rsa.rs Implements RSA PCTs.
fw/​plat/​uno/​fw/​crates/​pct/​src/​lib.rs Defines the PCT crate API.
fw/​plat/​uno/​fw/​crates/​pct/​src/​ecc.rs Implements ECC PCTs.
fw/​plat/​uno/​fw/​crates/​pct/​Cargo.toml Configures the PCT crate.
fw/​plat/​uno/​fw/​crates/​fault/​src/​lib.rs Implements the FIPS error state.
fw/​plat/​uno/​fw/​crates/​fault/​Cargo.toml Adds mailbox dependencies.
fw/​plat/​uno/​fw/​Cargo.toml Registers the PCT crate.
fw/​plat/​uno/​fw/​app/​src/​main.rs Certifies keys before host IO.
fw/​plat/​std/​pal/​src/​rsa.rs Accepts and ignores RSA import PCTs.
fw/​plat/​std/​pal/​src/​ecc.rs Accepts and ignores ECC import PCTs.
fw/​pal/​traits/​src/​crypto/​rsa.rs Extends RSA import API.
fw/​pal/​traits/​src/​crypto/​ecc.rs Extends ECC import API.
fw/​docs/​traits/​crypto.md Documents PCT behavior.
fw/​docs/​error_model.md Documents fatal PCT failures.
fw/​core/​lib/​src/​ddi/​tbor/​unwrap_key.rs Passes import attributes to decoding.
fw/​core/​lib/​src/​ddi/​tbor/​part_init.rs Enables the PTA generation PCT.
fw/​core/​lib/​src/​ddi/​tbor/​ecc_generate_key.rs Selects PCTs from usage.
fw/​core/​lib/​src/​ddi/​mbor/​rsa_unwrap.rs Selects import PCTs.
fw/​core/​lib/​src/​ddi/​mbor/​ecc_generate_key_pair.rs Selects generation PCTs.
fw/​core/​key-decode/​src/​rsa.rs Passes RSA PCT selection to PAL.
fw/​core/​key-decode/​src/​lib.rs Adds usage-to-PCT selection.
fw/​core/​key-decode/​src/​ecc.rs Passes ECC PCT selection to PAL.
fw/​core/​crypto/​hpke/​src/​kem.rs Tests ephemeral ECDH keys.
ddi/​tbor/​types/​tests/​SPEC_COVERAGE.md Records assurance coverage.
ddi/​tbor/​types/​tests/​commands/​unwrap_key.rs Reuses shared import helpers.
ddi/​tbor/​types/​tests/​commands/​rsa_mod_exp.rs Reuses shared RSA helpers.
ddi/​tbor/​types/​tests/​commands/​mod.rs Enables assurance tests.
ddi/​tbor/​types/​tests/​commands/​key_assurance.rs Adds TBOR assurance coverage.
ddi/​tbor/​types/​tests/​commands/​ecdh_derive.rs Reuses shared derivation helper.
ddi/​tbor/​types/​tests/​commands/​ecc_sign.rs Reuses shared ECDSA helpers.
ddi/​tbor/​types/​tests/​commands/​common.rs Adds cross-backend key helpers.
ddi/​mbor/​types/​tests/​integration/​rsa_unwrap_key_assurance.rs Adds MBOR assurance matrices.
ddi/​mbor/​types/​tests/​azihsm_ddi_tests.rs Registers MBOR assurance tests.
ddi/​mbor/​test_helpers/​src/​pkcs8.rs Builds valid and malformed test keys.
ddi/​mbor/​test_helpers/​src/​lib.rs Exports PKCS#8 helpers.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

// marking it published, so a consumer that observes it set must not have
// its subsequent payload loads (in `unwrapping_key_bk`) hoisted ahead of
// this observation.
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::Acquire);
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.

2 participants