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
338        // parameters.
339        let mut message = Vec::new();
340        message.extend_from_slice(client_random);
341        message.extend_from_slice(server_random);
342        message.extend_from_slice(&server_ephemeral_key.kx_params());
343
344        use webpki::ring as alg;
345        let sig_alg = match self.sig.alg {
346            SignatureAlgorithm::ECDSA_NISTP256_SHA256 => alg::ECDSA_P256_SHA256,
347            SignatureAlgorithm::ECDSA_NISTP256_SHA384 => alg::ECDSA_P256_SHA384,
348            SignatureAlgorithm::ECDSA_NISTP384_SHA256 => alg::ECDSA_P384_SHA256,
349            SignatureAlgorithm::ECDSA_NISTP384_SHA384 => alg::ECDSA_P384_SHA384,
350            SignatureAlgorithm::ED25519 => alg::ED25519,
351            SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA256 => alg::RSA_PKCS1_2048_8192_SHA256,
352            SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA384 => alg::RSA_PKCS1_2048_8192_SHA384,
353            SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA512 => alg::RSA_PKCS1_2048_8192_SHA512,
354            SignatureAlgorithm::RSA_PSS_2048_8192_SHA256_LEGACY_KEY => {
355                alg::RSA_PSS_2048_8192_SHA256_LEGACY_KEY
356            }
357            SignatureAlgorithm::RSA_PSS_2048_8192_SHA384_LEGACY_KEY => {
358                alg::RSA_PSS_2048_8192_SHA384_LEGACY_KEY
359            }
360            SignatureAlgorithm::RSA_PSS_2048_8192_SHA512_LEGACY_KEY => {
361                alg::RSA_PSS_2048_8192_SHA512_LEGACY_KEY
362            }
363        };
364
365        let end_entity = webpki_types::CertificateDer::from(end_entity.0.as_slice());
366        let end_entity = webpki::EndEntityCert::try_from(&end_entity)
367            .map_err(|_| HandshakeVerificationError::InvalidEndEntityCertificate)?;
368
369        end_entity
370            .verify_signature(sig_alg, &message, &self.sig.sig)
371            .map_err(|_| HandshakeVerificationError::InvalidServerSignature)?;
372
373        Ok(())
374    }
375}
376
377/// Errors that can occur when verifying a certificate chain or signature.
378#[derive(Debug, thiserror::Error)]
379#[allow(missing_docs)]
380pub enum HandshakeVerificationError {
381    #[error("invalid end entity certificate")]
382    InvalidEndEntityCertificate,
383    #[error("missing server certificates")]
384    MissingCerts,
385    #[error("invalid server signature")]
386    InvalidServerSignature,
387    #[error("invalid server ephemeral key")]
388    InvalidServerEphemeralKey,
389    #[error("server certificate verification failed: {0}")]
390    ServerCert(ServerCertVerifierError),
391}
392
393#[cfg(test)]
394mod tests {
395    use super::*;
396    use crate::{fixtures::ConnectionFixture, transcript::Transcript, webpki::RootCertStore};
397
398    use hex::FromHex;
399    use rstest::*;
400    use tlsn_data_fixtures::http::{request::GET_WITH_HEADER, response::OK_JSON};
401
402    #[fixture]
403    #[once]
404    fn verifier() -> ServerCertVerifier {
405        let mut root_store = RootCertStore {
406            roots: webpki_root_certs::TLS_SERVER_ROOT_CERTS
407                .iter()
408                .map(|c| CertificateDer(c.to_vec()))
409                .collect(),
410        };
411
412        // Add a cert which is no longer included in the Mozilla root store.
413        root_store.roots.push(
414            appliedzkp()
415                .server_cert_data
416                .certs
417                .last()
418                .expect("chain is valid")
419                .clone(),
420        );
421
422        ServerCertVerifier::new(&root_store).unwrap()
423    }
424
425    fn tlsnotary() -> ConnectionFixture {
426        ConnectionFixture::tlsnotary(Transcript::new(GET_WITH_HEADER, OK_JSON).length())
427    }
428
429    fn appliedzkp() -> ConnectionFixture {
430        ConnectionFixture::appliedzkp(Transcript::new(GET_WITH_HEADER, OK_JSON).length())
431    }
432
433    /// Expect chain verification to succeed.
434    #[rstest]
435    #[case::tlsnotary(tlsnotary())]
436    #[case::appliedzkp(appliedzkp())]
437    fn test_verify_cert_chain_sucess_ca_implicit(
438        verifier: &ServerCertVerifier,
439        #[case] mut data: ConnectionFixture,
440    ) {
441        // Remove the CA cert
442        data.server_cert_data.certs.pop();
443
444        assert!(
445            data.server_cert_data
446                .verify(
447                    verifier,
448                    data.connection_info.time,
449                    data.server_ephemeral_key(),
450                    &data.server_name,
451                )
452                .is_ok()
453        );
454    }
455
456    /// Expect chain verification to succeed even when a trusted CA is provided
457    /// among the intermediate certs. webpki handles such cases properly.
458    #[rstest]
459    #[case::tlsnotary(tlsnotary())]
460    #[case::appliedzkp(appliedzkp())]
461    fn test_verify_cert_chain_success_ca_explicit(
462        verifier: &ServerCertVerifier,
463        #[case] data: ConnectionFixture,
464    ) {
465        assert!(
466            data.server_cert_data
467                .verify(
468                    verifier,
469                    data.connection_info.time,
470                    data.server_ephemeral_key(),
471                    &data.server_name,
472                )
473                .is_ok()
474        );
475    }
476
477    /// Expect to fail since the end entity cert was not valid at the time.
478    #[rstest]
479    #[case::tlsnotary(tlsnotary())]
480    #[case::appliedzkp(appliedzkp())]
481    fn test_verify_cert_chain_fail_bad_time(
482        verifier: &ServerCertVerifier,
483        #[case] data: ConnectionFixture,
484    ) {
485        // unix time when the cert chain was NOT valid
486        let bad_time: u64 = 1571465711;
487
488        let err = data.server_cert_data.verify(
489            verifier,
490            bad_time,
491            data.server_ephemeral_key(),
492            &data.server_name,
493        );
494
495        assert!(matches!(
496            err.unwrap_err(),
497            HandshakeVerificationError::ServerCert(_)
498        ));
499    }
500
501    /// Expect to fail when no intermediate cert provided.
502    #[rstest]
503    #[case::tlsnotary(tlsnotary())]
504    #[case::appliedzkp(appliedzkp())]
505    fn test_verify_cert_chain_fail_no_interm_cert(
506        verifier: &ServerCertVerifier,
507        #[case] mut data: ConnectionFixture,
508    ) {
509        // Remove the CA cert
510        data.server_cert_data.certs.pop();
511        // Remove the intermediate cert
512        data.server_cert_data.certs.pop();
513
514        let err = data.server_cert_data.verify(
515            verifier,
516            data.connection_info.time,
517            data.server_ephemeral_key(),
518            &data.server_name,
519        );
520
521        assert!(matches!(
522            err.unwrap_err(),
523            HandshakeVerificationError::ServerCert(_)
524        ));
525    }
526
527    /// Expect to fail when no intermediate cert provided even if a trusted CA
528    /// cert is provided.
529    #[rstest]
530    #[case::tlsnotary(tlsnotary())]
531    #[case::appliedzkp(appliedzkp())]
532    fn test_verify_cert_chain_fail_no_interm_cert_with_ca_cert(
533        verifier: &ServerCertVerifier,
534        #[case] mut data: ConnectionFixture,
535    ) {
536        // Remove the intermediate cert
537        data.server_cert_data.certs.remove(1);
538
539        let err = data.server_cert_data.verify(
540            verifier,
541            data.connection_info.time,
542            data.server_ephemeral_key(),
543            &data.server_name,
544        );
545
546        assert!(matches!(
547            err.unwrap_err(),
548            HandshakeVerificationError::ServerCert(_)
549        ));
550    }
551
552    /// Expect to fail because end-entity cert is wrong.
553    #[rstest]
554    #[case::tlsnotary(tlsnotary())]
555    #[case::appliedzkp(appliedzkp())]
556    fn test_verify_cert_chain_fail_bad_ee_cert(
557        verifier: &ServerCertVerifier,
558        #[case] mut data: ConnectionFixture,
559    ) {
560        let ee: &[u8] = include_bytes!("./fixtures/data/unknown/ee.der");
561
562        // Change the end entity cert
563        data.server_cert_data.certs[0] = CertificateDer(ee.to_vec());
564
565        let err = data.server_cert_data.verify(
566            verifier,
567            data.connection_info.time,
568            data.server_ephemeral_key(),
569            &data.server_name,
570        );
571
572        assert!(matches!(
573            err.unwrap_err(),
574            HandshakeVerificationError::ServerCert(_)
575        ));
576    }
577
578    /// Expect sig verification to fail because client_random is wrong.
579    #[rstest]
580    #[case::tlsnotary(tlsnotary())]
581    #[case::appliedzkp(appliedzkp())]
582    fn test_verify_sig_ke_params_fail_bad_client_random(
583        verifier: &ServerCertVerifier,
584        #[case] mut data: ConnectionFixture,
585    ) {
586        let CertBinding::V1_2(CertBindingV1_2 { client_random, .. }) =
587            &mut data.server_cert_data.binding;
588        client_random[31] = client_random[31].wrapping_add(1);
589
590        let err = data.server_cert_data.verify(
591            verifier,
592            data.connection_info.time,
593            data.server_ephemeral_key(),
594            &data.server_name,
595        );
596
597        assert!(matches!(
598            err.unwrap_err(),
599            HandshakeVerificationError::InvalidServerSignature
600        ));
601    }
602
603    /// Expect sig verification to fail because the sig is wrong.
604    #[rstest]
605    #[case::tlsnotary(tlsnotary())]
606    #[case::appliedzkp(appliedzkp())]
607    fn test_verify_sig_ke_params_fail_bad_sig(
608        verifier: &ServerCertVerifier,
609        #[case] mut data: ConnectionFixture,
610    ) {
611        data.server_cert_data.sig.sig[31] = data.server_cert_data.sig.sig[31].wrapping_add(1);
612
613        let err = data.server_cert_data.verify(
614            verifier,
615            data.connection_info.time,
616            data.server_ephemeral_key(),
617            &data.server_name,
618        );
619
620        assert!(matches!(
621            err.unwrap_err(),
622            HandshakeVerificationError::InvalidServerSignature
623        ));
624    }
625
626    /// Expect to fail because the dns name is not in the cert.
627    #[rstest]
628    #[case::tlsnotary(tlsnotary())]
629    #[case::appliedzkp(appliedzkp())]
630    fn test_check_dns_name_present_in_cert_fail_bad_host(
631        verifier: &ServerCertVerifier,
632        #[case] data: ConnectionFixture,
633    ) {
634        let bad_name = ServerName::Dns(DnsName::try_from("badhost.com").unwrap());
635
636        let err = data.server_cert_data.verify(
637            verifier,
638            data.connection_info.time,
639            data.server_ephemeral_key(),
640            &bad_name,
641        );
642
643        assert!(matches!(
644            err.unwrap_err(),
645            HandshakeVerificationError::ServerCert(_)
646        ));
647    }
648
649    /// Expect to fail because the ephemeral key provided is wrong.
650    #[rstest]
651    #[case::tlsnotary(tlsnotary())]
652    #[case::appliedzkp(appliedzkp())]
653    fn test_invalid_ephemeral_key(verifier: &ServerCertVerifier, #[case] data: ConnectionFixture) {
654        let wrong_ephemeral_key = ServerEphemKey {
655            typ: KeyType::SECP256R1,
656            key: Vec::<u8>::from_hex(include_bytes!("./fixtures/data/unknown/pubkey")).unwrap(),
657        };
658
659        let err = data.server_cert_data.verify(
660            verifier,
661            data.connection_info.time,
662            &wrong_ephemeral_key,
663            &data.server_name,
664        );
665
666        assert!(matches!(
667            err.unwrap_err(),
668            HandshakeVerificationError::InvalidServerEphemeralKey
669        ));
670    }
671
672    /// Expect to fail when no cert provided.
673    #[rstest]
674    #[case::tlsnotary(tlsnotary())]
675    #[case::appliedzkp(appliedzkp())]
676    fn test_verify_cert_chain_fail_no_cert(
677        verifier: &ServerCertVerifier,
678        #[case] mut data: ConnectionFixture,
679    ) {
680        // Empty certs
681        data.server_cert_data.certs = Vec::new();
682
683        let err = data.server_cert_data.verify(
684            verifier,
685            data.connection_info.time,
686            data.server_ephemeral_key(),
687            &data.server_name,
688        );
689
690        assert!(matches!(
691            err.unwrap_err(),
692            HandshakeVerificationError::MissingCerts
693        ));
694    }
695}