use crate::utils::{
codec::{CodecError, Decode, Encode},
codec_vec::CodecVec,
};
use p256::{
ecdsa::{Signature as EcdsaSignature, VerifyingKey, signature::Verifier},
pkcs8::DecodePublicKey,
};
use serde::{Deserialize, Serialize};
use std::{
fmt::Display,
io::{Cursor, Read, Write},
marker::PhantomData,
};
use thiserror::Error;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub(crate) struct Signature<T> {
algorithm: SignatureAndHashAlgorithm,
signature: CodecVec<u16>,
inner: PhantomData<T>,
}
impl<T: std::fmt::Debug> std::fmt::Debug for Signature<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Signature")
.field("algorithm", &self.algorithm)
.field("signature", &hex::encode(&self.signature))
.finish()
}
}
impl<T> Encode for Signature<T> {
fn encode(&self, mut writer: impl Write) -> Result<(), CodecError> {
self.algorithm.encode(&mut writer)?;
self.signature.encode(&mut writer)?;
Ok(())
}
}
impl<T> Decode for Signature<T> {
fn decode(mut reader: impl Read) -> Result<Self, CodecError> {
Ok(Self {
algorithm: SignatureAndHashAlgorithm::decode(&mut reader)?,
signature: CodecVec::decode(&mut reader)?,
inner: PhantomData,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum SignatureValidationError {
#[error("Hash algorithm {0} is not supported by the implementation")]
UnsupportedHashAlgorithm(HashAlgorithm),
#[error("Signature algorithm {0} is not supported by the implementation")]
UnsupportedSignatureAlgorithm(SignatureAlgorithm),
#[error("Key could not be parsed for the specified signature algorithm")]
MalformedKey,
#[error("Signature could not be parsed for the specified signature algorithm")]
MalformedSignature,
#[error("Signature verification failed")]
InvalidSignature,
#[error("Error decoding a value: {0}")]
CodecError(#[from] CodecError),
}
impl<T: Encode> Signature<T> {
pub fn validate(&self, val: &T, key: &[u8]) -> Result<(), SignatureValidationError> {
let mut data = Cursor::new(vec![]);
val.encode(&mut data)?;
match &self.algorithm.signature {
SignatureAlgorithm::Ecdsa => {
match &self.algorithm.hash {
HashAlgorithm::Sha256 => (),
alg => {
return Err(SignatureValidationError::UnsupportedHashAlgorithm(
alg.clone(),
));
}
}
let verifying_key = VerifyingKey::from_public_key_der(key)
.map_err(|_| SignatureValidationError::MalformedKey)?;
let signature = EcdsaSignature::from_der(self.signature.as_ref())
.map_err(|_| SignatureValidationError::MalformedSignature)?;
verifying_key
.verify(&data.into_inner(), &signature)
.map_err(|_| SignatureValidationError::InvalidSignature)?;
Ok(())
}
alg => Err(SignatureValidationError::UnsupportedSignatureAlgorithm(
alg.clone(),
)),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub(crate) struct SignatureAndHashAlgorithm {
pub hash: HashAlgorithm,
pub signature: SignatureAlgorithm,
}
impl Encode for SignatureAndHashAlgorithm {
fn encode(&self, mut writer: impl Write) -> Result<(), CodecError> {
self.hash.encode(&mut writer)?;
self.signature.encode(&mut writer)?;
Ok(())
}
}
impl Decode for SignatureAndHashAlgorithm {
fn decode(mut reader: impl Read) -> Result<Self, CodecError> {
Ok(Self {
hash: HashAlgorithm::decode(&mut reader)?,
signature: SignatureAlgorithm::decode(&mut reader)?,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum HashAlgorithm {
None,
Md5,
Sha1,
Sha224,
Sha256,
Sha384,
Sha512,
}
impl Encode for HashAlgorithm {
fn encode(&self, mut writer: impl Write) -> Result<(), CodecError> {
let discriminant = match self {
HashAlgorithm::None => 0,
HashAlgorithm::Md5 => 1,
HashAlgorithm::Sha1 => 2,
HashAlgorithm::Sha224 => 3,
HashAlgorithm::Sha256 => 4,
HashAlgorithm::Sha384 => 5,
HashAlgorithm::Sha512 => 6,
};
Ok(writer.write_all(&[discriminant])?)
}
}
impl Decode for HashAlgorithm {
fn decode(mut reader: impl Read) -> Result<Self, CodecError> {
let mut buf = vec![0u8];
reader.read_exact(&mut buf)?;
match buf[0] {
0 => Ok(HashAlgorithm::None),
1 => Ok(HashAlgorithm::Md5),
2 => Ok(HashAlgorithm::Sha1),
3 => Ok(HashAlgorithm::Sha224),
4 => Ok(HashAlgorithm::Sha256),
5 => Ok(HashAlgorithm::Sha384),
6 => Ok(HashAlgorithm::Sha512),
x => Err(CodecError::UnknownVariant("HashAlgorithm", x as u64)),
}
}
}
impl Display for HashAlgorithm {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
HashAlgorithm::None => write!(f, "None"),
HashAlgorithm::Md5 => write!(f, "Md5"),
HashAlgorithm::Sha1 => write!(f, "Sha1"),
HashAlgorithm::Sha224 => write!(f, "Sha224"),
HashAlgorithm::Sha256 => write!(f, "Sha256"),
HashAlgorithm::Sha384 => write!(f, "Sha384"),
HashAlgorithm::Sha512 => write!(f, "Sha512"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum SignatureAlgorithm {
Anonymous,
Rsa,
Dsa,
Ecdsa,
}
impl Encode for SignatureAlgorithm {
fn encode(&self, mut writer: impl Write) -> Result<(), CodecError> {
let discriminant = match self {
SignatureAlgorithm::Anonymous => 0,
SignatureAlgorithm::Rsa => 1,
SignatureAlgorithm::Dsa => 2,
SignatureAlgorithm::Ecdsa => 3,
};
Ok(writer.write_all(&[discriminant])?)
}
}
impl Decode for SignatureAlgorithm {
fn decode(mut reader: impl Read) -> Result<Self, CodecError> {
let mut buf = vec![0u8];
reader.read_exact(&mut buf)?;
match buf[0] {
0 => Ok(SignatureAlgorithm::Anonymous),
1 => Ok(SignatureAlgorithm::Rsa),
2 => Ok(SignatureAlgorithm::Dsa),
3 => Ok(SignatureAlgorithm::Ecdsa),
x => Err(CodecError::UnknownVariant("SignatureAlgorithm", x as u64)),
}
}
}
impl Display for SignatureAlgorithm {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SignatureAlgorithm::Anonymous => write!(f, "Anonymous"),
SignatureAlgorithm::Rsa => write!(f, "Rsa"),
SignatureAlgorithm::Dsa => write!(f, "Dsa"),
SignatureAlgorithm::Ecdsa => write!(f, "Ecdsa"),
}
}
}