pub trait VerifyKey: Sized + Send {
type Error: Into<Error>;
// Required methods
fn init<'life0, 'life1, 'life2, 'async_trait>(
req: &'life0 HttpRequest,
key_id: &'life1 str,
algorithm: Option<&'life2 Algorithm>,
) -> Pin<Box<dyn Future<Output = Result<Self, Self::Error>> + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn verify(
&mut self,
signature: &str,
signing_string: &str,
) -> Result<bool, Self::Error>;
}
Expand description
Extracts a key from the request
use actix_web::{http::StatusCode, web::Data, HttpRequest, HttpResponse, ResponseError};
use http_signature_normalization_actix_extractor::{Algorithm, DeprecatedAlgorithm, VerifyKey};
use openssl::{hash::MessageDigest, pkey::{PKey, Public}, sign::Verifier};
pub struct OpenSSLPublicKey(PKey<Public>);
#[async_trait::async_trait(?Send)]
impl VerifyKey for OpenSSLPublicKey {
type Error = VerifyError;
async fn init(
req: &HttpRequest,
key_id: &str,
algorithm: Option<&Algorithm>,
) -> Result<Self, Self::Error> {
match algorithm {
Some(Algorithm::Hs2019 | Algorithm::Deprecated(DeprecatedAlgorithm::RsaSha256)) => (),
_ => return Err(VerifyError::Algorithm),
};
if key_id != "my-key-id" {
return Err(VerifyError::Key);
}
let key = req.app_data::<Data<PKey<Public>>>().expect("Key loaded").as_ref().clone();
Ok(OpenSSLPublicKey(key))
}
fn verify(&mut self, signature: &str, signing_string: &str) -> Result<bool, Self::Error> {
let decoded = openssl::base64::decode_block(&signature).map_err(|_| VerifyError::Decode)?;
let verifier = Verifier::new(MessageDigest::sha256(), &self.0).map_err(|_| VerifyError::Verifier)?;
verifier.verify(&decoded).map_err(|_| VerifyError::Verify)
}
}
#[derive(Debug, thiserror::Error)]
pub enum VerifyError {
#[error("Unsupported algorithm")]
Algorithm,
#[error("Couldn't decode signature")]
Decode,
#[error("Invalid key")]
Key,
#[error("Failed to create Verifier from key")]
Verifier,
#[error("Failed to verify signature")]
Verify,
}
impl ResponseError for VerifyError {
fn status_code(&self) -> StatusCode {
StatusCode::BAD_REQUEST
}
fn error_response(&self) -> HttpResponse {
HttpResponse::BadRequest().finish()
}
}
Required Associated Types§
Required Methods§
Sourcefn init<'life0, 'life1, 'life2, 'async_trait>(
req: &'life0 HttpRequest,
key_id: &'life1 str,
algorithm: Option<&'life2 Algorithm>,
) -> Pin<Box<dyn Future<Output = Result<Self, Self::Error>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn init<'life0, 'life1, 'life2, 'async_trait>(
req: &'life0 HttpRequest,
key_id: &'life1 str,
algorithm: Option<&'life2 Algorithm>,
) -> Pin<Box<dyn Future<Output = Result<Self, Self::Error>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Extract the key from the request, given the key_id and algorithm
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.