Skip to content

MinorGlitch/zerofido

Repository files navigation

License: GPL-3.0-or-later Platform: Flipper Zero Protocols: FIDO2 + U2F

ZeroFIDO banner: FIDO2 for Flipper Zero

⚠️ ⚠️ Experimental software. Updates may break it. Keep backup sign-in methods. ⚠️ ⚠️

ZeroFIDO turns a Flipper Zero into a passkey and security-key app. Install the .fap, open ZeroFIDO, and approve sign-ins on services that support FIDO2/WebAuthn or legacy U2F.

The app stores credentials on the Flipper, asks for local approval, supports ClientPIN, and speaks the CTAP2/FIDO2 protocol used by browsers and security keys. USB HID handles desktop browser flows. NFC builds handle phone flows.

NFC has been tested on iPhone. Android NFC support is next. In the meantime, connect the Flipper to the phone over USB when the phone accepts USB security keys.

U2F and FIDO2.0 pass their respective tests in the current FIDO Conformance Tools suite. FIDO2.1 support is in development behind a developer-only build flag. Bug reports, feature requests, and pull requests are welcome.

Showcase

ZeroFIDO waiting for a request ZeroFIDO create passkey approval prompt ZeroFIDO saved credentials list
Waiting for a browser or phone request Approving a new passkey Saved discoverable credentials
ZeroFIDO passkey detail screen ZeroFIDO settings screen ZeroFIDO PIN menu
Passkey details On-device settings PIN management
ZeroFIDO PIN entry keyboard ZeroFIDO reset confirmation ZeroFIDO delete passkey confirmation
PIN entry on the Flipper Reset confirmation Deleting a saved passkey

Quick Start

  1. Download a release .fap from GitHub Releases.
  2. Copy it to your Flipper SD card under the Tools apps folder, or install it through qFlipper or Flipper Lab.
  3. Open ZeroFIDO on the Flipper.
  4. Register it as a passkey or security key on a site that supports WebAuthn/FIDO2.
  5. Approve registration and sign-in prompts on the Flipper screen.

What Works

Capability Status
USB HID Supported in the usb and full release profiles
NFC Supported in the nfc and full release profiles
U2F V2 Supported
FIDO2.0 / CTAP2.0 Supported
FIDO2.1 / CTAP2.1 Developer-only experimental build flag
ClientPIN Supported
Discoverable credentials Supported
Attestation Local software attestation when requested

ZeroFIDO builds as an external .fap in the Flipper Tools category.

Daily Use

Open ZeroFIDO before starting a passkey or security-key flow.

  • On desktop, connect the Flipper over USB and use the USB HID build.
  • On phones, hold the Flipper near the NFC reader and use the NFC build. NFC is currently tested on iPhone; Android NFC support is planned. If the phone supports USB security keys, USB is the fallback.
  • When the Flipper asks for approval, confirm only if the site and account look right.
  • If a site asks for a PIN, use the browser or phone prompt. ZeroFIDO keeps the PIN retry state on the Flipper and uses the standard CTAP PIN token flow.

Settings

ZeroFIDO includes an on-device Settings screen.

Setting Use
Transport Choose USB HID or NFC when the build includes both transports.
Attestation Choose how MakeCredential answers attestation requests.
PIN Set, change, or manage the ClientPIN used by sites that require user verification.
Auto-accept Test mode for flows that should not require a touch prompt. Only appears when built with ZEROFIDO_AUTO_ACCEPT_REQUESTS=1.

Security Model and Limits

  • ZeroFIDO runs on general-purpose Flipper Zero hardware. There is no secure element, so physical access to the device changes the risk model.
  • Credential private keys are generated on the device and stored only after being wrapped with the Flipper crypto enclave unique key and a per-record IV. App storage still contains the metadata needed to find and use credentials, including relying-party IDs, user fields, public keys, wrapped private keys, IVs, and counters.
  • Counter floor files and PIN retry state are sealed with the same Flipper crypto APIs. ZeroFIDO protects key material and rollback-sensitive state; it does not encrypt the whole app directory.
  • Attestation is local software attestation, not hardware-backed vendor provenance, and ZeroFIDO is not FIDO Alliance certified.
  • Keep at least one backup sign-in method for accounts you care about.

Attestation

Choosing Attest: none or Attest: packed

ZeroFIDO defaults to Attest: none and supports two MakeCredential attestation modes from the on-device Settings screen:

  • Attest: none returns fmt: "none" with an empty attestation statement. The credential is still created normally, but ZeroFIDO does not include the local attestation certificate chain or attestation signature.
  • Attest: packed allows local software packed attestation when the relying party requests direct attestation. This identifies the ZeroFIDO install, not hardware-backed vendor provenance.

If the CTAP request includes attestationFormats and names a supported format, that explicit preference wins over the saved setting. ZeroFIDO currently supports none and packed.

For Developers

Developer setup, builds, validation, releases, and certification metadata

Setup

Install uv, then sync the Python tools:

uv sync

The Python toolchain declares Python 3.14+ in pyproject.toml. C validation expects clang-format, clang-tidy, cppcheck, and a host C compiler.

On macOS:

brew install llvm cppcheck

Build Profiles

The app manifest reads ZEROFIDO_PROFILE at build time. The default profile is usb, with the stable FIDO2.0 profile enabled by default. Release builds default to ZEROFIDO_RELEASE_DIAGNOSTICS=0.

Profile Build flag Use
USB HID only ZEROFIDO_PROFILE=usb Default; desktop browser WebAuthn and U2F testing.
NFC only ZEROFIDO_PROFILE=nfc Phone and NFC conformance work.
Full ZEROFIDO_PROFILE=full Both transports in one app.

Release-default builds exclude the NFC trace implementation. Diagnostics must opt in:

ZEROFIDO_PROFILE=nfc ZEROFIDO_RELEASE_DIAGNOSTICS=1 uv run python -m ufbt

Build a profile:

ZEROFIDO_PROFILE=nfc uv run python -m ufbt
ZEROFIDO_PROFILE=usb uv run python -m ufbt
ZEROFIDO_PROFILE=full uv run python -m ufbt

Build and launch on a connected Flipper:

ZEROFIDO_PROFILE=usb uv run python -m ufbt launch

The normal build output is dist/zerofido.fap.

Validation

Run the maintained Python tests:

uv run python -m unittest discover -s tests -t . -p 'test_*.py'

Run native protocol regressions:

uv run python tools/run_protocol_regressions.py

The native harness checks packed attestation, runtime Attest: none, explicit attestationFormats: ["none"], and required packed-attestation failures.

Run C formatting and analyzers:

uv run python tools/check_c.py format
uv run python tools/check_c.py format --fix
uv run python tools/check_c.py tidy
uv run python tools/check_c.py cppcheck
uv run python tools/check_c.py native
uv run python tools/check_c.py all

Check SDK symbols against a local Flipper firmware checkout:

uv run python host_tools/check_symbol_gate.py --sdk-root <flipper-firmware-checkout>

Check and package a built .fap with the release export gate:

uv run python host_tools/check_symbol_gate.py \
  --fap dist/zerofido.fap \
  --output-fap dist/zerofido-release.fap

Host Tools

List and probe FIDO HID devices:

uv run python host_tools/ctaphid_probe.py --cmd list
uv run python host_tools/ctaphid_probe.py --cmd init
uv run python host_tools/ctaphid_probe.py --cmd getinfo
uv run python host_tools/ctaphid_probe.py --cmd makecredential
uv run python host_tools/ctaphid_probe.py --cmd getassertion

Run U2F transport probes:

uv run python host_tools/ctaphid_probe.py --cmd u2fversion
uv run python host_tools/ctaphid_probe.py --cmd u2fregister --u2f-cert-out metadata/u2f-attestation.der
uv run python host_tools/ctaphid_probe.py --cmd u2finvalidcla
uv run python host_tools/ctaphid_probe.py --cmd u2fversiondata
uv run python host_tools/ctaphid_probe.py --cmd u2fauthinvalid

Capture a FIDO2 attestation leaf certificate from MakeCredential:

uv run python host_tools/ctaphid_probe.py \
  --cmd makecredential \
  --fido2-cert-out metadata/fido2-attestation.der

Capture NFC trace lines from the Flipper USB CDC console:

uv run python host_tools/nfc_trace_console.py --port auto
uv run python host_tools/nfc_trace_console.py --port <serial-port> --level info --output .tmp/nfc-trace.log

The iPhone NFC transport notes are in docs/writeup_ios.md.

Capture reconnecting crash logs from the same CDC console:

uv run python tools/flipper_crash_log.py --port auto --output .tmp/flipper-crash.log

Print firmware footprint data after building:

uv run python host_tools/size_ledger.py --artifact dist/zerofido.fap --artifact dist/zerofido-release.fap

Release Packaging

Build a release .fap for the selected profile and verify that the app exports only zerofido_main:

ZEROFIDO_PROFILE=usb \
ZEROFIDO_RELEASE_DIAGNOSTICS=0 \
uv run python host_tools/package_release.py

Package an existing dist/zerofido.fap without rebuilding:

uv run python host_tools/package_release.py \
  --skip-build \
  --fap dist/zerofido.fap \
  --output-fap dist/zerofido-release.fap

The packaged artifact lands at dist/zerofido-release.fap by default.

GitHub Releases

The Build profiles workflow verifies every push and pull request. The Release workflow publishes GitHub Releases from existing v* tags.

Create and push a tag:

git tag v0.7.0
git push origin v0.7.0

The release workflow builds the nfc, usb, and full profiles with ZEROFIDO_RELEASE_DIAGNOSTICS=0, packages the stripped *-release.fap artifacts, and uploads SHA256SUMS.

You can also run the workflow from GitHub Actions with an existing tag such as v0.7.0.

Certification Metadata

Metadata and captured attestation certificates belong to your local certification run. Keep them under metadata/; git ignores that directory. The exporter creates metadata/ and a default metadata/statement.json when they are missing.

uv run python host_tools/export_certification_metadata.py \
  --statement metadata/statement.json \
  --profile fido2-2.0 \
  --client-pin-state unset

uv run python host_tools/export_certification_metadata.py \
  --statement metadata/statement.json \
  --profile fido2-2.1-experimental \
  --client-pin-state unset

The fido2-2.1-experimental metadata profile is for development builds created with ZEROFIDO_DEV_FIDO2_1=1; release builds ship the FIDO2.0 profile.

The default outputs are:

  • metadata/metadata-ctap20.json
  • metadata/metadata-ctap21-experimental.json

For FIDO2 packed attestation chain checks, export metadata with the certificate returned by the same device:

uv run python host_tools/ctaphid_probe.py \
  --cmd makecredential \
  --fido2-cert-out metadata/fido2-attestation.der

uv run python host_tools/export_certification_metadata.py \
  --statement metadata/statement.json \
  --profile fido2-2.0 \
  --fido2-attestation-cert metadata/fido2-attestation.der

For U2F, export metadata from the certificate returned by U2F Register:

uv run python host_tools/ctaphid_probe.py \
  --cmd u2fregister \
  --u2f-cert-out metadata/u2f-attestation.der

uv run python host_tools/export_certification_metadata.py \
  --statement metadata/statement.json \
  --profile u2f \
  --u2f-attestation-cert metadata/u2f-attestation.der

If U2F metadata reports an attestation SKID or certificate-path mismatch, regenerate metadata/u2f-attestation.der and metadata/metadata-u2f.json from the same device build you are testing. Older builds regenerated U2F attestation during reset, so metadata captured before a reset can be stale.

If the conformance tool changes PIN state, regenerate metadata with the matching --client-pin-state before rerunning that profile.

Support

ZeroFIDO is built and maintained in spare time. If it helped you, you can support the work here:

Buy me a coffee

Support is optional and does not affect releases, issues, or support requests.

License

ZeroFIDO uses the GNU General Public License, version 3 or later. See LICENSE.

Dependency and provenance notes live in THIRD_PARTY_NOTICES.md.

Sponsor this project

Packages

 
 
 

Contributors