Skip to main content

tlsn_core/
connection.rs

1//! TLS connection types.
2
3use std::fmt;
4
5use rustls_pki_types as webpki_types;
6use serde::{Deserialize, Serialize};
7use tls_core::msgs::{codec::Codec, enums::NamedGroup, handshake::ServerECDHParams};
8
9use crate::webpki::{CertificateDer, ServerCertVerifier, ServerCertVerifierError};
10
11/// TLS version.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14pub enum TlsVersion {
15    /// TLS 1.2.
16    V1_2,
17    /// TLS 1.3.
18    V1_3,
19}
20
21impl TryFrom<tls_core::msgs::enums::ProtocolVersion> for TlsVersion {
22    type Error = &'static str;
23
24    fn try_from(value: tls_core::msgs::enums::ProtocolVersion) -> Result<Self, Self::Error> {
25        Ok(match value {
26            tls_core::msgs::enums::ProtocolVersion::TLSv1_2 => TlsVersion::V1_2,
27            tls_core::msgs::enums::ProtocolVersion::TLSv1_3 => TlsVersion::V1_3,
28            _ => return Err("unsupported TLS version"),
29        })
30    }
31}
32
33/// Server's name.
34#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
35pub enum ServerName {
36    /// DNS name.
37    Dns(DnsName),
38}
39
40impl ServerName {
41    pub(crate) fn to_webpki(&self) -> webpki_types::ServerName<'static> {
42        match self {
43            ServerName::Dns(name) => webpki_types::ServerName::DnsName(
44                webpki_types::DnsName::try_from(name.0.as_str())
45                    .expect("name was validated")
46                    .to_owned(),
47            ),
48        }
49    }
50}
51
52impl fmt::Display for ServerName {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        match self {
55            ServerName::Dns(name) => write!(f, "{name}"),
56        }
57    }
58}
59
60/// DNS name.
61#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
62#[serde(try_from = "String")]
63pub struct DnsName(String);
64
65impl DnsName {
66    /// Returns the DNS name as a string.
67    pub fn as_str(&self) -> &str {
68        self.0.as_str()
69    }
70}
71
72impl fmt::Display for DnsName {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        write!(f, "{}", self.0)
75    }
76}
77
78impl AsRef<str> for DnsName {
79    fn as_ref(&self) -> &str {
80        &self.0
81    }
82}
83
84/// Error returned when a DNS name is invalid.
85#[derive(Debug, thiserror::Error)]
86#[error("invalid DNS name")]
87pub struct InvalidDnsNameError {}
88
89impl TryFrom<&str> for DnsName {
90    type Error = InvalidDnsNameError;
91
92    fn try_from(value: &str) -> Result<Self, Self::Error> {
93        // Borrow validation from rustls
94        match webpki_types::DnsName::try_from_str(value) {
95            Ok(_) => Ok(DnsName(value.to_string())),
96            Err(_) => Err(InvalidDnsNameError {}),
97        }
98    }
99}
100
101impl TryFrom<String> for DnsName {
102    type Error = InvalidDnsNameError;
103
104    fn try_from(value: String) -> Result<Self, Self::Error> {
105        Self::try_from(value.as_str())
106    }
107}
108
109/// Type of a public key.
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
111#[serde(rename_all = "lowercase")]
112#[non_exhaustive]
113#[allow(non_camel_case_types)]
114pub enum KeyType {
115    /// secp256r1.
116    SECP256R1 = 0x0017,
117}
118
119/// Signature algorithm used on the key exchange parameters.
120#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
121#[serde(rename_all = "lowercase")]
122#[allow(non_camel_case_types, missing_docs)]
123pub enum SignatureAlgorithm {
124    ECDSA_NISTP256_SHA256,
125    ECDSA_NISTP256_SHA384,
126    ECDSA_NISTP384_SHA256,
127    ECDSA_NISTP384_SHA384,
128    ED25519,
129    RSA_PKCS1_2048_8192_SHA256,
130    RSA_PKCS1_2048_8192_SHA384,
131    RSA_PKCS1_2048_8192_SHA512,
132    RSA_PSS_2048_8192_SHA256_LEGACY_KEY,
133    RSA_PSS_2048_8192_SHA384_LEGACY_KEY,
134    RSA_PSS_2048_8192_SHA512_LEGACY_KEY,
135}
136
137impl fmt::Display for SignatureAlgorithm {
138    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139        match self {
140            SignatureAlgorithm::ECDSA_NISTP256_SHA256 => write!(f, "ECDSA_NISTP256_SHA256"),
141            SignatureAlgorithm::ECDSA_NISTP256_SHA384 => write!(f, "ECDSA_NISTP256_SHA384"),
142            SignatureAlgorithm::ECDSA_NISTP384_SHA256 => write!(f, "ECDSA_NISTP384_SHA256"),
143            SignatureAlgorithm::ECDSA_NISTP384_SHA384 => write!(f, "ECDSA_NISTP384_SHA384"),
144            SignatureAlgorithm::ED25519 => write!(f, "ED25519"),
145            SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA256 => {
146                write!(f, "RSA_PKCS1_2048_8192_SHA256")
147            }
148            SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA384 => {
149                write!(f, "RSA_PKCS1_2048_8192_SHA384")
150            }
151            SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA512 => {
152                write!(f, "RSA_PKCS1_2048_8192_SHA512")
153            }
154            SignatureAlgorithm::RSA_PSS_2048_8192_SHA256_LEGACY_KEY => {
155                write!(f, "RSA_PSS_2048_8192_SHA256_LEGACY_KEY")
156            }
157            SignatureAlgorithm::RSA_PSS_2048_8192_SHA384_LEGACY_KEY => {
158                write!(f, "RSA_PSS_2048_8192_SHA384_LEGACY_KEY")
159            }
160            SignatureAlgorithm::RSA_PSS_2048_8192_SHA512_LEGACY_KEY => {
161                write!(f, "RSA_PSS_2048_8192_SHA512_LEGACY_KEY")
162            }
163        }
164    }
165}
166
167impl From<tls_core::verify::SignatureAlgorithm> for SignatureAlgorithm {
168    fn from(value: tls_core::verify::SignatureAlgorithm) -> Self {
169        use tls_core::verify::SignatureAlgorithm as Core;
170        match value {
171            Core::ECDSA_NISTP256_SHA256 => SignatureAlgorithm::ECDSA_NISTP256_SHA256,
172            Core::ECDSA_NISTP256_SHA384 => SignatureAlgorithm::ECDSA_NISTP256_SHA384,
173            Core::ECDSA_NISTP384_SHA256 => SignatureAlgorithm::ECDSA_NISTP384_SHA256,
174            Core::ECDSA_NISTP384_SHA384 => SignatureAlgorithm::ECDSA_NISTP384_SHA384,
175            Core::ED25519 => SignatureAlgorithm::ED25519,
176            Core::RSA_PKCS1_2048_8192_SHA256 => SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA256,
177            Core::RSA_PKCS1_2048_8192_SHA384 => SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA384,
178            Core::RSA_PKCS1_2048_8192_SHA512 => SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA512,
179            Core::RSA_PSS_2048_8192_SHA256_LEGACY_KEY => {
180                SignatureAlgorithm::RSA_PSS_2048_8192_SHA256_LEGACY_KEY
181            }
182            Core::RSA_PSS_2048_8192_SHA384_LEGACY_KEY => {
183                SignatureAlgorithm::RSA_PSS_2048_8192_SHA384_LEGACY_KEY
184            }
185            Core::RSA_PSS_2048_8192_SHA512_LEGACY_KEY => {
186                SignatureAlgorithm::RSA_PSS_2048_8192_SHA512_LEGACY_KEY
187            }
188        }
189    }
190}
191
192/// Server's signature of the key exchange parameters.
193#[derive(Debug, Clone, Serialize, Deserialize)]
194pub struct ServerSignature {
195    /// Signature algorithm.
196    pub alg: SignatureAlgorithm,
197    /// Signature data.
198    pub sig: Vec<u8>,
199}
200
201/// Server's ephemeral public key.
202#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
203pub struct ServerEphemKey {
204    /// Type of the public key.
205    #[serde(rename = "type")]
206    pub typ: KeyType,
207    /// Public key data.
208    pub key: Vec<u8>,
209}
210
211impl ServerEphemKey {
212    /// Encodes the key exchange parameters as in TLS.
213    pub(crate) fn kx_params(&self) -> Vec<u8> {
214        let group = match self.typ {
215            KeyType::SECP256R1 => NamedGroup::secp256r1,
216        };
217
218        let mut kx_params = Vec::new();
219        ServerECDHParams::new(group, &self.key).encode(&mut kx_params);
220
221        kx_params
222    }
223}
224
225impl TryFrom<tls_core::key::PublicKey> for ServerEphemKey {
226    type Error = &'static str;
227
228    fn try_from(value: tls_core::key::PublicKey) -> Result<Self, Self::Error> {
229        let tls_core::msgs::enums::NamedGroup::secp256r1 = value.group else {
230            return Err("unsupported key type");
231        };
232
233        Ok(ServerEphemKey {
234            typ: KeyType::SECP256R1,
235            key: value.key,
236        })
237    }
238}
239
240/// TLS session information.
241#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
242pub struct ConnectionInfo {
243    /// UNIX time when the TLS connection started.
244    pub time: u64,
245    /// TLS version used in the connection.
246    pub version: TlsVersion,
247    /// Transcript length.
248    pub transcript_length: TranscriptLength,
249}
250
251/// Transcript length information.
252#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
253pub struct TranscriptLength {
254    /// Number of bytes sent by the Prover to the Server.
255    pub sent: u32,
256    /// Number of bytes received by the Prover from the Server.
257    pub received: u32,
258}
259
260/// TLS 1.2 certificate binding.
261#[derive(Debug, Clone, Serialize, Deserialize)]
262pub struct CertBindingV1_2 {
263    /// Client random.
264    pub client_random: [u8; 32],
265    /// Server random.
266    pub server_random: [u8; 32],
267    /// Server's ephemeral public key.
268    pub server_ephemeral_key: ServerEphemKey,
269}
270
271/// TLS certificate binding.
272///
273/// This is the data that the server signs using its public key in the
274/// certificate it presents during the TLS handshake. This provides a binding
275/// between the server's identity and the ephemeral keys used to authenticate
276/// the TLS session.
277#[derive(Debug, Clone, Serialize, Deserialize)]
278#[serde(rename_all = "snake_case")]
279#[non_exhaustive]
280pub enum CertBinding {
281    /// TLS 1.2 certificate binding.
282    V1_2(CertBindingV1_2),
283}
284
285/// TLS handshake data.
286#[derive(Debug, Clone, Serialize, Deserialize)]
287pub struct HandshakeData {
288    /// Server certificate chain.
289    pub certs: Vec<CertificateDer>,
290    /// Server certificate signature over the binding message.
291    pub sig: ServerSignature,
292    /// Certificate binding.
293    pub binding: CertBinding,
294}
295
296impl HandshakeData {
297    /// Verifies the handshake data.
298    ///
299    /// # Arguments
300    ///
301    /// * `verifier` - Cerificate verifier.
302    /// * `time` - The time of the connection.
303    /// * `server_ephemeral_key` - The server's ephemeral key.
304    /// * `server_name` - The server name.
305    pub fn verify(
306        &self,
307        verifier: &ServerCertVerifier,
308        time: u64,
309        server_ephemeral_key: &ServerEphemKey,
310        server_name: &ServerName,
311    ) -> Result<(), HandshakeVerificationError> {
312        #[allow(irrefutable_let_patterns)]
313        let CertBinding::V1_2(CertBindingV1_2 {
314            client_random,
315            server_random,
316            server_ephemeral_key: expected_server_ephemeral_key,
317        }) = &self.binding
318        else {
319            unreachable!("only TLS 1.2 is implemented")
320        };
321
322        if server_ephemeral_key != expected_server_ephemeral_key {
323            return Err(HandshakeVerificationError::InvalidServerEphemeralKey);
324        }
325
326        let (end_entity, intermediates) = self
327            .certs
328            .split_first()
329            .ok_or(HandshakeVerificationError::MissingCerts)?;
330
331        // Verify the end entity cert is valid for the provided server name
332        // and that it chains to at least one of the roots we trust.
333        verifier
334            .verify_server_cert(end_entity, intermediates, server_name, time)
335            .map_err(HandshakeVerificationError::ServerCert)?;
336
337        // Verify the signature matches the certificate and key exchange parameters.
338        let mut message = Vec::new();
339        message.extend_from_slice(client_random);
340        message.extend_from_slice(server_random);
341        message.extend_from_slice(&server_ephemeral_key.kx_params());
342
343        use webpki::ring as alg;
344        let sig_alg = match self.sig.alg {
345            SignatureAlgorithm::ECDSA_NISTP256_SHA256 => alg::ECDSA_P256_SHA256,
346            SignatureAlgorithm::ECDSA_NISTP256_SHA384 => alg::ECDSA_P256_SHA384,
347            SignatureAlgorithm::ECDSA_NISTP384_SHA256 => alg::ECDSA_P384_SHA256,
348            SignatureAlgorithm::ECDSA_NISTP384_SHA384 => alg::ECDSA_P384_SHA384,
349            SignatureAlgorithm::ED25519 => alg::ED25519,
350            SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA256 => alg::RSA_PKCS1_2048_8192_SHA256,
351            SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA384 => alg::RSA_PKCS1_2048_8192_SHA384,
352            SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA512 => alg::RSA_PKCS1_2048_8192_SHA512,
353            SignatureAlgorithm::RSA_PSS_2048_8192_SHA256_LEGACY_KEY => {
354                alg::RSA_PSS_2048_8192_SHA256_LEGACY_KEY
355            }
356            SignatureAlgorithm::RSA_PSS_2048_8192_SHA384_LEGACY_KEY => {
357                alg::RSA_PSS_2048_8192_SHA384_LEGACY_KEY
358            }
359            SignatureAlgorithm::RSA_PSS_2048_8192_SHA512_LEGACY_KEY => {
360                alg::RSA_PSS_2048_8192_SHA512_LEGACY_KEY
361            }
362        };
363
364        let end_entity = webpki_types::CertificateDer::from(end_entity.0.as_slice());
365        let end_entity = webpki::EndEntityCert::try_from(&end_entity)
366            .map_err(|_| HandshakeVerificationError::InvalidEndEntityCertificate)?;
367
368        end_entity
369            .verify_signature(sig_alg, &message, &self.sig.sig)
370            .map_err(|_| HandshakeVerificationError::InvalidServerSignature)?;
371
372        Ok(())
373    }
374}
375
376/// Errors that can occur when verifying a certificate chain or signature.
377#[derive(Debug, thiserror::Error)]
378#[allow(missing_docs)]
379pub enum HandshakeVerificationError {
380    #[error("invalid end entity certificate")]
381    InvalidEndEntityCertificate,
382    #[error("missing server certificates")]
383    MissingCerts,
384    #[error("invalid server signature")]
385    InvalidServerSignature,
386    #[error("invalid server ephemeral key")]
387    InvalidServerEphemeralKey,
388    #[error("server certificate verification failed: {0}")]
389    ServerCert(ServerCertVerifierError),
390}
391
392#[cfg(test)]
393mod tests {
394    use super::*;
395    use crate::{fixtures::ConnectionFixture, transcript::Transcript, webpki::RootCertStore};
396
397    use hex::FromHex;
398    use rstest::*;
399    use tlsn_data_fixtures::http::{request::GET_WITH_HEADER, response::OK_JSON};
400
401    #[fixture]
402    #[once]
403    fn verifier() -> ServerCertVerifier {
404        let mut root_store = RootCertStore {
405            roots: webpki_root_certs::TLS_SERVER_ROOT_CERTS
406                .iter()
407                .map(|c| CertificateDer(c.to_vec()))
408                .collect(),
409        };
410
411        // Add a cert which is no longer included in the Mozilla root store.
412        root_store.roots.push(
413            appliedzkp()
414                .server_cert_data
415                .certs
416                .last()
417                .expect("chain is valid")
418                .clone(),
419        );
420
421        ServerCertVerifier::new(&root_store).unwrap()
422    }
423
424    fn tlsnotary() -> ConnectionFixture {
425        ConnectionFixture::tlsnotary(Transcript::new(GET_WITH_HEADER, OK_JSON).length())
426    }
427
428    fn appliedzkp() -> ConnectionFixture {
429        ConnectionFixture::appliedzkp(Transcript::new(GET_WITH_HEADER, OK_JSON).length())
430    }
431
432    /// Expect chain verification to succeed.
433    #[rstest]
434    #[case::tlsnotary(tlsnotary())]
435    #[case::appliedzkp(appliedzkp())]
436    fn test_verify_cert_chain_sucess_ca_implicit(
437        verifier: &ServerCertVerifier,
438        #[case] mut data: ConnectionFixture,
439    ) {
440        // Remove the CA cert
441        data.server_cert_data.certs.pop();
442
443        assert!(
444            data.server_cert_data
445                .verify(
446                    verifier,
447                    data.connection_info.time,
448                    data.server_ephemeral_key(),
449                    &data.server_name,
450                )
451                .is_ok()
452        );
453    }
454
455    /// Expect chain verification to succeed even when a trusted CA is provided
456    /// among the intermediate certs. webpki handles such cases properly.
457    #[rstest]
458    #[case::tlsnotary(tlsnotary())]
459    #[case::appliedzkp(appliedzkp())]
460    fn test_verify_cert_chain_success_ca_explicit(
461        verifier: &ServerCertVerifier,
462        #[case] data: ConnectionFixture,
463    ) {
464        assert!(
465            data.server_cert_data
466                .verify(
467                    verifier,
468                    data.connection_info.time,
469                    data.server_ephemeral_key(),
470                    &data.server_name,
471                )
472                .is_ok()
473        );
474    }
475
476    /// Expect to fail since the end entity cert was not valid at the time.
477    #[rstest]
478    #[case::tlsnotary(tlsnotary())]
479    #[case::appliedzkp(appliedzkp())]
480    fn test_verify_cert_chain_fail_bad_time(
481        verifier: &ServerCertVerifier,
482        #[case] data: ConnectionFixture,
483    ) {
484        // unix time when the cert chain was NOT valid
485        let bad_time: u64 = 1571465711;
486
487        let err = data.server_cert_data.verify(
488            verifier,
489            bad_time,
490            data.server_ephemeral_key(),
491            &data.server_name,
492        );
493
494        assert!(matches!(
495            err.unwrap_err(),
496            HandshakeVerificationError::ServerCert(_)
497        ));
498    }
499
500    /// Expect to fail when no intermediate cert provided.
501    #[rstest]
502    #[case::tlsnotary(tlsnotary())]
503    #[case::appliedzkp(appliedzkp())]
504    fn test_verify_cert_chain_fail_no_interm_cert(
505        verifier: &ServerCertVerifier,
506        #[case] mut data: ConnectionFixture,
507    ) {
508        // Remove the CA cert
509        data.server_cert_data.certs.pop();
510        // Remove the intermediate cert
511        data.server_cert_data.certs.pop();
512
513        let err = data.server_cert_data.verify(
514            verifier,
515            data.connection_info.time,
516            data.server_ephemeral_key(),
517            &data.server_name,
518        );
519
520        assert!(matches!(
521            err.unwrap_err(),
522            HandshakeVerificationError::ServerCert(_)
523        ));
524    }
525
526    /// Expect to fail when no intermediate cert provided even if a trusted CA
527    /// cert is provided.
528    #[rstest]
529    #[case::tlsnotary(tlsnotary())]
530    #[case::appliedzkp(appliedzkp())]
531    fn test_verify_cert_chain_fail_no_interm_cert_with_ca_cert(
532        verifier: &ServerCertVerifier,
533        #[case] mut data: ConnectionFixture,
534    ) {
535        // Remove the intermediate cert
536        data.server_cert_data.certs.remove(1);
537
538        let err = data.server_cert_data.verify(
539            verifier,
540            data.connection_info.time,
541            data.server_ephemeral_key(),
542            &data.server_name,
543        );
544
545        assert!(matches!(
546            err.unwrap_err(),
547            HandshakeVerificationError::ServerCert(_)
548        ));
549    }
550
551    /// Expect to fail because end-entity cert is wrong.
552    #[rstest]
553    #[case::tlsnotary(tlsnotary())]
554    #[case::appliedzkp(appliedzkp())]
555    fn test_verify_cert_chain_fail_bad_ee_cert(
556        verifier: &ServerCertVerifier,
557        #[case] mut data: ConnectionFixture,
558    ) {
559        let ee: &[u8] = include_bytes!("./fixtures/data/unknown/ee.der");
560
561        // Change the end entity cert
562        data.server_cert_data.certs[0] = CertificateDer(ee.to_vec());
563
564        let err = data.server_cert_data.verify(
565            verifier,
566            data.connection_info.time,
567            data.server_ephemeral_key(),
568            &data.server_name,
569        );
570
571        assert!(matches!(
572            err.unwrap_err(),
573            HandshakeVerificationError::ServerCert(_)
574        ));
575    }
576
577    /// Expect sig verification to fail because client_random is wrong.
578    #[rstest]
579    #[case::tlsnotary(tlsnotary())]
580    #[case::appliedzkp(appliedzkp())]
581    fn test_verify_sig_ke_params_fail_bad_client_random(
582        verifier: &ServerCertVerifier,
583        #[case] mut data: ConnectionFixture,
584    ) {
585        let CertBinding::V1_2(CertBindingV1_2 { client_random, .. }) =
586            &mut data.server_cert_data.binding;
587        client_random[31] = client_random[31].wrapping_add(1);
588
589        let err = data.server_cert_data.verify(
590            verifier,
591            data.connection_info.time,
592            data.server_ephemeral_key(),
593            &data.server_name,
594        );
595
596        assert!(matches!(
597            err.unwrap_err(),
598            HandshakeVerificationError::InvalidServerSignature
599        ));
600    }
601
602    /// Expect sig verification to fail because the sig is wrong.
603    #[rstest]
604    #[case::tlsnotary(tlsnotary())]
605    #[case::appliedzkp(appliedzkp())]
606    fn test_verify_sig_ke_params_fail_bad_sig(
607        verifier: &ServerCertVerifier,
608        #[case] mut data: ConnectionFixture,
609    ) {
610        data.server_cert_data.sig.sig[31] = data.server_cert_data.sig.sig[31].wrapping_add(1);
611
612        let err = data.server_cert_data.verify(
613            verifier,
614            data.connection_info.time,
615            data.server_ephemeral_key(),
616            &data.server_name,
617        );
618
619        assert!(matches!(
620            err.unwrap_err(),
621            HandshakeVerificationError::InvalidServerSignature
622        ));
623    }
624
625    /// Expect to fail because the dns name is not in the cert.
626    #[rstest]
627    #[case::tlsnotary(tlsnotary())]
628    #[case::appliedzkp(appliedzkp())]
629    fn test_check_dns_name_present_in_cert_fail_bad_host(
630        verifier: &ServerCertVerifier,
631        #[case] data: ConnectionFixture,
632    ) {
633        let bad_name = ServerName::Dns(DnsName::try_from("badhost.com").unwrap());
634
635        let err = data.server_cert_data.verify(
636            verifier,
637            data.connection_info.time,
638            data.server_ephemeral_key(),
639            &bad_name,
640        );
641
642        assert!(matches!(
643            err.unwrap_err(),
644            HandshakeVerificationError::ServerCert(_)
645        ));
646    }
647
648    /// Expect to fail because the ephemeral key provided is wrong.
649    #[rstest]
650    #[case::tlsnotary(tlsnotary())]
651    #[case::appliedzkp(appliedzkp())]
652    fn test_invalid_ephemeral_key(verifier: &ServerCertVerifier, #[case] data: ConnectionFixture) {
653        let wrong_ephemeral_key = ServerEphemKey {
654            typ: KeyType::SECP256R1,
655            key: Vec::<u8>::from_hex(include_bytes!("./fixtures/data/unknown/pubkey")).unwrap(),
656        };
657
658        let err = data.server_cert_data.verify(
659            verifier,
660            data.connection_info.time,
661            &wrong_ephemeral_key,
662            &data.server_name,
663        );
664
665        assert!(matches!(
666            err.unwrap_err(),
667            HandshakeVerificationError::InvalidServerEphemeralKey
668        ));
669    }
670
671    /// Expect to fail when no cert provided.
672    #[rstest]
673    #[case::tlsnotary(tlsnotary())]
674    #[case::appliedzkp(appliedzkp())]
675    fn test_verify_cert_chain_fail_no_cert(
676        verifier: &ServerCertVerifier,
677        #[case] mut data: ConnectionFixture,
678    ) {
679        // Empty certs
680        data.server_cert_data.certs = Vec::new();
681
682        let err = data.server_cert_data.verify(
683            verifier,
684            data.connection_info.time,
685            data.server_ephemeral_key(),
686            &data.server_name,
687        );
688
689        assert!(matches!(
690            err.unwrap_err(),
691            HandshakeVerificationError::MissingCerts
692        ));
693    }
694}