use crate::error::{Error, Result};
use soft_fido2_ctap::types::{RelyingParty, User};
use alloc::string::String;
use alloc::vec;
use alloc::vec::Vec;
pub const DEFAULT_TIMEOUT_MS: i32 = 30000;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ClientDataHash([u8; 32]);
impl ClientDataHash {
pub fn new(hash: [u8; 32]) -> Self {
Self(hash)
}
pub fn from_slice(slice: &[u8]) -> Result<Self> {
if slice.len() != 32 {
return Err(Error::InvalidClientDataHash);
}
let mut hash = [0u8; 32];
hash.copy_from_slice(slice);
Ok(Self(hash))
}
pub fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
pub fn as_slice(&self) -> &[u8] {
&self.0
}
}
impl AsRef<[u8]> for ClientDataHash {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl From<[u8; 32]> for ClientDataHash {
fn from(hash: [u8; 32]) -> Self {
Self::new(hash)
}
}
#[non_exhaustive]
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub enum CredentialType {
#[default]
PublicKey,
}
impl CredentialType {
pub fn as_str(&self) -> &'static str {
match self {
CredentialType::PublicKey => "public-key",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CredentialDescriptor {
pub id: Vec<u8>,
pub credential_type: CredentialType,
}
impl CredentialDescriptor {
pub fn new(id: Vec<u8>, credential_type: CredentialType) -> Self {
Self {
id,
credential_type,
}
}
pub fn public_key(id: Vec<u8>) -> Self {
Self {
id,
credential_type: CredentialType::PublicKey,
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum PinUvAuthProtocol {
V1 = 1,
V2 = 2,
}
impl PinUvAuthProtocol {
pub fn as_u8(self) -> u8 {
self as u8
}
}
impl From<PinUvAuthProtocol> for u8 {
fn from(protocol: PinUvAuthProtocol) -> u8 {
protocol.as_u8()
}
}
#[derive(Debug, Clone)]
pub struct PinUvAuth {
param: Vec<u8>,
protocol: PinUvAuthProtocol,
}
impl PinUvAuth {
pub fn new(param: Vec<u8>, protocol: PinUvAuthProtocol) -> Self {
Self { param, protocol }
}
pub fn param(&self) -> &[u8] {
&self.param
}
pub fn protocol(&self) -> PinUvAuthProtocol {
self.protocol
}
pub fn protocol_u8(&self) -> u8 {
self.protocol.as_u8()
}
}
#[derive(Debug)]
pub struct MakeCredentialRequest {
pub(crate) client_data_hash: ClientDataHash,
pub(crate) rp: RelyingParty,
pub(crate) user: User,
pub(crate) pin_uv_auth: Option<PinUvAuth>,
pub(crate) timeout_ms: i32,
pub(crate) resident_key: Option<bool>,
pub(crate) user_verification: Option<bool>,
pub(crate) algorithms: Vec<i32>,
}
impl MakeCredentialRequest {
pub fn new(client_data_hash: ClientDataHash, rp: RelyingParty, user: User) -> Self {
Self {
client_data_hash,
rp,
user,
pin_uv_auth: None,
timeout_ms: DEFAULT_TIMEOUT_MS, resident_key: None,
user_verification: None,
algorithms: vec![-7], }
}
pub fn with_pin_uv_auth(mut self, auth: PinUvAuth) -> Self {
self.pin_uv_auth = Some(auth);
self
}
pub fn with_timeout(mut self, timeout_ms: i32) -> Self {
self.timeout_ms = timeout_ms;
self
}
pub fn with_resident_key(mut self, resident_key: bool) -> Self {
self.resident_key = Some(resident_key);
self
}
pub fn with_user_verification(mut self, user_verification: bool) -> Self {
self.user_verification = Some(user_verification);
self
}
pub fn with_algorithms(mut self, algorithms: Vec<i32>) -> Self {
self.algorithms = algorithms;
self
}
pub fn client_data_hash(&self) -> &ClientDataHash {
&self.client_data_hash
}
pub fn rp(&self) -> &RelyingParty {
&self.rp
}
pub fn user(&self) -> &User {
&self.user
}
pub fn pin_uv_auth(&self) -> Option<&PinUvAuth> {
self.pin_uv_auth.as_ref()
}
pub fn timeout_ms(&self) -> i32 {
self.timeout_ms
}
pub fn algorithms(&self) -> &[i32] {
&self.algorithms
}
}
#[derive(Debug)]
pub struct GetAssertionRequest {
pub(crate) client_data_hash: ClientDataHash,
pub(crate) rp_id: String,
pub(crate) allow_list: Vec<CredentialDescriptor>,
pub(crate) pin_uv_auth: Option<PinUvAuth>,
pub(crate) timeout_ms: i32,
pub(crate) user_verification: Option<bool>,
}
impl GetAssertionRequest {
pub fn new(client_data_hash: ClientDataHash, rp_id: impl Into<String>) -> Self {
Self {
client_data_hash,
rp_id: rp_id.into(),
allow_list: Vec::new(),
pin_uv_auth: None,
timeout_ms: DEFAULT_TIMEOUT_MS, user_verification: None,
}
}
pub fn with_credential(mut self, credential: CredentialDescriptor) -> Self {
self.allow_list.push(credential);
self
}
pub fn with_credentials(mut self, credentials: Vec<CredentialDescriptor>) -> Self {
self.allow_list = credentials;
self
}
pub fn with_pin_uv_auth(mut self, auth: PinUvAuth) -> Self {
self.pin_uv_auth = Some(auth);
self
}
pub fn with_timeout(mut self, timeout_ms: i32) -> Self {
self.timeout_ms = timeout_ms;
self
}
pub fn with_user_verification(mut self, user_verification: bool) -> Self {
self.user_verification = Some(user_verification);
self
}
pub fn client_data_hash(&self) -> &ClientDataHash {
&self.client_data_hash
}
pub fn rp_id(&self) -> &str {
&self.rp_id
}
pub fn allow_list(&self) -> &[CredentialDescriptor] {
&self.allow_list
}
pub fn pin_uv_auth(&self) -> Option<&PinUvAuth> {
self.pin_uv_auth.as_ref()
}
pub fn timeout_ms(&self) -> i32 {
self.timeout_ms
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Permission {
MakeCredential = 0x01,
GetAssertion = 0x02,
CredentialManagement = 0x04,
BioEnrollment = 0x08,
LargeBlobWrite = 0x10,
AuthenticatorConfiguration = 0x20,
}
impl Permission {
pub fn to_u8(self) -> u8 {
self as u8
}
}
#[derive(Debug, Clone)]
pub struct CredentialManagementRequest {
pin_uv_auth: Option<PinUvAuth>,
}
impl CredentialManagementRequest {
pub fn new(pin_uv_auth: Option<PinUvAuth>) -> Self {
Self { pin_uv_auth }
}
pub fn pin_uv_auth(&self) -> Option<&PinUvAuth> {
self.pin_uv_auth.as_ref()
}
}
#[derive(Debug, Clone)]
pub struct EnumerateCredentialsRequest {
pin_uv_auth: Option<PinUvAuth>,
rp_id_hash: [u8; 32],
}
impl EnumerateCredentialsRequest {
pub fn new(pin_uv_auth: Option<PinUvAuth>, rp_id_hash: [u8; 32]) -> Self {
Self {
pin_uv_auth,
rp_id_hash,
}
}
pub fn pin_uv_auth(&self) -> Option<&PinUvAuth> {
self.pin_uv_auth.as_ref()
}
pub fn rp_id_hash(&self) -> &[u8; 32] {
&self.rp_id_hash
}
}
#[derive(Debug, Clone)]
pub struct DeleteCredentialRequest {
pin_uv_auth: Option<PinUvAuth>,
credential_id: Vec<u8>,
}
impl DeleteCredentialRequest {
pub fn new(pin_uv_auth: Option<PinUvAuth>, credential_id: Vec<u8>) -> Self {
Self {
pin_uv_auth,
credential_id,
}
}
pub fn pin_uv_auth(&self) -> Option<&PinUvAuth> {
self.pin_uv_auth.as_ref()
}
pub fn credential_id(&self) -> &[u8] {
&self.credential_id
}
}
#[derive(Debug, Clone)]
pub struct UpdateUserRequest {
pin_uv_auth: Option<PinUvAuth>,
credential_id: Vec<u8>,
user: User,
}
impl UpdateUserRequest {
pub fn new(pin_uv_auth: Option<PinUvAuth>, credential_id: Vec<u8>, user: User) -> Self {
Self {
pin_uv_auth,
credential_id,
user,
}
}
pub fn pin_uv_auth(&self) -> Option<&PinUvAuth> {
self.pin_uv_auth.as_ref()
}
pub fn credential_id(&self) -> &[u8] {
&self.credential_id
}
pub fn user(&self) -> &User {
&self.user
}
}