diff --git a/crates/webauthn3-proto/.gitignore b/crates/webauthn3-proto/.gitignore
new file mode 100644
index 0000000..4fffb2f
--- /dev/null
+++ b/crates/webauthn3-proto/.gitignore
@@ -0,0 +1,2 @@
+/target
+/Cargo.lock
diff --git a/crates/webauthn3-proto/Cargo.toml b/crates/webauthn3-proto/Cargo.toml
new file mode 100644
index 0000000..f19abed
--- /dev/null
+++ b/crates/webauthn3-proto/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "webauthn3-proto"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+base64 = "0.21.0"
+credential-management-proto = { path = "../credential-management-proto" }
+fido-common = { path = "../fido-common" }
+serde = { version = "1.0", features = ["derive"], optional = true }
+
+[features]
+serde = ["dep:serde"]
diff --git a/crates/webauthn3-proto/src/attestation.rs b/crates/webauthn3-proto/src/attestation.rs
new file mode 100644
index 0000000..a6e1707
--- /dev/null
+++ b/crates/webauthn3-proto/src/attestation.rs
@@ -0,0 +1,28 @@
+#[cfg(feature = "serde")]
+use serde::{Deserialize, Serialize};
+
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[derive(Clone, Copy, Debug)]
+/// > WebAuthn Relying Parties may use AttestationConveyancePreference to
+/// > specify their preference regarding attestation conveyance during
+/// > credential generation.
+/// >
+/// >
+pub enum ConveyancePreference {
+ /// > The Relying Party is not interested in authenticator attestation.
+ #[cfg_attr(feature = "serde", serde(rename = "none"))]
+ None,
+ /// > The Relying Party wants to receive a verifiable attestation statement,
+ /// > but allows the client to decide how to obtain such an attestation
+ /// > statement.
+ #[cfg_attr(feature = "serde", serde(rename = "indirect"))]
+ Indirect,
+ /// > The Relying Party wants to receive the attestation statement as
+ /// > generated by the authenticator.
+ #[cfg_attr(feature = "serde", serde(rename = "direct"))]
+ Direct,
+ /// > The Relying Party wants to receive an attestation statement that may
+ /// > include uniquely identifying information.
+ #[cfg_attr(feature = "serde", serde(rename = "enterprise"))]
+ Enterprise,
+}
diff --git a/crates/webauthn3-proto/src/authenticator.rs b/crates/webauthn3-proto/src/authenticator.rs
new file mode 100644
index 0000000..925d1ee
--- /dev/null
+++ b/crates/webauthn3-proto/src/authenticator.rs
@@ -0,0 +1,35 @@
+#[cfg(feature = "serde")]
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Clone, Copy)]
+/// > This enumeration’s values describe authenticators' attachment modalities.
+/// > Relying Parties use this to express a preferred authenticator attachment
+/// > modality when calling `navigator.credentials.create()` to create a
+/// > credential, and clients use this to report the authenticator attachment
+/// > modality used to complete a registration or authentication ceremony.
+/// >
+/// >
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum Attachment {
+ #[cfg_attr(feature = "serde", serde(rename = "platform"))]
+ Platform,
+ #[cfg_attr(feature = "serde", serde(rename = "cross-platform"))]
+ CrossPlatform,
+}
+
+#[derive(Debug)]
+/// Contains the contents of an authenticator's response to a Relying Party's
+/// request.
+///
+/// >
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum Response {
+ // TODO: Fill out response???
+ // Attestation {
+ // client_data: client::Data<{ client::DataType::Create }>,
+ // attestation_object: Vec,
+ // },
+ // Assertion {
+ // client_data: client::Data<{ client::DataType::Get }>,
+ // },
+}
diff --git a/crates/webauthn3-proto/src/client.rs b/crates/webauthn3-proto/src/client.rs
new file mode 100644
index 0000000..1cb9379
--- /dev/null
+++ b/crates/webauthn3-proto/src/client.rs
@@ -0,0 +1,49 @@
+use crate::token;
+
+#[cfg(feature = "serde")]
+use serde::{Deserialize, Serialize};
+
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[derive(PartialEq, Eq, Clone, Copy)]
+pub enum DataType {
+ #[cfg_attr(feature = "serde", serde(rename = "webauthn.create"))]
+ Create,
+ #[cfg_attr(feature = "serde", serde(rename = "webauthn.get"))]
+ Get,
+}
+
+/// > The client data represents the contextual bindings of both the
+/// > `WebAuthn` Relying Party and the client.
+/// >
+/// >
+pub struct Data {
+ /// > This member contains the base64url encoding of the challenge
+ /// > provided by the Relying Party.
+ pub challenge: String,
+ /// > This member contains the fully qualified origin of the requester,
+ /// > as provided to the authenticator by the client, in the syntax
+ /// > defined by
+ /// > [RFC6454](https://www.w3.org/TR/webauthn-3/#biblio-rfc6454).
+ pub origin: String,
+ // TODO: Description
+ pub cross_origin: Option,
+ /// > ...contains information about the state of the Token Binding
+ /// > protocol... used when communicating with the Relying Party. Its
+ /// > absence indicates that the client doesn’t support token binding.
+ pub token_binding: Option,
+}
+
+#[cfg(feature = "serde")]
+impl Serialize for Data {
+ fn serialize(&self, serializer: S) -> Result
+ where
+ S: serde::Serializer,
+ {
+ // Keys are: "type", "challenge", "origin", "topOrigin", "crossOrigin"
+ const LEN: usize = 5;
+ let mut map = serializer.serialize_map(Some(LEN))?;
+
+ // map.serialize_entry("type", value)
+ todo!()
+ }
+}
diff --git a/crates/webauthn3-proto/src/lib.rs b/crates/webauthn3-proto/src/lib.rs
new file mode 100644
index 0000000..883f9e3
--- /dev/null
+++ b/crates/webauthn3-proto/src/lib.rs
@@ -0,0 +1,34 @@
+#![feature(async_fn_in_trait, adt_const_params, associated_const_equality)]
+#![allow(incomplete_features, clippy::unused_async, clippy::doc_markdown)]
+
+pub mod attestation;
+pub mod authenticator;
+pub mod client;
+pub mod public_key;
+pub mod token;
+
+#[cfg(feature = "serde")]
+use serde::{Deserialize, Serialize};
+
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[derive(Debug, Clone, Copy)]
+/// > A WebAuthn Relying Party may require user verification for some of its
+/// > operations but not for others, and may use this type to express its needs.
+pub enum UserVerificationRequirement {
+ /// > The Relying Party requires user verification for the operation and
+ /// > will fail the overall ceremony if the response does not have the UV
+ /// > flag set. The client MUST return an error if user verification cannot
+ /// > be performed.
+ #[cfg_attr(feature = "serde", serde(rename = "required"))]
+ Required,
+ /// > The Relying Party prefers user verification for the operation if
+ /// > possible, but will not fail the operation if the response does not
+ /// > have the UV flag set.
+ #[cfg_attr(feature = "serde", serde(rename = "preferred"))]
+ Preferred,
+ /// > The Relying Party does not want user verification employed during the
+ /// > operation (e.g., in the interest of minimizing disruption to the user
+ /// > interaction flow).
+ #[cfg_attr(feature = "serde", serde(rename = "discouraged"))]
+ Discouraged,
+}
diff --git a/crates/webauthn3-proto/src/public_key.rs b/crates/webauthn3-proto/src/public_key.rs
new file mode 100644
index 0000000..e42759e
--- /dev/null
+++ b/crates/webauthn3-proto/src/public_key.rs
@@ -0,0 +1,51 @@
+use crate::authenticator;
+use credential_management_proto::{credential, discovery};
+
+pub mod create;
+pub mod request;
+
+/// > The [`public_key::Credential`] interface inherits from
+/// > [`credential::Credential`], and contains the attributes that are returned
+/// > to the caller when a new credential is created, or a new assertion is
+/// > requested.
+/// >
+/// >
+pub trait Credential: credential::Credential {
+ /// Returns the raw byte array of the credential's `id`.
+ fn raw_id(&self) -> &[u8];
+
+ /// > This attribute contains the authenticator's response to the client’s
+ /// > request to either create a public key credential, or generate an
+ /// > authentication assertion. If the [`public_key::Credential`] is created
+ /// > in response to `create()`, this attribute’s value will be an
+ /// > [`authenticator::Response::Attestation`], otherwise, the
+ /// > [`public_key::Credential`] was created in response to `get()`, and
+ /// > this attribute’s value will be an
+ /// > [`authenticator::Response::Assertion`].
+ fn response(&self) -> &authenticator::Response;
+
+ /// > This attribute reports the authenticator attachment modality in effect
+ /// > at the time the `navigator.credentials.create()` or
+ /// > `navigator.credentials.get()` methods successfully complete.
+ ///
+ /// If the attachment method is unknown, this function returns `None`.
+ fn authenticator_attachment(&self) -> Option;
+}
+
+pub trait Container:
+ for<'a> credential::Container<
+ Credential = Self::PublicKeyCredential,
+ RequestOptions = Self::PublicKeyRequestOptions,
+ CreateOptions = Self::PublicKeyCreateOptions,
+ DISCOVERY_MODE = { discovery::Mode::Remote },
+>
+{
+ type PublicKeyCredential: Credential;
+ type PublicKeyRequestOptions: request::Options;
+ type PublicKeyCreateOptions: create::Options;
+
+ /// > ...indicate[s] availability for conditional mediation.
+ /// >
+ /// >
+ async fn is_conditional_mediation_available() -> bool;
+}
diff --git a/crates/webauthn3-proto/src/public_key/create.rs b/crates/webauthn3-proto/src/public_key/create.rs
new file mode 100644
index 0000000..519245b
--- /dev/null
+++ b/crates/webauthn3-proto/src/public_key/create.rs
@@ -0,0 +1,106 @@
+use fido_common::{attestation::FormatIdentifier, credential::public_key};
+
+use crate::{attestation, authenticator, UserVerificationRequirement};
+
+#[cfg(feature = "serde")]
+use serde::{Deserialize, Serialize};
+
+/// >
+pub trait Options {
+ /// > This member contains a name and an identifier for the Relying Party
+ /// > responsible for the request.
+ fn public_key_credential_relying_party_entity(&self) -> &public_key::RelyingPartyEntity;
+
+ /// > This member contains names and an identifier for the user account
+ /// > performing the registration.
+ fn public_key_credential_user_entity(&self) -> &public_key::UserEntity;
+
+ /// > This member specifies a challenge that the authenticator signs, along
+ /// > with other data, when producing an attestation object for the newly
+ /// > created credential.
+ fn challenge(&self) -> &[u8];
+
+ /// > This member lists the key types and signature algorithms the Relying
+ /// > Party supports, ordered from most preferred to least preferred.
+ fn public_key_credential_parameters(&self) -> &[public_key::Parameters];
+
+ /// > This OPTIONAL member specifies a time, in milliseconds, that the
+ /// > Relying Party is willing to wait for the call to complete. This is
+ /// > treated as a hint, and MAY be overridden by the client.
+ fn timeout(&self) -> Option;
+
+ /// > The Relying Party SHOULD use this OPTIONAL member to list any existing
+ /// > credentials mapped to this user account (as identified by `user.id`).
+ /// > This ensures that the new credential is not created on an
+ /// > authenticator that already contains a credential mapped to this user
+ /// > account. If it would be, the client is requested to instead guide the
+ /// > user to use a different authenticator, or return an error if that
+ /// > fails.
+ fn exclude_credentials(&self) -> Option<&[public_key::Descriptor]>;
+
+ /// > The Relying Party MAY use this OPTIONAL member to specify capabilities
+ /// > and settings that the authenticator MUST or SHOULD satisfy to
+ /// > participate in the `create()` operation.
+ fn authenticator_selection(&self) -> Option;
+
+ /// > The Relying Party MAY use this OPTIONAL member to specify a preference
+ /// > regarding attestation conveyance.
+ fn attestation(&self) -> Option;
+
+ /// > The Relying Party MAY use this OPTIONAL member to specify a preference
+ /// > regarding the attestation statement format used by the authenticator.
+ fn attestation_formats(&self) -> &[FormatIdentifier];
+}
+
+/// > WebAuthn Relying Parties may use the [`AuthenticatorSelectionCriteria`]
+/// > dictionary to specify their requirements regarding authenticator
+/// > attributes.
+/// >
+/// >
+#[derive(Debug, Clone, Copy)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct AuthenticatorSelectionCriteria {
+ /// > If this member is present, eligible authenticators are filtered to be
+ /// > only those authenticators attached with the specified authenticator
+ /// > attachment modality... If this member is absent, then any attachment
+ /// > modality is acceptable.
+ #[cfg_attr(feature = "serde", serde(rename = "authenticatorAttachment"))]
+ pub attachment: Option,
+ /// > Specifies the extent to which the Relying Party desires to create a
+ /// > client-side discoverable credential.
+ #[cfg_attr(feature = "serde", serde(rename = "residentKey"))]
+ pub resident_key_requirement: ResidentKeyRequirement,
+ /// > This member specifies the Relying Party's requirements regarding user
+ /// > verification for the `create()` operation.
+ pub user_verification_requirement: UserVerificationRequirement,
+}
+
+/// > This enumeration’s values describe the Relying Party's requirements for
+/// > client-side discoverable credentials (formerly known as resident
+/// > credentials or resident keys):
+/// >
+/// >
+#[derive(Debug, Clone, Copy)]
+#[cfg_attr(
+ feature = "serde",
+ derive(Serialize, Deserialize),
+ serde(rename_all = "camelCase")
+)]
+pub enum ResidentKeyRequirement {
+ /// > The Relying Party prefers creating a server-side credential, but will
+ /// > accept a client-side discoverable credential. The client and
+ /// > authenticator SHOULD create a server-side credential if possible.
+ Discouraged,
+ /// > The Relying Party strongly prefers creating a client-side discoverable
+ /// > credential, but will accept a server-side credential. The client and
+ /// > authenticator SHOULD create a discoverable credential if possible. For
+ /// > example, the client SHOULD guide the user through setting up user
+ /// > verification if needed to create a discoverable credential. This takes
+ /// > precedence over the setting of
+ /// > [`AuthenticatorSelectionCriteria::user_verification`].
+ Preferred,
+ /// > The Relying Party requires a client-side discoverable credential. The
+ /// > client MUST return an error if a client-side discoverable credential
+ /// > cannot be created.
+ Required,
+}
diff --git a/crates/webauthn3-proto/src/public_key/request.rs b/crates/webauthn3-proto/src/public_key/request.rs
new file mode 100644
index 0000000..6434fee
--- /dev/null
+++ b/crates/webauthn3-proto/src/public_key/request.rs
@@ -0,0 +1,46 @@
+use fido_common::{attestation::FormatIdentifier, credential::public_key};
+
+use crate::{attestation, UserVerificationRequirement};
+
+/// > [This struct] supplies `get()` with the data it needs to generate an
+/// > assertion.
+pub trait Options {
+ /// > This member specifies a challenge that the authenticator signs, along
+ /// > with other data, when producing an authentication assertion.
+ fn challenge(&self) -> &[u8];
+ /// > This OPTIONAL member specifies a time, in milliseconds, that the
+ /// > Relying Party is willing to wait for the call to complete. The value
+ /// > is treated as a hint, and MAY be overridden by the client.
+ fn timeout(&self) -> Option;
+ /// > This OPTIONAL member specifies the RP ID claimed by the Relying Party.
+ /// > The client MUST verify that the Relying Party's origin matches the
+ /// > scope of this RP ID. The authenticator MUST verify that this RP ID
+ /// > exactly equals the rpId of the credential to be used for the
+ /// > authentication ceremony.
+ /// >
+ /// > If not specified, its value will be the [`CredentialsContainer`]
+ /// > object’s relevant settings object's origin's effective domain.
+ fn relying_party_id(&self) -> Option<&str>;
+ /// > This OPTIONAL member is used by the client to find authenticators
+ /// > eligible for this authentication ceremony.
+ /// > ...
+ /// > If not empty, the client MUST return an error if none of the listed
+ /// > credentials can be used.
+ /// >
+ /// > The list is ordered in descending order of preference: the first item
+ /// > in the list is the most preferred credential, and the last is the
+ /// > least preferred.
+ fn allow_credentials(&self) -> Option<&[public_key::Descriptor]>;
+ /// > ... specifies the Relying Party's requirements regarding user
+ /// > verification for the get() operation... Eligible authenticators are
+ /// > filtered to only those capable of satisfying this requirement.
+ fn user_verification(&self) -> Option;
+ /// > The Relying Party MAY use this OPTIONAL member to specify a preference
+ /// > regarding attestation conveyance.
+ fn attestation(&self) -> Option;
+ /// > The Relying Party MAY use this OPTIONAL member to specify a preference
+ /// > regarding the attestation statement format used by the
+ /// > authenticator... Values are ordered from most preferable to least
+ /// > preferable.
+ fn attestation_formats(&self) -> Option<&[FormatIdentifier]>;
+}
diff --git a/crates/webauthn3-proto/src/token.rs b/crates/webauthn3-proto/src/token.rs
new file mode 100644
index 0000000..2fd466b
--- /dev/null
+++ b/crates/webauthn3-proto/src/token.rs
@@ -0,0 +1,20 @@
+pub enum BindingStatus {
+ /// > Indicates token binding was used when communicating with the
+ /// > Relying
+ /// > Party. In this case, the `TokenBinding::id` member MUST be
+ /// > present.
+ Present,
+ /// > Indicates the client supports token binding, but it was not
+ /// > negotiated
+ /// > when communicating with the Relying Party.
+ Supported,
+}
+
+pub struct Binding {
+ /// > ...a base64url encoding of the Token Binding ID that was used when
+ /// > communicating with the Relying Party.
+ pub id: String,
+ /// Indicates the usage and support status of token binding by the
+ /// client.
+ pub status: BindingStatus,
+}