-
Notifications
You must be signed in to change notification settings - Fork 2
Getting Started
Welcome, this guide should help you get started with keylib. If you have any questions or encounter bugs, please open an issue.
Keylib is a library designed to assist you in implementing PassKeys, which are platform authenticators compatible with FIDO2. This library handles the task of generating new credentials and assertions when required, and your responsibility is to furnish it with the necessary callbacks. Keylib currently offers two interfaces, one for Zig and another one for C.
The first step when using this library is to implement the required callbacks (C, Zig).
C
The first thing we must do is include the keylib.h
, header file into our code. This file includes enum definitions, the callback signatures, the definition of the Data
struct which we will need when implementing the read
callback, and functions for interacting with the library.
#include "keylib/keylib.h" // Data, Denied, DoesNotExist
Next we implement the uv
(user verification) and up
(user presence) callbacks. The uv
callback is used to authenticate a user, e.g. by asking for a password. What authentication method you want to use for your application is up to you. The up
callback is used to verify the (physical) presence of a user. You can for example do this by displaying a button the user can click on. Both functions return Accepted
on success, Denied
if rejected (e.g. user entered wrong password or clicked cancel), and Timeout
if a timeout has occurred.
// Make a user presence check, e.g. display a button and ask the user if she wants to confirm the action.
// The arguments info, user, and rp are null terminated strings that provide additional context that
// you can display.
//
// This function should return Accepted, Denied, or Timeout
int my_up(const char* info, const char* user, const char* rp) {
printf("up\n");
return Denied;
}
// This callback should implement some form of user verification, e.g. when called, ask a user for a password.
//
// This function should return Accepted, Denied, or Timeout
int my_uv() {
printf("uv\n");
return Denied;
}
Next we implement the select_cred
callback. This callback is used if more than one credential is bound to the same relying party (the service the credential was created for). The callback will provide a null terminated array of user strings. Those strings should be displayed on the screen and the user must then select a user. The function returns either a user index (starting from 0) or a negative error value.
// Let the user select one of multiple credentials associated with a relying party.
//
// You should either return the users index or -1.
int my_select_cred(const char* rpId, char** users) {
printf("select\n");
return -1;
}
The authenticator also needs some way to read
, write
and delete
data. The read
callback takes a id
string (the unique credential id), a rp
string (the relying party id/ base url), and a pointer to a string array.
- If
id
is not null:- Create a string array with two elements, where the first element contains the requested data and the second element is a null terminator. Assign the array to out. Then return
SUCCESS
.
- Create a string array with two elements, where the first element contains the requested data and the second element is a null terminator. Assign the array to out. Then return
- If
id
is null andrp
is not null:- Create a null terminated string array that contains all data associated with the given
rp
. Assign the array to out. Then returnSUCCESS
.
- Create a null terminated string array that contains all data associated with the given
- Else:
- Create a null terminated string array that contains all stored data. Assign the array to out. Then return
SUCCESS
.
- Create a null terminated string array that contains all stored data. Assign the array to out. Then return
Return DoesNotExist
if no data could be found.
// Read data from permanent storage.
int my_read(const char* id, const char* rp, char*** out) {
printf("read");
return DoesNotExist;
}
NOTE: It is important that the array itself and all (data) strings are null terminated!
The following is an example how the creation of a array with one element could look like:
char** x = malloc(sizeof(char*) * 2); x[0] = data; // think of data as a hex encodex, null terminated string x[1] = NULL; *out = x; return Error_SUCCESS;
All memory assigned to
out
is owned by the authenticator, i.e. it's NOT you responsibility to free it.
The write
callback is used to persist the given data
. It is both used to create new entries and to update existing ones. You can assume that the credential id
is unique, i.e. if the id already exists update (overwrite) the existing entry, otherwise create a new one. Make sure you associate the data with the given relying party id (rp
) so you can find it later.
// Persist the given data and make sure that it can be found using its id and associated rp (relying party).
int my_write(const char* id, const char* rp, const char* data) {
printf("write");
return -1;
}
The delete
callback is quite simple, find and delete the data associated with the given id
.
// Delete the data associated with the given id.
int my_delete(const char* id, const char* rp) {
printf("delete\n");
return -1;
}