Skip to content

Commit

Permalink
Merge pull request #17 from mdsol/errors-to-thiserror
Browse files Browse the repository at this point in the history
Convert from anyhow to thiserror
  • Loading branch information
masongup-mdsol authored Jun 3, 2024
2 parents a7e7c62 + d5758fa commit 3114291
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 33 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ keywords = ["security", "authentication"]
categories = ["authentication"]

[dependencies]
anyhow = "1"
thiserror = "1"
base64 = "0.22"
hex = "0.4"
lazy-regex = "3"
rsa = "0.9.0"
regex = { version = "1", default_features = false, features = ["std"] }
sha2 = { version = "0.10", features = ["oid"] }
urlencoding = "2"
spki = "0.7"

[dev-dependencies]
serde = { version = "1", features = ["derive"] }
Expand Down
27 changes: 27 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use thiserror::Error;

/// All of the possible errors that can happen while performing mauth operations
#[derive(Debug, Error)]
pub enum Error {
/// A UTF8 decode error while attempting to process the URL
#[error("Unable to handle the URL as the format was invalid: {0}")]
UrlEncodingError(#[from] std::string::FromUtf8Error),
/// A MAuth version that is not supported was requested
#[error("Version {0} is not supported")]
UnsupportedVersion(u8),
/// The provided private key could not be parsed
#[error("Unable to parse RSA private key: {0}")]
PrivateKeyDecodeError(#[from] rsa::pkcs1::Error),
/// The provided public key could not be parsed
#[error("Unable to parse RSA public key: {0}")]
PublicKeyDecodeError(#[from] spki::Error),
/// An algorithm failure occurred while trying to sign a request
#[error("RSA algorithm error: {0}")]
RsaSignError(#[from] rsa::Error),
/// An algorithm failure occurred while trying to verify a request
#[error("Unable to verify RSA signature: {0}")]
SignatureVerifyError(#[from] rsa::signature::Error),
/// A base64 error was encountered while attempting to verify a v1 signature
#[error("Unable to decode base64-encoded signature: {0}")]
SignatureDecodeError(#[from] base64::DecodeError),
}
6 changes: 5 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
pub mod signable;
/// Error types
pub mod error;
pub(crate) mod signable;
/// Signing for outgoing requests
pub mod signer;
/// Signature verification for incoming requests
pub mod verifier;
14 changes: 7 additions & 7 deletions src/signable.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use anyhow::Result;
use crate::error::Error;
use lazy_regex::*;
use regex::{Captures, Regex};
use sha2::{Digest, Sha512};
Expand Down Expand Up @@ -38,7 +38,7 @@ impl<'a> Signable<'a> {
}
}

pub fn signing_string_v1(&self) -> Result<Vec<u8>> {
pub fn signing_string_v1(&self) -> Result<Vec<u8>, Error> {
let mut hasher = Sha512::default();

hasher.update(&self.verb);
Expand All @@ -54,7 +54,7 @@ impl<'a> Signable<'a> {
Ok(hex::encode(hasher.finalize()).into_bytes())
}

pub fn signing_string_v2(&self) -> Result<Vec<u8>> {
pub fn signing_string_v2(&self) -> Result<Vec<u8>, Error> {
let encoded_query: String = Self::encode_query(&self.query)?;
let body_digest = hex::encode(Sha512::digest(self.body));

Expand All @@ -70,14 +70,14 @@ impl<'a> Signable<'a> {
.into_bytes())
}

fn encode_query(qstr: &str) -> Result<String> {
fn encode_query(qstr: &str) -> Result<String, Error> {
if qstr.is_empty() {
return Ok("".to_string());
}
let mut temp_param_list = qstr
.split('&')
.map(Self::split_equal_and_decode)
.collect::<Result<Vec<[String; 2]>>>()?;
.collect::<Result<Vec<[String; 2]>, Error>>()?;

temp_param_list.sort();

Expand Down Expand Up @@ -109,15 +109,15 @@ impl<'a> Signable<'a> {
}
}

fn split_equal_and_decode(value: &str) -> Result<[String; 2]> {
fn split_equal_and_decode(value: &str) -> Result<[String; 2], Error> {
let (k, v) = value.split_once('=').unwrap_or((value, ""));
Ok([
Self::replace_plus_and_decode(k)?,
Self::replace_plus_and_decode(v)?,
])
}

fn replace_plus_and_decode(value: &str) -> Result<String> {
fn replace_plus_and_decode(value: &str) -> Result<String, Error> {
Ok(decode(&value.replace('+', " "))?.into_owned())
}
}
Expand Down
13 changes: 6 additions & 7 deletions src/signer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::signable::Signable;
use anyhow::{bail, Result};
use crate::{error::Error, signable::Signable};
use base64::{engine::general_purpose, Engine as _};
use rsa::pkcs1::DecodeRsaPrivateKey;
use rsa::RsaPrivateKey;
Expand All @@ -13,7 +12,7 @@ pub struct Signer {
}

impl Signer {
pub fn new(app_uuid: impl Into<String>, private_key_data: String) -> Result<Self> {
pub fn new(app_uuid: impl Into<String>, private_key_data: String) -> Result<Self, Error> {
let private_key = RsaPrivateKey::from_pkcs1_pem(&private_key_data)?;
let signing_key = rsa::pkcs1v15::SigningKey::<Sha512>::new(private_key.to_owned());

Expand All @@ -32,25 +31,25 @@ impl Signer {
query: impl Into<String>,
body: &[u8],
timestamp: impl Into<String>,
) -> Result<String> {
) -> Result<String, Error> {
let signable = Signable::new(verb, path, query, body, timestamp, &self.app_uuid);

match version {
1 => self.sign_string_v1(&signable),
2 => self.sign_string_v2(&signable),
_ => bail!("Version {version} is not supported."),
v => Err(Error::UnsupportedVersion(v)),
}
}

fn sign_string_v1(&self, signable: &Signable) -> Result<String> {
fn sign_string_v1(&self, signable: &Signable) -> Result<String, Error> {
let signature = self.private_key.sign(
rsa::Pkcs1v15Sign::new_unprefixed(),
&signable.signing_string_v1()?,
)?;
Ok(general_purpose::STANDARD.encode(signature))
}

fn sign_string_v2(&self, signable: &Signable) -> Result<String> {
fn sign_string_v2(&self, signable: &Signable) -> Result<String, Error> {
use rsa::signature::{SignatureEncoding, Signer};

let sign = self.signing_key.sign(&signable.signing_string_v2()?);
Expand Down
25 changes: 16 additions & 9 deletions src/verifier.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::signable::Signable;
use anyhow::{bail, Result};
use crate::{error::Error, signable::Signable};
use base64::{engine::general_purpose, Engine as _};
use rsa::pkcs1v15::Signature;
use rsa::pkcs8::DecodePublicKey;
Expand All @@ -14,7 +13,7 @@ pub struct Verifier {
}

impl Verifier {
pub fn new(app_uuid: impl Into<String>, public_key_data: String) -> Result<Self> {
pub fn new(app_uuid: impl Into<String>, public_key_data: String) -> Result<Self, Error> {
let public_key = RsaPublicKey::from_public_key_pem(&public_key_data)?;
let verifying_key = rsa::pkcs1v15::VerifyingKey::<Sha512>::new(public_key.to_owned());

Expand All @@ -34,34 +33,42 @@ impl Verifier {
body: &[u8],
timestamp: impl Into<String>,
signature: impl Into<String>,
) -> Result<bool> {
) -> Result<(), Error> {
let signable = Signable::new(verb, path, query, body, timestamp, &self.app_uuid);

match version {
1 => self.verify_signature_v1(&signable, signature.into()),
2 => self.verify_signature_v2(&signable, signature.into()),
_ => bail!("Version {version} is not supported."),
v => Err(Error::UnsupportedVersion(v)),
}
}

fn verify_signature_v1(&self, signable: &Signable, signature: String) -> Result<bool> {
fn verify_signature_v1(
&self,
signable: &Signable,
signature: String,
) -> Result<(), Error> {
self.public_key.verify(
rsa::Pkcs1v15Sign::new_unprefixed(),
&signable.signing_string_v1()?,
&general_purpose::STANDARD.decode(signature)?,
)?;

Ok(true)
Ok(())
}

fn verify_signature_v2(&self, signable: &Signable, signature: String) -> Result<bool> {
fn verify_signature_v2(
&self,
signable: &Signable,
signature: String,
) -> Result<(), Error> {
use rsa::signature::Verifier;

let signature =
Signature::try_from(general_purpose::STANDARD.decode(signature)?.as_slice())?;
self.verifying_key
.verify(&signable.signing_string_v2()?, &signature)?;

Ok(true)
Ok(())
}
}
10 changes: 2 additions & 8 deletions tests/protocol_test_suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,9 @@ fn test_verifier(
_ => vec![],
};

let result = verifier
verifier
.verify_signature(version, req.verb, path, query, &body_data, timestamp, sig)
.unwrap();

if result {
Ok(())
} else {
Err(format!("[{test_case}] failed"))
}
.map_err(|_| format!("[{test_case}] failed"))
}

#[test]
Expand Down

0 comments on commit 3114291

Please sign in to comment.