1use std::fmt;
26
27use serde::{Deserialize, Serialize};
28
29use crate::{
30 attestation::{Attestation, AttestationError, AttestationProof, Extension},
31 connection::{ConnectionInfo, ServerIdentityProof, ServerIdentityProofError, ServerName},
32 signing::VerifyingKey,
33 transcript::{PartialTranscript, TranscriptProof, TranscriptProofError},
34 CryptoProvider,
35};
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct Presentation {
43 attestation: AttestationProof,
44 identity: Option<ServerIdentityProof>,
45 transcript: Option<TranscriptProof>,
46}
47
48impl Presentation {
49 pub fn builder<'a>(
51 provider: &'a CryptoProvider,
52 attestation: &'a Attestation,
53 ) -> PresentationBuilder<'a> {
54 PresentationBuilder::new(provider, attestation)
55 }
56
57 pub fn verifying_key(&self) -> &VerifyingKey {
59 self.attestation.verifying_key()
60 }
61
62 pub fn verify(
64 self,
65 provider: &CryptoProvider,
66 ) -> Result<PresentationOutput, PresentationError> {
67 let Self {
68 attestation,
69 identity,
70 transcript,
71 } = self;
72
73 let attestation = attestation.verify(provider)?;
74
75 let server_name = identity
76 .map(|identity| {
77 identity.verify_with_provider(
78 provider,
79 attestation.body.connection_info().time,
80 attestation.body.server_ephemeral_key(),
81 attestation.body.cert_commitment(),
82 )
83 })
84 .transpose()?;
85
86 let transcript = transcript
87 .map(|transcript| {
88 transcript.verify_with_provider(
89 provider,
90 &attestation.body.connection_info().transcript_length,
91 attestation.body.transcript_commitments(),
92 )
93 })
94 .transpose()?;
95
96 let connection_info = attestation.body.connection_info().clone();
97
98 let extensions = attestation.body.extensions().cloned().collect();
99
100 Ok(PresentationOutput {
101 attestation,
102 server_name,
103 connection_info,
104 transcript,
105 extensions,
106 })
107 }
108}
109
110#[derive(Debug)]
112#[non_exhaustive]
113pub struct PresentationOutput {
114 pub attestation: Attestation,
116 pub server_name: Option<ServerName>,
118 pub connection_info: ConnectionInfo,
120 pub transcript: Option<PartialTranscript>,
122 pub extensions: Vec<Extension>,
124}
125
126pub struct PresentationBuilder<'a> {
128 provider: &'a CryptoProvider,
129 attestation: &'a Attestation,
130 identity_proof: Option<ServerIdentityProof>,
131 transcript_proof: Option<TranscriptProof>,
132}
133
134impl<'a> PresentationBuilder<'a> {
135 pub(crate) fn new(provider: &'a CryptoProvider, attestation: &'a Attestation) -> Self {
136 Self {
137 provider,
138 attestation,
139 identity_proof: None,
140 transcript_proof: None,
141 }
142 }
143
144 pub fn identity_proof(&mut self, proof: ServerIdentityProof) -> &mut Self {
146 self.identity_proof = Some(proof);
147 self
148 }
149
150 pub fn transcript_proof(&mut self, proof: TranscriptProof) -> &mut Self {
152 self.transcript_proof = Some(proof);
153 self
154 }
155
156 pub fn build(self) -> Result<Presentation, PresentationBuilderError> {
158 let attestation = AttestationProof::new(self.provider, self.attestation)?;
159
160 Ok(Presentation {
161 attestation,
162 identity: self.identity_proof,
163 transcript: self.transcript_proof,
164 })
165 }
166}
167
168#[derive(Debug, thiserror::Error)]
170pub struct PresentationBuilderError {
171 kind: BuilderErrorKind,
172 source: Option<Box<dyn std::error::Error + Send + Sync>>,
173}
174
175#[derive(Debug)]
176enum BuilderErrorKind {
177 Attestation,
178}
179
180impl fmt::Display for PresentationBuilderError {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 f.write_str("presentation builder error: ")?;
183
184 match self.kind {
185 BuilderErrorKind::Attestation => f.write_str("attestation error")?,
186 }
187
188 if let Some(source) = &self.source {
189 write!(f, " caused by: {}", source)?;
190 }
191
192 Ok(())
193 }
194}
195
196impl From<AttestationError> for PresentationBuilderError {
197 fn from(error: AttestationError) -> Self {
198 Self {
199 kind: BuilderErrorKind::Attestation,
200 source: Some(Box::new(error)),
201 }
202 }
203}
204
205#[derive(Debug, thiserror::Error)]
207pub struct PresentationError {
208 kind: ErrorKind,
209 source: Option<Box<dyn std::error::Error + Send + Sync>>,
210}
211
212#[derive(Debug)]
213enum ErrorKind {
214 Attestation,
215 Identity,
216 Transcript,
217}
218
219impl fmt::Display for PresentationError {
220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221 f.write_str("presentation error: ")?;
222
223 match self.kind {
224 ErrorKind::Attestation => f.write_str("attestation error")?,
225 ErrorKind::Identity => f.write_str("server identity error")?,
226 ErrorKind::Transcript => f.write_str("transcript error")?,
227 }
228
229 if let Some(source) = &self.source {
230 write!(f, " caused by: {}", source)?;
231 }
232
233 Ok(())
234 }
235}
236
237impl From<AttestationError> for PresentationError {
238 fn from(error: AttestationError) -> Self {
239 Self {
240 kind: ErrorKind::Attestation,
241 source: Some(Box::new(error)),
242 }
243 }
244}
245
246impl From<ServerIdentityProofError> for PresentationError {
247 fn from(error: ServerIdentityProofError) -> Self {
248 Self {
249 kind: ErrorKind::Identity,
250 source: Some(Box::new(error)),
251 }
252 }
253}
254
255impl From<TranscriptProofError> for PresentationError {
256 fn from(error: TranscriptProofError) -> Self {
257 Self {
258 kind: ErrorKind::Transcript,
259 source: Some(Box::new(error)),
260 }
261 }
262}