use std::fmt;
use serde::{Deserialize, Serialize};
use crate::{
attestation::{Attestation, AttestationError, AttestationProof},
connection::{ConnectionInfo, ServerIdentityProof, ServerIdentityProofError, ServerName},
signing::VerifyingKey,
transcript::{PartialTranscript, TranscriptProof, TranscriptProofError},
CryptoProvider,
};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Presentation {
attestation: AttestationProof,
identity: Option<ServerIdentityProof>,
transcript: Option<TranscriptProof>,
}
impl Presentation {
pub fn builder<'a>(
provider: &'a CryptoProvider,
attestation: &'a Attestation,
) -> PresentationBuilder<'a> {
PresentationBuilder::new(provider, attestation)
}
pub fn verifying_key(&self) -> &VerifyingKey {
self.attestation.verifying_key()
}
pub fn verify(
self,
provider: &CryptoProvider,
) -> Result<PresentationOutput, PresentationError> {
let Self {
attestation,
identity,
transcript,
} = self;
let attestation = attestation.verify(provider)?;
let server_name = identity
.map(|identity| {
identity.verify_with_provider(
provider,
attestation.body.connection_info().time,
attestation.body.server_ephemeral_key(),
attestation.body.cert_commitment(),
)
})
.transpose()?;
let transcript = transcript
.map(|transcript| transcript.verify_with_provider(provider, &attestation.body))
.transpose()?;
let connection_info = attestation.body.connection_info().clone();
Ok(PresentationOutput {
attestation,
server_name,
connection_info,
transcript,
})
}
}
#[derive(Debug)]
#[non_exhaustive]
pub struct PresentationOutput {
pub attestation: Attestation,
pub server_name: Option<ServerName>,
pub connection_info: ConnectionInfo,
pub transcript: Option<PartialTranscript>,
}
pub struct PresentationBuilder<'a> {
provider: &'a CryptoProvider,
attestation: &'a Attestation,
identity_proof: Option<ServerIdentityProof>,
transcript_proof: Option<TranscriptProof>,
}
impl<'a> PresentationBuilder<'a> {
pub(crate) fn new(provider: &'a CryptoProvider, attestation: &'a Attestation) -> Self {
Self {
provider,
attestation,
identity_proof: None,
transcript_proof: None,
}
}
pub fn identity_proof(&mut self, proof: ServerIdentityProof) -> &mut Self {
self.identity_proof = Some(proof);
self
}
pub fn transcript_proof(&mut self, proof: TranscriptProof) -> &mut Self {
self.transcript_proof = Some(proof);
self
}
pub fn build(self) -> Result<Presentation, PresentationBuilderError> {
let attestation = AttestationProof::new(self.provider, self.attestation)?;
Ok(Presentation {
attestation,
identity: self.identity_proof,
transcript: self.transcript_proof,
})
}
}
#[derive(Debug, thiserror::Error)]
pub struct PresentationBuilderError {
kind: BuilderErrorKind,
source: Option<Box<dyn std::error::Error + Send + Sync>>,
}
#[derive(Debug)]
enum BuilderErrorKind {
Attestation,
}
impl fmt::Display for PresentationBuilderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("presentation builder error: ")?;
match self.kind {
BuilderErrorKind::Attestation => f.write_str("attestation error")?,
}
if let Some(source) = &self.source {
write!(f, " caused by: {}", source)?;
}
Ok(())
}
}
impl From<AttestationError> for PresentationBuilderError {
fn from(error: AttestationError) -> Self {
Self {
kind: BuilderErrorKind::Attestation,
source: Some(Box::new(error)),
}
}
}
#[derive(Debug, thiserror::Error)]
pub struct PresentationError {
kind: ErrorKind,
source: Option<Box<dyn std::error::Error + Send + Sync>>,
}
#[derive(Debug)]
enum ErrorKind {
Attestation,
Identity,
Transcript,
}
impl fmt::Display for PresentationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("presentation error: ")?;
match self.kind {
ErrorKind::Attestation => f.write_str("attestation error")?,
ErrorKind::Identity => f.write_str("server identity error")?,
ErrorKind::Transcript => f.write_str("transcript error")?,
}
if let Some(source) = &self.source {
write!(f, " caused by: {}", source)?;
}
Ok(())
}
}
impl From<AttestationError> for PresentationError {
fn from(error: AttestationError) -> Self {
Self {
kind: ErrorKind::Attestation,
source: Some(Box::new(error)),
}
}
}
impl From<ServerIdentityProofError> for PresentationError {
fn from(error: ServerIdentityProofError) -> Self {
Self {
kind: ErrorKind::Identity,
source: Some(Box::new(error)),
}
}
}
impl From<TranscriptProofError> for PresentationError {
fn from(error: TranscriptProofError) -> Self {
Self {
kind: ErrorKind::Transcript,
source: Some(Box::new(error)),
}
}
}