license

ctap-hid-fido2

Rust FIDO2 CTAP library

for Mac & Win & raspberry Pi

Some features of CTAP2.1PRE have been implemented.

HMAC Secret Extension implemented.

Description

Author

gebo

Build and run

Windows

raspberry Pi

``` [dependencies]

hidapi = "1.2.3" <- comment out

serde_cbor = "0.11.1" ```

$ chmod +x test_for_pi.sh $ ./test_for_pi.sh

Examples

get_info()

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")]

getinfou2f()

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"

getpinretries()

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

enableinfoparam()

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), };

enableinfooption()

Same as get_info(), but checks if it has a specific option.
It is specified by the enum of InfoOption.

rust match ctap_hid_fido2::enable_info_option(&HidParam::get_default_params(),InfoOption::BioEnroll) { Ok(result) => println!("BioEnroll = {:?}", result), Err(e) => println!("- error: {:?}", e), };

wink()

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 -----"); } ```

Register and Authenticate ( non-discoverable credentials/non-resident-key)

```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 ----- ```

HMAC Secret Extension - Register

```Rust use ctaphidfido2::verifier; use ctaphidfido2::makecredentialparams::Extension as Mext; use ctaphidfido2::HidParam;

fn main() -> Result<()> {

let rpid = "test.com"; let pin = "1234"; let challenge = verifier::create_challenge();

let ext = Mext::HmacSecret(Some(true)); let att = ctaphidfido2::makecredentialwithextensions( &HidParam::getdefault_params(), rpid, &challenge, Some(pin), Some(&vec![ext]), )?; } ```

HMAC Secret Extension - Authenticate

```Rust use ctaphidfido2::verifier; use ctaphidfido2::getassertionparams::Extension as Gext; use ctaphidfido2::HidParam;

fn main() -> Result<()> {

let rpid = "test.com"; let pin = "1234"; let challenge = verifier::createchallenge(); let credentialid = ???;

let ext = Gext::createhmacsecretfromstring("this is salt"); let ass = ctaphidfido2::getassertionwithextensios( &HidParam::getdefaultparams(), rpid, &challenge, &credentialid, Some(pin), Some(&vec![ext]), )?; } ```

Register and Authenticate ( discoverable credentials/resident-key)

```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(())

} ```

CTAP 2.1 PRE

authenticatorCredentialManagement

This command manages discoverable credentials(resident key) in the authenticator.
6.8. authenticatorCredentialManagement (0x0A)

credentialmanagementgetcredsmetadata()

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), };

credentialmanagementenumerate_rps()

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), }

credentialmanagementenumerate_credentials()

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), }

credentialmanagementdelete_credential()

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), } ```

authenticatorBioEnrollment

This command manages the fingerprints in the authenticator.
6.7. authenticatorBioEnrollment (0x09)

bioenrollmentgetfingerprintsensor_info()

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), }

bioenrollmentenumerate_enrollments()

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) }

bioenrollmentbegin(),bioenrollmentnext()

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 { println!("bioenrollmentnext"); let result = ctaphidfido2::bioenrollmentnext(enrollstatus, Some(10000))?; println!("{}", result); println!(""); Ok(result.is_finish) } ```

bioenrollmentsetfriendlyname()

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), }

bioenrollmentremove()

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), }

Nitrokey Custom Commands

for Nitrokey FIDO2 only.

nitrokey::get_version()

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 -----

nitrokey::get_status()

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 -----

nitrokey::get_rng()

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 -----

Nitrokey Firmware Update Tool

see nitro-update

```zsh NitoroKey Firmwware Update Tool(Non-Formula)

USAGE: nitro-update [FLAGS] [OPTIONS]

FLAGS: -b, --bootloader Set to bootloader mode. -d, --download Download Firmware json file from Web. -h, --help Prints help information -i, --info Get Firmware Information. -V, --version Prints version information

OPTIONS: -j, --json Checking Firmware json file. -f, --flash Write firmware. ```