Skip to content

Add piv perso set-mgmt-key functionality - #12

Closed
episource wants to merge 2 commits into
cryptnox:mainfrom
episource:feature/set-mgmt-key
Closed

episource wants to merge 2 commits into
cryptnox:mainfrom
episource:feature/set-mgmt-key

Conversation

@episource

Copy link
Copy Markdown

This PR adds a new piv perso set-mgmt-key subcommand that writes AES key material into the 9B management key slot. Setting the management key remains optional: once 9B holds a value, the PIV-standard PUT DATA and GENERATE ASYMMETRIC KEY PAIR commands can also be authorized via a GENERAL AUTHENTICATE challenge-response, not only via SCP03 admin commands. This is the authorization scheme typical third-party PIV management tools rely on (e.g. keyroost).

New `piv perso set-mgmt-key` sets the PIV management key (9B, AES) the
same way set-pin/set-puk work: CHANGE REFERENCE DATA ADMIN over SCP03.
Unlike PIN/PUK, 9B is a key object, not a verifier, so the value is raw
AES key material (hex, 16/24/32 bytes per --algorithm) sent as a CLEAR
element followed by the key-value element (tag 0x80) - the same
CLEAR-first, one-element-per-SCP03-session shape import-key already
uses. keyimport.py gains sym_key_plan()/aes_key_len() alongside the
existing asymmetric element_plan(), verified against the OpenFIPS201
v2 applet source (PIVKeySYM.java) rather than guessed.

`piv status` now also reports whether 9B is set, via a non-destructive
GENERAL AUTHENTICATE probe (PivApplet.mgmt_key_status()) tried across
AES-128/192/256. The SW-to-state mapping (6A86/6A88 no object, 6983
not initialised, 6985 initialised, everything else left unknown rather
than guessed) is likewise verified against the OpenFIPS201 v2 applet
source, scoped to this command only - not wired into the shared
StateDetector used by info/doctor/report/quickstart.

Docs cover both the SCP03-only admin commands (set-pin/set-puk/
import-key/set-mgmt-key, which have no 9B alternative) and the genuine
PIV-standard management-key model 9B enables for ordinary writes (PUT
DATA, GENERATE ASYMMETRIC KEY PAIR via GENERAL AUTHENTICATE).

Co-Authored-By: Claude <noreply@anthropic.com>
Wrap two lines exceeding ruff's 100-char limit, and guard against
mgmt_key.mechanism being None before the ALGORITHMS dict lookup to
satisfy mypy.

Co-Authored-By: Claude <noreply@anthropic.com>
@mmlado

mmlado commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator

Thank you for this pull request, and for the clear write-up of the use case.

We are closing it without merging, for two reasons unrelated to the quality of the change.

The repository is not able to accept outside contributions yet. Contributor terms are being prepared and will be linked from the repository once they are published. Until then no contribution can be merged, whoever it comes from.

Separately, a management-key command was already in progress on the maintainers' side as part of a fix for on-card RSA key generation, now open as #17. It was written independently and takes nothing from this pull request.

Authorizing writes and key generation with the management key from a third-party tool is a use case worth supporting. Once the terms are in place, a pull request against the then-current main would be welcome.

@mmlado mmlado closed this Sep 25, 2026
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