1use 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14pub enum TlsVersion {
15 V1_2,
17 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#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
35pub enum ServerName {
36 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#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
62#[serde(try_from = "String")]
63pub struct DnsName(String);
64
65impl DnsName {
66 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#[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 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#[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 = 0x0017,
117}
118
119#[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#[derive(Debug, Clone, Serialize, Deserialize)]
194pub struct ServerSignature {
195 pub alg: SignatureAlgorithm,
197 pub sig: Vec<u8>,
199}
200
201#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
203pub struct ServerEphemKey {
204 #[serde(rename = "type")]
206 pub typ: KeyType,
207 pub key: Vec<u8>,
209}
210
211impl ServerEphemKey {
212 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#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
242pub struct ConnectionInfo {
243 pub time: u64,
245 pub version: TlsVersion,
247 pub transcript_length: TranscriptLength,
249}
250
251#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
253pub struct TranscriptLength {
254 pub sent: u32,
256 pub received: u32,
258}
259
260#[derive(Debug, Clone, Serialize, Deserialize)]
262pub struct CertBindingV1_2 {
263 pub client_random: [u8; 32],
265 pub server_random: [u8; 32],
267 pub server_ephemeral_key: ServerEphemKey,
269}
270
271#[derive(Debug, Clone, Serialize, Deserialize)]
278#[serde(rename_all = "snake_case")]
279#[non_exhaustive]
280pub enum CertBinding {
281 V1_2(CertBindingV1_2),
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize)]
287pub struct HandshakeData {
288 pub certs: Vec<CertificateDer>,
290 pub sig: ServerSignature,
292 pub binding: CertBinding,
294}
295
296impl HandshakeData {
297 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 verifier
334 .verify_server_cert(end_entity, intermediates, server_name, time)
335 .map_err(HandshakeVerificationError::ServerCert)?;
336
337 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#[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 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 #[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 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 #[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 #[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 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 #[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 data.server_cert_data.certs.pop();
511 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 #[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 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 #[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 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 #[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 #[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 #[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 #[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 #[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 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}