Rust FIDO2 CTAP library ( and cli tool ctapcli ).
Authentication using FIDO2-compliant security keys (e.g. Yubikey) is possible.
- Register and Authenticate.
- Register or change PIN.
- Enrollment and deletion of fingerprints.
- Management of credentials recorded in security keys.
use ctap_hid_fido2::{
fidokey::{GetAssertionArgsBuilder, MakeCredentialArgsBuilder},
verifier, Cfg, FidoKeyHidFactory,
};
fn main() {
let rpid = "reg-auth-example-app";
let pin = get_input_with_message("input PIN:");
println!("Register");
// create `challenge`
let challenge = verifier::create_challenge();
// create `MakeCredentialArgs`
let make_credential_args = MakeCredentialArgsBuilder::new(rpid, &challenge)
.pin(&pin)
.build();
// create `FidoKeyHid`
let device = FidoKeyHidFactory::create(&Cfg::init()).unwrap();
// get `Attestation` Object
let attestation = device
.make_credential_with_args(&make_credential_args)
.unwrap();
println!("- Register Success");
// verify `Attestation` Object
let verify_result = verifier::verify_attestation(rpid, &challenge, &attestation);
if !verify_result.is_success {
println!("- ! Verify Failed");
return;
}
// store Credential Id and Publickey
let userdata_credential_id = verify_result.credential_id;
let userdata_credential_public_key = verify_result.credential_public_key;
println!("Authenticate");
// create `challenge`
let challenge = verifier::create_challenge();
// create `GetAssertionArgs`
let get_assertion_args = GetAssertionArgsBuilder::new(rpid, &challenge)
.pin(&pin)
.credential_id(&userdata_credential_id)
.build();
// get `Assertion` Object
let assertions = device.get_assertion_with_args(&get_assertion_args).unwrap();
println!("- Authenticate Success");
// verify `Assertion` Object
if !verifier::verify_assertion(
rpid,
&userdata_credential_public_key,
&challenge,
&assertions[0],
) {
println!("- ! Verify Assertion Failed");
}
}
pub fn get_input() -> String {
let mut word = String::new();
std::io::stdin().read_line(&mut word).ok();
return word.trim().to_string();
}
pub fn get_input_with_message(message: &str) -> String {
println!("{}", message);
let input = get_input();
println!();
input
}- See [How to use](#How to use) and Examples for detailed instructions.
ctap-hid-fido2 is a crate implementing CTAP 2.0 and 2.1, allowing direct control of FIDO2-compliant Authenticators such as Yubikey.
For more information on FIDO, see FIDO Alliance Page.
- Implements FIDO2 CTAP 2.0 & 2.1 (HID)
- Client to Authenticator Protocol (CTAP)
- Supported FIDO key
- Yubikey Bio
- Yubikey
- FEITIAN ePass FIDO(A4B)
- FEITIAN BioPass K27 USB Security Key
- FEITIAN AllinPass FIDO2 K33
- SoloKey
- Nitrokey FIDO2
- OpenSK
- Idem Key
gebo
Nothing in particular to worry about using it.
- Run as administrator
In Windows, the security key via HID cannot be accessed unless the executing exe has administrator privileges.
- installing
libusbandlibudevpackage
(The same may be true for Linux, such as Ubuntu)
If you get the following error with the libusb-1.0 dependency and cannot build, you can solve the problem by doing the following.
sudo apt install -y libusb-1.0-0-dev libudev-devThis crate uses either ring or aws-lc-rs for cryptography. Choose one via Cargo features.
| Feature | Description |
|---|---|
| ring | Default. Uses ring as the crypto backend. |
| aws-lc-rs | Uses aws-lc-rs (Apache 2.0 / BSD). |
| fips | Builds aws-lc-rs in FIPS-validated mode. For regulated environments. |
- By default ring is enabled (
default = ["ring"]). - To use aws-lc-rs:
cargo build --no-default-features --features aws-lc-rs - To use FIPS mode:
cargo build --no-default-features --features fips
FIPS build requires Go and CMake (e.g.brew install go cmakeon macOS).
When using as a dependency:
ctap-hid-fido2 = "3.5" # default: ring
ctap-hid-fido2 = { version = "3.5", default-features = false, features = ["aws-lc-rs"] }
ctap-hid-fido2 = { version = "3.5", default-features = false, features = ["fips"] }PIN has to be set
Unless noted in the following Examples, a PIN must be set in the Authenticator.
create FidoKeyHid object
First, create a device object with FidoKeyHidFactory::create.
If no Authenticator can be detected on the HID device, an error will result.
use ctap_hid_fido2::{Cfg, FidoKeyHidFactory};
...
let device = match FidoKeyHidFactory::create(&Cfg::init()) {
Ok(d) => d,
Err(e) => {
println!("error: {:?}", e);
return;
}
};If more than one Authenticator is detected, an error will result. See the following description for Multi-Authenticator support
Cfg
The argument Cfg is fine with the default value you create using init(), but you can customize it to change the behavior a bit, see Cfg definition.
FidoKeyHid
Use Authenticator with the methods implemented in FidoKeyHid.
For example, get_pin_retries() can be used to obtain the number of PIN retries.
match device.get_pin_retries() {
Ok(retry) => println!("{}", retry),
Err(e) => println!("error: {:?}", e),
}Multi-Authenticator support
If you have multiple Authenticators connected to the HID and want to control each device individually, use get_fidokey_devices() and create_by_params().
let devs = ctap_hid_fido2::get_fidokey_devices();
for dev in devs {
println!("- vid=0x{:04x} , pid=0x{:04x} , info={:?}",dev.vid, dev.pid, dev.info);
let fidokey = FidoKeyHidFactory::create_by_params(&vec![dev.param], &Cfg::init()).unwrap();
let info = fidokey.get_info().unwrap();
println!("{}", info);
}See the following links for examples of various patterns.
CLI tool can be used.