Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- `factory piv preperso load-config` warns that structural operations are
permanent (existing elements cannot be changed or removed; only new ones can
be added) instead of calling them reversible before finalize.
- Error messages and docs no longer suggest reinstalling the applet as a
recovery step; a full reset of the PIV applet is a Cryptnox operation. The
`load-config` failure message points at adding missing key objects with
`--create-key-object`.
- `PivPersonalized` no longer requires the optional Discovery Object; CHUID,
CCC and a set PIN suffice. Discovery is still probed and listed.
- `factory piv preperso status` reports `finalize_allowed` under the rule
Expand Down
3 changes: 2 additions & 1 deletion docs/factory/factory-commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ coexists on 9A — see the
.. warning::

``finalize`` is **irreversible** — it locks the applet's structure for the
card's lifetime (recovery means reinstalling the applet). It is gated by a
card's lifetime. A full reset of the PIV applet is a Cryptnox operation:
contact Cryptnox support. It is gated by a
typed confirmation token when run interactively, or the
``--i-understand-this-is-irreversible`` flag when run non-interactively —
either satisfies the gate. Never run it on a card you are still developing
Expand Down
9 changes: 5 additions & 4 deletions docs/factory/pre-personalization-profiles.rst
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,11 @@ give a YAML list): ``AUTHENTICATE``, ``KEY_ESTABLISH``, ``SIGN``.
worse than an absent one: the Windows inbox PIV minidriver rejects the
whole card. This tool never writes that form.

The container also cannot be removed afterwards, because ``load-config``
stops at the first element that already exists. Recovering a card requires
reinstalling the PIV applet, which erases its keys and certificates.
Discovery is optional in PIV, and a card without it works normally.
The container also cannot be removed afterwards: existing elements cannot
be changed or removed, only new ones added, and ``load-config`` stops at
the first element that already exists. A full reset of the PIV applet
erases its keys and certificates and is a Cryptnox operation (contact
Cryptnox support).

``from_yaml`` rejects unknown mode/role/mechanism names and validates the
whole profile before anything is sent to a card:
Expand Down
5 changes: 3 additions & 2 deletions docs/piv/piv-commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@ prompts or the ``CRYPTNOX_PIV_PIN`` / ``CRYPTNOX_PIV_NEW_PIN`` / ``CRYPTNOX_PIV_
The PUK has its own retry counter, and every wrong PUK — entered through
``piv pin unblock``, ``piv puk change``, or any other tool — consumes one
retry. Exhausting the PUK retries is **permanent**: a blocked PUK has no
recovery path short of reinstalling the applet, which erases all keys and
certificates. Check ``piv pin status`` (non-decrementing) before guessing.
recovery path. A full reset of the PIV applet, which erases all keys and
certificates, is a Cryptnox operation (contact Cryptnox support). Check
``piv pin status`` (non-decrementing) before guessing.

Admin channel
-------------
Expand Down
3 changes: 2 additions & 1 deletion docs/piv/piv-personalization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,8 @@ Step 6 — finalize (irreversible, factory)
:doc:`/factory/factory-commands`.

``finalize`` transitions the applet to its ``SECURED`` operational state. It
is irreversible — recovery is a full applet reinstall. Interactively it asks
is irreversible; a full reset of the PIV applet is a Cryptnox operation
(contact Cryptnox support). Interactively it asks
you to type the token ``FINALIZE-PIV``; non-interactively it requires the
``--i-understand-this-is-irreversible`` flag instead — either satisfies the
gate.
Expand Down
10 changes: 6 additions & 4 deletions docs/piv/ssh-public-key-authentication.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,12 @@ SIGN``); everything else is identical to ``cryptnox-default``. See
This only applies at **pre-personalization** — it defines the key's role at
the structural level, not something a later ``piv perso`` step can change.
If your card already has a different profile applied (e.g. it already went
through :doc:`/piv/quick-start-a-working-piv-card` on 9C), it needs a factory-level applet
reinstall before this profile can be loaded — that's a manufacturing
operation outside this guide's (and this CLI's) scope; a blank/pre-perso
card needs no such step.
through :doc:`/piv/quick-start-a-working-piv-card` on 9C), this profile
cannot be loaded over it: existing key objects keep their role, and
``--create-key-object`` creates new ones with the default profile's roles
(AUTHENTICATE only on 9A). A full reset of the PIV applet is a Cryptnox
operation: contact Cryptnox support. A blank/pre-perso card needs no such
step.

.. code-block:: console

Expand Down
11 changes: 7 additions & 4 deletions src/cryptnox_id_cli/cli/commands/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,9 @@ def human(con: Console) -> None:

# Real write.
app.out.warn(
f"This writes {len(ops)} structural operations to the card's data model "
"(reversible only before finalize)."
f"This writes {len(ops)} structural operations. They are permanent: existing "
"elements cannot be changed or removed later (only new ones can be added), and "
"finalize locks the structure completely."
)
if not app.yes and not click.confirm("Proceed with writing to the card?", default=False):
raise click.Abort()
Expand Down Expand Up @@ -287,8 +288,10 @@ def report(con: Console) -> None:
raise RuntimeError("stopped without a failing operation")
con.print(f"\n[red]Stopped at[/red] {failed[0]} (SW={failed[1]}).")
con.print(
" Operations before it were applied. An existing object/verifier/key is "
"rejected; reinstall the PIV applet for a clean load, or edit the profile."
" Operations before it were applied. An existing element cannot be changed "
"or removed; add missing key objects with `piv perso generate-key "
"--create-key-object` or `piv perso import-key --create-key-object`. A full "
"reset of the PIV applet is a Cryptnox operation: contact Cryptnox support."
)

app.out.result({"profile": profile.name, "applied": applied_ok, "operations": sent}, report)
Expand Down
3 changes: 2 additions & 1 deletion src/cryptnox_id_cli/cli/commands/piv.py
Original file line number Diff line number Diff line change
Expand Up @@ -1247,7 +1247,8 @@ def _create_key_object(
if resp.sw == 0x6985:
raise CryptnoxError(
"the applet is finalized (SECURED): key objects can no longer be created. "
"Import into an existing object, or reinstall the applet."
"Import into an existing object. A full reset of the PIV applet is a Cryptnox "
"operation: contact Cryptnox support."
)
if not resp.ok:
raise StatusWordError(resp.sw1, resp.sw2, context=f"CREATE KEY {slot}")
Expand Down
Loading