v0.15.0
No command or flag is renamed or removed (piv key import
and fido info --reader are additions). A PIN or touch policy
on a Nitrokey 3 is now refused without --force, and a few
JSON values change. The library crates and the CLI now need Rust 1.87 or
newer (was 1.85). Library consumers: several public structs
gain fields, keyroost-piv renames one enum variant to
match, and keyroost-ctap drops an error variant (see the
table at the end).
CLI
| Before | Now |
|---|---|
piv key generate --pin-policy/--touch-policy other
than default on a Nitrokey 3 with firmware newer than
1.8.3, up to 1.9.1: warned, then sent |
Refused unless --force. |
JSON output
| Before | Now |
|---|---|
piv --json info:
"applet_fingerprint": "Trussed::NitroKey" |
"applet_fingerprint": "Trussed::Nitrokey" |
fido --json info: "firmware" always a
string, the version from the key's USB handshake (CTAPHID INIT;
a Solo 2 showed "2.3.196") |
The firmware the way the vendor states it (a Solo 2's
"2.964", a Token2 PIN+'s "R3.4"), or
null when the key doesn't say. The CTAP2 getInfo number
is still in ctap2.firmware_version. |
list --json: a U2F-only key's
capabilities held "FIDO2" |
"U2F". "FIDO2" can now also appear in
capabilities_unverified (a key that didn't properly
answer). |
Library (crates.io) API changes
| Crate | Change |
|---|---|
keyroost-piv |
TrussedVariant::NitroKey is renamed
TrussedVariant::Nitrokey. New: key import
(import_key, import_key_chained,
import_key_body, ImportKey) and the
per-applet checks import_layout /
import_slot_allowed. |
keyroost-ctap |
HidTransportError::NonceMismatch is removed. A
CTAPHID INIT answer carrying another program's nonce is now
skipped, and the wait ends with the usual timeout if no answer
for this one arrives. |
keyroost-oath |
Listing gains touch_required:
Vec<String> (filled by the new
parse_list_with_properties), SelectInfo
gains serial: Option<Vec<u8>>, and
Tag gains SerialNumber. New:
parse_calculate_all (all codes in one read) and
get_response. |
keyroost-resolve |
Device gains smart_card_unlisted and
EnumerateOptions gains
skip_protocol_asks (both bool; struct
literals need the new field; for EnumerateOptions,
..Default::default() also works). New: the
firmware module (key_firmware, each key's
firmware the way its vendor states it). |
keyroost-transport |
ReaderProbe gains
fido_ctap2_confirmed: bool.
identity::ctaphid_vendor_read and
identity::token2_serial_reply_hid return
KeyAnswer<Vec<u8>> (a reply, the key
declining, or no answer) instead of
Option<Vec<u8>>. New: the
piv_import module (PIV key import from a .p12/.pfx
file). |
| New crates | keyroost-p12 (PKCS#12 .p12/.pfx reader, used by PIV
key import). |
v0.14.0
One command changes: openpgp key import --generate now
makes a full OpenPGP key set and saves it before writing the card, so it
needs --backup FILE and --name. In the app,
Generate & import is replaced by Create keys with a
backup…. The macOS builds now need macOS 11 (Big Sur) or
newer. Library consumers: keyroost-hid and
keyroost-transport replace the USB bus and address fields
with one usb_device field, and
keyroost-rsakey drops generate_2048 (see the
table at the end).
CLI
| Before | Now |
|---|---|
openpgp key import --generate [--slot sign|decrypt|auth]:
one RSA-2048 key made on the computer, loaded into one slot, then
discarded |
openpgp key import --generate --backup FILE --name NAME
[--email EMAIL] [--algorithm TYPE] [--expires WHEN]: a
signing key with decryption and authentication subkeys, saved as
FILE.asc (passphrase-protected backup),
FILE.pub.asc and FILE.rev.asc, then loaded
into all three slots. --slot now goes with
--in only; without --backup or
--name the command is refused before the card is
touched. |
openpgp key import --in FILE with an RSA key file |
Unchanged (into sign unless --slot);
--in also restores a keyroost or GnuPG backup into
every slot it has a key for. |
Library (crates.io) API changes
| Crate | Change |
|---|---|
keyroost-hid |
HidDevice's usb_bus and
usb_address are replaced by
usb_device: Option<UsbDeviceKey>
(BusAddr(bus, address) on Linux, WinNode
on Windows). Compare two with same_usb_device;
UsbDeviceKey::from_bus_addr builds the Linux one. |
keyroost-transport |
The same change on ReaderProbe and
YubiKeyCcid: usb_bus /
usb_address become usb_device.
ReaderProbe also gains usb_product (the
USB product string, when Windows reports it). |
keyroost-rsakey |
generate_2048 is removed. Loading a key file
(load_from_file) is unchanged, now for 2048, 3072 and
4096 bits. To make keys, use the new keyroost-pgpkey
crate (cert::create). |
keyroost-resolve |
New, additive: vendor_name (the display name for a
USB vendor ID). |
| New crates | keyroost-pgpkey (OpenPGP key sets, backups, restore,
expiry) and keyroost-windevtree (Windows device-tree
reads, used by keyroost-hid and
keyroost-transport on Windows). |
v0.13.0
Every command now finds its key the same way, and more commands ask
before they erase or replace something. In a terminal you answer a
y/N question; a script must pass --yes. With several keys
connected and no selector, a script is refused instead of acting on
the first key found: pick one with --device (the refusal
lists the exact values, and list --json gives them too).
No secret is taken on the command line any more: each secret has one
flag whose value says where it comes from (--pin env:NAME
or --pin stdin), and with no flag a terminal asks for it
at a hidden prompt (see secrets below).
Output is more consistent too: stdout carries only the result,
--json always prints one object with every field present,
and piv cert export prints PEM (see
output and JSON below). Commands are
regrouped by what they act on (piv pin change,
fido credential list), five short flags mean the same
thing everywhere (-d, -y, -o,
-i, -s), and an existing output file is no
longer replaced without asking (see
command and flag names below).
A key can now carry its own name, and keys.json no longer
holds serials (see names below).
Authenticator exports can now be imported into OATH keys and Token2
OTP storage as well as a Molto2, and molto import --in
follows the same rules (see importing
codes below).
Library consumers: keyroost-resolve drops its HID-only
name resolver for the shared device model, and
keyroost-ctap, keyroost-keyring and
keyroost-resolve change their public API (see the table
at the end).
CLI
| Before | Now |
|---|---|
These ran without asking (v0.12 names): oath delete,
otp delete, otp button-hotp (with a seed
already set), otp delete-button-hotp,
fido creds-delete, fido fingerprint-delete,
molto seed / import /
import-file (on used slots), molto
customer-key, prog seed,
prog config, piv set-retries, and
piv generate-key / import-cert /
self-sign / --generate-key on
self-sign and request-cert (on a slot in
use) |
A y/N question in a terminal: oath delete,
otp delete, otp button set,
otp button clear, fido credential
delete, fido fingerprint delete,
molto seed set and molto import (on used
slots), molto customer-key change, prog seed
set, prog config set, piv retries set (which also
resets the PIN and PUK to their factory defaults), and
piv key generate, piv cert import,
piv cert generate and --generate-key on
a slot in use. A script, or a command whose PIN, seed or
management key is piped in on stdin, must add --yes
(-y), or the command refuses and changes nothing.
piv key move still doesn't ask: it refuses when the
card reports that the destination slot already holds a key. |
Commands that already took --yes refused without
it, even in a terminal |
In a terminal they ask y/N instead (the hidden molto
probe still needs --yes). Scripts still need
--yes. |
factory-reset needed --yes |
In a terminal, type reset to confirm.
--yes skips the question; scripts still need it. |
factory-reset printed N wiped, K
failed, counted a skipped step as wiped, and exited 0 when
steps were only skipped |
Prints N wiped, M skipped, K failed and exits with
an error if any step was skipped or failed (the key was not fully
reset). |
factory-reset's FIDO2 step waited for Enter
after the replug; fido reset sent the reset at
once |
Both wait (up to 60 seconds) for you to unplug and replug the USB key, check it is the same key, then ask for a touch. No replug: nothing is wiped. A card in a reader is still reset in place. |
otp interface read its confirmation phrase from
stdin |
The phrase is read from the terminal only. A script passes
--yes. |
With several keys and no selector, molto (except
molto reset) and otp used the first key
found; fido and
key-name add showed a picker (not on Windows) |
Every command: a numbered picker in a terminal (on every
platform), a refusal in a script that lists each key's
--device value. A lone key is still used
automatically. |
prog ignored --device and used
whichever reader was alone |
Only programmable tokens qualify, and --device /
--reader are honored. |
--reader with --device was refused
only by the reset commands |
Refused by every command (they may name different keys). |
--device took a friendly name |
A name, a serial or a list number. Prefix
name:, serial: or list: to
force which. A value that matches several keys is refused. A
Molto2 answers to either serial keyroost shows for it: the one in
keyroostctl list or the one molto info
prints. |
--device was ignored by commands that touch no
key |
Refused on doctor, name list,
completions and manpage. Remove it.
(molto import --in … --dry-run now reads slot use
from the Molto2 it names; see importing
codes.) name clear
takes a NAME or -d, not both. |
completions <shell> printed a full static
script |
Prints a short script that calls back into
keyroostctl (through the
KEYROOSTCTL_COMPLETE variable), so
--device completes saved names. Regenerate an installed
completion file to get this. |
list had no numbers and no JSON |
Each key has a number (usable as --device N; it
can change when keys are added or removed, so scripts should use
a name or serial). list --json prints
{"keys": [...]}, one row per key with the exact
--device value; list
--device X shows just that key. |
piv self-sign / request-cert without
--key-usage wrote no key usage |
piv cert generate / piv cert request write the slot's standard PIV key usage, marked critical
(same as --key-usage default). Use --key-usage
undefined for the old output. |
Names and keys.json
A name can now be kept on the key itself
(keyroostctl name set NAME --store key), where every
computer running keyroost shows it. Names kept on this computer work
as before. See Naming.
| Before | Now |
|---|---|
keys.json held each named key's serial |
It holds a salted fingerprint of the key instead, with the salt
in keys.salt beside it. The first time v0.13.0 reads
an older keys.json it converts it, keeping a backup of
the old file until the conversion succeeds and then removing it.
Nothing to do. If you go back to v0.12, it can't read the converted
file and shows your keys unnamed; don't name or rename a key with
v0.12 after upgrading, since v0.12 then saves a new
keys.json over the converted one and its names are
lost. If keys.salt is
lost, clear the names and set them again; restoring the old
keys.salt doesn't bring them back. |
fido blob clear erased the whole array |
It still does, and the warning now names the key's name if one
is stored on the key. --keep-name keeps it.
fido blob edit refuses the name entry (use
name set), and fido blob delete on it
warns first. |
One large-blob element that wasn't in the standard entry
format made fido blob list fail |
That element is skipped and counted (skipped in the
JSON), and every write keeps it unchanged. |
list --json rows had a name |
They also have name_source: "key",
"computer" or null. A key carrying a
name another key holds here shows "Name (1234)" (the
last four characters of its serial); select it by the row's
device value. fido blob list --json has
a "key-name" kind, and name list --json
prints {"names": [{"name", "stored", "status",
"number"}]}. |
CLI: secrets
Each PIN, password, key, seed and otpauth:// URI has one
flag, and its value says where the secret comes from:
env:NAME reads the environment variable
NAME, stdin reads one line from standard
input, and --mgmt-key default uses the factory-default
management key. With no flag, a terminal asks at a hidden prompt; that
is the normal way to run a command by hand. New PINs, passwords and
keys typed at the prompt are asked twice. A script with no flag is
refused with an error naming it. The secret itself typed as the value
(--pin 123456) is refused with exit 2 and never shown.
The --old-… flags are now the plain name:
--pin is the current PIN and --new-pin the
new one. A removed or renamed flag is refused with an error naming its
replacement; the value given with it is never printed.
keyroostctl piv pin change # by hand: asks for both PINs, hidden
keyroostctl piv pin change --pin env:OLD_PIN --new-pin env:NEW_PIN # in a script
| Old (≤ 0.12.x) | New (0.13.0+) |
|---|---|
keyroostctl molto --key HEX …keyroostctl molto --key-env VAR … |
keyroostctl molto --customer-key env:VAR … (with no
--customer-key, the factory-default key is used, as
before) |
keyroostctl molto --key-ascii TEXT …keyroostctl molto --key-ascii-env VAR … |
keyroostctl molto --customer-key env:VAR
--customer-key-encoding ascii … |
keyroostctl molto seed -p 5 --hex HEXkeyroostctl molto seed -p 5 --hex-env VAR / --hex-stdin |
keyroostctl molto seed set --slot 5 --seed env:VAR
--encoding hex or --seed stdin --encoding
hex |
keyroostctl molto seed -p 5 --base32 B32keyroostctl molto seed -p 5 --base32-env VAR / --base32-stdin |
keyroostctl molto seed set --slot 5 --seed env:VAR or
--seed stdin (base32 is the default encoding); with
no --seed, a terminal asks (hidden) |
keyroostctl prog seed --hex HEXkeyroostctl prog seed --hex-env VAR / --hex-stdin |
keyroostctl prog seed set --seed env:VAR --encoding
hex or --seed stdin --encoding hex |
keyroostctl prog seed --base32 B32keyroostctl prog seed --base32-env VAR / --base32-stdin |
keyroostctl prog seed set --seed env:VAR or
--seed stdin; with no --seed, a terminal
asks (hidden) |
keyroostctl prog seed --base32-stdin read all of stdin |
--seed stdin reads one line, like every other
source. |
keyroostctl molto customer-key --hex HEXkeyroostctl molto customer-key --hex-env VAR / --hex-stdin |
keyroostctl molto customer-key change --new-customer-key
env:VAR or --new-customer-key stdin (hex is the
default encoding); with no flag, a terminal asks twice
(hidden) |
keyroostctl molto customer-key --ascii TEXTkeyroostctl molto customer-key --ascii-env VAR / --ascii-stdin |
keyroostctl molto customer-key change --new-customer-key
env:VAR --encoding ascii |
keyroostctl molto import -p 0 'otpauth://…' |
keyroostctl molto import --slot 0 --uri env:VAR,
--uri stdin, or --qr IMAGE; with none of
them, a terminal asks for the URI (hidden) |
keyroostctl oath add NAME --secret-env VARkeyroostctl oath add NAME --secret-stdin |
keyroostctl oath add NAME --seed env:VAR or
--seed stdin (base32 unless --encoding
hex) |
keyroostctl openpgp verify --pin admin |
keyroostctl openpgp pin verify --admin (the PIN
itself comes from --pin env:VAR, --pin
stdin or the prompt) |
keyroostctl otp change-pin --current-env OLD --new-env NEW |
keyroostctl otp pin change --pin env:OLD --new-pin
env:NEW |
keyroostctl otp change-pin --pin-stdin (current PIN on line 1, new PIN on line 2) |
keyroostctl otp pin change --pin stdin --new-pin
stdin (same two lines, same order) |
keyroostctl otp set-pin --pin-env VAR / --pin-stdin |
keyroostctl otp pin set --new-pin env:VAR /
--new-pin stdin |
--pin-env VAR / --pin-stdin |
--pin env:VAR / --pin stdin |
--old-pin-env VAR / --old-pin-stdin |
--pin env:VAR / --pin stdin (the
current PIN) |
--new-pin-env VAR / --new-pin-stdin |
--new-pin env:VAR / --new-pin stdin |
--puk-env VAR / --puk-stdin |
--puk env:VAR / --puk stdin |
--old-puk-env VAR / --old-puk-stdin |
--puk env:VAR / --puk stdin (the
current PUK) |
--new-puk-env VAR / --new-puk-stdin |
--new-puk env:VAR / --new-puk stdin |
--admin-pin-env VAR / --admin-pin-stdin |
--admin-pin env:VAR / --admin-pin
stdin |
--mgmt-key-env VAR / --mgmt-key-stdin / --mgmt-key-default |
--mgmt-key env:VAR / --mgmt-key stdin
/ --mgmt-key default |
--old-mgmt-key-env VAR / --old-mgmt-key-stdin / --old-mgmt-key-default |
--mgmt-key env:VAR / --mgmt-key stdin
/ --mgmt-key default (the current management
key) |
--new-mgmt-key-env VAR / --new-mgmt-key-stdin |
--new-mgmt-key env:VAR / --new-mgmt-key
stdin |
keyroostctl molto import-file FILE --password-env VAR / --password-stdin (an encrypted Aegis export) |
keyroostctl molto import --in FILE --file-password
env:VAR / --file-password stdin (with
--customer-key stdin too, the customer key is line 1
and the export's password line 2) |
--password-env VAR / --password-stdin |
--password env:VAR / --password
stdin (the key's password; an export file's password is
--file-password) |
--new-password-env VAR / --new-password-stdin |
--new-password env:VAR / --new-password
stdin |
--seed-env VAR / --seed-stdin |
--seed env:VAR / --seed stdin |
keyroostctl oath set-password --password-stdin --new-password-stdin read the new password on line 1 and the current one on line 2 |
keyroostctl oath password set --password stdin
--new-password stdin reads the current password on line 1
and the new one on line 2. Swap the lines in a script that pipes
both. |
keyroostctl piv change-management-key --old-mgmt-key-stdin --new-mgmt-key-stdin read the new key on line 1 and the current one on line 2 |
keyroostctl piv mgmt-key change --mgmt-key stdin
--new-mgmt-key stdin reads the current key on line 1 and
the new one on line 2. Swap the lines in a script that pipes
both. |
No -env / -stdin flag: refused, even in a terminal. A -stdin flag typed at a terminal showed the secret, with a warning |
In a terminal: a hidden prompt, for every secret (the Molto2
and prog seeds and the new Molto2 customer key
included). stdin typed at a terminal is hidden too.
In a script: refused, naming the flag. After a secret is typed at
the prompt, keyroost checks it is still the same key before
acting. |
keyroostctl piv reset / factory-reset ignored an unset --mgmt-key-env or --pin-env variable when the card didn't need it |
The --mgmt-key or --pin source is read
before anything is reset, so an unset variable is an error up
front. Drop the flag if the card doesn't need it. |
In Git Bash (mintty) on Windows the hidden prompt needs a real
console: run winpty keyroostctl …, or pass the secret
with env:NAME.
CLI: output and JSON
stdout now carries only a command's result; prompts, progress and
notes go to stderr, so keyroostctl molto list >
slots.txt saves just the table. With --json, a
command prints one object, lists sit under a named key, and every
field is present (null when unknown). Key order is not
part of the shape.
| Before | Now |
|---|---|
keyroostctl --json (the overview) printed a bare
array |
{"keys": [...]} (list --json, new in
this release, has the same shape) |
oath list --json and otp list --json
printed a bare array |
{"accounts": [...]} |
Overview: caps, caps_unverified |
capabilities,
capabilities_unverified |
molto info: utc |
utc_time |
molto slots: algorithm as a code
(1, 2), time_step,
digits |
algorithm is "sha1" or
"sha256"; time_step is now
period (null when 0); algorithm
and digits are null for a code keyroost
doesn't know |
oath list and otp list:
algorithm as "SHA1",
"SHA256", "SHA512" |
Lowercase ("sha1", "sha256",
"sha512"), the same as molto list. The
human [TOTP/SHA1] text is unchanged. |
piv status slots[].slot and
piv test slot:
"authentication (9A)" |
slot is the --slot value
("9a"); the old text is in the new
slot_name |
openpgp status: serial as a number;
pin_retries_pw1, pin_retries_rc,
pin_retries_pw3 |
serial is a decimal string;
user_pin_retries, reset_code_retries,
admin_pin_retries |
otp pin-status: retries_left,
max_retries |
pin_retries, pin_retries_max |
oath list: oath_type;
otp list: otp_type |
type |
fido large-blob list / get:
ssh_cert.serial as a number |
A decimal string (a 64-bit serial doesn't fit every JSON reader's numbers) |
Fields left out when unknown: molto slots
title; prog info model;
fido info ctap2,
max_msg_size, min_pin_length,
force_pin_change, firmware_version;
piv status cert_unreadable and
cert_compressed (left out when false);
piv test detail; openpgp
status serial, fingerprint_sig,
fingerprint_dec, fingerprint_aut;
otp pin-status pin_set and the retry
counts; fido creds-list rp_name,
user_name, user_display_name,
algorithm, algorithm_name; fido
large-blob list / get text,
ssh_cert |
Always present: null when unknown
(cert_compressed is always true or
false) |
On stdout: the Molto2 serial and UTC lines (on every
molto command), "authenticated" and the button
prompts; fido fingerprint-enroll progress and the
reader power-cycle line; the "Wrote" lines of fido ssh-cert
extract and fido large-blob export;
openpgp generate / import progress; the
PIV compressed-certificate note |
On stderr. molto info still prints the serial and
UTC on stdout, since they are its result. |
piv export-cert wrote DER, and refused to write
it to a terminal |
piv cert export writes PEM, so keyroostctl
piv cert export --slot 9a at a terminal prints the
certificate. Add --format
der for the old bytes. |
Some out-of-range values (oath add --digits 9,
piv set-retries --pin-tries 0) exited 1 |
Exit 2, like any other usage error |
--debug showed nothing for FIDO over USB
(KEYROOST_CTAP_DEBUG did) |
--debug traces FIDO over USB, not FIDO through a
smart-card reader; the variable still works. FIDO PIN exchanges
(clientPIN, authenticatorConfig) are hidden except the retry count
and key agreement, like PIV and OpenPGP PIN checks. Every group
uses one line format; it is for people and may change. |
Messages mixed styles: WARNING: /
Note:, "profile #N" in Molto2 messages |
warning: / note:, sentences, and
"slot #N" (Seed written to slot #5.) |
Human labels: device serial:,
device UTC:, slot #N title:,
occupied:, prog info
model: / serial: /
utc_time:, fido info
MaxMsgSize:, CTAP fwVer: |
Serial:, Device UTC:,
Title:, Occupied:, Model: /
Serial: / Device UTC:,
Max message size:,
CTAP firmware version:. Read values in a script with
--json where it exists. |
CLI: command and flag names
Commands are grouped by what they act on, in separate words, and
flags are renamed to match. Every command ends in an action word, and
one action has one word in every group: status shows the
state of one feature, show prints one item,
export saves one to a file, clear removes a
value set with set, and change replaces a
secret. The item a command acts on (a credential ID, a fingerprint's
ID and name) is an argument, not a flag; an input file is
--in. An old name is refused with an error naming the
new one; there are no hidden aliases, so update scripts as follows.
Secret flags are listed under
secrets above.
| Old (≤ 0.12.x) | New (0.13.0+) |
|---|---|
keyroostctl fido pin-set | keyroostctl fido pin set |
keyroostctl fido pin-change | keyroostctl fido pin change |
keyroostctl fido pin-retries | keyroostctl fido pin status |
keyroostctl fido creds-list | keyroostctl fido credential list |
keyroostctl fido creds-delete --cred-id HEX | keyroostctl fido credential delete HEX |
keyroostctl fido creds-metadata | keyroostctl fido credential status |
keyroostctl fido fingerprint-list | keyroostctl fido fingerprint list |
keyroostctl fido fingerprint-enroll --name NAME | keyroostctl fido fingerprint add NAME (the name is optional) |
keyroostctl fido fingerprint-rename --template-id HEX --name NAME | keyroostctl fido fingerprint rename HEX NAME |
keyroostctl fido fingerprint-delete --template-id HEX | keyroostctl fido fingerprint delete HEX |
keyroostctl fido always-uv | keyroostctl fido config always-uv enable or keyroostctl fido config always-uv disable; no longer a toggle (see below) |
keyroostctl fido set-min-pin | keyroostctl fido pin min-length set |
keyroostctl fido force-pin-change | keyroostctl fido pin force-change |
keyroostctl fido enterprise-attestation | keyroostctl fido config attestation enable |
keyroostctl fido large-blob | keyroostctl fido blob; same subcommands, except get |
keyroostctl fido large-blob get INDEX | keyroostctl fido blob show INDEX |
keyroostctl fido ssh-cert list | keyroostctl fido ssh list |
keyroostctl fido ssh-cert extract | keyroostctl fido ssh export |
keyroostctl piv status | keyroostctl piv info |
keyroostctl piv change-pin | keyroostctl piv pin change |
keyroostctl piv unblock-pin | keyroostctl piv pin unblock |
keyroostctl piv change-puk | keyroostctl piv puk change |
keyroostctl piv set-retries | keyroostctl piv retries set |
keyroostctl piv change-management-key | keyroostctl piv mgmt-key change |
keyroostctl piv generate-key | keyroostctl piv key generate |
keyroostctl piv delete-key | keyroostctl piv key delete |
keyroostctl piv move-key | keyroostctl piv key move |
keyroostctl piv import-cert | keyroostctl piv cert import |
keyroostctl piv export-cert | keyroostctl piv cert export |
keyroostctl piv delete-cert | keyroostctl piv cert delete |
keyroostctl piv request-cert | keyroostctl piv cert request |
keyroostctl piv self-sign | keyroostctl piv cert generate |
keyroostctl piv new-chuid | keyroostctl piv chuid generate |
keyroostctl openpgp status | keyroostctl openpgp info |
keyroostctl openpgp verify | keyroostctl openpgp pin verify; the admin PIN is --admin |
keyroostctl openpgp change-pin | keyroostctl openpgp pin change |
keyroostctl openpgp change-admin-pin | keyroostctl openpgp pin change --admin |
keyroostctl openpgp unblock-pin | keyroostctl openpgp pin unblock |
keyroostctl openpgp generate-key | keyroostctl openpgp key generate |
keyroostctl openpgp import-key | keyroostctl openpgp key import |
keyroostctl openpgp public-key | keyroostctl openpgp key show |
keyroostctl openpgp algorithms | keyroostctl openpgp key algorithms |
keyroostctl openpgp set-name | keyroostctl openpgp name set |
keyroostctl openpgp set-url | keyroostctl openpgp url set |
keyroostctl oath set-password | keyroostctl oath password set |
keyroostctl oath clear-password | keyroostctl oath password clear |
keyroostctl otp get | keyroostctl otp code |
keyroostctl otp config | keyroostctl otp info |
keyroostctl otp erase-all | keyroostctl otp reset |
keyroostctl otp button-hotp | keyroostctl otp button set |
keyroostctl otp delete-button-hotp | keyroostctl otp button clear |
keyroostctl otp pin-status | keyroostctl otp pin status |
keyroostctl otp set-pin | keyroostctl otp pin set |
keyroostctl otp verify | keyroostctl otp pin verify |
keyroostctl otp change-pin | keyroostctl otp pin change |
keyroostctl otp remove-pin | keyroostctl otp pin clear |
keyroostctl otp fp-status | keyroostctl otp fingerprint status |
keyroostctl otp fp-enable | keyroostctl otp fingerprint enable |
keyroostctl otp fp-disable | keyroostctl otp fingerprint disable |
keyroostctl otp fp-list | keyroostctl otp list --unlock fingerprint |
keyroostctl otp unlock-list | keyroostctl otp list --unlock auto; --pin-only is --unlock pin, the default |
keyroostctl molto sync-time | keyroostctl molto sync |
keyroostctl molto import-file | keyroostctl molto import --in FILE; --start is --slot (the first slot to fill), and the export's password is --file-password |
keyroostctl molto slots | keyroostctl molto list |
keyroostctl molto seed … | keyroostctl molto seed set … |
keyroostctl molto config … | keyroostctl molto config set … |
keyroostctl molto customer-key … | keyroostctl molto customer-key change … |
keyroostctl molto title -p 99 (shows the title) | keyroostctl molto title --slot 99; without set it only shows the title |
keyroostctl prog seed … | keyroostctl prog seed set … |
keyroostctl prog config … | keyroostctl prog config set … |
keyroostctl key-name | keyroostctl name set, name list, name clear (key-name add is now name set, key-name remove is now name clear) |
keyroostctl --list-readers |
keyroostctl list; the flag is removed |
keyroostctl molto title -p 99 NAME (also --profile, on seed, title, delete, config, sync-time and import) |
keyroostctl molto title set --slot 99 NAME or
-s 99 (Token2 calls slots profiles) |
keyroostctl molto config -p 5 --time-step 60 |
keyroostctl molto config set --slot 5 --period 60
(same values) |
keyroostctl prog config --time-step 60 |
keyroostctl prog config set --period 60 (same
values) |
keyroostctl molto import-file export.json --start 10 |
keyroostctl molto import --in export.json --slot
10 (or -i export.json; an encrypted export
adds --file-password env:VAR) |
keyroostctl piv import-cert --slot 9a --file cert.pem |
keyroostctl piv cert import --slot 9a --in cert.pem
(or -i cert.pem) |
keyroostctl piv export-cert --slot 9a --file cert.pem (also request-cert and self-sign) |
keyroostctl piv cert export --slot 9a --out cert.pem
(or -o cert.pem; also piv cert request
and piv cert generate) |
keyroostctl piv generate-key --slot 9a --save-pubkey pub.pem |
keyroostctl piv key generate --slot 9a --out
pub.pem |
keyroostctl piv self-sign --generate-key --save-pubkey pub.pem … (also request-cert) |
keyroostctl piv cert generate --generate-key --pubkey-out
pub.pem … (also piv cert request) |
keyroostctl piv request-cert --load-pubkey pub.pem … (also self-sign) |
keyroostctl piv cert request --pubkey-in pub.pem …
(also piv cert generate) |
keyroostctl piv change-management-key --new-algorithm aes256 |
keyroostctl piv mgmt-key change --algorithm
aes256 |
keyroostctl fido ssh-cert extract --credential ssh:demo |
keyroostctl fido ssh export --rp ssh:demo (the SSH
credential's RP ID) |
keyroostctl fido ssh-cert extract --force |
keyroostctl fido ssh export --overwrite |
keyroostctl fido large-blob export 1 entry.bin |
keyroostctl fido blob export 1 --out entry.bin (or
-o entry.bin) |
| Before | Now |
|---|---|
Short flags differed by command (-p for a Molto2
slot) |
Five short flags, with the same meaning on every command:
-d (--device), -y
(--yes), -o (--out),
-i (--in) and -s
(--slot). -p is gone. |
The flag name said how a seed or customer key was written
(--hex-env, --base32-env,
--key-ascii-env) |
--encoding: seeds are base32 unless
--encoding hex (oath add, otp
add, otp button set, molto seed
set, prog seed set); a new Molto2 customer key is hex unless
--encoding ascii. The current customer key uses
--customer-key-encoding. |
An existing output file was replaced without asking
(fido ssh-cert extract refused it unless
--force) |
piv cert export, piv cert request,
piv cert generate and piv key generate
--out, openpgp sign, decrypt and
authenticate, and fido blob export and
fido ssh export ask "overwrite? [y/N]" at a terminal
and refuse in a script. Add --overwrite to replace
the file. A directory as the output (and a symlink, for the
openpgp outputs) is refused before the key is
touched. --overwrite covers only the file;
--yes still confirms what happens on the
key. |
fido always-uv flipped the setting, whatever it
was |
keyroostctl fido config always-uv enable turns it
on and keyroostctl fido config always-uv disable
turns it off. Each does nothing, says so and exits 0 when the key
is already in that state. |
otp unlock-list --pin-only never asked for the
PIN |
keyroostctl otp list --unlock pin asks for it at a
terminal when the key needs one and no --pin gives
it. A script still needs --pin env:VAR or
--pin stdin. --unlock fingerprint with
--pin is a usage error (exit 2). |
piv status and the GUI called every slot without
a certificate "empty" |
"empty" when the card says the slot holds no key, "key present, no certificate" when the card confirms a key, and "no certificate (a key may be present)" when keyroost can't tell. keyroost can't tell on cards where it doesn't use GET METADATA's key type, and on cards whose GET METADATA answer neither names a key nor says there is none: their slots that read "empty" before now read "no certificate (a key may be present)". On a YubiKey, a slot with a key but no certificate now reads "key present, no certificate" in the CLI. JSON is unchanged. |
openpgp status showed a Token2 key's shortened
OpenPGP serial |
keyroostctl openpgp info (and its JSON
serial) shows the full serial, read from the key's
OTP applet like piv info does. |
Importing codes
New: oath import and otp import add every
code in an authenticator export to a key, and the desktop app does
the same for every key that stores codes. molto import
--in now follows the same rules: it reads the key first, shows
what each entry becomes, skips what the key can't store, and asks once
before writing.
keyroostctl molto import -i export.json --slot 90 --dry-run # check the new preview first
| Before | Now |
|---|---|
| The Molto2 view's Bulk import… button opened a Molto2-only dialog | Import file… (or dropping a file on the window) opens the Import authenticator codes dialog, the same one used for every key that stores codes. A certificate or key file gets a note saying where to import it instead. |
molto import --in refused the whole file when one
entry couldn't be stored on a Molto2 (for example a SHA-512 code),
or when the entries didn't all fit before slot #99 |
That entry is skipped with the reason, the rest are written, and entries past slot #99 are skipped. |
| An entry with no issuer or account left its slot empty | It is skipped without using up a slot, so the next entry takes that slot. Check slot numbers in a script that relied on the gap. |
molto import --in asked only when a target slot
was in use |
It asks once whenever it will write anything. A script adds
--yes, as before. |
molto import --in … --dry-run printed
Found N entries; would fill slots … and touched no
key |
It prints the same preview as oath import, reads
which slots are in use from a connected Molto2 (no customer key
needed; it still works with none connected), and takes
--device / --reader. |
oath code NAME computed a code at 30 seconds
unless --period was given, so a code stored as
60/Issuer:account was wrong (also in the app) |
--period defaults to the name's
period/ prefix, else 30. --period 0 is
refused (exit 2). |
oath add sent any name to a Solo 2 |
A Solo 2 name over 127 bytes is refused before anything is sent
(a 128-byte name made the key stop responding until it was
unplugged). On YubiKey 4 firmware 4.0 to 4.3.4, a name that is the
start of another name on the key is refused, following the same
rule as Yubico's ykman. |
Library (crates.io) API changes
| Crate | Change |
|---|---|
keyroost-resolve |
connected_keys and read_effective_serial
are removed. Use enumerate() and pick a row with
select::resolve_target; a row's serial
replaces the effective serial. |
keyroost-resolve |
New: correlate_with, correlate_live,
enumerate_with, MatchOptions,
EnumerateOptions and MatchStep; the
identity module (IdentityReader,
read_identities, plan_identity_reads) and
the select module (resolve_target,
Need, Selector, Picker,
SelectError, list_order,
device_value). enumerate() now also reads
each side's identity where USB position can't match a key
(read-only; enumerate_with with
skip_identity_reads turns it off).
correlate() keeps its signature. New dependency on
keyroost-token2otp. |
keyroost-transport |
New identity module (read-only identity reads:
ctaphid_vendor_read, ccid_applet_read,
token2_serial_reply_hid) and
PivSession::metadata_status. |
keyroost-transport |
New, additive: OpenPgpStatus::otp_applet_serial
and OpenPgpStatus::full_serial() (a Token2 key's full
serial); PivSlotStatus::key, the
SlotKeyPresence enum (Present,
NoKey, Unknown) and
PivSession::slot_key_presence (what keyroost can tell
about a slot's key). Both structs and the enum are
#[non_exhaustive], so nothing existing
breaks. |
keyroost-ctap |
LargeBlobArray's entries and
raw_array fields are now methods
(entries(), entry(i), len(),
raw_array()), and the array is built with
LargeBlobArray::parse.
serialize_with_checksum returns
Result: it refuses an array read with bytes after its
end. EntryKind gains KeyName, so an
exhaustive match needs a new arm.
extract_cert_from_entries takes the
&LargeBlobArray. New: the
device_label module (the on-key name format, see
PROTOCOL-device-label.md),
skipped_count, without_entry,
label, with_label,
only_label, and cbor::item_len,
split_array, split_map,
array_header. |
keyroost-keyring |
keys.json format 2. KeyEntry is
KeyRecord: serial is replaced by
fingerprint and stored
(NameStore). Removed: add,
by_name, by_serial,
name_for, resolve,
ConnectedKey, ResolveError and
KeyringError::DuplicateSerial; remove returns the removed record. New:
set_name,
holder, local_name_for,
records_for, record_first_seen,
clear_key, load_report, the
fingerprint API (Salt, Fingerprint,
fingerprint, SALT_FILE) and
KeyringError variants MalformedSalt,
NoSerial, Unconverted,
NewerFormat and Damaged.
save_to and save_default take
&mut self. New dependencies on
getrandom and keyroost-proto. |
keyroost-resolve |
Device gains public fields naming
and hid_serial, EnumerateOptions gains
skip_key_names, and SelectError gains
NameNotConnected; code that builds these structs or
matches the enum exhaustively needs updating. New: the
names module (Naming,
NameSource, KeyLabel,
apply_names, …). enumerate() reads the
name stored on each FIDO key unless skip_key_names
is set. New dependency on keyroost-ctap. |
keyroost-proto, keyroost-ctap |
New, additive: the keyroost_proto::trace module (the
shared --debug line format) and
keyroost_ctap::set_trace (turns the CTAP trace on
without the environment variable). Nothing existing
changes. |
v0.12.0
PIV gained applet fingerprinting, per-key feature support and certificate
compression. Scripts should check the piv status --json
serial (today piv info --json) and any piv reset
that relied on being refused.
Library consumers: PivSession now lives inside a
transaction closure, and several PIV signatures gained a parameter.
CLI
| Before | Now |
|---|---|
piv status --json: "serial": 12345678 |
"serial": "12345678" — a string, decimal, or
0x-hex when too long for decimal. Token2 serials now
match the number printed on the key. New fields:
applet_fingerprint, applet_name,
version_firmware, and cert_compressed on a
slot holding a compressed certificate. |
piv reset --yes failed unless the PIN and PUK were
both already blocked |
On a key listed as supporting reset, it blocks them itself and resets. A script that relied on the refusal as a stop will now wipe PIV. |
piv delete-key / move-key refused
unless the card reported version 5.7 or newer |
Decided per applet: run on a key listed as supporting them, run
with a warning on an unknown one, and need --force on
one listed without them (including a YubiKey older than 5.7). |
change-management-key, generate-key,
reset always sent the command |
Refused on a key listed without the feature, policy or key type,
unless --force. |
piv import-cert wrote any certificate |
Refuses a certificate whose public key doesn't match the slot's key (when both are known); nothing is written. |
self-sign / new-chuid without a
validity: 365 days |
One calendar year. --years, --months and
--days combine. |
factory-reset order: OATH, OpenPGP, PIV, Token2
OTP, FIDO2 |
OATH, OpenPGP, Token2 OTP, PIV, FIDO2. |
Library (crates.io) API changes
| Crate | Change |
|---|---|
keyroost-transport |
PivSession::open(reader) and set_debug are
removed. Use PivSession::with_transaction(reader, |s| { .. }),
or with_transaction_traced(reader, true, f) for a trace
that includes the first SELECT; with_cached_transaction
reuses fingerprint state across calls. PivSession is now
PivSession<'tx>, holds the PC/SC transaction, can't
outlive the closure, and is no longer UnwindSafe. |
keyroost-transport |
New parameters:
set_management_key(current, alg, key, touch) (pass the
current CurrentMgmtAuth; only HID Crescendo uses it);
import_certificate(slot, der, CertCompression) returns a
CertImport (CertCompression::Never is the
old behavior); self_signed_certificate(.., pin, compression)
returns (Vec<u8>, CertImport);
reset(None); force_reset(None) returns a
FactoryResetOutcome. Prefer
factory_reset or
force_reset_if_known_supported(auth, force), which pick
the route for the applet. |
keyroost-transport |
TransportError::PivForceResetUnsupported →
PivResetUnsupported;
PivForceResetIncomplete →
PivResetIncomplete;
PivFirmwareTooOld is removed: move_key and
delete_key no longer check the version themselves —
call PivSession::feature_gate first (before management
authentication; it re-selects PIV). PivCertTooLarge
gains compressed_len. |
keyroost-transport |
PivStatus::serial is Option<u128>
(was Option<u32>); display it with
keyroost_piv::format_serial_long /
format_serial_short. GET METADATA and ATTEST are
skipped on an applet listed without them unless
set_send_unsupported_reads(true). |
keyroost-piv |
encode_certificate(der) →
encode_certificate(payload, CertInfo::Uncompressed).
KeyAlg::EccP521 and SigHash::Sha512 are new
variants of exhaustive enums (add match arms); the implicit
discriminants of later variants shifted. |
keyroost-resolve |
ResetStep::Token2Otp now comes before
Piv. StepOutcome::Skipped carries a reason
(Skipped(String)); new WipedGlobal and
WipedWithWarning(String). |
v0.11.0
Two CLI changes that can affect scripts, both making destructive or
one-way commands stricter. piv status --json also gains a
cert_unreadable field, present only for a slot whose
compressed certificate cannot be read. For library consumers: one
removal, and two behavior changes when reading and importing
certificates.
CLI
| Before | Now |
|---|---|
molto reset, oath reset,
openpgp reset, piv reset with several matching
keys and no selector: acted on the first Molto2 found, or asked for
--reader |
Stops with an error listing the candidates; name one with
--device. A single connected key still works without
flags. |
These resets and fido reset with both
--reader and --device: --reader
silently won |
An error; pass one selector. |
fido set-min-pin --length 8 --pin-env KR_PIN |
keyroostctl fido pin min-length set --length 8 --yes --pin
env:KR_PIN — without --yes it refuses and
leaves the key unchanged. Same for keyroostctl fido config
attestation enable. (From v0.11.0 to v0.12.x this was
fido set-min-pin --length 8 --yes --pin-env KR_PIN
and fido enterprise-attestation.) |
Library (crates.io) API changes
| Crate | Change |
|---|---|
keyroost-transport |
PivSession::management_key_algorithm is removed; it had
no callers since v0.10.0. Use
PivSession::resolve_management_key_algorithm (given the
key length) or PivSession::reported_management_key_algorithm
(what the card reports, if anything). |
keyroost-transport |
PivSession::read_certificate now returns the
certificate decompressed when the card stores it gzip-compressed
(it used to return Ok(Some(..)) holding the
still-compressed bytes). A compressed certificate that cannot be
read now returns the new
TransportError::PivCertUnreadable;
PivSlotStatus reports it in its new
cert_unreadable field. |
keyroost-transport |
PivSession::import_certificate retries an oversized
certificate with command chaining. A card refusal is now
TransportError::PivCertTooLarge (SW 6700) or
TransportError::PivCardFull (SW 6A84)
instead of a generic write error. Not a compile break:
TransportError is #[non_exhaustive]. |
v0.10.0
Nothing changes for scripts or the CLI — the new commands
(otp fp-*, otp unlock-list, piv test)
are additions. One published-library break, for consumers that construct
a Token2 OTP response type by hand.
Library (crates.io) API changes
| Crate | Change |
|---|---|
keyroost-token2otp |
PinFlag gained an fp_enable: bool field
(the R3.4 fingerprint flag) and is now #[non_exhaustive],
like the other response types. A struct literal that set every field
no longer compiles — obtain a PinFlag from
PinFlag::parse. With the type now sealed, this is the
last field addition that can affect a consumer. |
v0.9.0
Nothing changes for scripts beyond three output details, listed first. The version jump is again about the published library crates: the OpenPGP applet learned ECC keys and the Token2 OTP applet learned PINs, and both reshaped public types.
CLI output details
openpgp statusnames the algorithm in full —RSA-2048,EdDSA Ed25519— where it printed the bare family (RSA,EdDSA). The--jsonfieldssig_algo/dec_algo/aut_algocarry the same fuller text.openpgp signandopenpgp authenticatehand an ECC slot the bare digest and an RSA slot a PKCS#1DigestInfo, chosen from the slot's algorithm; a slot whose algorithm cannot be read is an error rather than a guess.--hash sha1is refused on an ECC slot.piv status'scert_len(text and--json) is now the certificate's DER length, not the card's object size — typically nine bytes smaller than before.
Library (crates.io) API changes
| Crate | Change |
|---|---|
keyroost-openpgp |
PublicKey is an enum — Rsa { modulus,
exponent } or Ecc { point }; match on it instead
of reading fields. rsa_v4_fingerprint_from is gone: use
v4_fingerprint(&key, &attrs, time), which routes by
the slot's parsed algorithm attributes. |
keyroost-transport |
OpenPgpSession::generate_key(crt, alg) takes an
Option<KeyAlg> — pass None for the
old behavior. OpenPgpStatus gained
sig_attrs / dec_attrs / aut_attrs
(struct literals must set them). TransportError gained
OpenPgpSlotMismatch and OpenPgpSlotNotRsa;
OtpTransportError gained PinRequired and
PinSessionMissing — exhaustive matches need arms. |
keyroost-token2otp |
EncryptError gained BadLength,
BadCiphertext and BadAuthTag;
OtpError gained PinInvalidRetries. |
keyroost-piv |
parse_version is removed; PivStatus keeps the
GET VERSION reply as raw bytes and
format_version_bytes renders it, so cards that answer
with more or fewer than three bytes work. |
| all library crates | The public error enums and status structs are now
#[non_exhaustive] — an exhaustive match
needs a _ => arm and struct literals of status types are
no longer possible outside their crate. From now on adding a variant
or field is not a breaking change. |
v0.8.0
No CLI or GUI changes break anything — the version jump is entirely about the published library crates (there is no v0.7.9; the 0.7 series ends at 0.7.8). Two adjustments for library consumers:
| Crate | Change |
|---|---|
keyroost-piv |
Instruction gained the Attest variant and is
now #[non_exhaustive] — add a catch-all arm (_ =>)
to any exhaustive match. Future instruction additions will
then no longer be breaking. |
keyroost-resolve |
Device gained the unverified: Caps field
(the tri-state capability display). Struct literals must set it —
Caps::default() preserves the old behavior. |
v0.7.8
Bug-fix release — no breaking changes for scripts or library
consumers. One addition: keyroostctl fido reset --reader <substring>
resets a FIDO2 card in a smart-card reader in place (no replug, no touch). Also
restores behavior v0.7.7 narrowed: every Token2 key is offered the on-device OTP
surface again, regardless of USB product id.
v0.7.7
No flag or API renames. One reused name to watch for, and three additions that break nothing:
keyroostctl factory-resetis a new top-level command that resets every applet on a key. It reuses a name that was removed in v0.6.0 with a different meaning — see the warning under v0.6.0 below.piv move-key --from <slot> --to <slot>(todaykeyroostctl piv key move) — new; the 20 retired PIV slots (82–95) are now accepted anywhere--slotis.fido ssh-cert list/extract(todaykeyroostctl fido ssh list/export) — new; read-only.
v0.7.6
Bug-fix release — no breaking changes for scripts or library consumers.
v0.7.5
CLI: the global device selector is now --device
The global flag that selects a key by its friendly name was renamed:
keyroostctl --name mykey fido info # ≤ 0.7.4
keyroostctl --device mykey fido info # 0.7.5+
--name collided with the --name option of the fingerprint
subcommands (fido fingerprint-enroll / fingerprint-rename,
today fido fingerprint add / rename),
where it names the fingerprint. No compatibility alias is provided — an
alias would recreate the exact collision the rename fixes.
From v0.7.5 to v0.12.x, --name under the fingerprint subcommands
still parsed — it meant the fingerprint's label, not the device, so a
script that passed the old global spelling there didn't error; it named the
fingerprint instead. Since v0.13.0 --name is refused there too (the
fingerprint's name is an argument: fido fingerprint add NAME).
Everywhere else the old spelling fails loudly with an "unexpected argument"
error.
OATH: partial listings are now reported
oath list prints a stderr warning when the key holds
entries that could not be decoded (written by another tool, or with a non-UTF-8
name) — previously they were silently omitted. The stdout / --json
output format is unchanged, so scripts that only read stdout are unaffected.
Library (crates.io) API changes
For consumers of the published crates — CLI and GUI users are unaffected.
| Crate | Change |
|---|---|
keyroost-oath |
parse_list returns Listing { credentials, skipped }
instead of Vec<CredentialInfo>; skipped > 0
means the listing is partial. |
keyroost-transport |
OathSession::list returns oath::Listing;
TransportError::AuthFailed.tries_remaining is now
Option<u8> (None = the card gave no count —
don't render it as 0). |
keyroost-piv |
pad_pin (and the VERIFY / CHANGE / UNBLOCK builders using it)
asserts a 6–8 byte PIN instead of silently truncating longer input. Validate
length before calling, as the in-tree transport does. |
keyroost-ctap |
The CtapTransport trait gains read_timeout() (a
default impl is provided, so existing implementations keep compiling).
reset() and the bio-enroll operations now restore the
caller's timeout rather than the crate default. |
v0.6.0 — command names moved under molto / fido
The Molto2 and FIDO commands were nested under molto and
fido groups. The old flat names were removed — update scripts as
follows:
| Old (≤ 0.5.x) | New (0.6.0+) |
|---|---|
keyroostctl info | keyroostctl molto info |
keyroostctl set-seed … | keyroostctl molto seed set … |
keyroostctl set-title … | keyroostctl molto title set … |
keyroostctl configure … | keyroostctl molto config set … |
keyroostctl sync-time … | keyroostctl molto sync … |
keyroostctl set-customer-key … | keyroostctl molto customer-key change … |
keyroostctl import … | keyroostctl molto import … |
keyroostctl import-file … | keyroostctl molto import --in … |
keyroostctl factory-reset … | keyroostctl molto reset … — see the warning below |
keyroostctl fido-info | keyroostctl fido info |
keyroostctl fido-reset … | keyroostctl fido reset … |
keyroostctl fido-pin-set … | keyroostctl fido pin set … |
keyroostctl fido-pin-change … | keyroostctl fido pin change … |
keyroostctl fido-pin-retries | keyroostctl fido pin status |
keyroostctl fido-creds-list … | keyroostctl fido credential list … |
keyroostctl fido-creds-metadata … | keyroostctl fido credential status … |
keyroostctl fido-creds-delete … | keyroostctl fido credential delete … |
keyroostctl manpage > x.1 | keyroostctl manpage ./man |
The New column shows today's names: from v0.6.0 to v0.12.x the
commands were molto seed, molto title,
molto config, molto customer-key,
molto sync-time, molto
import-file, fido pin-set,
pin-change, pin-retries,
creds-list, creds-metadata and
creds-delete (see v0.13.0).
factory-reset was reusedSince v0.7.7 keyroostctl factory-reset exists again as a top-level
command — but it is not the old Molto2 reset. It wipes
every resettable applet on the selected key: OATH, OpenPGP, Token2 OTP, PIV,
then FIDO2. Both the old flat command and the new one are confirmed with
--yes, so a stale keyroostctl factory-reset --yes will
not fail with "unknown subcommand" — it will run and destroy far more
than the script intended. Audit any script from ≤ 0.5.x for that exact string and
change it to keyroostctl molto reset.
The customer-key flags (--key, --key-ascii,
--key-env, --key-ascii-env) moved under
molto. Since v0.13.0 they are --customer-key env:K
(with --customer-key-encoding ascii for an ASCII key) — e.g.
keyroostctl molto customer-key change --customer-key env:K.
The piv, oath, openpgp, otp,
key-name, list, doctor, and
completions commands were unchanged.