Added
- Swissbit iShield serial, name and firmware. keyroost reads the serial,
device name and firmware version of Swissbit iShield Key 1 and 2 cards from
their own management applications, and shows them inpiv infoand the
GUI. Contributed by @episource. (#163) - X.509 key usage for PIV certificates and requests. Self-signed
certificates and CSRs carry a keyUsage extension, in the GUI and with
piv cert generate/piv cert request --key-usage. By default it is
the slot's standard PIV usage, marked critical;--key-usage undefined
(or "Undefined" in the GUI) writes none. Contributed by @episource.
(#164) - Shell completion for saved key names.
keyroostctl completions <shell>now prints a short script that asks keyroostctl for
suggestions, so--devicecompletes the names you saved. The AUR and
Homebrew packages install completions and man pages. (#165) --encodingfor seeds and Molto2 customer keys. 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 key's encoding is
--customer-key-encoding. (#165)- Numbered
listandlist --json.listnumbers each key (sorted by
serial, so a number can change when keys are added or removed), and
--json listprints{"keys": [...]}, one row per key with the exact
--devicevalue that selects it.list --deviceshows just that key.
(#165) - Five short flags.
-d(--device),-y(--yes),-o
(--out),-i(--in) and-s(--slot), with the same meaning on
every command. (#165) fido blob clear --keep-nameclears the large-blob storage but keeps
the key's name ("Keep the key's name" in the app). Without it, the
warning names the name that goes.fido blob listshows the name entry
askey name, andfido blob editpoints toname setinstead of
changing it. (#166)- A key can carry its own name.
keyroostctl name set NAME --store key
(or "On this key" in the app's naming dialog) writes the name into the
key's FIDO2 large-blob storage, and every computer running keyroost shows
it, without a PIN. Saving it needs the FIDO PIN; the name is visible to
anyone who has the key.name setalso renames,name clearremoves a
name wherever it is stored, andname listshows where each name lives.
The entry's format is published with test vectors in
docs/PROTOCOL-device-label.mdso other tools can use it. If a key loses
its name,name listand the app offer to write it back. Proposed by
@token2. (#166) - Two keys with the same name stay apart. The first key this computer
saw with a name keeps it, and--device NAMEalways means that key.
Another key carrying the same name shows as "Name (1234)", the last four
characters of its serial, for display only; select it by itslist
number orserial:…. (#166) - Import authenticator codes into any key that stores them.
oath importadds every code in an Aegis (plain or encrypted), 2FAS,
otpauth://list or QR export to a YubiKey, Solo 2 or Nitrokey 3, and
otp importto a Token2 key's OTP storage. In the GUI, drop the file on
the window or click "Import file…" in the Authenticator, On-device OTP or
Molto2 view; the "Import authenticator codes" dialog works for every key
that stores codes. keyroost reads the key first and previews each entry:
a code whose name is already on the key is skipped (--replace
replaces it), and one the key can't store is listed with the reason.
--dry-runwrites nothing. It asks once, writes one code at a time, and
stops at the first error with a report of what was added. (#170) - Solo 2 names are capped at 127 bytes.
oath add,oath importand
the GUI refuse a longer Solo 2 name before sending it: a 128-byte name
made the key stop responding until it was unplugged. (#170) - YubiKey 4 prefix names. On YubiKey 4 firmware 4.0 to 4.3.4,
oath add,oath importand the GUI refuse a name that is the start of
another name already on the key, following the same rule as Yubico's
ykman. (#170) - The AppImage is GPG-signed. Each release's AppImage carries an
embedded signature from a dedicated signing key; its fingerprint is in
SECURITY.md and the README, which also explain how to check it.
AppImageUpdate-based updaters (appimageupdatetool, AppImageLauncher)
now refuse an update signed by a different key. Users updating an
unsigned AppImage (v0.12.x or earlier) with these tools download this
release by hand once. (#171)
Changed
- Always-UV is set, not toggled.
fido config always-uv enableand
fido config always-uv disablereplace thefido always-uvtoggle, so
a script always knows the state it leaves. Each one does nothing, and
says so, when the key is already in that state. (#165) - Commands are grouped by what they act on, in separate words.
piv pin change,piv key generate,piv cert import,openpgp pin change --admin,openpgp key show,oath password set,otp pin set,
otp button set,fido credential list,fido fingerprint add,fido config always-uv enable,fido pin min-length set,fido blob …(was
large-blob),fido ssh …(wasssh-cert),molto sync,molto import --in, andname set|list|clear(waskey-name).piv info,
openpgp infoandotp inforeplacepiv status,openpgp statusand
otp config;otp getisotp code,otp erase-allisotp reset,
andotp fp-list/otp unlock-listareotp list --unlock fingerprint/--unlock auto(--pin-onlyis--unlock pin, the
default). An old name is refused with an error naming the new one. The
migration page lists every change. (#165) - Destructive commands ask first. In a terminal they show a y/N question
naming the key; in a script they need--yes(-y). A command whose
PIN or seed is piped in on stdin also needs--yes. This now also
covers replacing or deleting what the computer can't restore:oath delete,otp delete,otp button set(when a seed is already set) and
otp button clear,fido credential deleteandfido fingerprint delete,molto seed setandmolto importon used slots,molto customer-key change,prog seed setandprog config set, and on PIV
retries set
(which also resets the PIN and PUK to their factory defaults) and,
unless the slot is known to be empty,key generate,cert import,cert generateand
--generate-key. If the question was shown, keyroost checks it is
still the same key before acting.factory-resetasks you to type
reset, andotp interfacereads its phrase from the terminal only.
(#165) piv cert exportwrites PEM by default.piv cert export --slot 9a
at a terminal now prints the certificate instead of refusing. Add
--format derfor the raw DER bytespiv export-certwrote before.
(#165)- Flags renamed to match.
moltocommands take--slot(-s) in
place of-p/--profile(Token2 calls slots profiles), andmolto config setandprog config settake--periodin place of
--time-step(same values).piv cert importandmolto importread
--in FILE(-i), andpiv cert export,cert request,cert generateandkey generatewrite--out FILE(-o), in place of
--fileand--save-pubkey;--load-pubkeyis--pubkey-in, and
with--generate-key,--save-pubkeyis--pubkey-out.piv mgmt-key changetakes--algorithm(was--new-algorithm). The item a command
acts on is an argument:fido credential delete ID,fido fingerprint rename ID NAME,fido fingerprint delete IDandfido fingerprint add NAME(were--cred-id,--template-idand--name).fido ssh exporttakes the SSH credential's RP ID as--rp(was
--credential).fido blob exporttakes the output file as--out FILEinstead of a second argument:keyroostctl fido blob export 1 -o entry.bin. An old flag is refused with an error naming the new one.
(#165) - Clearer
--help. Every flag and argument has a description.
Commands that erase or replace something end their first line with one
marker, such as "Irreversible: asks first (--yesto skip)", and that
now includes commands that replace a key or seed (piv key generate,
molto seed set,otp button setand others),piv retries set
(which says it also resets the PIN and PUK) andotp interface.piv cert request --generate-keyreplaces the slot's key and asks first.
The top-level description covers every command group, and--debug,
--deviceand--jsonare listed under "Global options" after a
command's own flags. Two messages now say "canceled" (was
"cancelled"). (#165) - A hidden prompt for PINs, passwords, keys and seeds. Every secret
comes fromenv:NAME, fromstdin(one line), or, with no flag and a
terminal present, from a prompt that doesn't show what you type, like
sudoorssh.stdintyped at a terminal is hidden too. The Molto2
andprogseeds and the new Molto2 customer key now prompt as well
(--encodingsays how they are written). New PINs, passwords and keys
typed at the prompt are asked twice and must match; seeds and URIs are
asked once. A script with no source is refused with an error naming
the flag. Hex and base32 values lose surrounding spaces; PINs and
passwords are kept exactly. After you type a secret at the prompt,
keyroost checks it is still the same key before acting. In Git Bash
(mintty) on Windows the prompt needs a real console: runwinpty keyroostctl …or useenv:NAME. The prompt uses the newrpassword
dependency. (#165) - One JSON shape.
--jsonoutput is always one object. Lists sit under
a named key:keysfor the overview andlist,accountsforoath listandotp list. Every field is present,nullwhen unknown. Each
idea has one name and type:serialis a string, PIVslotis the
--slotvalue ("9a") withslot_namebeside it,molto inforeports
utc_time,molto listreportsalgorithm("sha1"),periodand
digits,oath listandotp listspellalgorithmthe same way
("sha1"), PIN retries areuser_pin_retries,pin_retriesand so on,
accounts have atype, and the overview sayscapabilities. The
migration page lists every field. (#165) - Every command finds its key the same way. A lone key is used
automatically. With several, a terminal shows a numbered list to pick
from (now on every platform); a script gets a refusal that lists the
--devicevalue for each key. No command takes "the first key found"
any more.--devicetakes a name, a serial or alistnumber
(name:,serial:orlist:forces which); a Molto2 answers to either
serial keyroost shows for it, the one inlistor the onemolto info
prints.--devicewith--readeror--pathis refused, and so is
--deviceon commands that touch no key.--readerand--pathskip
the capability check, and a value that matches no detected key is used
as typed. (#165) - One message style. Messages are sentences (
Seed written to slot #5.), warnings and notes start withwarning:/note:on stderr (the
import preview keeps its ownNote:lines),fido info,molto infoandprog infoeach line their fields up
block by block, and Molto2 messages say "slot" where they said "profile".
(#165) - One word per action, and every command ends in one. The same job
has the same word in every group:fido pin status(waspin-retries)
andfido credential status(wascreds-metadata) show state like
otp pin status;fido blob show(waslarge-blob get) prints one
entry;fido ssh export(wasssh-cert extract) saves a file like the
otherexportcommands;otp button clear(wasdelete-button-hotp)
is the opposite ofset;molto list(wasmolto slots) lists like
every other group. Writes end in an action word:molto seed set,
molto title set,molto config set,prog seed set,prog config set,fido pin min-length set(wasset-min-pin) andmolto customer-key change.molto title --slot Nwithoutsetonly shows
the slot's title. An old name is refused with an error naming the new
one, and nothing typed after it is repeated. (#165) - An existing output file is never replaced silently.
piv cert export,cert request,cert generateandkey generate --out,
openpgp sign,decryptandauthenticate, andfido blob export
andfido ssh exportask "overwrite? [y/N]" at a terminal when the
output file exists, and refuse in a script unless--overwriteis
given. A directory as the output is refused before the key is touched,
and so is a symlink for theopenpgpoutputs.--overwriteonly
covers the local file;--yesstill confirms what happens on the key.
(#165) - Out-of-range values exit 2. A number outside its range (
oath add --digits 9, Molto2 slot 100, a retry count of 0) is a usage error that
exits 2, like any other mistyped argument. Some of them used to exit 1.
(#165) - Reset credentials are read before the reset starts.
piv reset
andfactory-resetread their--mgmt-keyor--pinbefore anything
is reset, even on a card that turns out not to need it. An unset
env:NAMEvariable is now an error up front, where before it could be
ignored. (#165) - FIDO2 reset waits for the replug.
fido reseton a USB key and the
FIDO2 step offactory-resetnow ask you to unplug the key and plug it
back in (within 60 seconds), check it is the same key, then ask for a
touch. There is no Enter to press.factory-resetends with "N wiped,
M skipped, K failed" and exits with an error if any step was skipped
or failed. (#165) - One flag per secret; its value says where the secret comes from.
--pin env:NAMEreads an environment variable and--pin stdinreads
one line, replacing--pin-env NAMEand--pin-stdin. The same goes
for--new-pin,--puk,--new-puk,--admin-pin,--mgmt-key
(which also takesdefault),--new-mgmt-key,--password,
--new-password,--seed,--customer-key,--new-customer-keyand
--uri. The--old-…flags are now the plain name:--pinis the
current PIN and--new-pinthe new one.oath add --secret-envis
--seed env:NAME,openpgp verify --pin adminisopenpgp pin verify --admin, andotp change-pin --current-env/--new-envareotp pin change --pin env:NAME --new-pin env:NAME. A secret typed as the value
itself (--pin 123456) is refused with exit 2 and never shown. An old
flag is refused with an error naming the new one. (#165) fido ssh exporttakes--overwrite, not--force. The old
ssh-cert extract --forceis gone. (#165)- Two secrets on stdin: the current one first. When two flags read
stdin, the current secret is the first line and the new one the
second, and each flag's help says which line it reads. This changes the
order foroath password set(current password, then new) andpiv mgmt-key change(current key, then new); both read the new one first
before.otp addandoath addread the seed first, then the PIN or
password. Onmolto,--customer-key stdinis always the first line,
before the seed, URI or new key.prog seed set --seed stdinreads one
line, not all of stdin. (#165) - The screen output is split: result on stdout, the rest on stderr.
Prompts, progress, "Authenticated.", the Molto2 serial and clock lines
(except inmolto info, where they are the result) and the "Wrote FILE"
lines for saved files now go to stderr. Sokeyroostctl molto list > slots.txtsaves just the
table, and you still see the rest. (#165) - The Flatpak build's hash-pinned Python tools move to multidict 6.9.1
(every artifact hash listed, as before). (#166) keys.jsonno longer holds serials. Each name is stored with a
salted fingerprint of its key, the salt kept inkeys.saltbeside it, so
the file shows no serial and two computers' files can't be matched. An
olderkeys.jsonconverts the first time it is read; a backup of the old
file is kept until the conversion succeeds, then removed. v0.12 can't
read the converted file and shows keys unnamed; don't rename a key with
v0.12 after upgrading, since that replaces the converted file and its
names. Ifkeys.saltis lost, set the names again; restoring the old
salt doesn't bring them back.
(#166)- Library API (
keyroost-ctap):LargeBlobArray'sentriesand
raw_arrayfields are methods,serialize_with_checksumreturns a
Result,extract_cert_from_entriestakes the array, andEntryKind
gainsKeyName, so an exhaustivematchneeds a new arm. New: the
device_labelmodule. (#166) - Library API (
keyroost-keyring):keys.jsonformat 2.KeyEntryis
KeyRecord(afingerprintandstoredinstead ofserial);add,
by_name,by_serial,name_for,resolve,ConnectedKey,
ResolveErrorandKeyringError::DuplicateSerialare removed, and the
save methods take&mut self. (#166) - Library API (
keyroost-resolve):Devicegains the public fields
namingandhid_serial,EnumerateOptionsgainsskip_key_names, and
SelectErrorgainsNameNotConnected. New: thenamesmodule. The
migration page lists every change. (#166) molto import --file-password. An encrypted Aegis export's password
now comes from--file-password env:NAMEor--file-password stdin, the
same flagoath importandotp importuse (v0.12'simport-file --password-env/--password-stdinare refused with an error naming
it). (#170)- The Molto2 "Bulk import" dialog is replaced. "Import file…" in the
Molto2 view, or a file dropped on the window, opens the shared "Import
authenticator codes" dialog. Every dropped file is identified first: a
certificate or key file gets a note saying where to import it, and any
other file gets "keyroost can't import this file". (#170) molto import --infollows the shared import rules. An entry the
Molto2 can't store (for example a SHA-512 code or a 45-second period) is
skipped with the reason instead of refusing the whole file, and entries
past slot #99 are skipped. An entry with no issuer or account no longer
takes a slot. The preview, the one question before writing (--yesin
a script), the report and--jsonare the same asoath import.
--dry-runshows which slots are in use when a Molto2 is connected
(--devicepicks which one). (#170)
Fixed
- One row per key on Windows and macOS. Where the system reports no USB
position, keyroost now asks each side of a key for the identity it reports
(a YubiKey's serial, a Solo 2's ID, a Token2 key's serial) and joins the
FIDO and smart-card halves into one row. The GUI sidebar and the CLI share
this matching. With two keys of the same make, one that doesn't answer
still shows as two rows. On Linux nothing changes. (#51) - PIV slots say what keyroost can tell about the key.
piv infoand the
GUI used to call every slot without a certificate "empty". A slot without
a certificate now reads "empty" when the card says it 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: slots on these cards 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 (it said "empty"). JSON output is
unchanged. (#113) openpgp infoshows a Token2 key's full serial. The OpenPGP card
data holds only a shortened serial, so keyroost now reads the full one
from the key's OTP applet, the waypiv infohas since 0.12.0 (built on
@episource's PIV work). This covers the CLI, its JSONserialfield and
the GUI's OpenPGP view. (#125)--debugtraces FIDO. FIDO commands over USB now show their messages
with--debug; before, onlyKEYROOST_CTAP_DEBUGdid, and it still
works. FIDO through a smart-card reader isn't traced. FIDO PIN exchanges
(clientPIN, authenticatorConfig) are hidden except the retry count and
key agreement, like PIV and OpenPGP PIN checks. Every group now shares one
line format (> label bytes), which is for people and may change.
With the GUI's debug capture on, Token2 OTP trace lines (redacted as on
stderr) now appear in its activity log. (#165)proguses the token you choose. It used to ignore--deviceand
write to whichever reader was alone, programmable token or not. It now
only considers programmable tokens and honors--deviceand
--reader. (#165)- Large-blob writes keep other tools' entries byte for byte. Adding,
editing or deleting an entry dropped fields keyroost didn't know from
every other entry it wrote back. Entries keyroost doesn't change are now
written back exactly as read, in order. (#166) - One malformed large-blob element no longer hides the whole store. An
element not in the standard entry format is skipped and counted infido blob list(and its JSONskipped), and kept unchanged by every write.
(#166) - Flatpak updates no longer fail on unsigned metadata. The published
repository's AppStream and.Debugrefs went out unsigned, so Flatpak
clients that verify them refused the metadata refresh. Every ref is now
signed, and publishing stops if one isn't. (#167) - The Molto2 import dialog closes and says why adding is gray. Close
in the import dialog, and Cancel in the "Import to slot" dialog, did
nothing; both now close the dialog, and closing either dialog by any
route wipes the typed file password or pasted URI and drops the parsed
entries (which carry seeds).
When adding can't start, one line under the buttons now says why: the
file is still loading, or the Molto2 isn't open or unlocked yet (with
an Authenticate button right there, and a failed attempt is reported in
that line too). (#170) - Codes for OATH entries named
60/…use their period.oath code
(without--period) and the GUI computed them at 30 seconds, so they
were wrong.--periodnow defaults to the name'speriod/prefix, and
the GUI shows the period next to the code. (#170) oath code --period 0is a usage error. It crashed; it is now
refused with exit 2. (#170)
Removed
--list-readersis gone.keyroostctl listshows the smart-card
readers along with every other connected key. (#165)- No secret on the command line. The flags that took a secret as a
plain argument are gone, because the command line ends up in shell
history andps:molto --key/--key-ascii(use--customer-key env:NAME, with--customer-key-encoding asciifor an ASCII key),
molto seedandprog seed--hex/--base32(usemolto seed set
orprog seed setwith--seed env:NAMEor--seed stdin, and
--encoding hexfor hex), andmolto customer-key --hex/--ascii
(usemolto customer-key change --new-customer-key).molto importno longer takes theotpauth://URI as an argument: use--uri env:NAME,--uri stdin,--qr IMAGE, or the prompt. Each removed flag
is refused with an error that names its replacement and doesn't repeat
the value. (#165)
Security
- Errors don't repeat a secret. A secret typed where its source goes
(--pin 123456,--pin123456,--seed=JBSWY3DP), a stray value after
a source, a literalotpauth://URI or a removed flag's value is
refused without being printed, and an error about anenv:NAMEsource
names the flag, not the variable, in case the secret was typed where the
name goes. (#165)
Full changelog: https://github.com/framefilter/keyroost/blob/v0.13.0/CHANGELOG.md