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§

Source

type Error: Into<Error>

Errors that can happen when extracting keys or verifying the signature

Required Methods§

Source

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

Source

fn verify( &mut self, signature: &str, signing_string: &str, ) -> Result<bool, Self::Error>

Verify the signature with the given signing string

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.

Implementors§