Skip to content

Commit

Permalink
Mark requests and responses as non-exhaustive
Browse files Browse the repository at this point in the history
  • Loading branch information
robin-nitrokey committed Jun 12, 2024
1 parent 261c928 commit 3e42568
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add support for permissions in `ctap2::client_pin`
- Replace `cose` module with `cosey` dependency ([#36][])
- Mark `get_assertion::{ExtensionsInput, ExtensionsOutput}` and `make_credential::Extensions` as non-exhaustive and implement `Default`
- Mark CTAP2 request and response types as non-exhaustive where possible

[#8]: https://github.com/trussed-dev/ctap-types/pull/8
[#9]: https://github.com/solokeys/ctap-types/issues/9
Expand Down
4 changes: 4 additions & 0 deletions src/ctap2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub mod make_credential;
pub type Result<T> = core::result::Result<T, Error>;

#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
#[allow(clippy::large_enum_variant)]
// clippy says...large size difference
/// Enum of all CTAP2 requests.
Expand Down Expand Up @@ -127,6 +128,7 @@ impl<'a> Request<'a> {
}

#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
/// Enum of all CTAP2 responses.
#[allow(clippy::large_enum_variant)]
pub enum Response {
Expand Down Expand Up @@ -176,6 +178,7 @@ impl Response {
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AuthenticatorOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub rk: Option<bool>,
Expand Down Expand Up @@ -247,6 +250,7 @@ impl<A: SerializeAttestedCredentialData, E: serde::Serialize> AuthenticatorData<
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Error {
Success = 0x00,
InvalidCommand = 0x01,
Expand Down
3 changes: 3 additions & 0 deletions src/ctap2/client_pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use serde_indexed::{DeserializeIndexed, SerializeIndexed};
use serde_repr::{Deserialize_repr, Serialize_repr};

#[derive(Clone, Debug, Eq, PartialEq, Serialize_repr, Deserialize_repr)]
#[non_exhaustive]
#[repr(u8)]
pub enum PinV1Subcommand {
GetRetries = 0x01,
Expand Down Expand Up @@ -34,6 +35,7 @@ bitflags! {
// maximum consecutive incorrect PIN attempts: 8

#[derive(Clone, Debug, Eq, PartialEq, SerializeIndexed, DeserializeIndexed)]
#[non_exhaustive]
#[serde_indexed(offset = 1)]
pub struct Request<'a> {
// 0x01
Expand Down Expand Up @@ -88,6 +90,7 @@ pub struct Request<'a> {
}

#[derive(Clone, Debug, Default, Eq, PartialEq, SerializeIndexed, DeserializeIndexed)]
#[non_exhaustive]
#[serde_indexed(offset = 1)]
pub struct Response {
// 0x01, like ClientPinParameters::key_agreement
Expand Down
4 changes: 4 additions & 0 deletions src/ctap2/credential_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub enum CredentialProtectionPolicy {
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize_repr, Deserialize_repr)]
#[non_exhaustive]
#[repr(u8)]
pub enum Subcommand {
GetCredsMetadata = 0x01,
Expand All @@ -34,6 +35,7 @@ pub enum Subcommand {
}

#[derive(Clone, Debug, Eq, PartialEq, SerializeIndexed, DeserializeIndexed)]
#[non_exhaustive]
#[serde_indexed(offset = 1)]
pub struct SubcommandParameters<'a> {
// 0x01
Expand All @@ -48,6 +50,7 @@ pub struct SubcommandParameters<'a> {
}

#[derive(Clone, Debug, Eq, PartialEq, SerializeIndexed, DeserializeIndexed)]
#[non_exhaustive]
#[serde_indexed(offset = 1)]
pub struct Request<'a> {
// 0x01
Expand All @@ -64,6 +67,7 @@ pub struct Request<'a> {
}

#[derive(Clone, Debug, Default, Eq, PartialEq, SerializeIndexed)]
#[non_exhaustive]
#[serde_indexed(offset = 1)]
pub struct Response {
// Metadata
Expand Down
28 changes: 26 additions & 2 deletions src/ctap2/get_assertion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::sizes::*;
use crate::webauthn::*;

#[derive(Clone, Debug, Eq, PartialEq, SerializeIndexed, DeserializeIndexed)]
#[non_exhaustive]
#[serde_indexed(offset = 1)]
pub struct HmacSecretInput {
pub key_agreement: EcdhEsHkdf256PublicKey,
Expand Down Expand Up @@ -52,6 +53,7 @@ pub type AuthenticatorData = super::AuthenticatorData<NoAttestedCredentialData,
pub type AllowList<'a> = Vec<PublicKeyCredentialDescriptorRef<'a>, MAX_CREDENTIAL_COUNT_IN_LIST>;

#[derive(Clone, Debug, Eq, PartialEq, SerializeIndexed, DeserializeIndexed)]
#[non_exhaustive]
#[serde_indexed(offset = 1)]
pub struct Request<'a> {
pub rp_id: String<64>,
Expand All @@ -72,10 +74,10 @@ pub struct Request<'a> {
// https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#authenticatorMakeCredential
// does not coincide with what python-fido2 expects in AttestationObject.__init__ *at all* :'-)
#[derive(Clone, Debug, Eq, PartialEq, SerializeIndexed, DeserializeIndexed)]
#[non_exhaustive]
#[serde_indexed(offset = 1)]
pub struct Response {
#[serde(skip_serializing_if = "Option::is_none")]
pub credential: Option<PublicKeyCredentialDescriptor>,
pub credential: PublicKeyCredentialDescriptor,
pub auth_data: Bytes<AUTHENTICATOR_DATA_LENGTH>,
pub signature: Bytes<ASN1_SIGNATURE_LENGTH>,
#[serde(skip_serializing_if = "Option::is_none")]
Expand All @@ -89,3 +91,25 @@ pub struct Response {
#[serde(skip_serializing_if = "Option::is_none")]
pub large_blob_key: Option<Bytes<32>>,
}

#[derive(Debug)]
pub struct ResponseBuilder {
pub credential: PublicKeyCredentialDescriptor,
pub auth_data: Bytes<AUTHENTICATOR_DATA_LENGTH>,
pub signature: Bytes<ASN1_SIGNATURE_LENGTH>,
}

impl ResponseBuilder {
#[inline(always)]
pub fn build(self) -> Response {
Response {
credential: self.credential,
auth_data: self.auth_data,
signature: self.signature,
user: None,
number_of_credentials: None,
user_selected: None,
large_blob_key: None,
}
}
}
27 changes: 27 additions & 0 deletions src/ctap2/get_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use serde_indexed::{DeserializeIndexed, SerializeIndexed};
pub type AuthenticatorInfo = Response;

#[derive(Clone, Debug, Eq, PartialEq, SerializeIndexed, DeserializeIndexed)]
#[non_exhaustive]
#[serde_indexed(offset = 1)]
pub struct Response {
// 0x01
Expand Down Expand Up @@ -78,7 +79,33 @@ impl Default for Response {
}
}

#[derive(Debug)]
pub struct ResponseBuilder {
pub versions: Vec<String<12>, 4>,
pub aaguid: Bytes<16>,
}

impl ResponseBuilder {
#[inline(always)]
pub fn build(self) -> Response {
Response {
versions: self.versions,
aaguid: self.aaguid,
extensions: None,
options: None,
max_msg_size: None,
pin_protocols: None,
max_creds_in_list: None,
max_cred_id_length: None,
transports: None,
algorithms: None,
max_serialized_large_blob_array: None,
}
}
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
#[serde(rename_all = "camelCase")]
pub struct CtapOptions {
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down
2 changes: 2 additions & 0 deletions src/ctap2/large_blobs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use serde_indexed::{DeserializeIndexed, SerializeIndexed};

// See: https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#largeBlobsRW
#[derive(Clone, Debug, Eq, PartialEq, SerializeIndexed, DeserializeIndexed)]
#[non_exhaustive]
#[serde_indexed(offset = 1)]
pub struct Request<'a> {
// 0x01
Expand All @@ -26,6 +27,7 @@ pub struct Request<'a> {
}

#[derive(Clone, Debug, Default, Eq, PartialEq, SerializeIndexed, DeserializeIndexed)]
#[non_exhaustive]
#[serde_indexed(offset = 1)]
pub struct Response {
// 0x01
Expand Down
24 changes: 24 additions & 0 deletions src/ctap2/make_credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub struct Extensions {
}

#[derive(Clone, Debug, Eq, PartialEq, SerializeIndexed, DeserializeIndexed)]
#[non_exhaustive]
#[serde_indexed(offset = 1)]
pub struct Request<'a> {
pub client_data_hash: &'a serde_bytes::Bytes,
Expand Down Expand Up @@ -102,6 +103,7 @@ impl super::SerializeAttestedCredentialData for AttestedCredentialData {
}

#[derive(Clone, Debug, Eq, PartialEq, SerializeIndexed)]
#[non_exhaustive]
#[serde_indexed(offset = 1)]
pub struct Response {
pub fmt: String<32>,
Expand All @@ -113,7 +115,28 @@ pub struct Response {
pub large_blob_key: Option<Bytes<32>>,
}

#[derive(Debug)]
pub struct ResponseBuilder {
pub fmt: String<32>,
pub auth_data: super::SerializedAuthenticatorData,
pub att_stmt: AttestationStatement,
}

impl ResponseBuilder {
#[inline(always)]
pub fn build(self) -> Response {
Response {
fmt: self.fmt,
auth_data: self.auth_data,
att_stmt: self.att_stmt,
ep_att: None,
large_blob_key: None,
}
}
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[non_exhaustive]
#[serde(untagged)]
#[allow(clippy::large_enum_variant)]
pub enum AttestationStatement {
Expand All @@ -122,6 +145,7 @@ pub enum AttestationStatement {
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[non_exhaustive]
#[serde(untagged)]
pub enum AttestationStatementFormat {
None,
Expand Down

0 comments on commit 3e42568

Please sign in to comment.