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!(data
453 .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 #[rstest]
466 #[case::tlsnotary(tlsnotary())]
467 #[case::appliedzkp(appliedzkp())]
468 fn test_verify_cert_chain_success_ca_explicit(
469 verifier: &ServerCertVerifier,
470 #[case] data: ConnectionFixture,
471 ) {
472 assert!(data
473 .server_cert_data
474 .verify(
475 verifier,
476 data.connection_info.time,
477 data.server_ephemeral_key(),
478 &data.server_name,
479 )
480 .is_ok());
481 }
482
483 #[rstest]
485 #[case::tlsnotary(tlsnotary())]
486 #[case::appliedzkp(appliedzkp())]
487 fn test_verify_cert_chain_fail_bad_time(
488 verifier: &ServerCertVerifier,
489 #[case] data: ConnectionFixture,
490 ) {
491 let bad_time: u64 = 1571465711;
493
494 let err = data.server_cert_data.verify(
495 verifier,
496 bad_time,
497 data.server_ephemeral_key(),
498 &data.server_name,
499 );
500
501 assert!(matches!(
502 err.unwrap_err(),
503 HandshakeVerificationError::ServerCert(_)
504 ));
505 }
506
507 #[rstest]
509 #[case::tlsnotary(tlsnotary())]
510 #[case::appliedzkp(appliedzkp())]
511 fn test_verify_cert_chain_fail_no_interm_cert(
512 verifier: &ServerCertVerifier,
513 #[case] mut data: ConnectionFixture,
514 ) {
515 data.server_cert_data.certs.pop();
517 data.server_cert_data.certs.pop();
519
520 let err = data.server_cert_data.verify(
521 verifier,
522 data.connection_info.time,
523 data.server_ephemeral_key(),
524 &data.server_name,
525 );
526
527 assert!(matches!(
528 err.unwrap_err(),
529 HandshakeVerificationError::ServerCert(_)
530 ));
531 }
532
533 #[rstest]
536 #[case::tlsnotary(tlsnotary())]
537 #[case::appliedzkp(appliedzkp())]
538 fn test_verify_cert_chain_fail_no_interm_cert_with_ca_cert(
539 verifier: &ServerCertVerifier,
540 #[case] mut data: ConnectionFixture,
541 ) {
542 data.server_cert_data.certs.remove(1);
544
545 let err = data.server_cert_data.verify(
546 verifier,
547 data.connection_info.time,
548 data.server_ephemeral_key(),
549 &data.server_name,
550 );
551
552 assert!(matches!(
553 err.unwrap_err(),
554 HandshakeVerificationError::ServerCert(_)
555 ));
556 }
557
558 #[rstest]
560 #[case::tlsnotary(tlsnotary())]
561 #[case::appliedzkp(appliedzkp())]
562 fn test_verify_cert_chain_fail_bad_ee_cert(
563 verifier: &ServerCertVerifier,
564 #[case] mut data: ConnectionFixture,
565 ) {
566 let ee: &[u8] = include_bytes!("./fixtures/data/unknown/ee.der");
567
568 data.server_cert_data.certs[0] = CertificateDer(ee.to_vec());
570
571 let err = data.server_cert_data.verify(
572 verifier,
573 data.connection_info.time,
574 data.server_ephemeral_key(),
575 &data.server_name,
576 );
577
578 assert!(matches!(
579 err.unwrap_err(),
580 HandshakeVerificationError::ServerCert(_)
581 ));
582 }
583
584 #[rstest]
586 #[case::tlsnotary(tlsnotary())]
587 #[case::appliedzkp(appliedzkp())]
588 fn test_verify_sig_ke_params_fail_bad_client_random(
589 verifier: &ServerCertVerifier,
590 #[case] mut data: ConnectionFixture,
591 ) {
592 let CertBinding::V1_2(CertBindingV1_2 { client_random, .. }) =
593 &mut data.server_cert_data.binding;
594 client_random[31] = client_random[31].wrapping_add(1);
595
596 let err = data.server_cert_data.verify(
597 verifier,
598 data.connection_info.time,
599 data.server_ephemeral_key(),
600 &data.server_name,
601 );
602
603 assert!(matches!(
604 err.unwrap_err(),
605 HandshakeVerificationError::InvalidServerSignature
606 ));
607 }
608
609 #[rstest]
611 #[case::tlsnotary(tlsnotary())]
612 #[case::appliedzkp(appliedzkp())]
613 fn test_verify_sig_ke_params_fail_bad_sig(
614 verifier: &ServerCertVerifier,
615 #[case] mut data: ConnectionFixture,
616 ) {
617 data.server_cert_data.sig.sig[31] = data.server_cert_data.sig.sig[31].wrapping_add(1);
618
619 let err = data.server_cert_data.verify(
620 verifier,
621 data.connection_info.time,
622 data.server_ephemeral_key(),
623 &data.server_name,
624 );
625
626 assert!(matches!(
627 err.unwrap_err(),
628 HandshakeVerificationError::InvalidServerSignature
629 ));
630 }
631
632 #[rstest]
634 #[case::tlsnotary(tlsnotary())]
635 #[case::appliedzkp(appliedzkp())]
636 fn test_check_dns_name_present_in_cert_fail_bad_host(
637 verifier: &ServerCertVerifier,
638 #[case] data: ConnectionFixture,
639 ) {
640 let bad_name = ServerName::Dns(DnsName::try_from("badhost.com").unwrap());
641
642 let err = data.server_cert_data.verify(
643 verifier,
644 data.connection_info.time,
645 data.server_ephemeral_key(),
646 &bad_name,
647 );
648
649 assert!(matches!(
650 err.unwrap_err(),
651 HandshakeVerificationError::ServerCert(_)
652 ));
653 }
654
655 #[rstest]
657 #[case::tlsnotary(tlsnotary())]
658 #[case::appliedzkp(appliedzkp())]
659 fn test_invalid_ephemeral_key(verifier: &ServerCertVerifier, #[case] data: ConnectionFixture) {
660 let wrong_ephemeral_key = ServerEphemKey {
661 typ: KeyType::SECP256R1,
662 key: Vec::<u8>::from_hex(include_bytes!("./fixtures/data/unknown/pubkey")).unwrap(),
663 };
664
665 let err = data.server_cert_data.verify(
666 verifier,
667 data.connection_info.time,
668 &wrong_ephemeral_key,
669 &data.server_name,
670 );
671
672 assert!(matches!(
673 err.unwrap_err(),
674 HandshakeVerificationError::InvalidServerEphemeralKey
675 ));
676 }
677
678 #[rstest]
680 #[case::tlsnotary(tlsnotary())]
681 #[case::appliedzkp(appliedzkp())]
682 fn test_verify_cert_chain_fail_no_cert(
683 verifier: &ServerCertVerifier,
684 #[case] mut data: ConnectionFixture,
685 ) {
686 data.server_cert_data.certs = Vec::new();
688
689 let err = data.server_cert_data.verify(
690 verifier,
691 data.connection_info.time,
692 data.server_ephemeral_key(),
693 &data.server_name,
694 );
695
696 assert!(matches!(
697 err.unwrap_err(),
698 HandshakeVerificationError::MissingCerts
699 ));
700 }
701}