use openmls_traits::{crypto::OpenMlsCrypto, signatures::Signer};
use thiserror::Error;
use tls_codec::Serialize;
use crate::ciphersuite::{OpenMlsSignaturePublicKey, SignContent, Signature};
#[derive(Error, Debug, PartialEq, Eq, Clone)]
pub enum SignatureError {
#[error("Signature verification failed.")]
VerificationError,
#[error("Signature generation failed.")]
SigningError,
}
pub trait SignedStruct<T> {
fn from_payload(payload: T, signature: Signature, serialized_payload: Vec<u8>) -> Self;
}
pub trait Signable: Sized {
type SignedOutput;
fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error>;
fn label(&self) -> &str;
fn sign(self, signer: &impl Signer) -> Result<Self::SignedOutput, SignatureError>
where
Self::SignedOutput: SignedStruct<Self>,
{
let payload = self
.unsigned_payload()
.map_err(|_| SignatureError::SigningError)?;
let payload_sign_content =
match SignContent::new(self.label(), payload.clone().into()).tls_serialize_detached() {
Ok(p) => p,
Err(e) => {
log::error!("Serializing SignContent failed, {e:?}");
return Err(SignatureError::SigningError);
}
};
let signature = signer
.sign(&payload_sign_content)
.map_err(|_| SignatureError::SigningError)?;
Ok(Self::SignedOutput::from_payload(
self,
signature.into(),
payload,
))
}
}
pub trait VerifiedStruct {}
pub trait Verifiable: Sized {
type VerifiedStruct: VerifiedStruct;
fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error>;
fn signature(&self) -> &Signature;
fn label(&self) -> &str;
fn verify(
self,
crypto: &impl OpenMlsCrypto,
pk: &OpenMlsSignaturePublicKey,
) -> Result<Self::VerifiedStruct, SignatureError>;
fn verify_no_out(
&self,
crypto: &impl OpenMlsCrypto,
pk: &OpenMlsSignaturePublicKey,
) -> Result<(), SignatureError> {
let payload = self
.unsigned_payload()
.map_err(|_| SignatureError::VerificationError)?;
let sign_content = SignContent::new(self.label(), payload.into());
let payload = match sign_content.tls_serialize_detached() {
Ok(p) => p,
Err(e) => {
log::error!("Serializing SignContent failed, {e:?}");
return Err(SignatureError::VerificationError);
}
};
crypto
.verify_signature(
pk.signature_scheme(),
&payload,
pk.as_slice(),
self.signature().value(),
)
.map_err(|_| SignatureError::VerificationError)
}
}