Rust FFI bindings for the keylib C API.
Add to your Cargo.toml:
[dependencies]
keylib = { version = "0.1", features = ["bundled"] }The bundled feature downloads prebuilt native libraries, so you don't need to install Zig or
libudev-dev. Just run:
cargo buildThat's it! No additional setup required.
Enable the bundled feature (shown above). This will automatically download prebuilt binaries for
your platform during build.
Supported platforms:
x86_64-unknown-linux-gnuaarch64-unknown-linux-gnux86_64-unknown-linux-musl
If you want to build from source or need a different platform:
In case you are downloading / checking out this repository directly via git, make sure to initialize the git submodules after cloning!
git submodule update --initTools required for building:
- Rust toolchain (stable)
- Zig compiler (for building keylib) - Install Zig
- libudev library (
sudo apt-get install libudev-devon Ubuntu/Debian)
Then omit the bundled feature:
[dependencies]
keylib = "0.1"- Safe Rust API with proper error handling
- RAII-based resource management
- Callback bridging from Rust closures to C function pointers
- Complete callback system (UP/UV/Select/Read/Write/Delete)
- Full CTAP protocol implementation
- PIN/UV Authentication Protocol - Complete CTAP 2.0/2.1 PIN protocol support
- ECDH key agreement (P-256)
- PIN protocol V1 (AES-256-CBC) and V2 (HMAC-based encryption)
- PIN token retrieval with permissions
- Shared secret derivation and encryption/decryption
- Credential Management API - Complete implementation for managing discoverable credentials
- Examples demonstrating client and authenticator usage
- Base64-encoded credential display for debugging
- PEM-formatted certificate display in examples
- USB HID transport layer
- Client-side device enumeration and communication
- Virtual authenticator support via UHID (Linux)
- Prebuilt binaries - Zero-setup builds with the
bundledfeature
This crate provides safe Rust abstractions over the unsafe FFI bindings.
Authenticator: Safe wrapper for authenticator instances with callback supportAuthenticatorConfig: Builder pattern for configuring authenticators with custom settingsAuthenticatorOptions: Fine-grained control over authenticator capabilities (rk, up, uv, clientPin, credMgmt, etc.)CtapCommand: Type-safe enum for CTAP commands (MakeCredential, GetAssertion, etc.)Callbacks: Configuration for user interaction callbacks (UP/UV/Select/Read/Write/Delete)CredentialManagement: Safe API for managing discoverable credentials on authenticatorsError: Error types that can occur during operationsClient: Client-side API for communicating with authenticatorsCredential: Representation of credentials stored on authenticators
You can customize the authenticator with specific AAGUID, commands, options, and extensions:
use keylib::{
Authenticator, AuthenticatorConfig, AuthenticatorOptions,
CallbacksBuilder, CtapCommand, UpResult
};
use std::sync::Arc;
// Configure specific capabilities
let options = AuthenticatorOptions::new()
.with_resident_keys(true)
.with_user_verification(Some(true)) // UV capable and configured
.with_client_pin(Some(true)) // PIN capable and set
.with_credential_management(Some(true));
// Build full configuration
let config = AuthenticatorConfig::builder()
.aaguid([0x6f, 0x15, 0x82, 0x74, 0xaa, 0xb6, 0x44, 0x3d,
0x9b, 0xcf, 0x8a, 0x3f, 0x69, 0x29, 0x7c, 0x88])
.commands(vec![
CtapCommand::MakeCredential,
CtapCommand::GetAssertion,
CtapCommand::GetInfo,
CtapCommand::ClientPin,
])
.options(options)
.max_credentials(100) // Allow up to 100 resident keys
.extensions(vec!["credProtect".to_string(), "hmac-secret".to_string()])
.build();
let callbacks = CallbacksBuilder::new()
.up(Arc::new(|_info, _user, _rp| Ok(UpResult::Accepted)))
.build();
let auth = Authenticator::with_config(callbacks, config)?;Configuration Options:
- AAGUID: Custom 16-byte authenticator identifier
- Commands: Select which CTAP commands to enable (default: MakeCredential, GetAssertion, GetInfo, ClientPin, Selection)
- Custom Commands: Add vendor-specific commands (0x40-0xFF) with custom handlers
- Options: Fine-tune capabilities:
rk: Resident key (discoverable credentials) supportup: User presence capabilityuv: User verification (None/Some(false)/Some(true) for not capable/capable but not configured/capable and configured)plat: Platform device flagclient_pin: Client PIN capability and statuspin_uv_auth_token: PIN/UV auth token supportcred_mgmt: Credential management supportbio_enroll: Biometric enrollment supportlarge_blobs: Large blobs supportep: Enterprise attestationalways_uv: Always require user verification
- Max Credentials: Maximum number of discoverable credentials (default: 25)
- Extensions: List of supported extensions (e.g., "credProtect", "hmac-secret", "largeBlobKey")
You can extend the CTAP protocol with vendor-specific commands:
use keylib::{AuthenticatorConfig, CustomCommand};
use std::sync::Arc;
// Define a custom command handler
let custom_handler = Arc::new(|_auth, request, response| {
// Parse request, perform operation, write response
response[0] = 0x00; // CTAP2_OK
1 // Response length
});
let custom_cmd = CustomCommand::new(0x41, custom_handler);
let config = AuthenticatorConfig::builder()
.commands(vec![
CtapCommand::MakeCredential,
CtapCommand::GetAssertion,
// ... standard commands ...
])
.custom_commands(vec![custom_cmd])
.build();Custom commands allow you to:
- Implement vendor-specific functionality
- Extend credential management with custom operations
- Add proprietary features while maintaining CTAP2 compatibility
- Use command bytes 0x40-0xFF (standard CTAP2 uses 0x01-0x0b)
See examples/custom_commands.rs for a complete example.
See examples/advanced_config.rs for a complete
demonstration.