Skip to content

Commit

Permalink
make request signer methods return a result
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Tate <ryan.michael.tate@gmail.com>
  • Loading branch information
Ryanmtate committed Aug 22, 2024
1 parent 129d22c commit a3bf215
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 13 deletions.
20 changes: 13 additions & 7 deletions src/verifier/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ pub trait Client: Debug {
pub struct DIDClient {
id: ClientId,
vm: String,
signer: Arc<dyn RequestSigner + Send + Sync>,
signer: Arc<dyn RequestSigner<Error = anyhow::Error> + Send + Sync>,
}

impl DIDClient {
pub async fn new(
vm: String,
signer: Arc<dyn RequestSigner + Send + Sync>,
signer: Arc<dyn RequestSigner<Error = anyhow::Error> + Send + Sync>,
resolver: impl JWKResolver,
) -> Result<Self> {
let (id, _f) = vm.rsplit_once('#').context(format!(
Expand All @@ -55,7 +55,7 @@ impl DIDClient {
.await
.context("unable to resolve key from verification method")?;

if &*jwk != signer.jwk() {
if *jwk != signer.jwk().context("signer did not have a JWK")? {
bail!(
"verification method resolved from DID document did not match public key of signer"
)
Expand All @@ -74,14 +74,14 @@ impl DIDClient {
pub struct X509SanClient {
id: ClientId,
x5c: Vec<Certificate>,
signer: Arc<dyn RequestSigner + Send + Sync>,
signer: Arc<dyn RequestSigner<Error = anyhow::Error> + Send + Sync>,
variant: X509SanVariant,
}

impl X509SanClient {
pub fn new(
x5c: Vec<Certificate>,
signer: Arc<dyn RequestSigner + Send + Sync>,
signer: Arc<dyn RequestSigner<Error = anyhow::Error> + Send + Sync>,
variant: X509SanVariant,
) -> Result<Self> {
let leaf = &x5c[0];
Expand Down Expand Up @@ -145,7 +145,10 @@ impl Client for DIDClient {
&self,
body: &AuthorizationRequestObject,
) -> Result<String> {
let algorithm = self.signer.alg();
let algorithm = self
.signer
.alg()
.context("failed to retrieve signing algorithm")?;
let header = json!({
"alg": algorithm,
"kid": self.vm,
Expand All @@ -172,7 +175,10 @@ impl Client for X509SanClient {
&self,
body: &AuthorizationRequestObject,
) -> Result<String> {
let algorithm = self.signer.alg();
let algorithm = self
.signer
.alg()
.context("failed to retrieve signing algorithm")?;
let x5c: Vec<String> = self
.x5c
.iter()
Expand Down
60 changes: 54 additions & 6 deletions src/verifier/request_signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,34 @@ use anyhow::Result;
use async_trait::async_trait;
#[cfg(feature = "p256")]
use p256::ecdsa::{signature::Signer, Signature, SigningKey};
#[cfg(feature = "p256")]
use ssi_claims::jws::{JWSSigner, JWSSignerInfo};
#[cfg(feature = "p256")]
use ssi_jwk::Algorithm;

use ssi_jwk::JWK;

use std::fmt::Debug;

#[async_trait]
pub trait RequestSigner: Debug {
type Error: std::fmt::Display;

/// The algorithm that will be used to sign.
fn alg(&self) -> &str;
fn alg(&self) -> Result<String, Self::Error>;

/// The public JWK of the signer.
fn jwk(&self) -> &JWK;
fn jwk(&self) -> Result<JWK, Self::Error>;

/// Sign the payload and return the signature.
async fn sign(&self, payload: &[u8]) -> Vec<u8>;

/// Attempt to sign the payload and return the signature.
async fn try_sign(&self, payload: &[u8]) -> Result<Vec<u8>, Self::Error> {
// default implementation will call sign.
// Override for custom error handling.
Ok(self.sign(payload).await)
}
}

#[cfg(feature = "p256")]
Expand All @@ -30,21 +47,52 @@ impl P256Signer {
let jwk = serde_json::from_str(&pk.to_jwk_string())?;
Ok(Self { key, jwk })
}

pub fn jwk(&self) -> &JWK {
&self.jwk
}
}

#[cfg(feature = "p256")]
#[async_trait]
impl RequestSigner for P256Signer {
fn alg(&self) -> &str {
"ES256"
type Error = anyhow::Error;

fn alg(&self) -> Result<String, Self::Error> {
Ok(self
.jwk
.algorithm
.map(|alg| alg)
.unwrap_or(Algorithm::ES256)
.to_string())
}

fn jwk(&self) -> &JWK {
&self.jwk
fn jwk(&self) -> Result<JWK, Self::Error> {
Ok(self.jwk.clone())
}

async fn sign(&self, payload: &[u8]) -> Vec<u8> {
let sig: Signature = self.key.sign(payload);
sig.to_vec()
}
}

#[cfg(feature = "p256")]
impl JWSSigner for P256Signer {
async fn fetch_info(&self) -> std::result::Result<JWSSignerInfo, ssi_claims::SignatureError> {
let algorithm = self.jwk.algorithm.unwrap_or(Algorithm::ES256);

let key_id = self.jwk.key_id.clone();

Ok(JWSSignerInfo { algorithm, key_id })
}

async fn sign_bytes(
&self,
signing_bytes: &[u8],
) -> std::result::Result<Vec<u8>, ssi_claims::SignatureError> {
self.try_sign(signing_bytes).await.map_err(|e| {
ssi_claims::SignatureError::Other(format!("Failed to sign bytes: {}", e).into())
})
}
}

0 comments on commit a3bf215

Please sign in to comment.