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 VerifyData {
288 pub client_finished: Vec<u8>,
290 pub server_finished: Vec<u8>,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize)]
296pub struct HandshakeData {
297 pub certs: Vec<CertificateDer>,
299 pub sig: ServerSignature,
301 pub binding: CertBinding,
303}
304
305impl HandshakeData {
306 pub fn verify(
315 &self,
316 verifier: &ServerCertVerifier,
317 time: u64,
318 server_ephemeral_key: &ServerEphemKey,
319 server_name: &ServerName,
320 ) -> Result<(), HandshakeVerificationError> {
321 #[allow(irrefutable_let_patterns)]
322 let CertBinding::V1_2(CertBindingV1_2 {
323 client_random,
324 server_random,
325 server_ephemeral_key: expected_server_ephemeral_key,
326 }) = &self.binding
327 else {
328 unreachable!("only TLS 1.2 is implemented")
329 };
330
331 if server_ephemeral_key != expected_server_ephemeral_key {
332 return Err(HandshakeVerificationError::InvalidServerEphemeralKey);
333 }
334
335 let (end_entity, intermediates) = self
336 .certs
337 .split_first()
338 .ok_or(HandshakeVerificationError::MissingCerts)?;
339
340 verifier
343 .verify_server_cert(end_entity, intermediates, server_name, time)
344 .map_err(HandshakeVerificationError::ServerCert)?;
345
346 let mut message = Vec::new();
348 message.extend_from_slice(client_random);
349 message.extend_from_slice(server_random);
350 message.extend_from_slice(&server_ephemeral_key.kx_params());
351
352 use webpki::ring as alg;
353 let sig_alg = match self.sig.alg {
354 SignatureAlgorithm::ECDSA_NISTP256_SHA256 => alg::ECDSA_P256_SHA256,
355 SignatureAlgorithm::ECDSA_NISTP256_SHA384 => alg::ECDSA_P256_SHA384,
356 SignatureAlgorithm::ECDSA_NISTP384_SHA256 => alg::ECDSA_P384_SHA256,
357 SignatureAlgorithm::ECDSA_NISTP384_SHA384 => alg::ECDSA_P384_SHA384,
358 SignatureAlgorithm::ED25519 => alg::ED25519,
359 SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA256 => alg::RSA_PKCS1_2048_8192_SHA256,
360 SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA384 => alg::RSA_PKCS1_2048_8192_SHA384,
361 SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA512 => alg::RSA_PKCS1_2048_8192_SHA512,
362 SignatureAlgorithm::RSA_PSS_2048_8192_SHA256_LEGACY_KEY => {
363 alg::RSA_PSS_2048_8192_SHA256_LEGACY_KEY
364 }
365 SignatureAlgorithm::RSA_PSS_2048_8192_SHA384_LEGACY_KEY => {
366 alg::RSA_PSS_2048_8192_SHA384_LEGACY_KEY
367 }
368 SignatureAlgorithm::RSA_PSS_2048_8192_SHA512_LEGACY_KEY => {
369 alg::RSA_PSS_2048_8192_SHA512_LEGACY_KEY
370 }
371 };
372
373 let end_entity = webpki_types::CertificateDer::from(end_entity.0.as_slice());
374 let end_entity = webpki::EndEntityCert::try_from(&end_entity)
375 .map_err(|_| HandshakeVerificationError::InvalidEndEntityCertificate)?;
376
377 end_entity
378 .verify_signature(sig_alg, &message, &self.sig.sig)
379 .map_err(|_| HandshakeVerificationError::InvalidServerSignature)?;
380
381 Ok(())
382 }
383}
384
385#[derive(Debug, thiserror::Error)]
387#[allow(missing_docs)]
388pub enum HandshakeVerificationError {
389 #[error("invalid end entity certificate")]
390 InvalidEndEntityCertificate,
391 #[error("missing server certificates")]
392 MissingCerts,
393 #[error("invalid server signature")]
394 InvalidServerSignature,
395 #[error("invalid server ephemeral key")]
396 InvalidServerEphemeralKey,
397 #[error("server certificate verification failed: {0}")]
398 ServerCert(ServerCertVerifierError),
399}
400
401#[cfg(test)]
402mod tests {
403 use super::*;
404 use crate::{fixtures::ConnectionFixture, transcript::Transcript, webpki::RootCertStore};
405
406 use hex::FromHex;
407 use rstest::*;
408 use tlsn_data_fixtures::http::{request::GET_WITH_HEADER, response::OK_JSON};
409
410 #[fixture]
411 #[once]
412 fn verifier() -> ServerCertVerifier {
413 let mut root_store = RootCertStore {
414 roots: webpki_root_certs::TLS_SERVER_ROOT_CERTS
415 .iter()
416 .map(|c| CertificateDer(c.to_vec()))
417 .collect(),
418 };
419
420 root_store.roots.push(
422 appliedzkp()
423 .server_cert_data
424 .certs
425 .last()
426 .expect("chain is valid")
427 .clone(),
428 );
429
430 ServerCertVerifier::new(&root_store).unwrap()
431 }
432
433 fn tlsnotary() -> ConnectionFixture {
434 ConnectionFixture::tlsnotary(Transcript::new(GET_WITH_HEADER, OK_JSON).length())
435 }
436
437 fn appliedzkp() -> ConnectionFixture {
438 ConnectionFixture::appliedzkp(Transcript::new(GET_WITH_HEADER, OK_JSON).length())
439 }
440
441 #[rstest]
443 #[case::tlsnotary(tlsnotary())]
444 #[case::appliedzkp(appliedzkp())]
445 fn test_verify_cert_chain_sucess_ca_implicit(
446 verifier: &ServerCertVerifier,
447 #[case] mut data: ConnectionFixture,
448 ) {
449 data.server_cert_data.certs.pop();
451
452 assert!(
453 data.server_cert_data
454 .verify(
455 verifier,
456 data.connection_info.time,
457 data.server_ephemeral_key(),
458 &data.server_name,
459 )
460 .is_ok()
461 );
462 }
463
464 #[rstest]
467 #[case::tlsnotary(tlsnotary())]
468 #[case::appliedzkp(appliedzkp())]
469 fn test_verify_cert_chain_success_ca_explicit(
470 verifier: &ServerCertVerifier,
471 #[case] data: ConnectionFixture,
472 ) {
473 assert!(
474 data.server_cert_data
475 .verify(
476 verifier,
477 data.connection_info.time,
478 data.server_ephemeral_key(),
479 &data.server_name,
480 )
481 .is_ok()
482 );
483 }
484
485 #[rstest]
487 #[case::tlsnotary(tlsnotary())]
488 #[case::appliedzkp(appliedzkp())]
489 fn test_verify_cert_chain_fail_bad_time(
490 verifier: &ServerCertVerifier,
491 #[case] data: ConnectionFixture,
492 ) {
493 let bad_time: u64 = 1571465711;
495
496 let err = data.server_cert_data.verify(
497 verifier,
498 bad_time,
499 data.server_ephemeral_key(),
500 &data.server_name,
501 );
502
503 assert!(matches!(
504 err.unwrap_err(),
505 HandshakeVerificationError::ServerCert(_)
506 ));
507 }
508
509 #[rstest]
511 #[case::tlsnotary(tlsnotary())]
512 #[case::appliedzkp(appliedzkp())]
513 fn test_verify_cert_chain_fail_no_interm_cert(
514 verifier: &ServerCertVerifier,
515 #[case] mut data: ConnectionFixture,
516 ) {
517 data.server_cert_data.certs.pop();
519 data.server_cert_data.certs.pop();
521
522 let err = data.server_cert_data.verify(
523 verifier,
524 data.connection_info.time,
525 data.server_ephemeral_key(),
526 &data.server_name,
527 );
528
529 assert!(matches!(
530 err.unwrap_err(),
531 HandshakeVerificationError::ServerCert(_)
532 ));
533 }
534
535 #[rstest]
538 #[case::tlsnotary(tlsnotary())]
539 #[case::appliedzkp(appliedzkp())]
540 fn test_verify_cert_chain_fail_no_interm_cert_with_ca_cert(
541 verifier: &ServerCertVerifier,
542 #[case] mut data: ConnectionFixture,
543 ) {
544 data.server_cert_data.certs.remove(1);
546
547 let err = data.server_cert_data.verify(
548 verifier,
549 data.connection_info.time,
550 data.server_ephemeral_key(),
551 &data.server_name,
552 );
553
554 assert!(matches!(
555 err.unwrap_err(),
556 HandshakeVerificationError::ServerCert(_)
557 ));
558 }
559
560 #[rstest]
562 #[case::tlsnotary(tlsnotary())]
563 #[case::appliedzkp(appliedzkp())]
564 fn test_verify_cert_chain_fail_bad_ee_cert(
565 verifier: &ServerCertVerifier,
566 #[case] mut data: ConnectionFixture,
567 ) {
568 let ee: &[u8] = include_bytes!("./fixtures/data/unknown/ee.der");
569
570 data.server_cert_data.certs[0] = CertificateDer(ee.to_vec());
572
573 let err = data.server_cert_data.verify(
574 verifier,
575 data.connection_info.time,
576 data.server_ephemeral_key(),
577 &data.server_name,
578 );
579
580 assert!(matches!(
581 err.unwrap_err(),
582 HandshakeVerificationError::ServerCert(_)
583 ));
584 }
585
586 #[rstest]
588 #[case::tlsnotary(tlsnotary())]
589 #[case::appliedzkp(appliedzkp())]
590 fn test_verify_sig_ke_params_fail_bad_client_random(
591 verifier: &ServerCertVerifier,
592 #[case] mut data: ConnectionFixture,
593 ) {
594 let CertBinding::V1_2(CertBindingV1_2 { client_random, .. }) =
595 &mut data.server_cert_data.binding;
596 client_random[31] = client_random[31].wrapping_add(1);
597
598 let err = data.server_cert_data.verify(
599 verifier,
600 data.connection_info.time,
601 data.server_ephemeral_key(),
602 &data.server_name,
603 );
604
605 assert!(matches!(
606 err.unwrap_err(),
607 HandshakeVerificationError::InvalidServerSignature
608 ));
609 }
610
611 #[rstest]
613 #[case::tlsnotary(tlsnotary())]
614 #[case::appliedzkp(appliedzkp())]
615 fn test_verify_sig_ke_params_fail_bad_sig(
616 verifier: &ServerCertVerifier,
617 #[case] mut data: ConnectionFixture,
618 ) {
619 data.server_cert_data.sig.sig[31] = data.server_cert_data.sig.sig[31].wrapping_add(1);
620
621 let err = data.server_cert_data.verify(
622 verifier,
623 data.connection_info.time,
624 data.server_ephemeral_key(),
625 &data.server_name,
626 );
627
628 assert!(matches!(
629 err.unwrap_err(),
630 HandshakeVerificationError::InvalidServerSignature
631 ));
632 }
633
634 #[rstest]
636 #[case::tlsnotary(tlsnotary())]
637 #[case::appliedzkp(appliedzkp())]
638 fn test_check_dns_name_present_in_cert_fail_bad_host(
639 verifier: &ServerCertVerifier,
640 #[case] data: ConnectionFixture,
641 ) {
642 let bad_name = ServerName::Dns(DnsName::try_from("badhost.com").unwrap());
643
644 let err = data.server_cert_data.verify(
645 verifier,
646 data.connection_info.time,
647 data.server_ephemeral_key(),
648 &bad_name,
649 );
650
651 assert!(matches!(
652 err.unwrap_err(),
653 HandshakeVerificationError::ServerCert(_)
654 ));
655 }
656
657 #[rstest]
659 #[case::tlsnotary(tlsnotary())]
660 #[case::appliedzkp(appliedzkp())]
661 fn test_invalid_ephemeral_key(verifier: &ServerCertVerifier, #[case] data: ConnectionFixture) {
662 let wrong_ephemeral_key = ServerEphemKey {
663 typ: KeyType::SECP256R1,
664 key: Vec::<u8>::from_hex(include_bytes!("./fixtures/data/unknown/pubkey")).unwrap(),
665 };
666
667 let err = data.server_cert_data.verify(
668 verifier,
669 data.connection_info.time,
670 &wrong_ephemeral_key,
671 &data.server_name,
672 );
673
674 assert!(matches!(
675 err.unwrap_err(),
676 HandshakeVerificationError::InvalidServerEphemeralKey
677 ));
678 }
679
680 #[rstest]
682 #[case::tlsnotary(tlsnotary())]
683 #[case::appliedzkp(appliedzkp())]
684 fn test_verify_cert_chain_fail_no_cert(
685 verifier: &ServerCertVerifier,
686 #[case] mut data: ConnectionFixture,
687 ) {
688 data.server_cert_data.certs = Vec::new();
690
691 let err = data.server_cert_data.verify(
692 verifier,
693 data.connection_info.time,
694 data.server_ephemeral_key(),
695 &data.server_name,
696 );
697
698 assert!(matches!(
699 err.unwrap_err(),
700 HandshakeVerificationError::MissingCerts
701 ));
702 }
703}