-
Notifications
You must be signed in to change notification settings - Fork 302
Add Support for User Verification (UV) and BioEnrollment #718
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
#[derive(Debug)] | ||
pub enum FingerprintCaptureError { | ||
NoTouch, | ||
ImageBad, | ||
ImagePartial, | ||
TooFast, | ||
Other, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub enum FingerprintCheckError { | ||
NoMatch, | ||
Timeout, | ||
Other, | ||
} | ||
|
||
pub trait Fingerprint { | ||
/// Get the maximum number of fingerprint enrollments the sensor can | ||
/// support. | ||
fn get_enrollment_count_maximum(&self) -> u8; | ||
|
||
/// Get the number of fingerprints currently enrolled. | ||
fn get_enrollment_count(&self) -> u8; | ||
|
||
/// Start an enrollment session for the fingerprint at the given index. | ||
/// | ||
/// `index` should be from 0 to `get_enrollment_count_maximum()-1`. | ||
fn prepare_enrollment(&self, index: u8); | ||
|
||
/// Capture a fingerprint image. | ||
/// | ||
/// `prepare_enrollment()` must be called first. | ||
/// | ||
/// Waits for a fingerprint image or returns if `timeout_ms` happens without | ||
/// a touch. | ||
/// | ||
/// ## Return | ||
/// | ||
/// `Ok(())` on success and `Err(())` on any failure. | ||
fn capture_sample(&self, timeout_ms: usize) -> Result<(), FingerprintCaptureError>; | ||
|
||
/// Store a fingerprint enrollment. | ||
/// | ||
/// ## Return | ||
/// | ||
/// `Ok(())` on success and `Err(())` on any failure. | ||
fn commit_enrollment(&self) -> Result<(), ()>; | ||
|
||
/// Cancel a fingerprint enrollment. | ||
fn cancel_enrollment(&self); | ||
|
||
/// Check all enrollments to see if they are enrolled. | ||
fn get_enrollments(&self, fingerlist: &mut [u8; 5]); | ||
|
||
/// Called before [`check_fingerprint()`]. | ||
/// | ||
/// Useful for starting any operation that needs to happen before | ||
/// potentially repeated fingerprint checks, such as blinking LEDs. | ||
fn check_fingerprint_init(&mut self); | ||
|
||
/// Require the user to touch the sensor and verify the fingerprint is | ||
/// valid. | ||
/// | ||
/// Waits for a fingerprint image or returns if `timeout_ms` happens without | ||
/// a touch. | ||
/// | ||
/// Returns: | ||
/// - `Ok(index)`: If fingerprint is valid, returns the index of the matched | ||
/// fingerprint. | ||
/// - `Err(e)`: Error if fingerprint is not valid. | ||
fn check_fingerprint(&self, timeout_ms: usize) -> Result<u8, FingerprintCheckError>; | ||
|
||
/// Called after checking fingerprints has finished. | ||
fn check_fingerprint_complete(&mut self); | ||
|
||
/// Delete the fingerprint enrolled at the given index. | ||
fn delete_enrollment(&self, index: u8); | ||
|
||
fn setloglevel(&self, level: u8); | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,7 @@ use crate::ctap::status_code::{Ctap2StatusCode, CtapResult}; | |
use crate::ctap::PIN_AUTH_LENGTH; | ||
use alloc::borrow::Cow; | ||
use alloc::boxed::Box; | ||
use alloc::string::String; | ||
use alloc::vec::Vec; | ||
use core::cmp; | ||
use core::convert::TryFrom; | ||
|
@@ -204,6 +205,27 @@ pub trait Persist { | |
self.remove(keys::PIN_RETRIES) | ||
} | ||
|
||
/// Returns the number of failed UV attempts. | ||
fn uv_fails(&self) -> CtapResult<u8> { | ||
match self.find(keys::UV_RETRIES)? { | ||
None => Ok(0), | ||
Some(value) if value.len() == 1 => Ok(value[0]), | ||
_ => Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR), | ||
} | ||
} | ||
|
||
/// Decrements the number of remaining UV retries. | ||
fn incr_uv_fails(&mut self) -> CtapResult<()> { | ||
let old_value = self.uv_fails()?; | ||
let new_value = old_value.saturating_add(1); | ||
self.insert(keys::UV_RETRIES, &[new_value]) | ||
} | ||
|
||
/// Resets the number of remaining UV retries. | ||
fn reset_uv_retries(&mut self) -> CtapResult<()> { | ||
self.remove(keys::UV_RETRIES) | ||
} | ||
|
||
/// Returns the minimum PIN length, if stored. | ||
fn min_pin_length(&self) -> CtapResult<Option<u8>> { | ||
match self.find(keys::MIN_PIN_LENGTH)? { | ||
|
@@ -386,6 +408,23 @@ pub trait Persist { | |
} | ||
} | ||
|
||
/// Store a Bio Enrollment friendly name for a given template_id. | ||
fn store_friendly_name(&mut self, template_id: u8, friendly_name: &str) -> CtapResult<()> { | ||
let key = keys::FRIENDLY_NAMES.start + template_id as usize; | ||
self.insert(key, friendly_name.as_bytes())?; | ||
Ok(()) | ||
} | ||
|
||
/// Retrieve the Bio Enrollment friendly name for a given template_id. | ||
fn get_friendly_name(&mut self, template_id: u8) -> CtapResult<String> { | ||
let key = keys::FRIENDLY_NAMES.start + template_id as usize; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. |
||
|
||
match self.find(key)? { | ||
None => Err(Ctap2StatusCode::CTAP1_ERR_OTHER), | ||
Some(value) => Ok(String::from_utf8(value).unwrap_or(String::from(""))), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should return an internal error if the value is not UTF-8. |
||
} | ||
} | ||
|
||
fn get_attestation(&self, id: AttestationId) -> CtapResult<Option<Attestation>> { | ||
let stored_id_bytes = self.find(keys::ATTESTATION_ID)?; | ||
if let Some(bytes) = stored_id_bytes { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -142,6 +142,12 @@ make_partition! { | |
/// | ||
/// If the entry is absent, the counter is 0. | ||
GLOBAL_SIGNATURE_COUNTER = 2047; | ||
|
||
/// Stored counter UV retries. | ||
UV_RETRIES = 2048; | ||
|
||
/// Stored friendly names for enrolled fingerprints. | ||
FRIENDLY_NAMES = 2100..2105; | ||
Comment on lines
+145
to
+150
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those should be between 2005 and 2037, or between 21 and 999, as per the comment line 60 reserving keys 2048 and above for migration purposes. Note that |
||
} | ||
|
||
#[cfg(test)] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should check
key < keys::FRIENDLY_NAMES.end
.