r4gus/keylib
FIDO2/ PassKey compatible authentication library
FIDO2 compatible authenticator and client library written in Zig. The authenticator part requires zero dynamic allocations.
We track the latest stable release of Zig (
0.12.0
)
If you want to see an example on how the library could be used, check out PassKeeZ.
Zig version | keylib version |
---|---|
0.13.0 | 0.5.0, 0.5.1, 0.5.2, 0.5.3 |
0.14.0 | 0.6.0 |
FIDO2 is a protocol designed for authentication purposes. It can be used as single factor (e.g., as a replacement for password based authentication) or as a second factor (e.g., instead of OTPs).
I've heard the term Passkey but what is that?Passkey is a marketing term which is used to refer to a specific FIDO2 authenticator configuration. A authenticator can be configured to use so called discoverable credentials (also referred to as resident keys). Those credentials are stored somewhere on your device, e.g. in a encrypted database. Devices can also be protected by some form of user verification. This can be a PIN or a built in user verification method like a finger print scanner. Passkey refers to FIDO2 using discoverable credentials and some form of user verification.
Please note that this is only one interpretation of what PassKey means as the term itself is nowhere defined (see also Passkeys's: A Shattered Dream).
How does it work?FIDO2 uses asymmetric cryptography to ensure the authenticity of the user. A unique credential (key-pair) is created for each relying party (typically a web server) and bound to the relying party id (e.g., google.com). The private key stays on the authenticator and the public key is stored by the relying party. When a user wants to authenticate herself, the relying party sends a nonce (a random byte string meant to be only used once) and some other data, over the client (typically your web browser), to the authenticator. The authenticator looks up the required private key and signs the data with it. The generated signature can then be verified by the relying party using the corresponding public key.
What is the difference between FIDO2, PassKey and WebAuthn?You might have noticed that FIDO2, PassKey and even WebAuthn are often used interchangeably by some articles and people which can be confusing, especially for people new to the protocol. Here is a short overview:
FIDO2
Protocol consisting of two sub-protocols: Client to Authenticator Protocol 2 (CTAP2
) and Web Authentication (WebAuthn
)CTAP2
Specification that governs how a authenticator (e.g. YubiKey) should behave and how a authenticator and a client (e.g. web-browser) can communicate with each other.WebAuthn
Specification that defines how web applications can use a authenticator for authentication. This includes the declaration of data structures and Java Script APIs.PassKey
: A authenticator with a specific configuration (see above).FIDO2 has a lot of advantages compared to passwords:
Yes, there are:
Answering this question isn't straightforward. The library, by its nature, is designed to be independent of any particular platform, meaning that you have the responsibility of supplying it with data for processing. To put it differently, you're in charge of creating a functional interface for communicating with a client, typically a web browser. On Linux, we offer a wrapper for the uhid interface, simplifying the process of presenting an application as a USB HID device with a Usage Page of F1D0 on the bus.
There are known issues with older browsers (including Firefox). Newer browser versions should work fine. Tested with:
Browser | Supported? | Tested version | Notes |
---|---|---|---|
Cromium | ✅ | 119.0.6045.159 (Official Build) Arch Linux (64-bit) | |
Brave | ✅ | Version 1.62.153 Chromium: 121.0.6167.85 (Official Build) (64-bit) | |
Firefox | ✅ | 122.0 (64-bit) | |
Opera | ✅ | version: 105.0.4970.16 chromium: 119.0.6045.159 |
Please let me know if you run into issues!
Does this library implement the whole CTAP2 sepc?No, we do not fully implement the entire CTAP2 specification. In the initial version of this library, which can be found on GitHub, our aim was to remain completely platform-agnostic and cover most of the CTAP2 specification. However, this approach introduced complexities for both users and developers. The current version of this library strikes a balance between usability and feature completeness.
We offer support for operations like authenticatorMakeCredential, authenticatorGetAssertion, authenticatorGetInfo, and authenticatorClientPin, with built-in support for user verification and the pinUvAuth protocol (versions 1 and 2). You are responsible for handling data management tasks (such as secure storage, updates, and deletions), verifying user presence, and conducting user verification. These responsibilities are fulfilled by implementing the necessary callbacks used to instantiate an authenticator (refer to the "Getting Started" section for details).
Zero dynamic allocations?The authenticator part of this library doesn't allocate any memory dynamically. This has some draw backs like a fixed size for strings (e.g., rpId, user name, etc.) but also reduces the complexity of the code.
The authenticator example uses 88655
bytes of stack space when compiled with -Doptimize=ReleaseSmall
on Linux (x86_64).
The authenticator example has been profiled using valgrind.
zig build auth-example -Doptimize=ReleaseSmall
valgrind --tool=drd --show-stack-usage=yes ./zig-out/bin/authenticator
- Test page: webauthn.io - Register + Authentication
thread 1 finished and used 88655 bytes out of 8388608 on its stack.
ThinkPad-X1-Yoga-3rd 6.5.0-35-generic #35~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC x86_64 GNU/Linux
We maintain two examples on how to use the library:
authenticator
- https://github.com/r4gus/keylib/blob/master/example/authenticator.zigclient
- https://github.com/r4gus/keylib/blob/master/example/client.zigFIDO2/Passkey test sites:
Microcontrollers like the rp2040 allow the creation of cheap authenticators but they provide no means to somehow protect secrets like master passwords, PINs, or credentials. One way one could securely store sensitive data is by making PIN protection mandatory. Note that this is a tradeof and will render some counters (like the pin retry counter) useless if an attacker has physical access to the chip, as one can not protect the counters from manipulation.