tlsn_core/
presentation.rs

1//! Verifiable presentation.
2//!
3//! We borrow the term "presentation" from the
4//! [W3C Verifiable Credentials Data Model](https://www.w3.org/TR/vc-data-model/#presentations-0).
5//!
6//! > Data derived from one or more verifiable credentials, issued by one or
7//! > more issuers, that is shared with a specific verifier. A verifiable
8//! > presentation is a tamper-evident presentation encoded in such a way that
9//! > authorship of the data can be trusted after a process of cryptographic
10//! > verification. Certain types of verifiable presentations might contain data
11//! > that is synthesized from, but do not contain, the original verifiable
12//! > credentials (for example, zero-knowledge proofs).
13//!
14//! Instead of a credential, a presentation in this context is a proof of an
15//! attestation from a Notary along with additional selectively disclosed
16//! information about the TLS connection such as the server's identity and the
17//! application data communicated with the server.
18//!
19//! A presentation is self-contained and can be verified by a Verifier without
20//! needing access to external data. The Verifier need only check that the key
21//! used to sign the attestation, referred to as a [`VerifyingKey`], is from a
22//! Notary they trust. See an [example](crate#verifying-a-presentation) in the
23//! crate level documentation.
24
25use 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/// A verifiable presentation.
38///
39/// See the [module level documentation](crate::presentation) for more
40/// information.
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct Presentation {
43    attestation: AttestationProof,
44    identity: Option<ServerIdentityProof>,
45    transcript: Option<TranscriptProof>,
46}
47
48impl Presentation {
49    /// Creates a new builder.
50    pub fn builder<'a>(
51        provider: &'a CryptoProvider,
52        attestation: &'a Attestation,
53    ) -> PresentationBuilder<'a> {
54        PresentationBuilder::new(provider, attestation)
55    }
56
57    /// Returns the verifying key.
58    pub fn verifying_key(&self) -> &VerifyingKey {
59        self.attestation.verifying_key()
60    }
61
62    /// Verifies the presentation.
63    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/// Output of a verified [`Presentation`].
111#[derive(Debug)]
112#[non_exhaustive]
113pub struct PresentationOutput {
114    /// Verified attestation.
115    pub attestation: Attestation,
116    /// Authenticated server name.
117    pub server_name: Option<ServerName>,
118    /// Connection information.
119    pub connection_info: ConnectionInfo,
120    /// Authenticated transcript data.
121    pub transcript: Option<PartialTranscript>,
122    /// Extensions.
123    pub extensions: Vec<Extension>,
124}
125
126/// Builder for [`Presentation`].
127pub 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    /// Includes a server identity proof.
145    pub fn identity_proof(&mut self, proof: ServerIdentityProof) -> &mut Self {
146        self.identity_proof = Some(proof);
147        self
148    }
149
150    /// Includes a transcript proof.
151    pub fn transcript_proof(&mut self, proof: TranscriptProof) -> &mut Self {
152        self.transcript_proof = Some(proof);
153        self
154    }
155
156    /// Builds the presentation.
157    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/// Error for [`PresentationBuilder`].
169#[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/// Error for [`Presentation`].
206#[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}