tlsn_core/request/
builder.rs

1use crate::{
2    connection::{ServerCertData, ServerCertOpening, ServerName},
3    request::{Request, RequestConfig},
4    secrets::Secrets,
5    transcript::{Transcript, TranscriptCommitment, TranscriptSecret},
6    CryptoProvider,
7};
8
9/// Builder for [`Request`].
10pub struct RequestBuilder<'a> {
11    config: &'a RequestConfig,
12    server_name: Option<ServerName>,
13    server_cert_data: Option<ServerCertData>,
14    transcript: Option<Transcript>,
15    transcript_commitments: Vec<TranscriptCommitment>,
16    transcript_commitment_secrets: Vec<TranscriptSecret>,
17}
18
19impl<'a> RequestBuilder<'a> {
20    /// Creates a new request builder.
21    pub fn new(config: &'a RequestConfig) -> Self {
22        Self {
23            config,
24            server_name: None,
25            server_cert_data: None,
26            transcript: None,
27            transcript_commitments: Vec::new(),
28            transcript_commitment_secrets: Vec::new(),
29        }
30    }
31
32    /// Sets the server name.
33    pub fn server_name(&mut self, name: ServerName) -> &mut Self {
34        self.server_name = Some(name);
35        self
36    }
37
38    /// Sets the server identity data.
39    pub fn server_cert_data(&mut self, data: ServerCertData) -> &mut Self {
40        self.server_cert_data = Some(data);
41        self
42    }
43
44    /// Sets the transcript.
45    pub fn transcript(&mut self, transcript: Transcript) -> &mut Self {
46        self.transcript = Some(transcript);
47        self
48    }
49
50    /// Sets the transcript commitments.
51    pub fn transcript_commitments(
52        &mut self,
53        secrets: Vec<TranscriptSecret>,
54        commitments: Vec<TranscriptCommitment>,
55    ) -> &mut Self {
56        self.transcript_commitment_secrets = secrets;
57        self.transcript_commitments = commitments;
58        self
59    }
60
61    /// Builds the attestation request and returns the corresponding secrets.
62    pub fn build(
63        self,
64        provider: &CryptoProvider,
65    ) -> Result<(Request, Secrets), RequestBuilderError> {
66        let Self {
67            config,
68            server_name,
69            server_cert_data,
70            transcript,
71            transcript_commitments,
72            transcript_commitment_secrets,
73        } = self;
74
75        let signature_alg = *config.signature_alg();
76        let hash_alg = *config.hash_alg();
77
78        let hasher = provider.hash.get(&hash_alg).map_err(|_| {
79            RequestBuilderError::new(format!("unsupported hash algorithm: {hash_alg}"))
80        })?;
81
82        let server_name =
83            server_name.ok_or_else(|| RequestBuilderError::new("server name is missing"))?;
84
85        let server_cert_opening = ServerCertOpening::new(
86            server_cert_data
87                .ok_or_else(|| RequestBuilderError::new("server identity data is missing"))?,
88        );
89
90        let transcript =
91            transcript.ok_or_else(|| RequestBuilderError::new("transcript is missing"))?;
92
93        let server_cert_commitment = server_cert_opening.commit(hasher);
94
95        let extensions = config.extensions().to_vec();
96
97        let request = Request {
98            signature_alg,
99            hash_alg,
100            server_cert_commitment,
101            extensions,
102        };
103
104        let secrets = Secrets {
105            server_name,
106            server_cert_opening,
107            transcript,
108            transcript_commitments,
109            transcript_commitment_secrets,
110        };
111
112        Ok((request, secrets))
113    }
114}
115
116/// Error for [`RequestBuilder`].
117#[derive(Debug, thiserror::Error)]
118#[error("request builder error: {message}")]
119pub struct RequestBuilderError {
120    message: String,
121}
122
123impl RequestBuilderError {
124    fn new(message: impl Into<String>) -> Self {
125        Self {
126            message: message.into(),
127        }
128    }
129}