Skip to content
framefilterPublic

About

Vendor Neutral, Rust-Based Management UI and CLI for U2F/FIDO2 and other hardware security keys

Topics

Resources

Contributing

Security policy

Stars

64 stars

Watchers

3 watching

Forks

Repository files navigation

keyroost

keyroost

An independent, vendor-neutral app for managing all your hardware security keys in one place.

What it is

keyroost is an open-source Rust toolchain for hardware security keys, working across vendors over PC/SC and USB HID. It speaks FIDO2/CTAP2, OATH (TOTP/HOTP), and the OpenPGP and PIV card protocols, manages on-device OTP on Token2 FIDO keys, and also programs the Token2 Molto2 / Molto2v2 TOTP token. Ships a Rust library, a CLI (keyroostctl), and a desktop GUI (keyroost) with a dark and light theme — implemented from public standards, with no vendor SDKs, no Python, and no Qt.

Built with AI. I saw a real need for this but never learned to code, so the parts I author — code, docs, and all — are written end-to-end with AI. (Contributions from others, such as Token2's, are their own human-designed and -developed work — see the Contributors section.) Since the AI I use learned from the vast commons of free and open-source software people have generously shared, releasing keyroost as FOSS isn't really a choice; it's giving back to what made it possible. Issues, review, and contributions are warmly welcome — see CONTRIBUTING.md.

New to hardware keys? Read the companion guide — "So you bought a hardware security key… now what?" — a short, vendor-neutral tour of what FIDO2, OATH, OpenPGP, and PIV actually do.

What it does

  • FIDO2 / CTAP2 — enumerate authenticators, read authenticatorGetInfo, manage resident credentials (list / metadata / delete), set / change the PIN and show how many attempts are left, reset a key (USB replug ceremony, or in place for a card in a reader). Fingerprint (bio) enrollment — list / enroll / rename / delete — and FIDO Metadata Service (MDS) authenticator identification in the GUI. PIN protocols v1 and v2. CTAP 2.1 security policy over authenticatorConfig (always-require-UV, minimum PIN length, force a PIN change, enterprise attestation) and a largeBlob store for plaintext notes (fido blob) over authenticatorLargeBlobs. Works over USB-HID and over a PC/SC reader — both NFC (CTAP-over-NFC) and a contact / ISO-7816 chip reader (T=0) — not just direct USB. Resident-credential metadata surfaces the fuller passkey detail too: the user's UPN, display name, user id, and the full credential id. Resident SSH credentials can be listed and their stored OpenSSH certificate extracted from largeBlob to a -cert.pub file (fido ssh).
  • OATH (TOTP/HOTP) — list, add, delete, and compute codes over PC/SC, including applet-password set / clear / unlock, and a factory reset of the applet (oath reset) — the recovery path for a forgotten password. In the GUI, secret fields have a reveal (eye) toggle so you can check an OTP secret before committing it.
  • OpenPGP card (v3.4) — read status; generate keys on-card in any algorithm the card accepts (RSA 2048/3072/4096, Ed25519, X25519, NIST P-256/384/521, secp256k1, brainpool) for the signature, encryption, or authentication slot, or import an RSA-2048 key (host keygen or a PKCS#1/PKCS#8 PEM/DER file) — each writes the v4 fingerprint and a generation timestamp so GnuPG recognizes the key; sign (SHA-256 or SHA-1); decrypt; authenticate (a client/SSH signature with the Authentication key via INTERNAL AUTHENTICATE); set cardholder name / URL; change the user / admin PIN and unblock a locked PIN; factory-reset the applet.
  • PIV (SP 800-73-4) — full management: status (detected applet, applet/firmware version, serial, PIN retries, which slots 9A/9C/9D/9E hold a certificate), on-card key generation (RSA, ECC P-256/384/521, Ed25519, X25519), certificate import / export, self-signed certs or a CSR for a CA, clearing a slot's certificate (piv cert delete) or key (piv key delete), moving a key between slots (piv key move), writing a fresh CHUID with a random GUID (piv chuid generate) so Windows re-reads a reprovisioned card, and PIN / PUK / management-key changes and applet reset. A certificate too large for a slot can be stored gzip-compressed, as the PIV standard allows (--compress / --no-compress). A read-only test runs every private-key operation a slot's key supports (decrypt for RSA, key-agree for the ECDH curves, sign for RSA / ECDSA / Ed25519) and checks each result against the slot certificate's public key. keyroost identifies which PIV implementation a card runs (YubiKey, Token2, Nitrokey, Swissbit, HID Crescendo and others) and offers vendor extensions such as piv key move and piv key delete according to a built-in list of what each supports. A feature the list marks unsupported stays visible, and the GUI's Enable Anyway or the CLI's --force turns it on. Every slot-taking command addresses 9A/9C/9D/9E and the 20 Yubico retired key-management slots (82–95), so keys can be archived and rotated. The GUI collects the management key per operation (and wipes it after), which is ideal for a slot or two; for provisioning many slots or keys, the CLI is the intended path — the management key and PIN come from env/stdin once, so a shell loop does the batch (see the PIV guide).
  • Token2 Molto2 / Molto2v2 — program a slot from an otpauth:// URI or a QR code scanned from a PNG/JPEG screenshot or the live screen; import a whole authenticator export into consecutive slots; sync the host clock; rotate the customer key; factory reset.
  • Importing authenticator codes — import an authenticator export (Aegis, plain or encrypted; 2FAS; a list of otpauth:// URIs; a QR screenshot, including a Google Authenticator export) into a YubiKey, Solo 2 or Nitrokey 3 (OATH), a Token2 key's OTP storage, or a Molto2. keyroost shows what each code becomes before it writes anything (oath import, otp import, molto import --in, or drop the file on the GUI); see Importing codes.
  • Token2 single-profile programmable TOTP token — program the seed and TOTP configuration onto Token2's single-account card/fob tokens (OTPC-P1-i / P2-i, miniOTP-2-i / 3-i, C301-i, C302-i) over a PC/SC reader. These authenticate with a fixed device key rather than a customer key, and hold one account rather than many; keyroost reads the device serial / model and on-device clock, writes the seed, and sets the HMAC algorithm, time-step, and display-timeout (prog info / seed / config, or the GUI's programmable-token pane). The wire protocol is documented in docs/PROTOCOL-token2prog.md.
  • Token2 on-device OTP (PIN+ Series FIDO keys) — store TOTP/HOTP credentials directly on a Token2 FIDO security key and read their codes over USB-HID, NFC, or CCID; configure the single HOTP-on-touch keystroke slot; read the serial; and enable / disable the key's USB interfaces (FIDO / keyboard-HID / CCID). On R3.4+ keys the codes can be put behind an OTP PIN (otp pin set, otp pin verify, otp pin change, otp pin clear, otp pin status); note there is no PIN reset — a blocked PIN is recoverable only by erasing every OTP entry. On Bio3 keys with a fingerprint enrolled, a fingerprint touch can release protected codes as an alternative to the PIN (otp fingerprint status, otp fingerprint enable, otp fingerprint disable, otp list --unlock fingerprint, and otp list --unlock auto, which tries the fingerprint and falls back to the PIN); fingerprint enrollment itself is done through the key's FIDO2 fingerprint setup.
  • One-shot factory reset — keyroostctl factory-reset (and a card on the GUI device Overview tab) resets every resettable applet on a key in turn: OATH, OpenPGP, Token2 OTP, PIV, then FIDO2. In a terminal you confirm by typing reset; a script passes --yes. On a USB key the FIDO2 step ends with an unplug/replug (detected automatically) and a touch; a card in a smart-card reader is instead reset in place (no replug, no touch — the card is power-cycled in the reader). Only manufacturer-intended resets are used, and each step reports its own outcome rather than being folded into one "done".
  • Friendly device names — name a key to target it with --device NAME when several are connected, instead of by a reshuffling /dev/hidrawN path. Keep the name on this computer (keys.json, which stores a salted fingerprint of the key, never its serial) or on the key itself, where every computer running keyroost sees it (see Naming a key). Destructive operations act on one specific key, never "the first key found": a lone key is used, and with several, a terminal asks you to pick and a script is refused. The confirmation question names the key. keys.json lives in %APPDATA%\keyroost on Windows and in $XDG_CONFIG_HOME/keyroost (else ~/.config/keyroost) elsewhere, macOS included, and names are validated with anti-spoofing checks while allowing a relaxed, readable character set. On Windows and macOS the OS reports no USB position, so keyroost 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 them into one entry when they match. If two keys of the same make are connected and one doesn't answer, it is shown as two entries rather than guessed at.

Supported devices

Device Capabilities Notes
Token2 Molto2 / Molto2v2 TOTP slot programming, code import Hardware-verified. Programmed over the vendor-specific SM4-MAC protocol (docs/PROTOCOL.md); supports importing Aegis / 2FAS / otpauth-list exports and QR screenshots, clock sync, and customer-key rotation.
Token2 single-profile tokens (OTPC-P1-i / P2-i, miniOTP-2-i / 3-i, C301-i, C302-i) Single-account TOTP seed + config programming Programmed over the vendor-specific SM4-MAC protocol with a fixed device key (docs/PROTOCOL-token2prog.md); writes the seed and the TOTP algorithm / time-step / display-timeout over a contact or contactless PC/SC reader. The model is recognized from the device serial.
Token2 PIN+ Series FIDO2 (+ bio), OTP (incl. import), OpenPGP, PIV FIDO2 with fingerprint/bio enrollment and FIDO Metadata Service (MDS) display, plus on-device OTP (TOTP/HOTP) over CCID / NFC / USB-HID, validated on PIN+ hardware. Importing an authenticator export into OTP storage follows Token2's published OTP specification (see Importing codes). HID/keyboard HOTP applies to the models that carry it — recent releases (R3.2+/R3.3+) have no HID-HOTP and ship with the HID channel disabled by design; CCID is the intended path there. Keys running the R3.4+ OTP applet can put codes behind an OTP PIN; keys without it answer the capability probe with "no such command" and are unaffected. Contributed by @token2. PIV management was exercised on Token2 hardware by @episource (#128), and keyroost decodes the BCD-coded serial Token2's PIV and OpenPGP applets report; piv info and openpgp info show the key's full serial, read from its OTP applet. The OATH / OpenPGP smart-card applets are handled by the standard byte layers but not yet exercised on PIN+ hardware by this project (experimental).
YubiKey (5 series) FIDO2, OATH (incl. import), OpenPGP, PIV Built and verified against a YubiKey 5.7.
SoloKeys Solo 2 FIDO2, OATH (incl. import) Trussed firmware; no OpenPGP applet. HOTP caveat: the last-shipped Solo 2 firmware (2.3.x) computes HOTP over a 4-byte counter where RFC 4226 specifies 8, so its HOTP codes won't verify against standards-compliant servers (hardware-verified; fixed in the current upstream Trussed secrets app, but Solo 2 no longer receives firmware updates). TOTP is unaffected — its 8-byte time challenge comes from the host.
Nitrokey 3 FIDO2, OATH (incl. import), PIV; OpenPGP detected Built around the same Trussed firmware core as Solo 2, but the final firmware is different — e.g. Nitrokey 3 has PIV support, while Solo 2 does not. PIV verified on a Nitrokey 3A NFC (firmware 1.8.3), contributed by @episource; keyroost reads the serial and firmware version from the Nitrokey admin application. Importing codes into its OATH storage follows Nitrokey's published secrets-app source (see Importing codes). The OpenPGP applet is detected but not yet exercised by this project.
Swissbit iShield Key 2 Pro (and iShield Key 1) PIV (partial) Key generation and certificate handling verified by @episource on their own iShield Key 2 Pro. keyroost doesn't use the slot key type and PIN/touch policy this card reports in GET METADATA (#113), so a slot without a certificate reads "no certificate (a key may be present)". Answers the Yubico version extension with four bytes instead of three; keyroost keeps the reply as sent. On the iShield Key 1 and 2, keyroost reads the serial and device name from Swissbit's own management applications (and, on the Key 1, the firmware version) for piv info and the GUI, contributed by @episource (#163). Other applets not yet exercised by this project.
Any standards-compliant FIDO2 key (e.g. Thales, Feitian, Titan) FIDO2 / CTAP2; OATH / OpenPGP / PIV only if the key carries those applets keyroost implements the published specs, not vendor-specific behavior, so the fido commands — getInfo, passkey management, PIN, reset — work on any CTAP2 authenticator, including ones not listed here. Optional features (fingerprint, largeBlob, authenticatorConfig) surface only when the key advertises them in getInfo. The smart-card applets apply only to keys that expose an OATH / OpenPGP / PIV applet over PC/SC. Older U2F-only (CTAP1) keys are detected by list but don't support the CTAP2 management commands.

Each listed row notes what's actually been verified on that device; the final, generic row describes the standards-based behavior expected on untested but compliant keys.

Roadmap

Planned hardware support, not yet shipped:

  • OnlyKey — it speaks FIDO2/CTAP2 over USB-HID, so the fido commands will apply, but it exposes no smart-card interface (no OATH / OpenPGP / PIV) and its firmware reports a fixed, non-unique serial that needs placeholder handling before it's first-class (#37). Test hardware ordered; support lands once it arrives.

Want a different key supported? Open an issue requesting it — hardware-support requests are tracked here and added to this roadmap.

Independence, trademarks & acknowledgements

keyroost is an independent implementation, not affiliated with or endorsed by any vendor named here. It works with their products by implementing publicly documented protocols; vendor and product names are used descriptively.

  • Token2 / Molto2 — trademarks of Token2 Sàrl. The Molto2 protocol was determined by observing the device and its public reference tool; SM4 and SHA-1 follow their published standards (GB/T 32907-2016, RFC 3174) and are checked against independent test vectors.
  • YubiKey — trademark of Yubico AB.
  • Solo / Solo 2 — trademarks of SoloKeys; Nitrokey — trademark of Nitrokey GmbH.

A genuine thank-you to these teams for their work on everyone's security: Yubico for helping create and champion U2F and FIDO2/WebAuthn and for publishing open specs and tooling; SoloKeys and Nitrokey for open, auditable security-key firmware and hardware (Nitrokey maintains the Trussed-based Solo 2 line); and Token2 for affordable programmable hardware TOTP. keyroost also rests on open standards from the FIDO Alliance, the OATH/IETF TOTP–HOTP RFCs, and the OpenPGP card specification.

Contributors

Beyond the maintainers, keyroost is grateful for community contributions:

  • @token2 — contributed on-device TOTP/HOTP management for Token2 FIDO keys (PIN+ / FIDO2+), and published the protocol reference it was built from (#24). Followed up with fingerprint/bio enrollment, FIDO Metadata Service (MDS) display, and a rounding-out of the on-device OTP support — all validated on real PIN+ hardware (#29, #30). Also added CTAP 2.1 authenticator-config (security policy) and largeBlob storage management, with a FIDO2 tab redesign (#38); T=0 contact-reader fixes, the single-profile programmable-token support (keyroost-token2prog) and QR-from-screen import (#50); and the OTP secret-reveal toggle plus a Windows key-naming / anti-spoofing fix (#52, #56); and OTP-PIN protection for R3.4+ keys, in the CLI and the GUI (#107, #108). Signs the Windows and macOS release builds out-of-band.
  • @Algoritter — the project's first external code contribution: found, fixed and hardware-verified two armed-reset replug bugs (a recycled /dev/hidrawN path reading as "never left", and card-serial keys failing to re-match after reinsertion) (#96).
  • @errant253 — README improvements: the distro-neutrality disclaimer, install-command corrections and an intro rewrite (#35, #45).
  • @MakeShiftArtist — the Nix flake: keyroost and keyroostctl packages plus a development shell, tested on x86_64 Linux (#109).
  • @plaflamme — Dependabot coverage for the flake's inputs, keeping flake.lock current (#132).
  • @episource — the project's most prolific external contributor: Nitrokey 3 PIV support and piv chuid generate (#102), short-APDU chaining (#101), Identiv uTrust mutual-auth tolerance (#104), any-length GET VERSION / Swissbit compat (#110), the PIV activity log and APDU trace (#114), --generate-key on piv cert generate / piv cert request (#116), status-word meanings in errors (#118), the PIV-refresh APDU deduplication (#119), and PIV applet fingerprinting with per-device feature gates, HID Crescendo management and ECC P-521 (#128), Swissbit iShield serial, device name and firmware reads (#163), and X.509 key usage for certificates and CSRs (#164) — most of it hardware-verified on their own cards.

(This credits their contributions to the codebase; it does not change keyroost's independent status described above.)

Standards & protocols

keyroost is built entirely from published specifications — no vendor SDKs. Every byte layer below is implemented in-tree against the documents named here. The two vendor-specific protocols are called out distinctly; everything else is an open industry standard.

FIDO2 / CTAP

  • FIDO CTAP 2.x (Client to Authenticator Protocol) over CTAP-HID — device info, resident-credential management, client-PIN (protocols v1 and v2), and bio (fingerprint) enrollment. Spec
  • ECDH on NIST P-256 (FIPS 186-4) for the client-PIN/UV key agreement.

OATH (one-time passwords)

OpenPGP card

PIV

  • NIST SP 800-73-4 / FIPS 201 Personal Identity Verification card interface, including X.509 certificate slots and their gzip-compressed form (RFC 1952). Spec

Token2 Molto2 / Molto2v2 (vendor-specific)

  • The Molto2 / Molto2v2 wire protocol, determined by observing the device and its public reference tool and documented independently in docs/PROTOCOL.md. It layers on:
    • SM4 block cipher — GB/T 32907-2016 — for seed/title encryption and the per-command MAC.
    • SHA-1 — RFC 3174 — to derive the SM4 key from the customer key.

Token2 single-profile programmable token (vendor-specific)

  • The wire protocol of Token2's single-profile programmable TOTP tokens (OTPC / miniOTP / C30x), a close relative of the Molto2 protocol — same NFC Type-4 / ISO 7816 transport, SM4 cipher, and ISO/IEC 9797-1 MAC — but authenticated with a fixed device key (no customer key) and addressing a single slot. Documented independently in docs/PROTOCOL-token2prog.md.

Token2 on-device OTP (vendor-specific)

  • The Token2 OTP-on-FIDO management protocol used by the PIN+ Series keys, published as the Token2 OTP SDK Protocol (issue #41). Seed-bearing commands use ECDH (NIST P-256) + AES payload encryption.

Cryptographic primitives & encodings

  • AES (FIPS 197) and HMAC (RFC 2104) — client-PIN, OTP payload encryption, and PIV management-key auth (also 3DES).
  • RSA with PKCS#1 (RFC 8017) and PKCS#8 (RFC 5208) key serialization, PEM/DER (X.509 / ASN.1 DER) — host-side OpenPGP key import, and host-side verification in the PIV slot self-test (keyroost-pivtest).
  • CBOR (RFC 8949, canonical encoding) — the CTAP2 message format.
  • base32 (RFC 4648) and the otpauth:// URI scheme — OTP secret encoding and 2FA import.
  • ISO 7816-4 APDUs (with BER-TLV / simple-TLV data objects) — the common framing for the OATH, OpenPGP, PIV, and Molto2 smart-card applets.

Design principles

  • Few dependencies, by design. The protocol and codec layers are hand-written: the Molto2 wire protocol (SM4, SHA-1, the MAC), base32, hex, CBOR, CTAP-HID framing, and the OATH / OpenPGP / PIV byte layers are all in-tree, pulling in nothing beyond zeroize for wiping secret buffers. External crates are added only when not doing so would be irresponsible or impractical — audited cryptography we won't hand-roll under forbid(unsafe_code) (RustCrypto: sha2 / hmac / aes / p256 / rsa / …) and platform glue (pcsc, hidapi on macOS/Windows, clap, eframe/egui). The per-crate list is in the table below, and the standing goal is to shrink it over time, not grow it.
  • Pure-Rust crypto — no OpenSSL or other C crypto; the in-tree primitives are checked against standard test vectors, and standard algorithms come from the audited RustCrypto crates.
  • Secrets stay yours. PINs, passwords, keys, seeds and otpauth:// URIs come from an environment variable, stdin or a hidden prompt, never argv. The tool never prints or persists them.
  • A single self-contained binary per OS — it dynamically links only the system C library and the PC/SC client; no scripts, no Python, no Qt.
  • Toward native installs everywhere. The longer-term goal is first-class distribution through each platform's mainstream channels. Available today: Homebrew, AUR, Flatpak, AppImage, and winget, plus the pre-built release binaries and cargo. All while continuing to shrink external dependencies toward a self-contained binary.

Install

keyroost ships through every mainstream channel below. The release archives, the Flatpak, Homebrew, winget and the AUR package all carry both keyroost (the GUI) and keyroostctl (the CLI); the AppImage is GUI-only. Pick whichever fits your platform; the smart-card features need a host PC/SC daemon (see Smart-card prerequisite).

Pre-1.0, availability tracks the latest release: when a version is published, these channels are updated to point at it. Replace vX.Y.Z below with that release tag.

Pre-built binaries (GitHub Releases)

No toolchain needed. Download from the latest release:

Platform Asset
Linux x86_64 keyroost-vX.Y.Z-linux-x86_64.tar.gz
macOS (Apple Silicon + Intel) keyroost-vX.Y.Z-macos-universal2.tar.gz
Windows x86_64 keyroost-vX.Y.Z-windows-x86_64.zip
Windows x86_64, code-signed keyroost-vX.Y.Z-windows-x86_64-signed.zip
macOS installer, code-signed keyroost-vX.Y.Z-macos-universal2-signed.pkg

The signed builds carry the same binaries as the CI archives, signed out-of-band by Token2 (Authenticode on Windows; an Apple Developer ID installer on macOS, signed but not notarization-stapled). They may trail a release by a few days — winget always waits for the signed zip. The CI archives are covered by SHA256SUMS and build-provenance attestation instead.

Each archive carries both keyroost and keyroostctl; unpack it and move the two executables onto your PATH. For example, on Linux x86_64:

curl -L https://github.com/framefilter/keyroost/releases/download/vX.Y.Z/keyroost-vX.Y.Z-linux-x86_64.tar.gz \
  | tar xz   # then move keyroostctl / keyroost onto your PATH

The prebuilt binaries need libpcsclite at runtime — on a FIDO-only machine install it (apt install libpcsclite1 / dnf install pcsc-lite) or use a package that declares the dependency.

cargo (from source)

Needs the Rust toolchain — 1.92+ for the GUI (keyroost), 1.85+ for the CLI (keyroostctl) and libraries — and, on Linux, the PC/SC dev package plus the GUI's X11/Wayland/GL libraries (see Smart-card prerequisite):

cargo install keyroostctl keyroost

The release binaries and the AppImage are built with the optional qr feature (scan a TOTP QR from the live screen). cargo install does not enable it — add cargo install keyroost --features qr if you want it.

Or let cargo-binstall fetch the same pre-built release archive instead of compiling — useful on atomic distros (e.g. Bazzite) where cargo install's build step is awkward:

cargo install cargo-binstall   # if you don't have it yet; ensure its dir is on PATH
cargo binstall keyroostctl keyroost

Homebrew (macOS + Linux)

brew tap framefilter/keyroost
brew install keyroost

AUR (Arch Linux)

The keyroost-bin package installs the prebuilt binaries plus the FIDO udev rules. Use any AUR helper (or makepkg):

yay -S keyroost-bin

Nix (flake)

The repository is a flake exposing keyroost (the default package), keyroostctl and a development shell. Builds from source. Contributed and tested on x86_64 Linux; other systems are declared but unverified (#109).

nix run github:framefilter/keyroost            # GUI
nix run github:framefilter/keyroost#keyroostctl -- --help
nix profile install github:framefilter/keyroost

winget (Windows)

Live in the Microsoft catalog (microsoft/winget-pkgs):

winget install Framefilter.Keyroost

Flatpak (Linux — auto-updating, recommended for the GUI)

Add Flathub (for the shared runtime) and the maintainer's GPG-signed remote in the same scope, then install the app (app-id io.github.framefilter.keyroost). Using --user needs no root and avoids the most common failure — a scope mismatch between Flathub and the keyroost remote, which makes the install fail to find its runtime even when it's installed:

flatpak remote-add --if-not-exists --user flathub \
  https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak remote-add --if-not-exists --user keyroost \
  https://framefilter.github.io/keyroost-flatpak/keyroost.flatpakrepo
flatpak install --user keyroost io.github.framefilter.keyroost
# updates ride along with `flatpak update`

The Flatpak carries the CLI as well; run it with flatpak run --command=keyroostctl io.github.framefilter.keyroost.

Prefer a system-wide install? Use --system on all three commands instead — the key is keeping Flathub and the keyroost remote in the same scope.

Or grab the offline single-file bundle (keyroost.flatpak) attached to each release:

flatpak install ./keyroost.flatpak

The Flatpak bundles the pcsc-lite client and talks to the host pcscd, so you still need that daemon running on the host (see Smart-card prerequisite).

AppImage (Linux — no install, GUI only)

Download keyroost-x86_64.AppImage from the latest release — the asset name is version-less, so this URL always fetches the current build. It needs glibc 2.35 or newer (see the note under Smart-card prerequisite):

curl -LO https://github.com/framefilter/keyroost/releases/latest/download/keyroost-x86_64.AppImage
chmod +x keyroost-x86_64.AppImage
./keyroost-x86_64.AppImage
# On FUSE3-only distros, install libfuse2, or run without FUSE:
./keyroost-x86_64.AppImage --appimage-extract-and-run

The AppImage is GPG-signed (key fingerprint F9E0 4EED 9DC5 DC94 AB2E 6100 6C81 DC35 3794 478B); see SECURITY.md → Verifying the AppImage.

Uses the host's pcsc-lite. The AppImage always prefers the host's pcsc-lite client library, so the smart-card client matches the host's pcscd daemon; smart cards need pcscd installed (see Smart-card prerequisite). On a host without pcsc-lite it still starts, using a bundled copy of the library: FIDO works and the smart-card features report unavailable until pcscd is installed.

Smart-card prerequisite

The smart-card features (OATH / OpenPGP / PIV, and Token2 Molto2 programming) talk to the card over PC/SC and need the pcscd daemon running on the host. macOS and Windows have PC/SC built in. On Linux, install the PC/SC library + daemon (the package name differs per distro). Building from source with cargo additionally needs the PC/SC dev package, and the GUI needs the X11/Wayland/GL libraries that eframe/egui link against.

Once installed, keyroostctl doctor checks all of this for you — PC/SC service, readers, FIDO HID access, and udev rules — read-only, touching no key.

keyroost is otherwise distro-neutral — it talks to the kernel's hidraw/sysfs and to PC/SC, both of which every mainstream distribution provides; only the package names differ. Common distro one-liners:

# Debian / Ubuntu
sudo apt install libpcsclite-dev pcscd \
  libxkbcommon-dev libwayland-dev libxcb1-dev libgl1-mesa-dev

# Fedora / RHEL
sudo dnf install pcsc-lite-devel pcsc-lite pkgconf-pkg-config gcc \
  libxkbcommon-devel libxkbcommon-x11-devel wayland-devel libxcb-devel \
  mesa-libGL-devel

# Arch
sudo pacman -S pcsclite ccid pkgconf gcc \
  libxkbcommon libxcb wayland mesa

sudo systemctl enable --now pcscd

(For the CLI only you can drop the libxkbcommon/wayland/xcb/mesa packages — those are just for the GUI.) macOS and Windows have PC/SC built in, and the FIDO HID backend uses hidapi (IOKit / hid.dll) automatically — no extra packages. macOS/Windows are tier-2 (best-effort, not yet hardware-verified).

(Building the GUI on Windows compiles a small build script that embeds the app icon and version info into keyroost.exe; it needs a resource compiler — rc.exe, part of the Windows SDK that ships with the standard MSVC toolchain setup. The CLI has no build script.)

Windows and FIDO: Windows reserves raw FIDO HID access for elevated processes (the OS routes normal apps through its own WebAuthn API instead). Expect the fido commands and the GUI's FIDO2 tab to require an elevated ("Run as administrator") session on Windows; the Molto2, OATH, OpenPGP, and PIV features go over PC/SC and work unelevated. Elevate for the FIDO command you need, then drop back — don't run the whole tool elevated as a habit. Even without admin the GUI now detects an attached FIDO key (via readable HID metadata, without opening the protected interface) and shows an "Administrator rights needed" card with a button to relaunch elevated or open Windows' own security-key settings.

Prebuilt binaries: the Linux release tarball and the AppImage are built on Ubuntu 22.04 and need glibc 2.35 or newer (Ubuntu 22.04, Debian 12, Fedora 36 and later); on an older system (e.g. RHEL 9) they fail with a GLIBC_… error. There, build from source with the commands above — cargo install handles the rest.

Wayland and clipboard auto-clear: after copying an OTP code the GUI clears the clipboard ~45 s later, but only if the clipboard still holds that code. The check reads the clipboard via X11/XWayland; on a pure-Wayland session without XWayland clipboard sync it can't see the contents and fails open (nothing is cleared) rather than clobbering whatever you copied since. GNOME and KDE sync the two clipboards, so the clear works there; on other compositors treat the auto-clear as best-effort.

Forcing X11 (KEYROOST_X11=1): the GUI runs natively on Wayland by default. The egui/eframe 0.35 bump fixed a Wayland/KDE input bug where text entry under native Wayland — notably on KDE Plasma — could misbehave, but if you still hit broken text input set KEYROOST_X11=1 to force the GUI onto XWayland as a fallback. It's opt-in; leave it unset for the native-Wayland path.

FIDO HID access (Linux udev rules)

The OATH, OpenPGP, and PIV applets are reached over PC/SC and need no special permissions. Talking to a key's FIDO interface (the fido commands, and the GUI's FIDO2 tab), though, opens a /dev/hidraw* node, which is root-only by default. Install the bundled udev rules to grant the logged-in user access:

sudo cp udev/70-keyroost-fido.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules
sudo udevadm trigger

The rules use uaccess (and a plugdev fallback), are keyed by vendor/USB so they apply before the hidraw node is created, and cover the common FIDO vendors (Yubico, SoloKeys, Nitrokey, Feitian, Token2, and others). Re-plug the key after installing them.

Shell completions

The Homebrew and AUR packages install keyroostctl's bash and fish completions, plus man pages; for zsh, add the line below to ~/.zshrc. Otherwise, set completions up once for your shell:

# bash: this session only, or for every session
source <(keyroostctl completions bash)
mkdir -p ~/.local/share/bash-completion/completions
keyroostctl completions bash > ~/.local/share/bash-completion/completions/keyroostctl

# zsh: add this line to ~/.zshrc (after compinit)
source <(keyroostctl completions zsh)

# fish
mkdir -p ~/.config/fish/completions
keyroostctl completions fish > ~/.config/fish/completions/keyroostctl.fish

# PowerShell: add this line to your $PROFILE
keyroostctl completions powershell | Out-String | Invoke-Expression

The script asks keyroostctl for suggestions as you type, so --device <Tab> offers the names recorded in this computer's keys.json (it never reads the keys). If you installed a completion file from v0.12.0 or earlier, generate it again to get this.

Quick start

# discover connected devices: PC/SC readers + FIDO authenticators (USB-HID and NFC)
keyroostctl list

# diagnose the local environment (PC/SC service, readers, FIDO HID access,
# udev rules, registry permissions) — read-only, touches no key
keyroostctl doctor

# --- FIDO2 (YubiKey / Solo 2 / Nitrokey 3), over USB-HID or an NFC reader ---
keyroostctl fido info
keyroostctl fido pin status
keyroostctl fido credential list             # asks for the PIN (nothing is shown as you type)
keyroostctl fido ssh list                     # list SSH certs stored in resident credentials
keyroostctl fido ssh export --rp ssh:demo --out demo-cert.pub

# --- OATH over PC/SC ---
keyroostctl oath list
keyroostctl oath code 'GitHub:me@x.com' --device my-yubikey
keyroostctl oath import -i export.json --dry-run   # show what an export would add; writes nothing

# --- OpenPGP card ---
keyroostctl openpgp info --device my-yubikey
keyroostctl openpgp sign --in msg.txt --device my-yubikey          # asks for the PIN
keyroostctl openpgp authenticate --in chal.bin --device my-yubikey  # client/SSH auth (Auth key)

# --- PIV ---
keyroostctl piv info --device my-yubikey
keyroostctl piv key generate --slot 9a --algorithm eccp256   # asks for the management key

# bulk-provision several slots: management key + PIN from env once, loop the rest.
# (the GUI asks per operation; the CLI is the path for many slots/keys)
export PIV_MGMT=...   # AES-192 / 3DES management key, hex; never put it in argv
export PIV_PIN=...
for slot in 9a 9c 9d 9e; do
  keyroostctl piv key generate --slot "$slot" --algorithm eccp256 \
      --mgmt-key env:PIV_MGMT --device my-yubikey
  keyroostctl piv cert generate --slot "$slot" --subject "CN=$USER" \
      --mgmt-key env:PIV_MGMT --pin env:PIV_PIN --device my-yubikey
done
# (in a terminal, a step that would replace a slot in use asks y/N first;
#  add --yes to overwrite without asking)
# on a card without GET METADATA (non-Yubico PIV, or Yubico firmware < 5.3)
# the two steps can't share the key by slot name across invocations; fold
# them into one so the fresh public key never needs a temp file:
#   keyroostctl piv cert generate --slot 9a --subject "CN=$USER" --generate-key \
#       --algorithm eccp256 --mgmt-key env:PIV_MGMT --pin env:PIV_PIN
# (same --generate-key convenience on `piv cert request`)

# --- Token2 Molto2 (TOTP programming) ---
keyroostctl molto info
keyroostctl molto import --slot 0                # asks for the otpauth:// URI (hidden)
keyroostctl molto import --slot 0 --uri env:URI  # or from an environment variable
keyroostctl molto import --in ~/Downloads/aegis.json --slot 0 --dry-run   # validate first
keyroostctl molto import --in ~/Downloads/aegis.json --slot 0 --file-password env:PW  # encrypted export
keyroostctl molto seed set --slot 5              # asks for the seed (base32; --encoding hex for hex)

# --- Token2 single-profile programmable token (OTPC / miniOTP / C30x) ---
keyroostctl prog info                          # serial, model, and on-device clock
keyroostctl prog seed set                      # asks for the base32 seed (hidden)
keyroostctl prog config set --algorithm sha1 --period 30 --display-timeout 30

# --- Token2 on-device OTP (PIN+ Series FIDO keys) ---
keyroostctl otp list
keyroostctl otp add --app GitHub --account me@x.com   # asks for the seed (hidden)
keyroostctl otp code --app GitHub --account me@x.com
keyroostctl otp import -i export.json                  # add every code in an export (asks first)

# --- Destructive operations (ask y/N, or type "reset", in a terminal) ---
keyroostctl factory-reset --device my-yubikey          # asks you to type "reset"
keyroostctl factory-reset --device my-yubikey --yes    # in a script

# name a key to target it when several are plugged in (opt-in)
keyroostctl name set my-yubikey                 # on this computer
keyroostctl name set my-yubikey --store key     # on the key (asks for the FIDO PIN)
keyroostctl name list

# machine-readable output for scripts (status and query commands)
keyroostctl --json list                     # {"keys": [...]}, each with its --device value
keyroostctl --json piv info --device my-yubikey

# man pages (completions: see "Shell completions" above)
keyroostctl manpage ./man && man -l ./man/keyroostctl-piv.1

# launch the GUI (per-device tabs: Overview, FIDO2, Authenticator, OpenPGP, PIV,
# On-device OTP, plus the distinct Molto2 and single-profile programmable-token views)
keyroost

Choosing a key

With one key connected, every command uses it. With several, a command run in a terminal shows a numbered list to pick from; a script is refused with the exact --device value for each key. --device takes a saved name, a serial, or the number keyroostctl list shows (prefix name:, serial: or list: to say which you mean); keyroostctl --json list gives scripts the same values. A Molto2 answers to either serial keyroost shows for it: the one in keyroostctl list or the one molto info prints. --reader (a reader name, or a unique part of one) and --path are expert overrides: they skip the capability check, and a value that matches no detected key is used as typed. Neither can be combined with --device.

Five flags have a short form, with the same meaning on every command: -d (--device), -y (--yes), -o (--out), -i (--in) and -s (--slot).

Commands that erase or replace something on the key (resets, deletes, overwriting a used slot or seed) name the key and ask y/N first (factory-reset and otp interface ask you to type a phrase). A script has no terminal to ask on, so it adds --yes; so does a command whose PIN or seed is piped in on stdin. If you answered a question, keyroost checks it is still the same key before acting.

Naming a key

keyroostctl name set "Work YubiKey"                # keep the name on this computer
keyroostctl name set "Work YubiKey" --store key    # keep it on the key (asks for the FIDO PIN)
keyroostctl name list                              # every name, where it lives, what is connected
keyroostctl piv info -d "Work YubiKey"             # use it
keyroostctl name clear "Work YubiKey"              # remove it, wherever it is stored

With several keys connected, say which one to name with -d (a list number or serial:…), or pick from the list a terminal shows. Running name set on a named key renames it where its name already is; a name on this computer moves to the key with --store key.

A name on this computer goes in keys.json with a salted fingerprint of the key, never its serial. The salt is a random value in keys.salt beside it. If keys.salt is lost, the names on this computer no longer match their keys: clear them and set them again (putting the old keys.salt back doesn't help). A keys.json from v0.12 or earlier, which held serials, is converted the first time this version reads it.

Names on the key

  • A name on the key is visible to anyone who has the key, and every computer running keyroost shows it, without a PIN.
  • Saving, changing or removing it needs the key's FIDO PIN, and the key needs FIDO2 large-blob storage. A key without it can only be named on a computer.
  • A name on the key is shown first; a name this computer saved for the key shows only when the key carries none.
  • If two keys carry the same name, the one this computer saw first keeps it, and -d "Work YubiKey" always means that one. The other shows as Work YubiKey (1234), with the last four characters of its serial; select it by its list number or serial:….
  • Keys that report the same serial on every unit (the OnlyKey, for example) can't be told apart by their fingerprint, so naming them works as it did before.
  • On Windows without administrator rights, keyroost can't read a key's FIDO side, so it shows only names saved on this computer.
  • fido blob clear and a FIDO reset erase the name with everything else (fido blob clear --keep-name keeps it). The FIDO2 standard also lets other software remove large-blob entries that no passkey uses; we haven't seen it happen. If a key loses its name, it shows as unnamed until the name is written back: name list prints the command to do so, and the desktop app offers to.

The format of the name entry, with test vectors for other tools, is in docs/PROTOCOL-device-label.md.

Giving keyroost a PIN

keyroostctl never takes a PIN, password, key, seed or otpauth:// URI on the command line, where it would land in shell history and ps. By hand, leave the flag out and a terminal asks for the secret without showing what you type. In a script, the flag's value says where the secret comes from: env:NAME reads an environment variable and stdin reads one line:

keyroostctl fido credential list                   # asks "PIN:" (nothing is shown as you type)
keyroostctl fido credential list --pin env:KR_PIN  # read from the KR_PIN environment variable
pass show fido-pin | keyroostctl fido credential list --pin stdin   # one line from stdin

Typing the secret itself as the value (--pin 123456) is refused, and the value is never shown. --mgmt-key default uses the factory-default PIV management key.

A new PIN, password or key typed at the prompt is asked twice and must match. When one command reads two secrets from stdin, the current one is the first line and the new one the second (each flag's --help says which line):

printf '%s\n%s\n' "$OLD_PIN" "$NEW_PIN" | keyroostctl piv pin change --pin stdin --new-pin stdin

otp add and oath add read the seed first, then the PIN or password; on molto, --customer-key stdin is always the first line. Seeds are base32 unless --encoding hex; a new Molto2 customer key is hex unless --encoding ascii, and --customer-key-encoding says how the current one is written. A Molto2 customer key left out means the factory default. In a script with no terminal, a command with no source for a secret it needs is refused, naming the flag. In Git Bash (mintty) on Windows the prompt needs a real console: run winpty keyroostctl …, or use env:NAME.

Importing codes

Move the codes from an authenticator app onto a key in one step. keyroost reads Aegis exports (plain or encrypted), 2FAS exports, a text file with one otpauth:// URI per line, and QR screenshots (PNG or JPEG), including a Google Authenticator export.

keyroostctl oath import -i export.json --dry-run    # show what would happen; writes nothing
keyroostctl oath import -i export.json              # YubiKey, Solo 2, Nitrokey 3: asks once, then adds
keyroostctl otp import -i export.json               # a Token2 key's OTP storage
keyroostctl molto import -i export.json --slot 90   # a Molto2, from slot #90 on
keyroostctl oath import -i export.json --file-password env:EXPORT_PW   # an encrypted Aegis export

In the GUI, drop the file on the window, or click Import file… in a key's Authenticator, On-device OTP or Molto2 view. The Import authenticator codes dialog lists the entries, lets you pick the key under Add to, and shows what each entry will become before anything is written. An encrypted export asks for its password in the dialog. A certificate or key file dropped on the window gets a note saying where it can be imported instead.

Before writing, keyroost reads what is already on the key and marks each entry:

  • add: it goes onto the key.
  • exists: a code with the same name is already on the key, so it is left as is. --replace (in the GUI, "Replace codes already on the key that have the same name") replaces it instead. Some keys refuse a second code with the same name; there, replacing removes the old code first, and if adding the new one then fails, the old code is gone.
  • skip: the key can't store it, and the preview says why (for example "Solo 2 doesn't take SHA-512 codes"). keyroost never changes an entry to make it fit. Steam codes are skipped on every key.

On a Molto2, entries fill consecutive slots from --slot. A slot already in use is replaced (replace), an entry with no issuer or account is skipped without using up a slot, and entries past slot #99 are skipped.

keyroost asks once before writing (a script adds -y). It writes one code at a time and stops at the first error, saying what was added and what was not. Running the same import again is safe: codes it already added now show as exists. --dry-run writes nothing; for oath import and otp import the key must be connected, because the preview depends on what is on it. molto import --dry-run reads slot use from a connected Molto2, and works without one too. --json prints the plan and, after writing, what happened to each entry.

An encrypted export's password comes from --file-password env:NAME or --file-password stdin, or a terminal asks for it. When the export's password and the key's password or PIN are both piped in, the export's password is the first line. On molto import, --customer-key stdin is the first line and the export's password the second.

What each key can store:

Key Holds Limits
YubiKey 32 codes, or 64 from firmware 5.7 names up to 64 bytes; SHA-512 from firmware 4.3.1; 6 to 8 digits
Solo 2 not reported (writing stops if it fills up) names up to 127 bytes; no SHA-512; secrets up to 64 bytes
Nitrokey 3 50 codes names up to 128 bytes; 30-second codes only (the key doesn't store the period); no SHA-512
Token2 OTP storage 50 codes app and account up to 64 bytes each, plain ASCII only; no SHA-512; HOTP only with a counter of 0 (the key always starts at 0)
Molto2 100 slots (#00 to #99) TOTP only, 30 or 60 seconds; SHA-1 or SHA-256; 4, 6, 8 or 10 digits; titles shortened to 12 bytes

On a YubiKey or Solo 2, a TOTP code with a period other than 30 seconds is stored under a name that starts with its period, such as 60/GitHub:alice (the naming Yubico's own tools use). oath code and the GUI compute those codes with that period.

A Solo 2 name longer than 127 bytes is refused by oath import, oath add and the GUI before anything is sent: on Solo 2 firmware 2.3.196, 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 already on the key is skipped (and oath add refuses it), following the same rule as Yubico's ykman.

Importing into a Token2 key's OTP storage and into a Nitrokey 3 is built from the published specifications (Token2's OTP specification and Nitrokey's secrets-app source). If you use one of these keys, reports in the issue tracker are welcome.

Reading the output

A command prints its result on stdout and everything else (prompts, progress, notes, warnings) on stderr. You see both at a terminal, but redirecting saves only the result:

keyroostctl molto list > slots.txt      # the file gets just the table
keyroostctl piv cert export --slot 9a   # prints the certificate as PEM

With --json (on the commands that support it), a command prints one object; a list sits under a named key such as keys or accounts, and every field is there, null when unknown. Don't rely on key order. The --debug output is for people reading along and may change between releases. So may the human-readable text of any command; to read values in a script, use --json where a command has it.

Breaking changes & migration

Breaking changes are tracked per release on the site's migration notes page, with the exact before → after for scripts and library consumers. v0.13.0 makes more commands ask before they erase or replace something (scripts pass --yes), refuses, in a script, to pick among several keys, and takes no secret on the command line (each secret flag takes env:NAME or stdin, and a terminal asks when it is left out). Commands are regrouped (piv pin change, fido credential list), five short flags mean the same everywhere, and two commands read their stdin lines in a new order. It also reshapes --json output, moves everything but the result to stderr, and makes piv cert export write PEM. Two older ones to know about: v0.7.5 renames the global device selector from --name to --device, and v0.6.0 moved the Molto2 / FIDO commands under the molto and fido groups.

One name to watch: in ≤0.5.x keyroostctl factory-reset meant the Molto2 profile reset (now keyroostctl molto reset). The name is live again, but it now wipes every applet on a key. See the migration page before re-running an old script.

Workspace layout

Crate Purpose External deps
keyroost-proto Pure-Rust Molto2 wire protocol (SM4, SHA-1, APDU, MAC) none
keyroost-transport PC/SC discovery, Molto2 session, CCID serial, OATH/OpenPGP/PIV applets, Token2 OTP session, import writers for OATH / Token2 OTP / Molto2 (in-tree keyroost-import) pcsc, aes/des/cipher (mgmt-key auth), getrandom, zeroize, miniz_oxide (gzip-compressed PIV certificates); hidapi on macOS/Windows
keyroost-hid USB HID enumeration of FIDO devices none on Linux (sysfs); hidapi on macOS/Windows
keyroost-ctap FIDO2/CTAP-HID transport, CBOR, PIN protocols, credential management, large-blob storage (including the name a key carries) RustCrypto (sha2/hmac/aes/cbc/p256/rand_core) for client-PIN, aes-gcm + miniz_oxide for largeBlob entries, zeroize; hidapi on macOS/Windows
keyroost-oath Pure-Rust Yubico/Trussed OATH (TOTP/HOTP) byte layer zeroize
keyroost-openpgp Pure-Rust OpenPGP Card v3.4 byte layer (APDU + BER-TLV) zeroize
keyroost-piv Pure-Rust PIV (SP 800-73-4) byte layer; full management + SPKI/PEM, applet fingerprinting and per-device feature gates zeroize
keyroost-pivtest Host-side round-trip self-test for a PIV slot key (decrypt / key-agree / sign), checked against the slot certificate's public key rsa, p256, p384, p521, ed25519-dalek, x25519-dalek, zeroize
keyroost-token2otp Pure-Rust Token2 OTP-on-FIDO byte/codec layer (APDU + HID framing) RustCrypto (sha2/hmac/aes/cbc/p256/rand_core) for ECDH seed encryption and the OTP-PIN session, zeroize
keyroost-token2prog Pure-Rust Token2 single-profile programmable-token wire protocol (SM4 seed/MAC, fixed device key, config TLV); reuses keyroost-proto zeroize
keyroost-keyring Friendly-name registry (keys.json, salted fingerprints) serde, serde_json, getrandom (the per-computer salt); in-tree SHA-256 from keyroost-proto
keyroost-resolve Shared key-identity resolution (USB + CCID serials, topology match) and naming (names on the key and on this computer) none (in-tree only, including keyroost-ctap)
keyroost-rsakey Host-side RSA-2048 keygen + PKCS#1/PKCS#8 (PEM/DER) loading rsa, rand, zeroize
keyroost-import otpauth:// + Aegis / 2FAS / otpauth-list parsers, file classification, and the per-key import plan and write loop zeroize; serde/serde_json (behind bulk); scrypt, aes-gcm, base64 (behind encrypted, which implies bulk)
keyroost-qr QR 2FA import from PNG/JPEG screenshots and Google Authenticator export batches — always built in; the GUI's live screen capture is behind the qr feature (on in the release archives and the AppImage, off in the Flatpak) rqrr, png, jpeg-decoder, zeroize
keyroost-winwebauthn Windows-only helper for the non-admin FIDO2 path: detect a FIDO key via the HID access-denied signal, open Windows' security-key settings, and relaunch elevated; inert on non-Windows windows-sys (Windows only)
keyroost-screengrab Windows-only still screen capture (GDI BitBlt) for QR-from-screen; isolates the unsafe Win32 FFI from the GUI crate; inert on non-Windows windows-sys (Windows only)
keyroostctl Command-line interface clap, clap_complete, clap_mangen, serde/serde_json, zeroize, rpassword (hidden PIN/password prompt)
keyroost egui desktop GUI eframe, egui, arboard, rfd, pollster, png, base64, serde/serde_json, zeroize; x11rb/ashpd on Linux (qr feature); winresource build-dep on Windows

Protocol

The Molto2 wire protocol is documented in docs/PROTOCOL.md — the APDUs, the SM4-based MAC, and the TLV config payload, described as facts about the device rather than any one implementation. The sibling single-profile programmable token (OTPC / miniOTP / C30x) is documented the same way in docs/PROTOCOL-token2prog.md. The name a key can carry in its FIDO2 large-blob array is documented, with test vectors, in docs/PROTOCOL-device-label.md. The FIDO2, OATH, OpenPGP and PIV layers follow their respective public standards.

Contact

General questions, packaging notes, and other non-security correspondence are welcome at framefilter@proton.me.

Security issues should not go to email — please use GitHub's private vulnerability reporting (see SECURITY.md) so the report stays private until a fix ships.

License

Licensed under either of

at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

This dual-license is the Rust ecosystem default and matches what serde, tokio, clap, and most of the ecosystem use.

About

Vendor Neutral, Rust-Based Management UI and CLI for U2F/FIDO2 and other hardware security keys

Topics

Resources

Contributing

Security policy

Stars

64 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages