use openmls_traits::OpenMlsCryptoProvider;
use crate::{
ciphersuite::Signature,
credentials::{errors::CredentialError, Credential, CredentialBundle},
error::LibraryError,
};
use super::SignaturePublicKey;
pub trait SignedStruct<T> {
fn from_payload(payload: T, signature: Signature) -> Self;
}
pub trait VerifiedStruct<T> {
type SealingType: Default;
#[doc(hidden)]
fn from_verifiable(verifiable: T, _seal: Self::SealingType) -> Self;
}
pub trait Signable: Sized {
type SignedOutput;
fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error>;
fn sign(
self,
backend: &impl OpenMlsCryptoProvider,
credential_bundle: &CredentialBundle,
) -> Result<Self::SignedOutput, LibraryError>
where
Self::SignedOutput: SignedStruct<Self>,
{
let payload = self
.unsigned_payload()
.map_err(LibraryError::missing_bound_check)?;
let signature = credential_bundle
.sign(backend, &payload)
.map_err(LibraryError::unexpected_crypto_error)?;
Ok(Self::SignedOutput::from_payload(self, signature))
}
}
pub trait Verifiable: Sized {
fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error>;
fn signature(&self) -> &Signature;
fn verify<T>(
self,
backend: &impl OpenMlsCryptoProvider,
credential: &Credential,
) -> Result<T, CredentialError>
where
T: VerifiedStruct<Self>,
{
let payload = self
.unsigned_payload()
.map_err(LibraryError::missing_bound_check)?;
credential.verify(backend, &payload, self.signature())?;
Ok(T::from_verifiable(self, T::SealingType::default()))
}
fn verify_with_key<T>(
self,
backend: &impl OpenMlsCryptoProvider,
signature_public_key: &SignaturePublicKey,
) -> Result<T, CredentialError>
where
T: VerifiedStruct<Self>,
{
let payload = self
.unsigned_payload()
.map_err(LibraryError::missing_bound_check)?;
signature_public_key
.verify(backend, self.signature(), &payload)
.map_err(|_| CredentialError::InvalidSignature)?;
Ok(T::from_verifiable(self, T::SealingType::default()))
}
fn verify_no_out(
&self,
backend: &impl OpenMlsCryptoProvider,
credential: &Credential,
) -> Result<(), CredentialError> {
let payload = self
.unsigned_payload()
.map_err(LibraryError::missing_bound_check)?;
credential.verify(backend, &payload, self.signature())
}
}