Move to partial updates for verification, put it on the threadpool

This commit is contained in:
asonix 2020-07-01 17:27:34 -05:00
parent 2366c9a917
commit cd1a824ebb
5 changed files with 115 additions and 51 deletions

View file

@ -1,7 +1,7 @@
[package]
name = "http-signature-normalization-actix"
description = "An HTTP Signatures library that leaves the signing to you"
version = "0.4.0-alpha.0"
version = "0.4.0-alpha.1"
authors = ["asonix <asonix@asonix.dog>"]
license-file = "LICENSE"
readme = "README.md"

View file

@ -5,9 +5,9 @@ use actix_web::{
dev::{MessageBody, Payload, Service, ServiceRequest, ServiceResponse, Transform},
error::PayloadError,
http::{header::HeaderValue, StatusCode},
FromRequest, HttpMessage, HttpRequest, HttpResponse, ResponseError,
web, FromRequest, HttpMessage, HttpRequest, HttpResponse, ResponseError,
};
use bytes::{Bytes, BytesMut};
use bytes::Bytes;
use futures::{
channel::mpsc,
future::{err, ok, ready, Ready},
@ -86,7 +86,7 @@ impl FromRequest for DigestVerified {
impl<T, S, B> Transform<S> for VerifyDigest<T>
where
T: DigestVerify + Clone + 'static,
T: DigestVerify + Clone + Send + 'static,
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = actix_web::Error>
+ 'static,
S::Error: 'static,
@ -108,7 +108,7 @@ type FutResult<T, E> = dyn Future<Output = Result<T, E>>;
impl<T, S, B> Service for VerifyMiddleware<T, S>
where
T: DigestVerify + Clone + 'static,
T: DigestVerify + Clone + Send + 'static,
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = actix_web::Error>
+ 'static,
S::Error: 'static,
@ -163,24 +163,29 @@ async fn verify_payload<T>(
mut tx: mpsc::Sender<Bytes>,
) -> Result<(), actix_web::Error>
where
T: DigestVerify + Clone + 'static,
T: DigestVerify + Clone + Send + 'static,
{
let mut output_bytes = BytesMut::new();
while let Some(res) = payload.next().await {
let bytes = res?;
output_bytes.extend(bytes);
let bytes2 = bytes.clone();
verify_digest = web::block(move || {
verify_digest.update(&bytes2.as_ref());
Ok(verify_digest) as Result<T, VerifyError>
})
.await?;
if tx.is_closed() {
warn!("Payload dropped. If this was unexpected, it could be that the payload isn't required in the route this middleware is guarding");
return Err(VerifyError.into());
}
tx.try_send(bytes).map_err(|_| VerifyError)?;
}
let bytes = output_bytes.freeze();
let verified =
web::block(move || Ok(verify_digest.verify(&vec)) as Result<_, VerifyError>).await?;
if verify_digest.verify(&vec, &bytes.as_ref()) {
tx.try_send(bytes).map_err(|_| VerifyError.into())
if verified {
Ok(())
} else {
warn!("Digest could not be verified");
Err(VerifyError.into())

View file

@ -33,10 +33,11 @@ pub trait DigestCreate {
/// A trait for verifying digests
pub trait DigestVerify {
/// Verify the payload of the request against a slice of digests
///
/// The slice of digests should never be empty
fn verify(&mut self, digests: &[DigestPart], payload: &[u8]) -> bool;
/// Update the verifier with bytes from the request body
fn update(&mut self, part: &[u8]);
/// Verify the request body against the digests from the request headers
fn verify(&mut self, digests: &[DigestPart]) -> bool;
}
/// Extend the Sign trait with support for adding Digest Headers to the request

View file

@ -8,13 +8,12 @@ fn create(digest: &mut impl sha2::Digest, input: &[u8]) -> String {
base64::encode(&digest.finalize_reset())
}
fn verify(digest: &mut impl sha2::Digest, name: &str, parts: &[DigestPart], bytes: &[u8]) -> bool {
fn verify(digest: &mut impl sha2::Digest, name: &str, parts: &[DigestPart]) -> bool {
if let Some(part) = parts
.iter()
.find(|p| p.algorithm.to_lowercase() == name.to_lowercase())
{
debug!("Verifying digest type, {}", name);
digest.update(bytes);
let encoded = base64::encode(&digest.finalize_reset());
return part.digest == encoded;
@ -44,8 +43,12 @@ impl DigestCreate for Sha224 {
}
impl DigestVerify for Sha224 {
fn verify(&mut self, parts: &[DigestPart], bytes: &[u8]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts, bytes)
fn update(&mut self, part: &[u8]) {
sha2::Digest::update(self, part);
}
fn verify(&mut self, parts: &[DigestPart]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts)
}
}
@ -58,8 +61,12 @@ impl DigestCreate for Sha256 {
}
impl DigestVerify for Sha256 {
fn verify(&mut self, parts: &[DigestPart], bytes: &[u8]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts, bytes)
fn update(&mut self, part: &[u8]) {
sha2::Digest::update(self, part);
}
fn verify(&mut self, parts: &[DigestPart]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts)
}
}
@ -72,8 +79,12 @@ impl DigestCreate for Sha384 {
}
impl DigestVerify for Sha384 {
fn verify(&mut self, parts: &[DigestPart], bytes: &[u8]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts, bytes)
fn update(&mut self, part: &[u8]) {
sha2::Digest::update(self, part);
}
fn verify(&mut self, parts: &[DigestPart]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts)
}
}
@ -86,8 +97,12 @@ impl DigestCreate for Sha512 {
}
impl DigestVerify for Sha512 {
fn verify(&mut self, parts: &[DigestPart], bytes: &[u8]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts, bytes)
fn update(&mut self, part: &[u8]) {
sha2::Digest::update(self, part);
}
fn verify(&mut self, parts: &[DigestPart]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts)
}
}
@ -100,8 +115,12 @@ impl DigestCreate for Sha512Trunc224 {
}
impl DigestVerify for Sha512Trunc224 {
fn verify(&mut self, parts: &[DigestPart], bytes: &[u8]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts, bytes)
fn update(&mut self, part: &[u8]) {
sha2::Digest::update(self, part);
}
fn verify(&mut self, parts: &[DigestPart]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts)
}
}
@ -114,7 +133,11 @@ impl DigestCreate for Sha512Trunc256 {
}
impl DigestVerify for Sha512Trunc256 {
fn verify(&mut self, parts: &[DigestPart], bytes: &[u8]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts, bytes)
fn update(&mut self, part: &[u8]) {
sha2::Digest::update(self, part);
}
fn verify(&mut self, parts: &[DigestPart]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts)
}
}

View file

@ -11,13 +11,12 @@ fn create(digest: &mut impl sha2::Digest, input: &[u8]) -> String {
base64::encode(&digest.finalize_reset())
}
fn verify(digest: &mut impl sha2::Digest, name: &str, parts: &[DigestPart], bytes: &[u8]) -> bool {
fn verify(digest: &mut impl sha2::Digest, name: &str, parts: &[DigestPart]) -> bool {
if let Some(part) = parts
.iter()
.find(|p| p.algorithm.to_lowercase() == name.to_lowercase())
{
debug!("Verifying digest type, {}", name);
digest.update(bytes);
let encoded = base64::encode(&digest.finalize_reset());
return part.digest == encoded;
@ -47,8 +46,12 @@ impl DigestCreate for Sha3_224 {
}
impl DigestVerify for Sha3_224 {
fn verify(&mut self, parts: &[DigestPart], bytes: &[u8]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts, bytes)
fn update(&mut self, part: &[u8]) {
sha3::Digest::update(self, part);
}
fn verify(&mut self, parts: &[DigestPart]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts)
}
}
@ -61,8 +64,12 @@ impl DigestCreate for Sha3_256 {
}
impl DigestVerify for Sha3_256 {
fn verify(&mut self, parts: &[DigestPart], bytes: &[u8]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts, bytes)
fn update(&mut self, part: &[u8]) {
sha3::Digest::update(self, part);
}
fn verify(&mut self, parts: &[DigestPart]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts)
}
}
@ -75,8 +82,12 @@ impl DigestCreate for Sha3_384 {
}
impl DigestVerify for Sha3_384 {
fn verify(&mut self, parts: &[DigestPart], bytes: &[u8]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts, bytes)
fn update(&mut self, part: &[u8]) {
sha3::Digest::update(self, part);
}
fn verify(&mut self, parts: &[DigestPart]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts)
}
}
@ -89,8 +100,12 @@ impl DigestCreate for Sha3_512 {
}
impl DigestVerify for Sha3_512 {
fn verify(&mut self, parts: &[DigestPart], bytes: &[u8]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts, bytes)
fn update(&mut self, part: &[u8]) {
sha3::Digest::update(self, part);
}
fn verify(&mut self, parts: &[DigestPart]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts)
}
}
@ -103,8 +118,12 @@ impl DigestCreate for Keccak224 {
}
impl DigestVerify for Keccak224 {
fn verify(&mut self, parts: &[DigestPart], bytes: &[u8]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts, bytes)
fn update(&mut self, part: &[u8]) {
sha3::Digest::update(self, part);
}
fn verify(&mut self, parts: &[DigestPart]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts)
}
}
@ -117,8 +136,12 @@ impl DigestCreate for Keccak256 {
}
impl DigestVerify for Keccak256 {
fn verify(&mut self, parts: &[DigestPart], bytes: &[u8]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts, bytes)
fn update(&mut self, part: &[u8]) {
sha3::Digest::update(self, part);
}
fn verify(&mut self, parts: &[DigestPart]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts)
}
}
@ -131,8 +154,12 @@ impl DigestCreate for Keccak256Full {
}
impl DigestVerify for Keccak256Full {
fn verify(&mut self, parts: &[DigestPart], bytes: &[u8]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts, bytes)
fn update(&mut self, part: &[u8]) {
sha3::Digest::update(self, part);
}
fn verify(&mut self, parts: &[DigestPart]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts)
}
}
@ -145,8 +172,12 @@ impl DigestCreate for Keccak384 {
}
impl DigestVerify for Keccak384 {
fn verify(&mut self, parts: &[DigestPart], bytes: &[u8]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts, bytes)
fn update(&mut self, part: &[u8]) {
sha3::Digest::update(self, part);
}
fn verify(&mut self, parts: &[DigestPart]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts)
}
}
@ -159,7 +190,11 @@ impl DigestCreate for Keccak512 {
}
impl DigestVerify for Keccak512 {
fn verify(&mut self, parts: &[DigestPart], bytes: &[u8]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts, bytes)
fn update(&mut self, part: &[u8]) {
sha3::Digest::update(self, part);
}
fn verify(&mut self, parts: &[DigestPart]) -> bool {
verify(self, <Self as DigestCreate>::NAME, parts)
}
}