Rust FIDO2 CTAP library
Some features of CTAP2.1PRE have been implemented.
for Mac & Win & raspberry Pi
gebo
``` [dependencies]
serde_cbor = "0.11.1" ```
$ chmod +x test_for_pi.sh
$ ./test_for_pi.sh
6.4. authenticatorGetInfo (0x04)
Using this method, platforms can request that the authenticator report a list of its supported protocol versions and extensions, its AAGUID, and other aspects of its overall capabilities. Platforms should use this information to tailor their command parameters choices.
```rust use ctaphidfido2; use ctaphidfido2::HidParam;
fn main() { println!("getinfo()"); match ctaphidfido2::getinfo(&ctaphidfido2::HidParam::getdefaultparams()) { Ok(info) => println!("{}",info), Err(e) => println!("error: {:?}", e), } } ```
console
sh
get_info()
- versions = ["U2F_V2", "FIDO_2_0", "FIDO_2_1_PRE"]
- extensions = ["credProtect", "hmac-secret"]
- aaguid(16) = EE882879721C491397753DFCCE97072A
- options = [("rk", true), ("up", true), ("plat", false), ("clientPin", true), ("credentialMgmtPreview", true)]
- max_msg_size = 1200
- pin_uv_auth_protocols = [1]
- max_credential_count_in_list = 8
- max_credential_id_length = 128
- transports = ["usb"]
- algorithms = [("alg", "-7"), ("type", "public-key"), ("alg", "-8"), ("type", "public-key")]
Created to test CTAPHID_MSG.
```rust use ctaphidfido2; use ctaphidfido2::HidParam;
fn main() { println!("getinfou2f()"); match ctaphidfido2::getinfou2f(&HidParam::getdefaultparams()) { Ok(result) => println!("{:?}", result), Err(e) => println!("error: {:?}", e), } } ```
console
sh
get_info_u2f()
"U2F_V2"
6.5.2.2. PIN-Entry and User Verification Retries Counters
pinRetries counter represents the number of attempts left before PIN is disabled.
```Rust use ctaphidfido2; use ctaphidfido2::HidParam;
fn main() { println!("getpinretries()"); match ctaphidfido2::getpinretries(&HidParam::getdefaultparams()) { Ok(retry) => println!("{}", retry), Err(e) => println!("error: {:?}", e), }; } ```
console
sh
get_pin_retries()
8
Same as get_info(), but checks if it has a specific feature/version.
It is specified by the enum of InfoParam.
rust
match ctap_hid_fido2::enable_info_param(&HidParam::get_default_params(),InfoParam::VersionsFIDO21PRE) {
Ok(result) => println!("FIDO 2.1 PRE = {:?}", result),
Err(e) => println!("- error: {:?}", e),
};
Same as get_info(), but checks if it has a specific option.
It is specified by the enum of InfoOption.
Option<bool>
Some(true)
: option is present and set to trueSome(false)
: option is present and set to falseNone
: option is absentrust
match ctap_hid_fido2::enable_info_option(&HidParam::get_default_params(),InfoOption::BioEnroll) {
Ok(result) => println!("BioEnroll = {:?}", result),
Err(e) => println!("- error: {:?}", e),
};
Just blink the LED on the FIDO key.
```Rust use ctaphidfido2;
fn main() { println!("----- wink start -----"); if let Err(msg) = ctaphidfido2::wink(&ctaphidfido2::HidParam::getdefaultparams()){ println!("error: {:?}", msg); } println!("----- wink end -----"); } ```
```rust use anyhow::Result; use ctaphidfido2; use ctaphidfido2::util; use ctaphidfido2::verifier; use ctaphidfido2::HidParam;
fn main() -> Result<()> { println!("----- test-with-pin-non-rk start -----");
// parameter
let rpid = "test.com";
let pin = "1234";
let challenge = verifier::create_challenge();
// Register
println!("Register - make_credential()");
println!("- rpid = {:?}", rpid);
println!(
"- challenge({:02}) = {:?}",
challenge.len(),
util::to_hex_str(&challenge)
);
let att = ctap_hid_fido2::make_credential(
&HidParam::get_default_params(),
rpid,
&challenge,
Some(pin),
)?;
println!("- Register Success!!");
println!("Attestation");
println!("{}", att);
println!("Verify");
let verify_result = verifier::verify_attestation(rpid, &challenge, &att);
println!(
"- is_success = {:?}",
verify_result.is_success
);
println!(
"- credential_id({:02}) = {:?}",
verify_result.credential_id.len(),
util::to_hex_str(&verify_result.credential_id)
);
println!(
"- credential_publickey_der({:02}) = {:?}",
verify_result.credential_publickey_der.len(),
util::to_hex_str(&verify_result.credential_publickey_der)
);
println!("");
// Authenticate
println!("Authenticate - get_assertion_with_pin()");
let challenge = verifier::create_challenge();
println!(
"- challenge({:02}) = {:?}",
challenge.len(),
util::to_hex_str(&challenge)
);
let ass = ctap_hid_fido2::get_assertion(
&HidParam::get_default_params(),
rpid,
&challenge,
&verify_result.credential_id,
Some(pin),
)?;
println!("- Authenticate Success!!");
println!("Assertion");
println!("{}", ass);
println!("Verify");
let is_success = verifier::verify_assertion(
rpid,
&verify_result.credential_publickey_der,
&challenge,
&ass,
);
println!("- is_success = {:?}", is_success);
println!("----- test-with-pin-non-rk end -----");
Ok(())
} ```
console
```sh ----- test-with-pin-non-rk start ----- Register - makecredential() - rpid = "test.com" - challenge(32) = "054E416942D60F9F584B58A1E53B3ED85E9ECBB486D72CE690569E884B038267" - touch fido key - Register Success!! Attestation - rpidhash(32) = 99AB715D84A3BC5E0E92AA50E67A5813637FD1744BD301AB08F87191DDB816E0 - flagsuserpresentresult = true - flagsuserverifiedresult = true - flagsattestedcredentialdataincluded = true - flagsextensiondataincluded = false - signcount = 1 - aaguid(16) = EE882879721C491397753DFCCE97072A - credentialdescriptor = (id : 4AE2... , type : ) - credentialpublickey = (der : 04A0... , pem : -----BEGIN PUBLIC KEY-----...) - attstmtalg = -7 - attstmtsig(71) = 3045... - attstmtx5cnum = 1 Verify - issuccess = true - credentialid(64) = "4AEA..." - credentialpublickeyder(65) = "04A0..."
Authenticate - getassertionwithpin() - challenge(32) = "0B1A3BF49C6D335592EE789C9C662365E06F4D9A63E6C4EA5B62B221E072A33E" - touch fido key - Authenticate Success!! Assertion - rpidhash(32) = 99AB715D84A3BC5E0E92AA50E67A5813637FD1744BD301AB08F87191DDB816E0 - flagsuserpresentresult = true - flagsuserverifiedresult = true - flagsattestedcredentialdataincluded = false - flagsextensiondataincluded = false - signcount = 4 - numberofcredentials = 0 - signature(71) = 3045... - user = (id : , name : , displayname : ) - credentialid(64) = 4AEA... Verify - is_success = true ----- test-with-pin-non-rk end ----- ```
```rust use anyhow::Result; use ctaphidfido2; use ctaphidfido2::publickeycredentialuserentity::PublicKeyCredentialUserEntity; use ctaphidfido2::util; use ctaphidfido2::verifier; use ctaphidfido2::HidParam;
fn main() -> Result<()> { println!("----- test-with-pin-rk start -----");
// parameter
let rpid = "ge.com";
let pin = "1234";
// Register
println!("Register - make_credential()");
let challenge = verifier::create_challenge();
let rkparam = PublicKeyCredentialUserEntity::new(Some(b"1111"),Some("gebo"),Some("GEBO GEBO"));
println!("- rpid = {:?}", rpid);
println!(
"- challenge({:02}) = {:?}",
challenge.len(),
util::to_hex_str(&challenge)
);
println!("- rkparam = {}", rkparam);
let att = ctap_hid_fido2::make_credential_rk(
&HidParam::get_default_params(),
rpid,
&challenge,
Some(pin),
&rkparam,
)?;
println!("- Register Success!!");
println!("{}", att);
println!("Verify");
let verify_result = verifier::verify_attestation(rpid, &challenge, &att);
println!(
"- is_success = {:?}",
verify_result.is_success
);
println!(
"- credential_publickey_der({:02}) = {:?}",
verify_result.credential_publickey_der.len(),
util::to_hex_str(&verify_result.credential_publickey_der)
);
println!(
"- credential_id({:02}) = {:?}",
verify_result.credential_id.len(),
util::to_hex_str(&verify_result.credential_id)
);
// Authenticate
println!("Authenticate - get_assertions_rk()");
let challenge = verifier::create_challenge();
let asss = ctap_hid_fido2::get_assertions_rk(
&HidParam::get_default_params(),
rpid,
&challenge,
Some(pin),
)?;
println!("Authenticate Success!!");
println!("- Assertion Num = {:?}", asss.len());
for ass in asss {
println!("- assertion = {}", ass);
println!("- user = {}", ass.user);
}
println!("----- test-with-pin-rk end -----");
Ok(())
} ```
username and userdisplay_name are set only when multiple Assertions are acquired.
If you want to enable UV-user verification, please specify None instead of a PIN. makecredential(),getassertion()
This command manages discoverable credentials(resident key) in the authenticator.
6.8. authenticatorCredentialManagement (0x0A)
Get discoverable credentials metadata.
rust
match ctap_hid_fido2::credential_management_get_creds_metadata(
&ctap_hid_fido2::HidParam::get_default_params(),
pin,
) {
Ok(result) => println!("{}", result),
Err(e) => println!("- error: {:?}", e),
};
Enumerate RPs present on the authenticator.
rust
match ctap_hid_fido2::credential_management_enumerate_rps(&HidParam::get_default_params(), pin)
{
Ok(results) => {
for r in results {
println!("## rps\n{}", r);
}
}
Err(e) => println!("- error: {:?}", e),
}
Enumerate the credentials for a RP.
rust
match ctap_hid_fido2::credential_management_enumerate_credentials(
&HidParam::get_default_params(),
pin,
rpid_hash_bytes,
) {
Ok(results) => {
for c in results {
println!("## credentials\n{}", c);
}
}
Err(e) => println!("- error: {:?}", e),
}
Delete a credential.
```rust let mut pkcd = PublicKeyCredentialDescriptor::default(); pkcd.id = util::tostrhex(credentialid.unwrap()); pkcd.ctype = "publickey".to_string();
match ctaphidfido2::credentialmanagementdeletecredential( &HidParam::getdefaultparams(), pin, Some(pkcd), ) { Ok() => println!("- success"), Err(e) => println!("- error: {:?}",e), } ```
This command manages the fingerprints in the authenticator.
6.7. authenticatorBioEnrollment (0x09)
Get fingerprint sensor information.
Rust
match ctap_hid_fido2::bio_enrollment_get_fingerprint_sensor_info(
&HidParam::get_default_params(),
) {
Ok(result) => println!("- {:?}", result),
Err(e) => println!("- error: {:?}", e),
}
Enumurate a list of registered fingerprints.
Rust
match ctap_hid_fido2::bio_enrollment_enumerate_enrollments(
&HidParam::get_default_params(),
pin,
) {
Ok(infos) => for i in infos {println!("- {}", i)},
Err(e) => println!("- error: {:?}", e)
}
Enroll one fingerprint.
run bio_enrollment_begin
first and then bio_enrollment_next
several times.is_finish
detects the completion of registration.
```rust fn bioenrollment(pin: &str) -> Result<(), String> { println!("bioenrollmentbegin"); let result = ctaphidfido2::bioenrollmentbegin( &HidParam::getdefault_params(), pin, Some(10000), )?; println!("{}", result.1); println!("");
for _counter in 0..10 {
if bio_enrollment_next(&result.0)? {
break;
}
}
Ok(())
}
fn bioenrollmentnext(enrollstatus: &EnrollStatus1) -> Result
Update the registered name of the fingerprint.
rust
match ctap_hid_fido2::bio_enrollment_set_friendly_name(
&HidParam::get_default_params(),
pin,
TemplateInfo::new(util::to_str_hex(template_id), name),
) {
Ok(()) => println!("- Success"),
Err(e) => println!("- error: {:?}", e),
}
Delete a fingerprint.
rust
match ctap_hid_fido2::bio_enrollment_remove(
&HidParam::get_default_params(),
pin,
util::to_str_hex(template_id),
) {
Ok(_) => println!("- Success"),
Err(e) => println!("- error: {:?}", e),
}
for Nitrokey FIDO2 only.
Query the firmware version of Nitrokey.
rust
fn main() {
println!("----- Nitrokey GETVERSION start -----");
// get 4byte payload "2001" -> ver 2.0.0.1
match ctap_hid_fido2::nitrokey::get_version(&ctap_hid_fido2::HidParam::get_default_params()) {
Ok(version) => println!("version = {}", version),
Err(err) => println!("version = {}", err),
};
println!("----- Nitrokey GETVERSION end -----");
}
console
sh
----- Nitrokey GETVERSION start -----
version = 2.2.0.1
----- Nitrokey GETVERSION end -----
Query the Status of Nitrokey.
rust
fn main() {
println!("----- Nitrokey GETSTATUS start -----");
match ctap_hid_fido2::nitrokey::get_status(&ctap_hid_fido2::HidParam::get_default_params()) {
Ok(status) => status.print("status"),
Err(err) => println!("status = {}", err),
};
println!("----- Nitrokey GETSTATUS end -----");
}
console
sh
----- Nitrokey GETSTATUS start -----
status
- is_button_pressed_raw = false
- button_state = 3
- button_state = BstUnpressed
- last_button_cleared_time_delta = 131
- last_button_pushed_time_delta = 131
- led_is_blinking = false
- u2f_ms_clear_button_period = 200
- u2f_ms_init_button_period = 5
- button_min_press_t_ms = 100
----- Nitrokey GETSTATUS end -----
Generate a random number.
rust
fn main() {
println!("----- Nitrokey GETRNG start -----");
// get 8 byte rundom data
match ctap_hid_fido2::nitrokey::get_rng(&ctap_hid_fido2::HidParam::get_default_params(), 8) {
Ok(rng) => println!("rng = {}", rng),
Err(err) => println!("rng = {}", err),
};
println!("----- Nitrokey GETRNG end -----");
}
console
sh
----- Nitrokey GETRNG start -----
rng = D93C4D39DAA8FEF8
----- Nitrokey GETRNG end -----