diff --git a/libraries/opensk/src/api/private_key.rs b/libraries/opensk/src/api/private_key.rs index c476a9a6..5d6771ae 100644 --- a/libraries/opensk/src/api/private_key.rs +++ b/libraries/opensk/src/api/private_key.rs @@ -16,7 +16,7 @@ use crate::api::crypto::ecdsa::{SecretKey as _, Signature}; use crate::ctap::crypto_wrapper::{aes256_cbc_decrypt, aes256_cbc_encrypt}; use crate::ctap::data_formats::{extract_array, extract_byte_string, CoseKey, SignatureAlgorithm}; use crate::ctap::secret::Secret; -use crate::ctap::status_code::Ctap2StatusCode; +use crate::ctap::status_code::{Ctap2StatusCode, CtapResult}; use crate::env::{AesKey, EcdsaSk, Env}; use alloc::vec; use alloc::vec::Vec; @@ -89,7 +89,7 @@ impl PrivateKey { } /// Returns the ECDSA private key. - pub fn ecdsa_key(&self) -> Result, Ctap2StatusCode> { + pub fn ecdsa_key(&self) -> CtapResult> { match self { PrivateKey::Ecdsa(bytes) => ecdsa_key_from_bytes::(bytes), #[allow(unreachable_patterns)] @@ -98,7 +98,7 @@ impl PrivateKey { } /// Returns the corresponding public key. - pub fn get_pub_key(&self) -> Result { + pub fn get_pub_key(&self) -> CtapResult { Ok(match self { PrivateKey::Ecdsa(bytes) => { CoseKey::from_ecdsa_public_key(ecdsa_key_from_bytes::(bytes)?.public_key()) @@ -109,7 +109,7 @@ impl PrivateKey { } /// Returns the encoded signature for a given message. - pub fn sign_and_encode(&self, message: &[u8]) -> Result, Ctap2StatusCode> { + pub fn sign_and_encode(&self, message: &[u8]) -> CtapResult> { Ok(match self { PrivateKey::Ecdsa(bytes) => ecdsa_key_from_bytes::(bytes)?.sign(message).to_der(), #[cfg(feature = "ed25519")] @@ -141,7 +141,7 @@ impl PrivateKey { &self, rng: &mut E::Rng, wrap_key: &AesKey, - ) -> Result { + ) -> CtapResult { let bytes = self.to_bytes(); let wrapped_bytes = aes256_cbc_encrypt::(rng, wrap_key, &bytes, true)?; Ok(cbor_array![ @@ -150,10 +150,7 @@ impl PrivateKey { ]) } - pub fn from_cbor( - wrap_key: &AesKey, - cbor_value: cbor::Value, - ) -> Result { + pub fn from_cbor(wrap_key: &AesKey, cbor_value: cbor::Value) -> CtapResult { let mut array = extract_array(cbor_value)?; if array.len() != 2 { return Err(Ctap2StatusCode::CTAP2_ERR_INVALID_CBOR); @@ -171,7 +168,7 @@ impl PrivateKey { } } -fn ecdsa_key_from_bytes(bytes: &[u8; 32]) -> Result, Ctap2StatusCode> { +fn ecdsa_key_from_bytes(bytes: &[u8; 32]) -> CtapResult> { EcdsaSk::::from_slice(bytes).ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR) } diff --git a/libraries/opensk/src/ctap/client_pin.rs b/libraries/opensk/src/ctap/client_pin.rs index e8bd92e7..59093445 100644 --- a/libraries/opensk/src/ctap/client_pin.rs +++ b/libraries/opensk/src/ctap/client_pin.rs @@ -28,6 +28,7 @@ use crate::api::crypto::sha256::Sha256; use crate::api::customization::Customization; use crate::api::key_store::KeyStore; use crate::api::persist::Persist; +use crate::ctap::status_code::CtapResult; use crate::ctap::storage; #[cfg(test)] use crate::env::EcdhSk; @@ -65,7 +66,7 @@ const PIN_PADDED_LENGTH: usize = 64; fn decrypt_pin( shared_secret: &SharedSecret, new_pin_enc: Vec, -) -> Result, Ctap2StatusCode> { +) -> CtapResult> { let decrypted_pin = shared_secret.decrypt(&new_pin_enc)?; if decrypted_pin.len() != PIN_PADDED_LENGTH { return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER); @@ -91,7 +92,7 @@ fn check_and_store_new_pin( env: &mut E, shared_secret: &SharedSecret, new_pin_enc: Vec, -) -> Result<(), Ctap2StatusCode> { +) -> CtapResult<()> { let pin = decrypt_pin(shared_secret, new_pin_enc)?; let min_pin_length = storage::min_pin_length(env)? as usize; let pin_length = str::from_utf8(&pin).unwrap_or("").chars().count(); @@ -168,7 +169,7 @@ impl ClientPin { &self, pin_uv_auth_protocol: PinUvAuthProtocol, key_agreement: CoseKey, - ) -> Result, Ctap2StatusCode> { + ) -> CtapResult> { self.get_pin_protocol(pin_uv_auth_protocol) .decapsulate(key_agreement, pin_uv_auth_protocol) } @@ -184,7 +185,7 @@ impl ClientPin { pin_uv_auth_protocol: PinUvAuthProtocol, shared_secret: &SharedSecret, pin_hash_enc: Vec, - ) -> Result<(), Ctap2StatusCode> { + ) -> CtapResult<()> { match env.persist().pin_hash()? { Some(pin_hash) => { if self.consecutive_pin_mismatches >= 3 { @@ -217,10 +218,7 @@ impl ClientPin { Ok(()) } - fn process_get_pin_retries( - &self, - env: &mut E, - ) -> Result { + fn process_get_pin_retries(&self, env: &mut E) -> CtapResult { Ok(AuthenticatorClientPinResponse { key_agreement: None, pin_uv_auth_token: None, @@ -232,7 +230,7 @@ impl ClientPin { fn process_get_key_agreement( &self, client_pin_params: AuthenticatorClientPinParameters, - ) -> Result { + ) -> CtapResult { let key_agreement = Some( self.get_pin_protocol(client_pin_params.pin_uv_auth_protocol) .get_public_key(), @@ -249,7 +247,7 @@ impl ClientPin { &mut self, env: &mut E, client_pin_params: AuthenticatorClientPinParameters, - ) -> Result<(), Ctap2StatusCode> { + ) -> CtapResult<()> { let AuthenticatorClientPinParameters { pin_uv_auth_protocol, key_agreement, @@ -276,7 +274,7 @@ impl ClientPin { &mut self, env: &mut E, client_pin_params: AuthenticatorClientPinParameters, - ) -> Result<(), Ctap2StatusCode> { + ) -> CtapResult<()> { let AuthenticatorClientPinParameters { pin_uv_auth_protocol, key_agreement, @@ -309,7 +307,7 @@ impl ClientPin { &mut self, env: &mut E, client_pin_params: AuthenticatorClientPinParameters, - ) -> Result { + ) -> CtapResult { let AuthenticatorClientPinParameters { pin_uv_auth_protocol, key_agreement, @@ -357,12 +355,12 @@ impl ClientPin { // If you want to support local user verification, implement this function. // Lacking a fingerprint reader, this subcommand is currently unsupported. _client_pin_params: AuthenticatorClientPinParameters, - ) -> Result { + ) -> CtapResult { // User verification is only supported through PIN currently. Err(Ctap2StatusCode::CTAP2_ERR_INVALID_SUBCOMMAND) } - fn process_get_uv_retries(&self) -> Result { + fn process_get_uv_retries(&self) -> CtapResult { // User verification is only supported through PIN currently. Err(Ctap2StatusCode::CTAP2_ERR_INVALID_SUBCOMMAND) } @@ -371,7 +369,7 @@ impl ClientPin { &mut self, env: &mut E, mut client_pin_params: AuthenticatorClientPinParameters, - ) -> Result { + ) -> CtapResult { // Mutating client_pin_params is just an optimization to move it into // process_get_pin_token, without cloning permissions_rp_id here. // getPinToken requires permissions* to be None. @@ -399,7 +397,7 @@ impl ClientPin { &mut self, env: &mut E, client_pin_params: AuthenticatorClientPinParameters, - ) -> Result { + ) -> CtapResult { if !env.customization().allows_pin_protocol_v1() && client_pin_params.pin_uv_auth_protocol == PinUvAuthProtocol::V1 { @@ -441,7 +439,7 @@ impl ClientPin { hmac_contents: &[u8], pin_uv_auth_param: &[u8], pin_uv_auth_protocol: PinUvAuthProtocol, - ) -> Result<(), Ctap2StatusCode> { + ) -> CtapResult<()> { if !self.pin_uv_auth_token_state.is_in_use() { return Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID); } @@ -477,7 +475,7 @@ impl ClientPin { env: &mut E, hmac_secret_input: GetAssertionHmacSecretInput, cred_random: &[u8; 32], - ) -> Result, Ctap2StatusCode> { + ) -> CtapResult> { let GetAssertionHmacSecretInput { key_agreement, salt_enc, @@ -523,7 +521,7 @@ impl ClientPin { } /// Checks if user verification is cached for use of the pinUvAuthToken. - pub fn check_user_verified_flag(&mut self) -> Result<(), Ctap2StatusCode> { + pub fn check_user_verified_flag(&mut self) -> CtapResult<()> { if self.pin_uv_auth_token_state.get_user_verified_flag_value() { Ok(()) } else { @@ -532,27 +530,24 @@ impl ClientPin { } /// Check if the required command's token permission is granted. - pub fn has_permission(&self, permission: PinPermission) -> Result<(), Ctap2StatusCode> { + pub fn has_permission(&self, permission: PinPermission) -> CtapResult<()> { self.pin_uv_auth_token_state.has_permission(permission) } /// Check if no RP ID is associated with the token permission. - pub fn has_no_rp_id_permission(&self) -> Result<(), Ctap2StatusCode> { + pub fn has_no_rp_id_permission(&self) -> CtapResult<()> { self.pin_uv_auth_token_state.has_no_permissions_rp_id() } /// Check if no or the passed RP ID is associated with the token permission. - pub fn has_no_or_rp_id_permission(&mut self, rp_id: &str) -> Result<(), Ctap2StatusCode> { + pub fn has_no_or_rp_id_permission(&mut self, rp_id: &str) -> CtapResult<()> { self.pin_uv_auth_token_state .has_no_permissions_rp_id() .or_else(|_| self.pin_uv_auth_token_state.has_permissions_rp_id(rp_id)) } /// Check if no RP ID is associated with the token permission, or it matches the hash. - pub fn has_no_or_rp_id_hash_permission( - &self, - rp_id_hash: &[u8], - ) -> Result<(), Ctap2StatusCode> { + pub fn has_no_or_rp_id_hash_permission(&self, rp_id_hash: &[u8]) -> CtapResult<()> { self.pin_uv_auth_token_state .has_no_permissions_rp_id() .or_else(|_| { @@ -564,7 +559,7 @@ impl ClientPin { /// Check if the passed RP ID is associated with the token permission. /// /// If no RP ID is associated, associate the passed RP ID as a side effect. - pub fn ensure_rp_id_permission(&mut self, rp_id: &str) -> Result<(), Ctap2StatusCode> { + pub fn ensure_rp_id_permission(&mut self, rp_id: &str) -> CtapResult<()> { if self .pin_uv_auth_token_state .has_no_permissions_rp_id() @@ -1277,7 +1272,7 @@ mod test { pin_uv_auth_protocol: PinUvAuthProtocol, cred_random: &[u8; 32], salt: Vec, - ) -> Result, Ctap2StatusCode> { + ) -> CtapResult> { let mut env = TestEnv::default(); let (client_pin, shared_secret) = create_client_pin_and_shared_secret(pin_uv_auth_protocol); diff --git a/libraries/opensk/src/ctap/command.rs b/libraries/opensk/src/ctap/command.rs index 7d4820f0..1c3f5a50 100644 --- a/libraries/opensk/src/ctap/command.rs +++ b/libraries/opensk/src/ctap/command.rs @@ -24,6 +24,7 @@ use super::data_formats::{ #[cfg(feature = "config_command")] use super::data_formats::{ConfigSubCommand, ConfigSubCommandParams, SetMinPinLengthParams}; use super::status_code::Ctap2StatusCode; +use crate::ctap::status_code::CtapResult; use alloc::string::String; use alloc::vec::Vec; #[cfg(feature = "fuzz")] @@ -70,7 +71,7 @@ impl Command { const AUTHENTICATOR_VENDOR_CREDENTIAL_MANAGEMENT: u8 = 0x41; const _AUTHENTICATOR_VENDOR_LAST: u8 = 0xBF; - pub fn deserialize(bytes: &[u8]) -> Result { + pub fn deserialize(bytes: &[u8]) -> CtapResult { if bytes.is_empty() { // The error to return is not specified, missing parameter seems to fit best. return Err(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER); @@ -157,7 +158,7 @@ pub struct AuthenticatorMakeCredentialParameters { impl TryFrom for AuthenticatorMakeCredentialParameters { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { 0x01 => client_data_hash, @@ -181,7 +182,7 @@ impl TryFrom for AuthenticatorMakeCredentialParameters { let pub_key_cred_params = cred_param_vec .into_iter() .map(PublicKeyCredentialParameter::try_from) - .collect::, Ctap2StatusCode>>()?; + .collect::>>()?; let exclude_list = match exclude_list { Some(entry) => { @@ -189,7 +190,7 @@ impl TryFrom for AuthenticatorMakeCredentialParameters { let exclude_list = exclude_list_vec .into_iter() .map(PublicKeyCredentialDescriptor::try_from) - .collect::, Ctap2StatusCode>>()?; + .collect::>>()?; Some(exclude_list) } None => None, @@ -244,7 +245,7 @@ pub struct AuthenticatorGetAssertionParameters { impl TryFrom for AuthenticatorGetAssertionParameters { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { 0x01 => rp_id, @@ -266,7 +267,7 @@ impl TryFrom for AuthenticatorGetAssertionParameters { let allow_list = allow_list_vec .into_iter() .map(PublicKeyCredentialDescriptor::try_from) - .collect::, Ctap2StatusCode>>()?; + .collect::>>()?; Some(allow_list) } None => None, @@ -315,7 +316,7 @@ pub struct AuthenticatorClientPinParameters { impl TryFrom for AuthenticatorClientPinParameters { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { 0x01 => pin_uv_auth_protocol, @@ -370,7 +371,7 @@ pub struct AuthenticatorLargeBlobsParameters { impl TryFrom for AuthenticatorLargeBlobsParameters { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { 0x01 => get, @@ -432,7 +433,7 @@ pub struct AuthenticatorConfigParameters { impl TryFrom for AuthenticatorConfigParameters { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { 0x01 => sub_command, @@ -474,7 +475,7 @@ pub struct AuthenticatorCredentialManagementParameters { impl TryFrom for AuthenticatorCredentialManagementParameters { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { 0x01 => sub_command, diff --git a/libraries/opensk/src/ctap/config_command.rs b/libraries/opensk/src/ctap/config_command.rs index 1f1447d0..822db5d2 100644 --- a/libraries/opensk/src/ctap/config_command.rs +++ b/libraries/opensk/src/ctap/config_command.rs @@ -19,14 +19,13 @@ use super::response::ResponseData; use super::status_code::Ctap2StatusCode; use crate::api::customization::Customization; use crate::api::persist::Persist; +use crate::ctap::status_code::CtapResult; use crate::ctap::storage; use crate::env::Env; use alloc::vec; /// Processes the subcommand enableEnterpriseAttestation for AuthenticatorConfig. -fn process_enable_enterprise_attestation( - env: &mut impl Env, -) -> Result { +fn process_enable_enterprise_attestation(env: &mut impl Env) -> CtapResult { if env.customization().enterprise_attestation_mode().is_some() { storage::enable_enterprise_attestation(env)?; Ok(ResponseData::AuthenticatorConfig) @@ -36,7 +35,7 @@ fn process_enable_enterprise_attestation( } /// Processes the subcommand toggleAlwaysUv for AuthenticatorConfig. -fn process_toggle_always_uv(env: &mut impl Env) -> Result { +fn process_toggle_always_uv(env: &mut impl Env) -> CtapResult { storage::toggle_always_uv(env)?; Ok(ResponseData::AuthenticatorConfig) } @@ -45,7 +44,7 @@ fn process_toggle_always_uv(env: &mut impl Env) -> Result Result { +) -> CtapResult { let SetMinPinLengthParams { new_min_pin_length, min_pin_length_rp_ids, @@ -78,7 +77,7 @@ pub fn process_config( env: &mut E, client_pin: &mut ClientPin, params: AuthenticatorConfigParameters, -) -> Result { +) -> CtapResult { let AuthenticatorConfigParameters { sub_command, sub_command_params, diff --git a/libraries/opensk/src/ctap/credential_management.rs b/libraries/opensk/src/ctap/credential_management.rs index 11c6767e..1dc79834 100644 --- a/libraries/opensk/src/ctap/credential_management.rs +++ b/libraries/opensk/src/ctap/credential_management.rs @@ -25,6 +25,7 @@ use super::{Channel, StatefulCommand, StatefulPermission}; use crate::api::crypto::sha256::Sha256; use crate::api::customization::Customization; use crate::ctap::data_formats::CredentialProtectionPolicy; +use crate::ctap::status_code::CtapResult; use crate::ctap::storage; use crate::env::{Env, Sha}; use alloc::collections::BTreeSet; @@ -33,7 +34,7 @@ use alloc::vec; use alloc::vec::Vec; /// Generates a set with all existing RP IDs. -fn get_stored_rp_ids(env: &mut impl Env) -> Result, Ctap2StatusCode> { +fn get_stored_rp_ids(env: &mut impl Env) -> CtapResult> { let mut rp_set = BTreeSet::new(); let mut iter_result = Ok(()); for (_, credential) in storage::iter_credentials(env, &mut iter_result)? { @@ -47,7 +48,7 @@ fn get_stored_rp_ids(env: &mut impl Env) -> Result, Ctap2Status fn enumerate_rps_response( rp_id: String, total_rps: Option, -) -> Result { +) -> CtapResult { let rp_id_hash = Some(Sha::::digest(rp_id.as_bytes()).to_vec()); let rp = Some(PublicKeyCredentialRpEntity { rp_id, @@ -67,7 +68,7 @@ fn enumerate_credentials_response( env: &mut E, credential: PublicKeyCredentialSource, total_credentials: Option, -) -> Result { +) -> CtapResult { let PublicKeyCredentialSource { key_type, credential_id, @@ -115,7 +116,7 @@ fn check_rp_id_permissions( env: &mut E, client_pin: &mut ClientPin, credential_id: &[u8], -) -> Result<(), Ctap2StatusCode> { +) -> CtapResult<()> { // Pre-check a sufficient condition before calling the store. if client_pin.has_no_rp_id_permission().is_ok() { return Ok(()); @@ -127,7 +128,7 @@ fn check_rp_id_permissions( /// Processes the subcommand getCredsMetadata for CredentialManagement. fn process_get_creds_metadata( env: &mut impl Env, -) -> Result { +) -> CtapResult { Ok(AuthenticatorCredentialManagementResponse { existing_resident_credentials_count: Some(storage::count_credentials(env)? as u64), max_possible_remaining_resident_credentials_count: Some( @@ -142,7 +143,7 @@ fn process_enumerate_rps_begin( env: &mut E, stateful_command_permission: &mut StatefulPermission, channel: Channel, -) -> Result { +) -> CtapResult { let mut rp_set = get_stored_rp_ids(env)?; let total_rps = rp_set.len(); @@ -159,7 +160,7 @@ fn process_enumerate_rps_begin( fn process_enumerate_rps_get_next_rp( env: &mut E, stateful_command_permission: &mut StatefulPermission, -) -> Result { +) -> CtapResult { let rp_id_index = stateful_command_permission.next_enumerate_rp(env)?; let rp_set = get_stored_rp_ids(env)?; // A BTreeSet is already sorted. @@ -177,7 +178,7 @@ fn process_enumerate_credentials_begin( client_pin: &mut ClientPin, sub_command_params: CredentialManagementSubCommandParameters, channel: Channel, -) -> Result { +) -> CtapResult { let rp_id_hash = sub_command_params .rp_id_hash .ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)?; @@ -214,7 +215,7 @@ fn process_enumerate_credentials_begin( fn process_enumerate_credentials_get_next_credential( env: &mut E, stateful_command_permission: &mut StatefulPermission, -) -> Result { +) -> CtapResult { let credential_key = stateful_command_permission.next_enumerate_credential(env)?; let credential = storage::get_credential(env, credential_key)?; enumerate_credentials_response(env, credential, None) @@ -225,7 +226,7 @@ fn process_delete_credential( env: &mut E, client_pin: &mut ClientPin, sub_command_params: CredentialManagementSubCommandParameters, -) -> Result<(), Ctap2StatusCode> { +) -> CtapResult<()> { let credential_id = sub_command_params .credential_id .ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)? @@ -239,7 +240,7 @@ fn process_update_user_information( env: &mut E, client_pin: &mut ClientPin, sub_command_params: CredentialManagementSubCommandParameters, -) -> Result<(), Ctap2StatusCode> { +) -> CtapResult<()> { let credential_id = sub_command_params .credential_id .ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)? @@ -258,7 +259,7 @@ pub fn process_credential_management( client_pin: &mut ClientPin, cred_management_params: AuthenticatorCredentialManagementParameters, channel: Channel, -) -> Result { +) -> CtapResult { let AuthenticatorCredentialManagementParameters { sub_command, sub_command_params, diff --git a/libraries/opensk/src/ctap/crypto_wrapper.rs b/libraries/opensk/src/ctap/crypto_wrapper.rs index 01050cee..53aca081 100644 --- a/libraries/opensk/src/ctap/crypto_wrapper.rs +++ b/libraries/opensk/src/ctap/crypto_wrapper.rs @@ -14,7 +14,7 @@ use crate::api::crypto::aes256::Aes256; use crate::ctap::secret::Secret; -use crate::ctap::status_code::Ctap2StatusCode; +use crate::ctap::status_code::{Ctap2StatusCode, CtapResult}; use crate::env::{AesKey, Env}; use alloc::vec::Vec; use rand_core::RngCore; @@ -25,7 +25,7 @@ pub fn aes256_cbc_encrypt( aes_key: &AesKey, plaintext: &[u8], embeds_iv: bool, -) -> Result, Ctap2StatusCode> { +) -> CtapResult> { if plaintext.len() % 16 != 0 { return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER); } @@ -48,7 +48,7 @@ pub fn aes256_cbc_decrypt( aes_key: &AesKey, ciphertext: &[u8], embeds_iv: bool, -) -> Result, Ctap2StatusCode> { +) -> CtapResult> { if ciphertext.len() % 16 != 0 || (embeds_iv && ciphertext.is_empty()) { return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER); } diff --git a/libraries/opensk/src/ctap/data_formats.rs b/libraries/opensk/src/ctap/data_formats.rs index bef16c12..7e1f3617 100644 --- a/libraries/opensk/src/ctap/data_formats.rs +++ b/libraries/opensk/src/ctap/data_formats.rs @@ -15,6 +15,7 @@ use super::status_code::Ctap2StatusCode; use crate::api::crypto::{ecdh, ecdsa, EC_FIELD_SIZE}; use crate::api::private_key::PrivateKey; +use crate::ctap::status_code::CtapResult; use crate::env::{AesKey, Env}; use alloc::string::String; use alloc::vec::Vec; @@ -44,7 +45,7 @@ pub struct PublicKeyCredentialRpEntity { impl TryFrom for PublicKeyCredentialRpEntity { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { "id" => rp_id, @@ -88,7 +89,7 @@ pub struct PublicKeyCredentialUserEntity { impl TryFrom for PublicKeyCredentialUserEntity { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { "id" => user_id, @@ -147,7 +148,7 @@ impl From for cbor::Value { impl TryFrom for PublicKeyCredentialType { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { let cred_type_string = extract_text_string(cbor_value)?; match &cred_type_string[..] { "public-key" => Ok(PublicKeyCredentialType::PublicKey), @@ -167,7 +168,7 @@ pub struct PublicKeyCredentialParameter { impl TryFrom for PublicKeyCredentialParameter { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { "alg" => alg, @@ -216,7 +217,7 @@ impl From for cbor::Value { impl TryFrom for AuthenticatorTransport { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { let transport_string = extract_text_string(cbor_value)?; match &transport_string[..] { "usb" => Ok(AuthenticatorTransport::Usb), @@ -240,7 +241,7 @@ pub struct PublicKeyCredentialDescriptor { impl TryFrom for PublicKeyCredentialDescriptor { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { "id" => key_id, @@ -257,7 +258,7 @@ impl TryFrom for PublicKeyCredentialDescriptor { let transports = transport_vec .into_iter() .map(AuthenticatorTransport::try_from) - .collect::, Ctap2StatusCode>>()?; + .collect::>>()?; Some(transports) } None => None, @@ -294,7 +295,7 @@ pub struct MakeCredentialExtensions { impl TryFrom for MakeCredentialExtensions { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { "credBlob" => cred_blob, @@ -338,7 +339,7 @@ pub struct GetAssertionExtensions { impl TryFrom for GetAssertionExtensions { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { "credBlob" => cred_blob, @@ -377,7 +378,7 @@ pub struct GetAssertionHmacSecretInput { impl TryFrom for GetAssertionHmacSecretInput { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { 1 => key_agreement, @@ -412,7 +413,7 @@ pub struct MakeCredentialOptions { impl TryFrom for MakeCredentialOptions { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { "rk" => rk, @@ -458,7 +459,7 @@ impl Default for GetAssertionOptions { impl TryFrom for GetAssertionOptions { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { "rk" => rk, @@ -536,7 +537,7 @@ impl From for SignatureAlgorithm { impl TryFrom for SignatureAlgorithm { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { extract_integer(cbor_value).map(SignatureAlgorithm::from) } } @@ -567,7 +568,7 @@ impl From for cbor::Value { impl TryFrom for CredentialProtectionPolicy { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { match extract_integer(cbor_value)? { 0x01 => Ok(CredentialProtectionPolicy::UserVerificationOptional), 0x02 => Ok(CredentialProtectionPolicy::UserVerificationOptionalWithCredentialIdList), @@ -637,7 +638,7 @@ impl PublicKeyCredentialSource { self, rng: &mut E::Rng, wrap_key: &AesKey, - ) -> Result { + ) -> CtapResult { Ok(cbor_map_options! { PublicKeyCredentialSourceField::CredentialId => Some(self.credential_id), PublicKeyCredentialSourceField::RpId => Some(self.rp_id), @@ -653,10 +654,7 @@ impl PublicKeyCredentialSource { }) } - pub fn from_cbor( - wrap_key: &AesKey, - cbor_value: cbor::Value, - ) -> Result { + pub fn from_cbor(wrap_key: &AesKey, cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { PublicKeyCredentialSourceField::CredentialId => credential_id, @@ -816,7 +814,7 @@ impl CoseKey { impl TryFrom for CoseKey { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { // This is sorted correctly, negative encoding is bigger. @@ -902,7 +900,7 @@ pub enum PinUvAuthProtocol { impl TryFrom for PinUvAuthProtocol { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { match extract_unsigned(cbor_value)? { 1 => Ok(PinUvAuthProtocol::V1), 2 => Ok(PinUvAuthProtocol::V2), @@ -934,7 +932,7 @@ impl From for cbor::Value { impl TryFrom for ClientPinSubCommand { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { let subcommand_int = extract_unsigned(cbor_value)?; match subcommand_int { 0x01 => Ok(ClientPinSubCommand::GetPinRetries), @@ -968,7 +966,7 @@ impl From for cbor::Value { impl TryFrom for ConfigSubCommand { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { let subcommand_int = extract_unsigned(cbor_value)?; match subcommand_int { 0x01 => Ok(ConfigSubCommand::EnableEnterpriseAttestation), @@ -1005,7 +1003,7 @@ pub struct SetMinPinLengthParams { impl TryFrom for SetMinPinLengthParams { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { 0x01 => new_min_pin_length, @@ -1025,7 +1023,7 @@ impl TryFrom for SetMinPinLengthParams { extract_array(entry)? .into_iter() .map(extract_text_string) - .collect::, Ctap2StatusCode>>()?, + .collect::>>()?, ), None => None, }; @@ -1064,7 +1062,7 @@ pub enum EnterpriseAttestationMode { impl TryFrom for EnterpriseAttestationMode { type Error = Ctap2StatusCode; - fn try_from(value: u64) -> Result { + fn try_from(value: u64) -> CtapResult { match value { 1 => Ok(EnterpriseAttestationMode::VendorFacilitated), 2 => Ok(EnterpriseAttestationMode::PlatformManaged), @@ -1094,7 +1092,7 @@ impl From for cbor::Value { impl TryFrom for CredentialManagementSubCommand { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { let subcommand_int = extract_unsigned(cbor_value)?; match subcommand_int { 0x01 => Ok(CredentialManagementSubCommand::GetCredsMetadata), @@ -1119,7 +1117,7 @@ pub struct CredentialManagementSubCommandParameters { impl TryFrom for CredentialManagementSubCommandParameters { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { 0x01 => rp_id_hash, @@ -1153,27 +1151,27 @@ impl From for cbor::Value { } } -fn ok_or_cbor_type(value_option: Option) -> Result { +fn ok_or_cbor_type(value_option: Option) -> CtapResult { value_option.ok_or(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE) } -pub fn extract_unsigned(cbor_value: cbor::Value) -> Result { +pub fn extract_unsigned(cbor_value: cbor::Value) -> CtapResult { ok_or_cbor_type(cbor_value.extract_unsigned()) } -pub fn extract_integer(cbor_value: cbor::Value) -> Result { +pub fn extract_integer(cbor_value: cbor::Value) -> CtapResult { ok_or_cbor_type(cbor_value.extract_integer()) } -pub fn extract_byte_string(cbor_value: cbor::Value) -> Result, Ctap2StatusCode> { +pub fn extract_byte_string(cbor_value: cbor::Value) -> CtapResult> { ok_or_cbor_type(cbor_value.extract_byte_string()) } -pub fn extract_text_string(cbor_value: cbor::Value) -> Result { +pub fn extract_text_string(cbor_value: cbor::Value) -> CtapResult { ok_or_cbor_type(cbor_value.extract_text_string()) } -pub fn extract_array(cbor_value: cbor::Value) -> Result, Ctap2StatusCode> { +pub fn extract_array(cbor_value: cbor::Value) -> CtapResult> { ok_or_cbor_type(cbor_value.extract_array()) } @@ -1183,11 +1181,11 @@ pub fn extract_map( ok_or_cbor_type(cbor_value.extract_map()) } -pub fn extract_bool(cbor_value: cbor::Value) -> Result { +pub fn extract_bool(cbor_value: cbor::Value) -> CtapResult { ok_or_cbor_type(cbor_value.extract_bool()) } -pub fn ok_or_missing(value_option: Option) -> Result { +pub fn ok_or_missing(value_option: Option) -> CtapResult { value_option.ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER) } diff --git a/libraries/opensk/src/ctap/mod.rs b/libraries/opensk/src/ctap/mod.rs index ae2c56d0..9cc430ec 100644 --- a/libraries/opensk/src/ctap/mod.rs +++ b/libraries/opensk/src/ctap/mod.rs @@ -57,7 +57,7 @@ use self::response::{ AuthenticatorMakeCredentialResponse, ResponseData, }; use self::secret::Secret; -use self::status_code::Ctap2StatusCode; +use self::status_code::{Ctap2StatusCode, CtapResult}; #[cfg(feature = "with_ctap1")] use self::u2f_up::U2fUserPresenceState; use crate::api::clock::Clock; @@ -175,18 +175,18 @@ pub enum Channel { } // Helpers to perform CBOR read/write while respecting CTAP2 nesting limits. -pub fn cbor_read(encoded_cbor: &[u8]) -> Result { +pub fn cbor_read(encoded_cbor: &[u8]) -> CtapResult { cbor::reader::read_nested(encoded_cbor, Some(MAX_CBOR_NESTING_DEPTH)) .map_err(|_e| Ctap2StatusCode::CTAP2_ERR_INVALID_CBOR) } -pub fn cbor_write(value: cbor::Value, encoded_cbor: &mut Vec) -> Result<(), Ctap2StatusCode> { +pub fn cbor_write(value: cbor::Value, encoded_cbor: &mut Vec) -> CtapResult<()> { cbor::writer::write_nested(value, encoded_cbor, Some(MAX_CBOR_NESTING_DEPTH)) .map_err(|_e| Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR) } /// Resets the all state for a CTAP Reset command. -pub fn reset(env: &mut impl Env) -> Result<(), Ctap2StatusCode> { +pub fn reset(env: &mut impl Env) -> CtapResult<()> { env.persist().reset()?; env.key_store().reset()?; storage::init(env) @@ -336,7 +336,7 @@ fn send_keepalive_up_needed( /// Blocks for user presence. /// /// Returns an error in case of timeout, user declining presence request, or keepalive error. -pub fn check_user_presence(env: &mut E, channel: Channel) -> Result<(), Ctap2StatusCode> { +pub fn check_user_presence(env: &mut E, channel: Channel) -> CtapResult<()> { env.user_presence().check_init(); // The timeout is N times the keepalive delay. @@ -480,7 +480,7 @@ impl StatefulPermission { } /// Gets a reference to the current command state, if any exists. - pub fn get_command(&mut self, env: &mut E) -> Result<&StatefulCommand, Ctap2StatusCode> { + pub fn get_command(&mut self, env: &mut E) -> CtapResult<&StatefulCommand> { self.clear_timer(env); self.command_type .as_ref() @@ -526,7 +526,7 @@ impl StatefulPermission { } /// Returns the index to the next RP ID for enumeration and advances it. - pub fn next_enumerate_rp(&mut self, env: &mut E) -> Result { + pub fn next_enumerate_rp(&mut self, env: &mut E) -> CtapResult { self.clear_timer(env); if let Some(StatefulCommand::EnumerateRps(rp_id_index)) = &mut self.command_type { let current_index = *rp_id_index; @@ -538,7 +538,7 @@ impl StatefulPermission { } /// Returns the next storage credential key for enumeration and advances it. - pub fn next_enumerate_credential(&mut self, env: &mut E) -> Result { + pub fn next_enumerate_credential(&mut self, env: &mut E) -> CtapResult { self.clear_timer(env); if let Some(StatefulCommand::EnumerateCredentials(rp_credentials)) = &mut self.command_type { @@ -596,10 +596,7 @@ impl CtapState { } } - pub fn increment_global_signature_counter( - &mut self, - env: &mut E, - ) -> Result<(), Ctap2StatusCode> { + pub fn increment_global_signature_counter(&mut self, env: &mut E) -> CtapResult<()> { if env.customization().use_signature_counter() { let increment = env.rng().next_u32() % 8 + 1; env.persist().incr_global_signature_counter(increment)?; @@ -611,7 +608,7 @@ impl CtapState { // If alwaysUv is enabled and the authenticator does not support internal UV, // CTAP1 needs to be disabled. #[cfg(feature = "with_ctap1")] - pub fn allows_ctap1(&self, env: &mut E) -> Result { + pub fn allows_ctap1(&self, env: &mut E) -> CtapResult { Ok(!storage::has_always_uv(env)?) } @@ -670,7 +667,7 @@ impl CtapState { env: &mut E, command: Command, channel: Channel, - ) -> Result { + ) -> CtapResult { // The auth token timeouts are checked once here, to make error codes consistent. If your // auth token hasn't timed out now, you can fully use it for this command. self.client_pin.update_timeouts(env); @@ -708,7 +705,7 @@ impl CtapState { env: &mut E, command: Command, channel: Channel, - ) -> Result { + ) -> CtapResult { match command { Command::AuthenticatorMakeCredential(params) => { self.process_make_credential(env, params, channel) @@ -744,7 +741,7 @@ impl CtapState { &mut self, env: &mut E, command: Command, - ) -> Result { + ) -> CtapResult { match command { Command::AuthenticatorGetInfo => self.process_get_info(env), _ => Err(Ctap2StatusCode::CTAP1_ERR_INVALID_COMMAND), @@ -757,7 +754,7 @@ impl CtapState { pin_uv_auth_param: &Option>, pin_uv_auth_protocol: Option, channel: Channel, - ) -> Result<(), Ctap2StatusCode> { + ) -> CtapResult<()> { if let Some(auth_param) = &pin_uv_auth_param { // This case was added in FIDO 2.1. if auth_param.is_empty() { @@ -778,7 +775,7 @@ impl CtapState { env: &mut E, make_credential_params: AuthenticatorMakeCredentialParameters, channel: Channel, - ) -> Result { + ) -> CtapResult { let AuthenticatorMakeCredentialParameters { client_data_hash, rp, @@ -1043,7 +1040,7 @@ impl CtapState { env: &mut E, private_key: &PrivateKey, has_uv: bool, - ) -> Result, Ctap2StatusCode> { + ) -> CtapResult> { let private_key_bytes = private_key.to_bytes(); let salt = array_ref!(private_key_bytes, 0, 32); let key = env.key_store().cred_random(has_uv)?; @@ -1061,7 +1058,7 @@ impl CtapState { assertion_input: AssertionInput, number_of_credentials: Option, is_next: bool, - ) -> Result { + ) -> CtapResult { let AssertionInput { client_data_hash, mut auth_data, @@ -1149,7 +1146,7 @@ impl CtapState { rp_id: &str, rp_id_hash: &[u8], has_uv: bool, - ) -> Result, Ctap2StatusCode> { + ) -> CtapResult> { for allowed_credential in allow_list { let credential = filter_listed_resident_credential( storage::find_credential(env, rp_id, &allowed_credential.key_id)?, @@ -1175,7 +1172,7 @@ impl CtapState { env: &mut E, get_assertion_params: AuthenticatorGetAssertionParameters, channel: Channel, - ) -> Result { + ) -> CtapResult { let AuthenticatorGetAssertionParameters { rp_id, client_data_hash, @@ -1307,7 +1304,7 @@ impl CtapState { ) } - fn process_get_next_assertion(&mut self, env: &mut E) -> Result { + fn process_get_next_assertion(&mut self, env: &mut E) -> CtapResult { let (assertion_input, credential_key) = self .stateful_command_permission .next_assertion_credential(env)?; @@ -1315,7 +1312,7 @@ impl CtapState { self.assertion_response(env, credential, assertion_input, None, true) } - fn process_get_info(&self, env: &mut E) -> Result { + fn process_get_info(&self, env: &mut E) -> CtapResult { let has_always_uv = storage::has_always_uv(env)?; #[cfg_attr(not(feature = "with_ctap1"), allow(unused_mut))] let mut versions = vec![ @@ -1394,11 +1391,7 @@ impl CtapState { )) } - fn process_reset( - &mut self, - env: &mut E, - channel: Channel, - ) -> Result { + fn process_reset(&mut self, env: &mut E, channel: Channel) -> CtapResult { if !matches!( self.stateful_command_permission.get_command(env)?, StatefulCommand::Reset @@ -1418,11 +1411,7 @@ impl CtapState { Ok(ResponseData::AuthenticatorReset) } - fn process_selection( - &self, - env: &mut E, - channel: Channel, - ) -> Result { + fn process_selection(&self, env: &mut E, channel: Channel) -> CtapResult { check_user_presence(env, channel)?; Ok(ResponseData::AuthenticatorSelection) } @@ -1432,7 +1421,7 @@ impl CtapState { env: &mut E, rp_id_hash: &[u8], flag_byte: u8, - ) -> Result, Ctap2StatusCode> { + ) -> CtapResult> { let mut auth_data = vec![]; auth_data.extend(rp_id_hash); auth_data.push(flag_byte); @@ -1490,7 +1479,7 @@ mod test { const VENDOR_CHANNEL: Channel = Channel::VendorHid([0x12, 0x34, 0x56, 0x78]); fn check_make_response( - make_credential_response: &Result, + make_credential_response: &CtapResult, flags: u8, expected_aaguid: &[u8], expected_credential_id_size: u8, @@ -2177,7 +2166,7 @@ mod test { ); } - fn check_ep(make_credential_response: Result, has_ep: bool) { + fn check_ep(make_credential_response: CtapResult, has_ep: bool) { let ep_att = if has_ep { Some(true) } else { None }; match make_credential_response.unwrap() { ResponseData::AuthenticatorMakeCredential(make_credential_response) => { @@ -2315,7 +2304,7 @@ mod test { } fn check_assertion_response_with_user( - response: Result, + response: CtapResult, expected_user: Option, flags: u8, signature_counter: u32, @@ -2350,7 +2339,7 @@ mod test { } fn check_assertion_response_with_extension( - response: Result, + response: CtapResult, expected_user_id: Option>, signature_counter: u32, expected_number_of_credentials: Option, @@ -2373,7 +2362,7 @@ mod test { } fn check_assertion_response( - response: Result, + response: CtapResult, expected_user_id: Vec, signature_counter: u32, expected_number_of_credentials: Option, diff --git a/libraries/opensk/src/ctap/pin_protocol.rs b/libraries/opensk/src/ctap/pin_protocol.rs index dc3a5a88..b9d0f451 100644 --- a/libraries/opensk/src/ctap/pin_protocol.rs +++ b/libraries/opensk/src/ctap/pin_protocol.rs @@ -21,7 +21,7 @@ use crate::ctap::client_pin::PIN_TOKEN_LENGTH; use crate::ctap::crypto_wrapper::{aes256_cbc_decrypt, aes256_cbc_encrypt}; use crate::ctap::data_formats::{CoseKey, PinUvAuthProtocol}; use crate::ctap::secret::Secret; -use crate::ctap::status_code::Ctap2StatusCode; +use crate::ctap::status_code::{Ctap2StatusCode, CtapResult}; #[cfg(test)] use crate::env::test::TestEnv; use crate::env::{AesKey, EcdhPk, EcdhSk, Env, Hkdf, Hmac, Sha}; @@ -69,7 +69,7 @@ impl PinProtocol { &self, peer_cose_key: CoseKey, pin_uv_auth_protocol: PinUvAuthProtocol, - ) -> Result, Ctap2StatusCode> { + ) -> CtapResult> { let (x_bytes, y_bytes) = peer_cose_key.try_into_ecdh_coordinates()?; let pk = EcdhPk::::from_coordinates(&x_bytes, &y_bytes) .ok_or(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)?; @@ -119,7 +119,7 @@ pub fn verify_pin_uv_auth_token( message: &[u8], signature: &[u8], pin_uv_auth_protocol: PinUvAuthProtocol, -) -> Result<(), Ctap2StatusCode> { +) -> CtapResult<()> { match pin_uv_auth_protocol { PinUvAuthProtocol::V1 => verify_v1::(token, message, signature), PinUvAuthProtocol::V2 => verify_v2::(token, message, signature), @@ -143,7 +143,7 @@ impl SharedSecret { } /// Returns the encrypted plaintext. - pub fn encrypt(&self, env: &mut E, plaintext: &[u8]) -> Result, Ctap2StatusCode> { + pub fn encrypt(&self, env: &mut E, plaintext: &[u8]) -> CtapResult> { match self { SharedSecret::V1(s) => s.encrypt(env, plaintext), SharedSecret::V2(s) => s.encrypt(env, plaintext), @@ -151,7 +151,7 @@ impl SharedSecret { } /// Returns the decrypted ciphertext. - pub fn decrypt(&self, ciphertext: &[u8]) -> Result, Ctap2StatusCode> { + pub fn decrypt(&self, ciphertext: &[u8]) -> CtapResult> { match self { SharedSecret::V1(s) => s.decrypt(ciphertext), SharedSecret::V2(s) => s.decrypt(ciphertext), @@ -159,7 +159,7 @@ impl SharedSecret { } /// Verifies that the signature is a valid MAC for the given message. - pub fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Ctap2StatusCode> { + pub fn verify(&self, message: &[u8], signature: &[u8]) -> CtapResult<()> { match self { SharedSecret::V1(s) => s.verify(message, signature), SharedSecret::V2(s) => s.verify(message, signature), @@ -177,11 +177,7 @@ impl SharedSecret { } } -fn verify_v1( - key: &[u8; 32], - message: &[u8], - signature: &[u8], -) -> Result<(), Ctap2StatusCode> { +fn verify_v1(key: &[u8; 32], message: &[u8], signature: &[u8]) -> CtapResult<()> { if signature.len() != 16 { return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER); } @@ -192,11 +188,7 @@ fn verify_v1( } } -fn verify_v2( - key: &[u8; 32], - message: &[u8], - signature: &[u8], -) -> Result<(), Ctap2StatusCode> { +fn verify_v2(key: &[u8; 32], message: &[u8], signature: &[u8]) -> CtapResult<()> { if signature.len() != 32 { return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER); } @@ -224,15 +216,15 @@ impl SharedSecretV1 { } } - fn encrypt(&self, env: &mut E, plaintext: &[u8]) -> Result, Ctap2StatusCode> { + fn encrypt(&self, env: &mut E, plaintext: &[u8]) -> CtapResult> { aes256_cbc_encrypt::(env.rng(), &self.aes_key, plaintext, false) } - fn decrypt(&self, ciphertext: &[u8]) -> Result, Ctap2StatusCode> { + fn decrypt(&self, ciphertext: &[u8]) -> CtapResult> { aes256_cbc_decrypt::(&self.aes_key, ciphertext, false) } - fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Ctap2StatusCode> { + fn verify(&self, message: &[u8], signature: &[u8]) -> CtapResult<()> { verify_v1::(&self.common_secret, message, signature) } @@ -262,15 +254,15 @@ impl SharedSecretV2 { } } - fn encrypt(&self, env: &mut E, plaintext: &[u8]) -> Result, Ctap2StatusCode> { + fn encrypt(&self, env: &mut E, plaintext: &[u8]) -> CtapResult> { aes256_cbc_encrypt::(env.rng(), &self.aes_key, plaintext, true) } - fn decrypt(&self, ciphertext: &[u8]) -> Result, Ctap2StatusCode> { + fn decrypt(&self, ciphertext: &[u8]) -> CtapResult> { aes256_cbc_decrypt::(&self.aes_key, ciphertext, true) } - fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Ctap2StatusCode> { + fn verify(&self, message: &[u8], signature: &[u8]) -> CtapResult<()> { verify_v2::(&self.hmac_key, message, signature) } diff --git a/libraries/opensk/src/ctap/storage.rs b/libraries/opensk/src/ctap/storage.rs index 659ad067..305fa504 100644 --- a/libraries/opensk/src/ctap/storage.rs +++ b/libraries/opensk/src/ctap/storage.rs @@ -18,7 +18,7 @@ use crate::api::persist::{Persist, PersistCredentialIter}; use crate::ctap::data_formats::{ extract_array, extract_text_string, PublicKeyCredentialSource, PublicKeyCredentialUserEntity, }; -use crate::ctap::status_code::Ctap2StatusCode; +use crate::ctap::status_code::{Ctap2StatusCode, CtapResult}; use crate::env::{AesKey, Env}; use alloc::string::String; use alloc::vec::Vec; @@ -26,7 +26,7 @@ use alloc::vec::Vec; use sk_cbor::cbor_array_vec; /// Initializes the store by creating missing objects. -pub fn init(env: &mut impl Env) -> Result<(), Ctap2StatusCode> { +pub fn init(env: &mut impl Env) -> CtapResult<()> { env.persist().init()?; env.key_store().init()?; Ok(()) @@ -37,10 +37,7 @@ pub fn init(env: &mut impl Env) -> Result<(), Ctap2StatusCode> { /// # Errors /// /// Returns `CTAP2_ERR_VENDOR_INTERNAL_ERROR` if the key does not hold a valid credential. -pub fn get_credential( - env: &mut E, - key: usize, -) -> Result { +pub fn get_credential(env: &mut E, key: usize) -> CtapResult { let credential_entry = env.persist().credential_bytes(key)?; let wrap_key = env.key_store().wrap_key::()?; deserialize_credential::(&wrap_key, &credential_entry) @@ -78,7 +75,7 @@ pub fn find_credential( env: &mut impl Env, rp_id: &str, credential_id: &[u8], -) -> Result, Ctap2StatusCode> { +) -> CtapResult> { let credential = match find_credential_item(env, credential_id) { Err(Ctap2StatusCode::CTAP2_ERR_NO_CREDENTIALS) => return Ok(None), Err(e) => return Err(e), @@ -96,7 +93,7 @@ pub fn find_credential( pub fn store_credential( env: &mut E, new_credential: PublicKeyCredentialSource, -) -> Result<(), Ctap2StatusCode> { +) -> CtapResult<()> { // Holds the key of the existing credential if this is an update. let mut old_key = None; let mut iter_result = Ok(()); @@ -132,7 +129,7 @@ pub fn store_credential( /// # Errors /// /// Returns `CTAP2_ERR_NO_CREDENTIALS` if the credential is not found. -pub fn delete_credential(env: &mut impl Env, credential_id: &[u8]) -> Result<(), Ctap2StatusCode> { +pub fn delete_credential(env: &mut impl Env, credential_id: &[u8]) -> CtapResult<()> { let (key, _) = find_credential_item(env, credential_id)?; env.persist().remove_credential(key) } @@ -146,7 +143,7 @@ pub fn update_credential( env: &mut E, credential_id: &[u8], user: PublicKeyCredentialUserEntity, -) -> Result<(), Ctap2StatusCode> { +) -> CtapResult<()> { let (key, mut credential) = find_credential_item(env, credential_id)?; credential.user_name = user.user_name; credential.user_display_name = user.user_display_name; @@ -157,12 +154,12 @@ pub fn update_credential( } /// Returns the number of credentials. -pub fn count_credentials(env: &mut impl Env) -> Result { +pub fn count_credentials(env: &mut impl Env) -> CtapResult { Ok(env.persist().iter_credentials()?.count()) } /// Returns the estimated number of credentials that can still be stored. -pub fn remaining_credentials(env: &mut impl Env) -> Result { +pub fn remaining_credentials(env: &mut impl Env) -> CtapResult { env.customization() .max_supported_resident_keys() .checked_sub(count_credentials(env)?) @@ -174,13 +171,13 @@ pub fn remaining_credentials(env: &mut impl Env) -> Result( env: &'a mut E, - result: &'a mut Result<(), Ctap2StatusCode>, + result: &'a mut CtapResult<()>, ) -> Result, Ctap2StatusCode> { IterCredentials::new(env, result) } /// Returns the next creation order. -pub fn new_creation_order(env: &mut impl Env) -> Result { +pub fn new_creation_order(env: &mut impl Env) -> CtapResult { let mut iter_result = Ok(()); let iter = iter_credentials(env, &mut iter_result)?; let max = iter.map(|(_, credential)| credential.creation_order).max(); @@ -189,7 +186,7 @@ pub fn new_creation_order(env: &mut impl Env) -> Result { } /// Returns the number of remaining PIN retries. -pub fn pin_retries(env: &mut impl Env) -> Result { +pub fn pin_retries(env: &mut impl Env) -> CtapResult { Ok(env .customization() .max_pin_retries() @@ -197,17 +194,17 @@ pub fn pin_retries(env: &mut impl Env) -> Result { } /// Decrements the number of remaining PIN retries. -pub fn decr_pin_retries(env: &mut impl Env) -> Result<(), Ctap2StatusCode> { +pub fn decr_pin_retries(env: &mut impl Env) -> CtapResult<()> { env.persist().incr_pin_fails() } /// Resets the number of remaining PIN retries. -pub fn reset_pin_retries(env: &mut impl Env) -> Result<(), Ctap2StatusCode> { +pub fn reset_pin_retries(env: &mut impl Env) -> CtapResult<()> { env.persist().reset_pin_retries() } /// Returns the minimum PIN length. -pub fn min_pin_length(env: &mut impl Env) -> Result { +pub fn min_pin_length(env: &mut impl Env) -> CtapResult { Ok(env .persist() .min_pin_length()? @@ -216,13 +213,13 @@ pub fn min_pin_length(env: &mut impl Env) -> Result { /// Sets the minimum PIN length. #[cfg(feature = "config_command")] -pub fn set_min_pin_length(env: &mut impl Env, min_pin_length: u8) -> Result<(), Ctap2StatusCode> { +pub fn set_min_pin_length(env: &mut impl Env, min_pin_length: u8) -> CtapResult<()> { env.persist().set_min_pin_length(min_pin_length) } /// Returns the list of RP IDs that are used to check if reading the minimum PIN length is /// allowed. -pub fn min_pin_length_rp_ids(env: &mut impl Env) -> Result, Ctap2StatusCode> { +pub fn min_pin_length_rp_ids(env: &mut impl Env) -> CtapResult> { let rp_ids_bytes = env.persist().min_pin_length_rp_ids_bytes()?; let rp_ids = if rp_ids_bytes.is_empty() { Some(env.customization().default_min_pin_length_rp_ids()) @@ -238,7 +235,7 @@ pub fn min_pin_length_rp_ids(env: &mut impl Env) -> Result, Ctap2Sta pub fn set_min_pin_length_rp_ids( env: &mut impl Env, mut min_pin_length_rp_ids: Vec, -) -> Result<(), Ctap2StatusCode> { +) -> CtapResult<()> { for rp_id in env.customization().default_min_pin_length_rp_ids() { if !min_pin_length_rp_ids.contains(&rp_id) { min_pin_length_rp_ids.push(rp_id); @@ -255,7 +252,7 @@ pub fn set_min_pin_length_rp_ids( /// /// Without the AuthenticatorConfig command, customization determines the result. #[cfg(not(feature = "config_command"))] -pub fn enterprise_attestation(env: &mut impl Env) -> Result { +pub fn enterprise_attestation(env: &mut impl Env) -> CtapResult { Ok(env.customization().enterprise_attestation_mode().is_some()) } @@ -263,18 +260,18 @@ pub fn enterprise_attestation(env: &mut impl Env) -> Result Result { +pub fn enterprise_attestation(env: &mut impl Env) -> CtapResult { env.persist().enterprise_attestation() } /// Marks enterprise attestation as enabled. #[cfg(feature = "config_command")] -pub fn enable_enterprise_attestation(env: &mut impl Env) -> Result<(), Ctap2StatusCode> { +pub fn enable_enterprise_attestation(env: &mut impl Env) -> CtapResult<()> { env.persist().enable_enterprise_attestation() } /// Returns whether alwaysUv is enabled. -pub fn has_always_uv(env: &mut impl Env) -> Result { +pub fn has_always_uv(env: &mut impl Env) -> CtapResult { if env.customization().enforce_always_uv() { return Ok(true); } @@ -283,7 +280,7 @@ pub fn has_always_uv(env: &mut impl Env) -> Result { /// Enables alwaysUv, when disabled, and vice versa. #[cfg(feature = "config_command")] -pub fn toggle_always_uv(env: &mut impl Env) -> Result<(), Ctap2StatusCode> { +pub fn toggle_always_uv(env: &mut impl Env) -> CtapResult<()> { if env.customization().enforce_always_uv() { return Err(Ctap2StatusCode::CTAP2_ERR_OPERATION_DENIED); } @@ -302,15 +299,12 @@ pub struct IterCredentials<'a, E: Env> { /// /// It starts as success and gets written at most once with an error if something fails. The /// iteration stops as soon as an error is encountered. - result: &'a mut Result<(), Ctap2StatusCode>, + result: &'a mut CtapResult<()>, } impl<'a, E: Env> IterCredentials<'a, E> { /// Creates a credential iterator. - fn new( - env: &'a mut E, - result: &'a mut Result<(), Ctap2StatusCode>, - ) -> Result { + fn new(env: &'a mut E, result: &'a mut CtapResult<()>) -> CtapResult { let wrap_key = env.key_store().wrap_key::()?; let iter = env.persist().iter_credentials()?; Ok(IterCredentials { @@ -362,7 +356,7 @@ fn serialize_credential( env: &mut E, wrap_key: &AesKey, credential: PublicKeyCredentialSource, -) -> Result, Ctap2StatusCode> { +) -> CtapResult> { let mut data = Vec::new(); super::cbor_write(credential.to_cbor::(env.rng(), wrap_key)?, &mut data)?; Ok(data) @@ -375,13 +369,13 @@ fn deserialize_min_pin_length_rp_ids(data: &[u8]) -> Option> { .ok()? .into_iter() .map(extract_text_string) - .collect::, Ctap2StatusCode>>() + .collect::>>() .ok() } /// Serializes a list of RP IDs to storage representation. #[cfg(feature = "config_command")] -fn serialize_min_pin_length_rp_ids(rp_ids: Vec) -> Result, Ctap2StatusCode> { +fn serialize_min_pin_length_rp_ids(rp_ids: Vec) -> CtapResult> { let mut data = Vec::new(); super::cbor_write(cbor_array_vec!(rp_ids), &mut data)?; Ok(data) diff --git a/libraries/opensk/src/ctap/token_state.rs b/libraries/opensk/src/ctap/token_state.rs index 041aee36..7930a489 100644 --- a/libraries/opensk/src/ctap/token_state.rs +++ b/libraries/opensk/src/ctap/token_state.rs @@ -15,7 +15,7 @@ use crate::api::clock::Clock; use crate::api::crypto::sha256::Sha256; use crate::ctap::client_pin::PinPermission; -use crate::ctap::status_code::Ctap2StatusCode; +use crate::ctap::status_code::{Ctap2StatusCode, CtapResult}; use crate::env::{Env, Sha}; use alloc::string::String; @@ -59,7 +59,7 @@ impl PinUvAuthTokenState { } /// Checks if the permission is granted. - pub fn has_permission(&self, permission: PinPermission) -> Result<(), Ctap2StatusCode> { + pub fn has_permission(&self, permission: PinPermission) -> CtapResult<()> { if permission as u8 & self.permissions_set != 0 { Ok(()) } else { @@ -68,7 +68,7 @@ impl PinUvAuthTokenState { } /// Checks if there is no associated permissions RPID. - pub fn has_no_permissions_rp_id(&self) -> Result<(), Ctap2StatusCode> { + pub fn has_no_permissions_rp_id(&self) -> CtapResult<()> { if self.permissions_rp_id.is_some() { return Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID); } @@ -76,7 +76,7 @@ impl PinUvAuthTokenState { } /// Checks if the permissions RPID is associated. - pub fn has_permissions_rp_id(&self, rp_id: &str) -> Result<(), Ctap2StatusCode> { + pub fn has_permissions_rp_id(&self, rp_id: &str) -> CtapResult<()> { match &self.permissions_rp_id { Some(p) if rp_id == p => Ok(()), _ => Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID), @@ -84,7 +84,7 @@ impl PinUvAuthTokenState { } /// Checks if the permissions RPID's association matches the hash. - pub fn has_permissions_rp_id_hash(&self, rp_id_hash: &[u8]) -> Result<(), Ctap2StatusCode> { + pub fn has_permissions_rp_id_hash(&self, rp_id_hash: &[u8]) -> CtapResult<()> { match &self.permissions_rp_id { Some(p) if rp_id_hash == Sha::::digest(p.as_bytes()) => Ok(()), _ => Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID), diff --git a/libraries/opensk/src/test_helpers/mod.rs b/libraries/opensk/src/test_helpers/mod.rs index d0aaaa8b..632f0049 100644 --- a/libraries/opensk/src/test_helpers/mod.rs +++ b/libraries/opensk/src/test_helpers/mod.rs @@ -16,7 +16,7 @@ use crate::api::persist::{Attestation, AttestationId, Persist}; use crate::ctap::command::{AuthenticatorConfigParameters, Command}; use crate::ctap::data_formats::ConfigSubCommand; use crate::ctap::secret::Secret; -use crate::ctap::status_code::Ctap2StatusCode; +use crate::ctap::status_code::CtapResult; use crate::ctap::{Channel, CtapState}; use crate::env::Env; @@ -27,7 +27,7 @@ const DUMMY_CHANNEL: Channel = Channel::MainHid([0x12, 0x34, 0x56, 0x78]); pub fn enable_enterprise_attestation( state: &mut CtapState, env: &mut E, -) -> Result { +) -> CtapResult { let attestation = Attestation { private_key: Secret::from_exposed_secret([0x41; 32]), certificate: vec![0xdd; 20], diff --git a/src/env/tock/commands.rs b/src/env/tock/commands.rs index d60ddbc9..8c6381ab 100644 --- a/src/env/tock/commands.rs +++ b/src/env/tock/commands.rs @@ -29,7 +29,7 @@ use opensk::ctap::data_formats::{ extract_bool, extract_byte_string, extract_map, extract_unsigned, ok_or_missing, }; use opensk::ctap::secret::Secret; -use opensk::ctap::status_code::Ctap2StatusCode; +use opensk::ctap::status_code::{Ctap2StatusCode, CtapResult}; use opensk::ctap::{cbor_read, cbor_write, Channel}; use opensk::env::{Env, Sha}; use sk_cbor::{cbor_map_options, destructure_cbor_map}; @@ -58,7 +58,7 @@ fn process_cbor, bytes: &[u8], channel: Channel, -) -> Result>, Ctap2StatusCode> { +) -> CtapResult>> { match bytes[0] { VENDOR_COMMAND_CONFIGURE => { let decoded_cbor = cbor_read(&bytes[1..])?; @@ -97,7 +97,7 @@ fn process_vendor_configure< params: VendorConfigureParameters, // Unused in std only _channel: Channel, -) -> Result { +) -> CtapResult { if params.attestation_material.is_some() || params.lockdown { // This is removed in std so we don't need too many mocks in TockEnv. #[cfg(not(feature = "std"))] @@ -154,7 +154,7 @@ fn process_vendor_upgrade< >( env: &mut TockEnv, params: VendorUpgradeParameters, -) -> Result<(), Ctap2StatusCode> { +) -> CtapResult<()> { let VendorUpgradeParameters { offset, data, hash } = params; let calculated_hash = Sha::>::digest(&data); if hash != calculated_hash { @@ -171,7 +171,7 @@ fn process_vendor_upgrade_info< C: platform::subscribe::Config + platform::allow_ro::Config, >( env: &mut TockEnv, -) -> Result { +) -> CtapResult { let upgrade_locations = env .upgrade_storage() .ok_or(Ctap2StatusCode::CTAP1_ERR_INVALID_COMMAND)?; @@ -189,7 +189,7 @@ pub struct AttestationMaterial { impl TryFrom for AttestationMaterial { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { 0x01 => certificate, @@ -218,7 +218,7 @@ pub struct VendorConfigureParameters { impl TryFrom for VendorConfigureParameters { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { 0x01 => lockdown, @@ -246,7 +246,7 @@ pub struct VendorUpgradeParameters { impl TryFrom for VendorUpgradeParameters { type Error = Ctap2StatusCode; - fn try_from(cbor_value: cbor::Value) -> Result { + fn try_from(cbor_value: cbor::Value) -> CtapResult { destructure_cbor_map! { let { 0x01 => offset,