Skip to content

Commit

Permalink
fix commoncacao webauthn verification
Browse files Browse the repository at this point in the history
  • Loading branch information
chunningham committed Oct 19, 2023
1 parent 9020c3d commit 9456416
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 23 deletions.
73 changes: 52 additions & 21 deletions src/v3/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use super::{
RecapVerify,
},
ucan_cacao::{Error as UcanError, UcanCacao, UcanSignature},
webauthn::{WebauthnCacao, WebauthnSignature, WebauthnVersion},
webauthn::{Error as WebauthnError, WebauthnCacao, WebauthnSignature, WebauthnVersion},
CacaoVerifier, Flattener,
};
use async_trait::async_trait;
Expand Down Expand Up @@ -186,16 +186,18 @@ where
}

#[derive(thiserror::Error, Debug)]
pub enum Error<U: std::error::Error = UcanError> {
pub enum Error<U: std::error::Error = UcanError, W: std::error::Error = WebauthnError> {
#[error(transparent)]
Ucan(U),
#[error(transparent)]
Recap(#[from] RecapError),
#[error(transparent)]
Webauthn(W),
#[error("Signature and Facts Mismatch")]
Mismatch,
}

impl From<UcanError> for Error {
impl<W: std::error::Error> From<UcanError> for Error<UcanError, W> {
fn from(e: UcanError) -> Self {
Self::Ucan(e)
}
Expand All @@ -207,25 +209,37 @@ impl From<VerificationError<jose::Error>> for Error {
}
}

impl<U: std::error::Error> From<WebauthnError> for Error<U, WebauthnError> {
fn from(e: WebauthnError) -> Self {
Self::Webauthn(e)
}
}

#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<'r, U, NB, W, R> CacaoVerifier<CommonCacao<U, NB, W>> for CommonVerifier<R>
where
R: 'r + Send + Sync + CacaoVerifier<UcanCacao<U, NB>>,
R: 'r + Send + Sync + CacaoVerifier<UcanCacao<U, NB>> + CacaoVerifier<WebauthnCacao<W, NB>>,
U: Send + Sync + for<'a> Deserialize<'a> + Serialize + Clone,
NB: Send + Sync + for<'a> Deserialize<'a> + Serialize + Clone,
W: Send + Sync + for<'a> Deserialize<'a> + Serialize + Clone,
{
type Error = Error<R::Error>;
type Error = Error<
<R as CacaoVerifier<UcanCacao<U, NB>>>::Error,
<R as CacaoVerifier<WebauthnCacao<W, NB>>>::Error,
>;

async fn verify(&self, cacao: &CommonCacao<U, NB, W>) -> Result<(), Self::Error> {
match RecapCacao::try_from(cacao.clone()) {
Ok(recap) => self.verify(&recap).await?,
Err(c) => match UcanCacao::try_from(c) {
Ok(ucan) => self.verify(&ucan).await.map_err(Error::Ucan)?,
Err(_) => {
return Err(Error::Mismatch);
}
Err(c) => match WebauthnCacao::try_from(c) {
Ok(webauthn) => self.verify(&webauthn).await.map_err(Error::Webauthn)?,
Err(_) => {
return Err(Error::Mismatch);
}
},
},
};
Ok(())
Expand Down Expand Up @@ -261,6 +275,21 @@ where
}
}

#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<'r, NB, R, F> CacaoVerifier<WebauthnCacao<F, NB>> for CommonVerifier<R>
where
R: 'r + Send + Sync + CacaoVerifier<WebauthnCacao<F, NB>>,
F: Send + Sync + for<'a> Deserialize<'a> + Serialize + Clone,
NB: Send + Sync + for<'a> Deserialize<'a> + Serialize + Clone,
{
type Error = R::Error;

async fn verify(&self, cacao: &WebauthnCacao<F, NB>) -> Result<(), Self::Error> {
self.0.verify(cacao).await
}
}

macro_rules! impl_from {
($from:ty, $typ:tt) => {
impl<U, NB, W> From<$from> for CommonCacao<U, NB, W> {
Expand Down Expand Up @@ -351,6 +380,7 @@ impl<U, NB, W> CommonCacao<U, NB, W> {
}
}

// because we can't use the `#[serde(flatten)]` attribute when serializing dagcbor
impl<U: Serialize, NB: Serialize, W: Serialize> Serialize for CommonCacao<U, NB, W> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
Expand All @@ -360,39 +390,39 @@ impl<U: Serialize, NB: Serialize, W: Serialize> Serialize for CommonCacao<U, NB,
let mut map = serializer.serialize_struct("CommonCacao", self.ser_len())?;
map.serialize_field("att", &self.attenuations)?;
map.serialize_field("aud", &self.audience)?;
map.serialize_field("iss", &self.issuer)?;
if let Some(nonce) = self.nonce() {
map.serialize_field("nnc", &nonce)?;
if let Some(expiration) = self.expiration() {
map.serialize_field("exp", &expiration)?;
};
if let Some(proof) = self.proof() {
map.serialize_field("prf", &proof)?;
if let Some(facts) = self.facts() {
map.serialize_field("fct", &facts)?;
};
if let Some(issued_at) = self.issued_at() {
map.serialize_field("iat", &issued_at)?;
};
map.serialize_field("iss", &self.issuer)?;
if let Some(not_before) = self.not_before() {
map.serialize_field("nbf", &not_before)?;
};
if let Some(expiration) = self.expiration() {
map.serialize_field("exp", &expiration)?;
if let Some(nonce) = self.nonce() {
map.serialize_field("nnc", &nonce)?;
};
if let Some(proof) = self.proof() {
map.serialize_field("prf", &proof)?;
};
match &self.typ {
Types::Ucan(t) => {
map.serialize_field("v", &t.version)?;
map.serialize_field("s", &t.signature)?;
map.serialize_field("v", &t.version)?;
}
Types::Recap(t) => {
map.serialize_field("v", &t.version)?;
map.serialize_field("s", &t.signature)?;
map.serialize_field("v", &t.version)?;
}
Types::Webauthn(t) => {
map.serialize_field("v", &t.version)?;
map.serialize_field("s", &t.signature)?;
map.serialize_field("v", &t.version)?;
}
};
if let Some(facts) = self.facts() {
map.serialize_field("fct", &facts)?;
};
map.end()
}
}
Expand All @@ -405,6 +435,7 @@ mod test {
async fn basic() {
let encoded = [
"qmNpc3NYG50aygECAbFNPE9fv7z7mK8tMwAA1JyVuTqnAGNhdWRYVp0a7QE4NstKM22BZAAHaojdiik61NN1l7wVRKwcQJWixAbFHzEjejZNa2lFaExWMmVxOWFqelBRQTZRMkJVU2t6WHdUMm1GYkR2TkdqTXl0VzRTV2g0YXZhMWNhdHSheEtrZXBsZXI6cGtoOmVpcDE1NToxOjB4QjE0ZDNjNEY1RkJGQkNGQjk4YWYyZDMzMDAwMGQ0OWM5NUI5M2FBNzovL2RlZmF1bHQva3alZmt2L2RlbIGgZmt2L2dldIGgZmt2L3B1dIGgZ2t2L2xpc3SBoGtrdi9tZXRhZGF0YYGgY25uY3FVajg5YkdHWmtoNFJKNjY4dmNwcmaAY2lhdBocvbpSY2V4cBsAAAAHda9C0mNmY3SkZWlhdC16ZC41MlplZXhwLXpkLjUyWmZkb21haW5pbG9jYWxob3N0aXJlc291cmNlc4Bhc1hINOcBG5HDAwx4ASjJGspMdIhMu2NX9o06hfQbz1SqCvdAWjwWOpO6aDh56KfReehDpmKEJxYXdQVVLMAmFVq1SZxBIzljSnkc",
"pWNhdHSheEZrZXBsZXI6a2V5OnpEbmFlVjlRd1VqM3ptTXdLWkNDTHBKam93b3gyNDNRQnNFemFOcHBhS0FpRXd2ZUE6Ly9kZWZhdWx0oWpvcmJpdC9ob3N0gaBjYXVkWCWdGu0BxaVmn3ormmAiYkPrdop5udsIiF0kgEQ1ZOgqvVwyCMIAY2lzc1gmnRqAJAJGDNbW2HLCLD0x0OXb5nFcyJaovfweaTp7xuzXHIG1_wBhdmR3YW4zYXNZAWU08swB9QF7InR5cGUiOiJ3ZWJhdXRobi5nZXQiLCJjaGFsbGVuZ2UiOiJFaUROQ0hjX3dreFNpZERTMzE0TWZFRXdxMmpDZEdDYlJkRlZ6MmZLM0V4UWdnIiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo4MDAwIiwiY3Jvc3NPcmlnaW4iOnRydWUsIm90aGVyX2tleXNfY2FuX2JlX2FkZGVkX2hlcmUiOiJkbyBub3QgY29tcGFyZSBjbGllbnREYXRhSlNPTiBhZ2FpbnN0IGEgdGVtcGxhdGUuIFNlZSBodHRwczovL2dvby5nbC95YWJQZXgifSVJlg3liA6MaHQ0Fw9kdmBbj-SuuaKGMseZXPO6gx2XYwUAAAAAgCQScbGAel3IpODAypqvDlwIcWpGJwYyCTF_5DEZ3-fFe2i_JYxCimMHtZFIeokvDPftr2Y4kjvvRIvxYA1eGPkZRX0"
];
let verifier = CommonVerifier::new(&did_method_key::DIDKey);
for e in encoded {
Expand Down
12 changes: 10 additions & 2 deletions src/v3/webauthn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize};
use serde_ipld_dagcbor::EncodeError;
use serde_json::Value;
use ssi_dids::did_resolve::DIDResolver;
use ssi_jwk::Algorithm;
use ssi_jws::verify_bytes;
use ssi_ucan::util::get_verification_key;
use std::collections::{BTreeMap, TryReserveError};
use ucan_capabilities_object::Capabilities;
use varsig::common::{
webauthn::{get_challenge_hash, Error as WebAuthnError},
PasskeySig, DAG_CBOR_ENCODING,
JoseSig, PasskeySig, DAG_CBOR_ENCODING,
};
use varsig::VarSig;

Expand Down Expand Up @@ -76,7 +77,14 @@ where
let key = get_verification_key(&cacao.issuer.to_string(), *self).await?;
// verify signature
verify_bytes(
key.algorithm.ok_or(ssi_jws::Error::MissingCurve)?,
match cacao.signature.sig().signature() {
JoseSig::EdDSA(_) => Algorithm::EdDSA,
JoseSig::Es256(_) => Algorithm::ES256,
JoseSig::Es512(_) => Algorithm::ES256,
JoseSig::Es256K(_) => Algorithm::ES256K,
JoseSig::Rsa256(_) => Algorithm::RS256,
JoseSig::Rsa512(_) => Algorithm::RS512,
},
&[
Code::Sha2_256
.digest(cacao.signature.sig().client_data())
Expand Down

0 comments on commit 9456416

Please sign in to comment.