diff --git a/Cargo.toml b/Cargo.toml index 1d96bc9..87e09e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,8 +7,6 @@ license = "Apache-2.0 OR MIT" description = "no_std friendly types for FIDO CTAP" homepage = "https://github.com/solokeys/ctap-types" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] bitflags = "1.3" cbor-smol = "0.4" @@ -30,5 +28,4 @@ log-all = ["cbor-smol/log-all"] log-none = [] [patch.crates-io] -# heapless = { git = "https://github.com/nickray/heapless", branch = "bytebuf-0.5.6" } serde-indexed = { git = "https://github.com/trussed-dev/serde-indexed.git", rev = "d95cbe064ef0bfd0ce2d01582110e29fbc22afbd" } diff --git a/src/authenticator.rs b/src/authenticator.rs index 393c35c..4e26da8 100644 --- a/src/authenticator.rs +++ b/src/authenticator.rs @@ -6,10 +6,6 @@ use crate::ctap2; pub use ctap1::Authenticator as Ctap1Authenticator; pub use ctap2::Authenticator as Ctap2Authenticator; -// pub trait Authenticator { -// fn process(&mut self, request: &mut Request) -> Result; -// } - #[derive(Clone, Debug, PartialEq)] // clippy says (2022-02-26): large size difference // - first is 88 bytes @@ -31,15 +27,6 @@ pub enum Response { } /// Authenticator which supports both CTAP1 and CTAP2. -pub trait Authenticator: ctap1::Authenticator + ctap2::Authenticator { - // fn call(&mut self, request: &Request) -> Result { - // Ok(match request { - // Request::Ctap1(request) => Response::Ctap1(self.call_ctap1(request)?), - // Request::Ctap2(request) => Response::Ctap2(self.call_ctap2(request)?), - // }) - // } -} +pub trait Authenticator: ctap1::Authenticator + ctap2::Authenticator {} impl Authenticator for A {} - -// pub type Result = core::result::Result; diff --git a/src/authenticator/ctap1.rs b/src/authenticator/ctap1.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/authenticator/ctap2.rs b/src/authenticator/ctap2.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ctap1.rs b/src/ctap1.rs index fc6f508..19e7ef2 100644 --- a/src/ctap1.rs +++ b/src/ctap1.rs @@ -26,16 +26,6 @@ pub mod authenticate { pub count: u32, pub signature: Bytes<72>, } - - // impl AuthenticateResponse { - // pub fn new(user_presence: u8, count: u32, signature: Bytes<72>) -> Self { - // Self { - // user_presence, - // count, - // signature, - // } - // } - // } } pub mod register { diff --git a/src/ctap2.rs b/src/ctap2.rs index 7273461..784609b 100644 --- a/src/ctap2.rs +++ b/src/ctap2.rs @@ -175,22 +175,6 @@ impl Response { } } -// TODO: this is a bit weird to model... -// Need to be able to "skip unknown keys" in deserialization -// -// I think we want to model this is a "set of enums", -// and allow skipping unknown enum entries during deserialization -// -// NB: This depends on the command -// -// We need two things: -// - skip unknown fields -// #[derive(Clone,Debug,Eq,PartialEq,Serialize,Deserialize)] -// pub struct AuthenticatorExtensions { -// // #[serde(skip_serializing_if = "Option::is_none")] -// // pub cred_protect: -// } - #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct AuthenticatorOptions { #[serde(skip_serializing_if = "Option::is_none")] @@ -204,81 +188,6 @@ pub struct AuthenticatorOptions { pub uv: Option, } -// #[derive(Clone,Debug,Eq,PartialEq,SerializeIndexed,DeserializeIndexed)] -// // #[serde(rename_all = "camelCase")] -// #[serde_indexed(offset = 1)] -// pub struct GetAssertionParameters { -// pub rp_id: String<64>, -// pub client_data_hash: Bytes<32>, -// pub allow_list: Vec, -// #[serde(skip_serializing_if = "Option::is_none")] -// pub extensions: Option, -// #[serde(skip_serializing_if = "Option::is_none")] -// pub options: Option, -// #[serde(skip_serializing_if = "Option::is_none")] -// pub pin_auth: Option>, -// #[serde(skip_serializing_if = "Option::is_none")] -// pub pin_protocol: Option, -// } - -//// This is some pretty weird stuff ^^ -//// Example serialization: -//// { 1: 2, // kty (key type): tstr / int [ 2 = EC2 = elliptic curve with x and y coordinate pair -//// 1 = OKP = Octet Key Pair = for EdDSA -//// // kid, bstr -//// 3: -7, // alg: tstr / int -//// [ 4: // key_ops: tstr / int 1 = sign, 2 = verify, 3 = encrypt, 4 = decrypt, ...many more -//// -//// // the curve: 1 = P-256 -//// -1: 1, -//// // x-coordinate -//// -2: b'\xa0\xc3\x14\x06!\xefM\xcc\x06u\xf0\xf5v\x0bXa\xe6\xacm\x8d\xd9O`\xbd\x81\xf1\xe0_\x1a*\xdd\x9e', -//// // y-coordinate -//// -3: b'\xb4\xd4L\x94-\xbeVr\xe9C\x13u V\xf4t^\xe4.\xa2\x87I\xfe \xa4\xb0KY\x03\x00\x8c\x01'} -//// -//// EdDSA -//// 1: 1 -//// 3: -8, -//// -1: 6, -//// -2: public key bytes -//#[derive(Clone,Debug,Eq,PartialEq,Serialize,Deserialize)] -//#[serde(rename_all = "camelCase")] -//pub struct CredentialPublicKey { -//} - -// #[derive(Clone,Debug,Eq,PartialEq)] -// // #[serde(rename_all = "camelCase")] -// pub struct AuthenticatorData { -// pub rp_id_hash: Bytes<32>, -// pub flags: u8, -// pub sign_count: u32, -// // this can get pretty long -// pub attested_credential_data: Option>, -// // pub extensions: ? -// } - -// impl AuthenticatorData { -// pub fn serialize(&self) -> Bytes { -// let mut bytes = Vec::::new(); - -// // 32 bytes, the RP id's hash -// bytes.extend_from_slice(&self.rp_id_hash).unwrap(); -// // flags -// bytes.push(self.flags).unwrap(); -// // signature counts as 32-bit unsigned big-endian integer. -// bytes.extend_from_slice(&self.sign_count.to_be_bytes()).unwrap(); -// match &self.attested_credential_data { -// Some(ref attested_credential_data) => { -// // finally the attested credential data -// bytes.extend_from_slice(&attested_credential_data).unwrap(); -// }, -// None => {}, -// } - -// Bytes::from(bytes) -// } -// } - bitflags! { pub struct AuthenticatorDataFlags: u8 { const USER_PRESENCE = 1 << 0; @@ -293,13 +202,10 @@ pub trait SerializeAttestedCredentialData { } #[derive(Clone, Debug, Eq, PartialEq)] -// #[serde(rename_all = "camelCase")] pub struct AuthenticatorData { pub rp_id_hash: Bytes<32>, pub flags: AuthenticatorDataFlags, pub sign_count: u32, - // this can get pretty long - // pub attested_credential_data: Option>, pub attested_credential_data: Option, pub extensions: Option, } @@ -311,7 +217,6 @@ pub type SerializedAuthenticatorData = Bytes; impl AuthenticatorData { #[inline(never)] pub fn serialize(&self) -> SerializedAuthenticatorData { - // let mut bytes = Vec::::new(); let mut bytes = SerializedAuthenticatorData::new(); // 32 bytes, the RP id's hash @@ -341,38 +246,6 @@ impl AuthenticatorData< } } -// // TODO: add Default and builder -// #[derive(Clone,Debug,Eq,PartialEq,Serialize)] -// pub struct AuthenticatorInfo<'l> { -// pub(crate) versions: &'l[&'l str], -// #[serde(skip_serializing_if = "Option::is_none")] -// pub(crate) extensions: Option<&'l[&'l str]>, -// // #[serde(serialize_with = "serde_bytes::serialize")] -// pub(crate) aaguid: &'l [u8],//; 16], -// #[serde(skip_serializing_if = "Option::is_none")] -// pub(crate) options: Option, -// // TODO: this is actually the constant MESSAGE_SIZE -// #[serde(skip_serializing_if = "Option::is_none")] -// pub(crate) max_msg_size: Option, -// #[serde(skip_serializing_if = "Option::is_none")] -// pub(crate) pin_protocols: Option<&'l[u8]>, - -// // not in the CTAP spec, but see https://git.io/JeNxG -// #[serde(skip_serializing_if = "Option::is_none")] -// pub(crate) max_creds_in_list: Option, -// #[serde(skip_serializing_if = "Option::is_none")] -// pub(crate) max_cred_id_length: Option, -// #[serde(skip_serializing_if = "Option::is_none")] -// pub(crate) transports: Option<&'l[u8]>, -// #[serde(skip_serializing_if = "Option::is_none")] -// pub(crate) algorithms: Option<&'l[u8]>, -// } - -// pub enum Algorithm { -// ES256, -// EdDSA, -// } - #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Error { Success = 0x00, diff --git a/src/ctap2/credential_management.rs b/src/ctap2/credential_management.rs index e70c607..fc8b049 100644 --- a/src/ctap2/credential_management.rs +++ b/src/ctap2/credential_management.rs @@ -13,28 +13,23 @@ use crate::{ type Bytes32 = Bytes<32>; #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize_repr, Deserialize_repr)] -// #[derive(Clone,Debug,Eq,PartialEq,Serialize, Deserialize)] -// #[serde(tag = "credProtect")] #[repr(u8)] pub enum CredentialProtectionPolicy { - // #[serde(rename = "userVerificationOptional")] #[default] Optional = 1, - // #[serde(rename = "userVerificationOptionalWithCredentialIDList")] // <-- len = 44 OptionalWithCredentialIdList = 2, - // #[serde(rename = "userVerificationRequired")] Required = 3, } #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize_repr, Deserialize_repr)] #[repr(u8)] pub enum Subcommand { - GetCredsMetadata = 0x01, // 1, 2 - EnumerateRpsBegin = 0x02, // 3, 4, 5 - EnumerateRpsGetNextRp = 0x03, // 3, 4 - EnumerateCredentialsBegin = 0x04, // 6, 7, 8 ,9, A - EnumerateCredentialsGetNextCredential = 0x05, // 6, 7, 8, A - DeleteCredential = 0x06, // - + GetCredsMetadata = 0x01, + EnumerateRpsBegin = 0x02, + EnumerateRpsGetNextRp = 0x03, + EnumerateCredentialsBegin = 0x04, + EnumerateCredentialsGetNextCredential = 0x05, + DeleteCredential = 0x06, UpdateUserInformation = 0x07, } @@ -70,7 +65,6 @@ pub struct Request<'a> { #[derive(Clone, Debug, Default, Eq, PartialEq, SerializeIndexed)] #[serde_indexed(offset = 1)] -// #[derive(Clone,Debug, Default,Eq,PartialEq,Serialize,Deserialize)] pub struct Response { // Metadata @@ -104,7 +98,6 @@ pub struct Response { // 0x08 #[serde(skip_serializing_if = "Option::is_none")] pub public_key: Option, - // pub public_key: Option>, // <-- AAAAHH. no Bytes, just COSE_Key // 0x09 #[serde(skip_serializing_if = "Option::is_none")] pub total_credentials: Option, diff --git a/src/ctap2/get_assertion.rs b/src/ctap2/get_assertion.rs index c560e1b..ed75b2a 100644 --- a/src/ctap2/get_assertion.rs +++ b/src/ctap2/get_assertion.rs @@ -7,13 +7,6 @@ use super::AuthenticatorOptions; use crate::sizes::*; use crate::webauthn::*; -// #[derive(Clone,Debug,Eq,PartialEq,Serialize,Deserialize)] -// pub struct AuthenticatorExtensions { -// #[serde(rename = "hmac-secret")] -// #[serde(skip_serializing_if = "Option::is_none")] -// pub hmac_secret: Option, -// } - #[derive(Clone, Debug, Eq, PartialEq, SerializeIndexed, DeserializeIndexed)] #[serde_indexed(offset = 1)] pub struct HmacSecretInput { @@ -57,7 +50,6 @@ pub type AuthenticatorData = super::AuthenticatorData = Vec, MAX_CREDENTIAL_COUNT_IN_LIST>; #[derive(Clone, Debug, Eq, PartialEq, SerializeIndexed, DeserializeIndexed)] -// #[serde(rename_all = "camelCase")] #[serde_indexed(offset = 1)] pub struct Request<'a> { pub rp_id: String<64>, @@ -95,5 +87,3 @@ pub struct Response { #[serde(skip_serializing_if = "Option::is_none")] pub large_blob_key: Option>, } - -pub type Responses = Vec; diff --git a/src/ctap2/get_info.rs b/src/ctap2/get_info.rs index 68459f3..01d3869 100644 --- a/src/ctap2/get_info.rs +++ b/src/ctap2/get_info.rs @@ -16,10 +16,6 @@ pub struct Response { pub extensions: Option, 4>>, // 0x03 - // #[serde(with = "serde_bytes")] - // #[serde(serialize_with = "serde_bytes::serialize", deserialize_with = "serde_bytes::deserialize")] - // #[serde(serialize_with = "serde_bytes::serialize")] - // pub(crate) aaguid: Vec, pub aaguid: Bytes<16>, // 0x04 @@ -27,7 +23,6 @@ pub struct Response { pub options: Option, // 0x05 - // TODO: this is actually the constant MESSAGE_SIZE #[serde(skip_serializing_if = "Option::is_none")] pub max_msg_size: Option, @@ -54,8 +49,6 @@ pub struct Response { // FIDO_2_1 #[serde(skip_serializing_if = "Option::is_none")] pub algorithms: Option, - // #[serde(skip_serializing_if = "Option::is_none")] - // pub(crate) algorithms: Option<&'l[u8]>, // 0x0B // FIDO_2_1 diff --git a/src/ctap2/make_credential.rs b/src/ctap2/make_credential.rs index 930d908..9f73a96 100644 --- a/src/ctap2/make_credential.rs +++ b/src/ctap2/make_credential.rs @@ -8,22 +8,6 @@ use crate::ctap2::credential_management::CredentialProtectionPolicy; use crate::sizes::*; use crate::webauthn::*; -// // Approach 1: -// pub type AuthenticatorExtensions = heapless::LinearMap, bool, 2>; - -// impl TryFrom<&String<44>> for CredentialProtectionPolicy { -// type Error = crate::authenticator::Error; - -// fn try_from(value: &String<44>) -> Result { -// Ok(match value.as_str() { -// "userVerificationOptional" => CredentialProtectionPolicy::Optional, -// "userVerificationOptionalWithCredentialIDList" => CredentialProtectionPolicy::OptionalWithCredentialIdList, -// "userVerificationRequired" => CredentialProtectionPolicy::Required, -// _ => return Err(Self::Error::InvalidParameter), -// }) -// } -// } - impl TryFrom for CredentialProtectionPolicy { type Error = super::Error; @@ -37,15 +21,11 @@ impl TryFrom for CredentialProtectionPolicy { } } -// Approach 2: #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct Extensions { #[serde(rename = "credProtect")] #[serde(skip_serializing_if = "Option::is_none")] - // pub cred_protect: Option, pub cred_protect: Option, - // #[serde(serialize_with = "u8::from")] - // pub cred_protect: Option, #[serde(rename = "hmac-secret")] #[serde(skip_serializing_if = "Option::is_none")] pub hmac_secret: Option, @@ -55,23 +35,7 @@ pub struct Extensions { pub large_blob_key: Option, } -// // Approach 3: -// #[derive(Clone,Debug,Eq,PartialEq,Serialize,Deserialize)] -// pub enum AuthenticatorExtension { -// #[serde(rename = "hmac-secret")] -// HmacSecret(bool), -// #[serde(rename = "credProtect")] -// CredProtect(bool), -// } - -// #[derive(Clone,Debug,Eq,PartialEq,Serialize,Deserialize)] -// pub struct AuthenticatorExtensions { -// #[serde(flatten)] -// pub extensions: Vec, -// } - #[derive(Clone, Debug, Eq, PartialEq, SerializeIndexed, DeserializeIndexed)] -// #[serde(rename_all = "camelCase")] #[serde_indexed(offset = 1)] pub struct Request<'a> { pub client_data_hash: &'a serde_bytes::Bytes, @@ -92,66 +56,10 @@ pub struct Request<'a> { pub enterprise_attestation: Option, } -// It would be logical to call this Reponse :) pub type AttestationObject = Response; -// -// TODO: We have `Option`, use it to combine -// `fmt` and `att_stmt`! -// -// #[derive(Clone,Debug,Eq,PartialEq,Serialize)] -// #[serde(into = "ResponseExplicitEnumOption")] -// pub struct Response { -// pub auth_data: Bytes, -// pub att_stmt: Option, -// } - pub type AuthenticatorData = super::AuthenticatorData; -// #[derive(Clone,Debug,Eq,PartialEq)] -// // #[serde(rename_all = "camelCase")] -// pub struct AuthenticatorData { -// pub rp_id_hash: Bytes<32>, -// pub flags: Flags, -// pub sign_count: u32, -// // this can get pretty long -// // pub attested_credential_data: Option>, -// pub attested_credential_data: Option, -// pub extensions: Option -// } - -// pub type SerializedAuthenticatorData = Bytes; - -// // The reason for this non-use of CBOR is for compatibility with -// // FIDO U2F authentication signatures. -// impl AuthenticatorData { -// pub fn serialize(&self) -> SerializedAuthenticatorData { -// // let mut bytes = Vec::::new(); -// let mut bytes = SerializedAuthenticatorData::new(); - -// // 32 bytes, the RP id's hash -// bytes.extend_from_slice(&self.rp_id_hash).unwrap(); -// // flags -// bytes.push(self.flags.bits()).unwrap(); -// // signature counts as 32-bit unsigned big-endian integer. -// bytes.extend_from_slice(&self.sign_count.to_be_bytes()).unwrap(); - -// // the attested credential data -// if let Some(ref attested_credential_data) = &self.attested_credential_data { -// bytes.extend_from_slice(&attested_credential_data.serialize()).unwrap(); -// } - -// // the extensions data -// if let Some(ref extensions) = &self.extensions { -// let mut extensions_buf = [0u8; 128]; -// let ser = crate::serde::cbor_serialize(&extensions, &mut extensions_buf).unwrap(); -// bytes.extend_from_slice(ser).unwrap(); -// } - -// bytes -// } -// } - // NOTE: This is not CBOR, it has a custom encoding... // https://www.w3.org/TR/webauthn/#sec-attested-credential-data #[derive(Clone, Debug, Eq, PartialEq)] @@ -160,7 +68,6 @@ pub struct AttestedCredentialData { // this is where "unlimited non-resident keys" get stored // TODO: Model as actual credential ID, with ser/de to bytes (format is up to authenticator) pub credential_id: Bytes, - // pub credential_public_key: crate::cose::PublicKey,//Bytes, pub credential_public_key: Bytes, } @@ -198,7 +105,6 @@ impl super::SerializeAttestedCredentialData for AttestedCredentialData { pub struct Response { pub fmt: String<32>, pub auth_data: super::SerializedAuthenticatorData, - // pub att_stmt: Bytes<64>, pub att_stmt: AttestationStatement, #[serde(skip_serializing_if = "Option::is_none")] pub ep_att: Option, @@ -219,10 +125,6 @@ pub enum AttestationStatement { pub enum AttestationStatementFormat { None, Packed, - // Tpm, - // AndroidKey, - // AndroidSafetynet, - // FidoU2f, } #[derive(Clone, Debug, Eq, PartialEq, Serialize)] diff --git a/src/maybe_owned.rs b/src/maybe_owned.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/maybe_owned.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/operation.rs b/src/operation.rs index 11360af..4f6f4ec 100644 --- a/src/operation.rs +++ b/src/operation.rs @@ -61,7 +61,6 @@ impl TryFrom for VendorOperation { fn try_from(from: u8) -> core::result::Result { match from { - // code if code >= Self::FIRST && code <= Self::LAST => Ok(VendorOperation(code)), code @ Self::FIRST..=Self::LAST => Ok(VendorOperation(code)), _ => Err(()), }