1use crate::encode::{ItemEncoder, ItemValueEncodable};
31use crate::parse::keyword::Keyword;
32use crate::parse::parser::{Section, SectionRules};
33use crate::parse::tokenize::{ItemResult, NetDocReader};
34use crate::parse2::{
35 ArgumentError, ErrorProblem, ItemValueParseable, SignaturesData, UnparsedItem, VerifyFailed,
36};
37use crate::types::descriptor::*;
38use crate::types::family::{RelayFamily, RelayFamilyIds};
39use crate::types::policy::*;
40use crate::types::version::TorVersion;
41use crate::types::{EmbeddedCert, misc::*};
42use crate::util::PeekableIterator;
43use crate::{
44 AllowAnnotations, Error, KeywordEncodable, NetdocErrorKind as EK, NormalItemArgument, Result,
45};
46
47use derive_deftly::Deftly;
48use ll::pk::ed25519::Ed25519Identity;
49use saturating_time::SaturatingTime;
50use std::fmt::Display;
51use std::sync::LazyLock;
52use std::{iter, net, time};
53use tor_basic_utils::intern::Intern;
54use tor_cert::{CertType, KeyUnknownCert};
55use tor_checkable::timed::{TimeRangeBound, TimeRangeBoundBuilder};
56use tor_checkable::{Timebound, signed, timed};
57use tor_error::{internal, into_internal};
58use tor_llcrypto as ll;
59use tor_llcrypto::pk::ed25519;
60use tor_llcrypto::pk::keymanip::convert_curve25519_to_ed25519_public;
61use tor_llcrypto::pk::rsa::RsaIdentity;
62
63use digest::Digest;
64
65pub const DOC_DIGEST_LEN: usize = 20;
67
68pub type RdDigest = [u8; DOC_DIGEST_LEN];
70
71pub type ExtraInfoDigest = [u8; DOC_DIGEST_LEN];
73
74#[non_exhaustive]
76pub struct AnnotatedRouterDesc {
77 pub ann: RouterAnnotation,
79 pub router: UncheckedRouterDesc,
81}
82
83#[derive(Default)]
85#[non_exhaustive]
86pub struct RouterAnnotation {
87 pub source: Option<String>,
89 pub downloaded: Option<time::SystemTime>,
91 pub purpose: Option<String>,
93}
94
95#[derive(Clone, Debug, Deftly, PartialEq)]
113#[derive_deftly(Constructor)]
114#[derive_deftly(NetdocParseableUnverified, NetdocEncodable)]
115#[allow(clippy::exhaustive_structs)]
116pub struct RouterDesc {
117 #[deftly(constructor)]
121 pub router: RouterDescIntroItem,
122
123 #[deftly(constructor)]
127 pub identity_ed25519: EmbeddedCert<Ed25519IdentityCert, KeyUnknownCert>,
128
129 #[deftly(netdoc(single_arg))]
133 #[deftly(constructor)]
134 pub master_key_ed25519: Ed25519Public,
135
136 pub bandwidth: Bandwidth,
140
141 pub platform: Option<RelayPlatform>,
145
146 #[deftly(netdoc(single_arg))]
150 #[deftly(constructor)]
151 pub published: Iso8601TimeSp,
152
153 #[deftly(netdoc(single_arg))]
157 pub fingerprint: Option<SpFingerprint>,
158
159 #[deftly(netdoc(single_arg, default(skip)))]
163 pub hibernating: NumericBoolean,
164
165 #[deftly(netdoc(single_arg))]
169 pub uptime: Option<u64>,
170
171 #[deftly(netdoc(single_arg))]
175 #[deftly(constructor)]
176 pub ntor_onion_key: Curve25519Public,
177
178 #[deftly(constructor)]
182 pub ntor_onion_key_crosscert: NtorOnionKeyCrossCert,
183
184 #[deftly(constructor)]
188 pub signing_key: ll::pk::rsa::PublicKey,
189
190 #[deftly(netdoc(flatten))]
199 pub ipv4_policy: AddrPolicy,
200
201 #[deftly(netdoc(default(skip)))]
205 pub ipv6_policy: Intern<PortPolicy>,
206
207 pub overload_general: Option<OverloadGeneral>,
212
213 pub contact: Option<ContactInfo>,
217
218 #[deftly(netdoc(default(skip)))]
222 pub family: Intern<RelayFamily>,
223
224 pub family_cert: RetainedOrderVec<EmbeddedCert<Ed25519FamilyCert, KeyUnknownCert>>,
228
229 pub caches_extra_info: Option<ItemPresent<CachesExtraInfoToken>>,
233
234 pub extra_info_digest: Option<ExtraInfoDigests>,
238
239 pub hidden_service_dir: Option<ItemPresent<HiddenServiceDirToken>>,
243
244 #[deftly(netdoc(single_arg))]
248 pub or_address: Vec<net::SocketAddr>,
249
250 pub tunnelled_dir_server: Option<ItemPresent<TunnelledDirServerToken>>,
254
255 pub proto: tor_protover::Protocols,
259
260 #[doc(hidden)]
261 #[deftly(netdoc(skip))]
262 pub __non_exhaustive: (),
263}
264
265#[derive(Clone, Debug, PartialEq, Deftly)]
269#[derive_deftly(NetdocParseableSignatures, NetdocEncodable)]
270#[deftly(netdoc(signatures(hashes_accu = "RouterHashAccu")))]
271#[non_exhaustive]
272pub struct RouterDescSignatures {
273 pub router_sig_ed25519: RouterSigEd25519,
279
280 pub router_signature: RouterSignature,
285}
286
287impl RouterDescUnverified {
289 #[deny(unused_variables)]
308 pub fn verify(self) -> std::result::Result<TimeRangeBound<RouterDesc>, VerifyFailed> {
309 let logic = |trbb: &mut TimeRangeBoundBuilder| -> _ {
310 let (mut body, sigs): (RouterDesc, SignaturesData<_>) = (self.body, self.sigs);
312
313 let identity_ed25519 =
316 Ed25519IdentityCert::verify(body.identity_ed25519.raw_unverified().clone())?
317 .unwrap_with(trbb);
318 let Ed25519IdentityCert {
319 id_ed25519,
320 sign_ed25519,
321 } = identity_ed25519;
322 if id_ed25519 != body.master_key_ed25519.0 {
323 return Err(VerifyFailed::Inconsistent);
324 }
325 body.identity_ed25519.set_verified(identity_ed25519);
326
327 trbb.intersect_bounds(TimeRangeBound::new((), body.published.0..));
329
330 if body
332 .fingerprint
333 .is_some_and(|fp| fp.0 != body.signing_key.to_rsa_identity())
334 {
335 return Err(VerifyFailed::Inconsistent);
336 }
337
338 let ntor_pk = convert_curve25519_to_ed25519_public(
342 &body.ntor_onion_key.0,
343 body.ntor_onion_key_crosscert.bit.0.into(),
345 )
346 .ok_or(VerifyFailed::Other)?;
347 let ntor_cc = Ed25519NtorCrossCert::verify(
348 ntor_pk.into(),
349 id_ed25519,
350 body.ntor_onion_key_crosscert.cert.raw_unverified().clone(),
351 )?
352 .unwrap_with(trbb);
353 body.ntor_onion_key_crosscert.cert.set_verified(ntor_cc);
354
355 if body.signing_key.bits() != 1024 || !body.signing_key.exponent_is(65537) {
358 return Err(VerifyFailed::Other);
359 }
360
361 for cert in body.family_cert.0.iter_mut() {
363 let cert_verified =
364 Ed25519FamilyCert::verify(id_ed25519, cert.raw_unverified().clone())?
365 .unwrap_with(trbb);
366 cert.set_verified(cert_verified);
367 }
368
369 ed25519::PublicKey::try_from(sign_ed25519)
374 .map_err(|_| VerifyFailed::Other)?
375 .verify(
376 &sigs.hashes.sha256.ok_or(VerifyFailed::VerifyFailed)?,
377 &sigs.sigs.router_sig_ed25519.0,
378 )?;
379 body.signing_key.verify(
380 sigs.hashes.sha1.ok_or(VerifyFailed::VerifyFailed)?.as_ref(),
381 sigs.sigs.router_signature.0.as_ref(),
382 )?;
383
384 Ok(body)
385 };
386
387 TimeRangeBound::build_intersect(logic)
388 }
389}
390
391#[derive(Debug, Clone, PartialEq, Eq)]
397#[non_exhaustive]
398pub enum RelayPlatform {
399 Tor(TorVersion, Option<String>),
401 Other(String),
403}
404
405#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
407#[non_exhaustive]
408pub struct CachesExtraInfoToken;
409
410#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
412#[non_exhaustive]
413pub struct HiddenServiceDirToken;
414
415#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
417#[non_exhaustive]
418pub struct TunnelledDirServerToken;
419
420impl std::str::FromStr for RelayPlatform {
421 type Err = Error;
422 fn from_str(args: &str) -> Result<Self> {
423 if args.starts_with("Tor ") {
424 let v: Vec<_> = args.splitn(4, ' ').collect();
425 match &v[..] {
426 ["Tor", ver, "on", p] => {
427 Ok(RelayPlatform::Tor(ver.parse()?, Some((*p).to_string())))
428 }
429 ["Tor", ver, ..] => Ok(RelayPlatform::Tor(ver.parse()?, None)),
430 _ => unreachable!(),
431 }
432 } else {
433 Ok(RelayPlatform::Other(args.to_string()))
434 }
435 }
436}
437
438impl Display for RelayPlatform {
439 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
440 match &self {
441 Self::Tor(v, Some(p)) => write!(f, "Tor {v} on {p}"),
442 Self::Tor(v, None) => write!(f, "Tor {v}"),
443 Self::Other(s) => write!(f, "{s}"),
444 }
445 }
446}
447
448impl ItemValueParseable for RelayPlatform {
449 fn from_unparsed(item: UnparsedItem<'_>) -> std::result::Result<Self, ErrorProblem> {
450 let mut args = item.args_copy();
451 item.check_no_object()?;
452 args.into_remaining()
453 .parse()
454 .map_err(|_| args.handle_error("platform", ArgumentError::Invalid))
455 }
456}
457
458impl ItemValueEncodable for RelayPlatform {
459 fn write_item_value_onto(
460 &self,
461 mut out: ItemEncoder,
462 ) -> std::result::Result<(), tor_error::Bug> {
463 out.args_raw_string(&self);
466 Ok(())
467 }
468}
469
470#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, strum::EnumString, strum::Display)]
474#[non_exhaustive]
475pub enum OverloadGeneralVersion {
476 #[strum(serialize = "1")]
478 V1,
479}
480
481impl NormalItemArgument for OverloadGeneralVersion {}
482
483#[derive(Debug, Clone, Copy, PartialEq, Eq, Deftly)]
487#[derive_deftly(ItemValueParseable, ItemValueEncodable)]
488#[non_exhaustive]
489pub struct OverloadGeneral {
490 pub version: OverloadGeneralVersion,
492 pub since: Iso8601TimeSp,
494}
495
496#[derive(Clone, Debug, PartialEq, Eq, Deftly)]
500#[derive_deftly(ItemValueParseable, ItemValueEncodable)]
501#[non_exhaustive]
502pub struct RouterDescIntroItem {
503 pub nickname: Nickname,
505
506 pub address: std::net::Ipv4Addr,
508
509 pub orport: u16,
511
512 pub socksport: u16,
514
515 pub dirport: u16,
517}
518
519#[derive(Clone, Debug, PartialEq, Eq, Deftly)]
523#[derive_deftly(ItemValueParseable, ItemValueEncodable)]
524#[non_exhaustive]
525pub struct ExtraInfoDigests {
526 pub sha1: FixedB16U<20>,
528
529 pub sha2: Option<FixedB64<32>>,
531}
532
533#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Deftly)]
539#[derive_deftly(ItemValueParseable, ItemValueEncodable)]
540#[non_exhaustive]
541pub struct Bandwidth {
542 pub average: u64,
544
545 pub burst: u64,
547
548 pub observed: u64,
550}
551
552#[derive(Debug, Clone, Deftly, PartialEq)]
562#[derive_deftly(ItemValueParseable, ItemValueEncodable)]
563#[deftly(netdoc(no_extra_args))]
564#[non_exhaustive]
565pub struct NtorOnionKeyCrossCert {
566 pub bit: NumericBoolean,
573
574 #[deftly(netdoc(object))]
576 pub cert: EmbeddedCert<Ed25519NtorCrossCert, KeyUnknownCert>,
577}
578
579decl_keyword! {
580 RouterKwd {
583 annotation "@source" => ANN_SOURCE,
584 annotation "@downloaded-at" => ANN_DOWNLOADED_AT,
585 annotation "@purpose" => ANN_PURPOSE,
586 "accept" | "reject" => POLICY,
587 "bandwidth" => BANDWIDTH,
588 "bridge-distribution-request" => BRIDGE_DISTRIBUTION_REQUEST,
589 "caches-extra-info" => CACHES_EXTRA_INFO,
590 "contact" => CONTACT,
591 "extra-info-digest" => EXTRA_INFO_DIGEST,
592 "family" => FAMILY,
593 "family-cert" => FAMILY_CERT,
594 "fingerprint" => FINGERPRINT,
595 "hibernating" => HIBERNATING,
596 "identity-ed25519" => IDENTITY_ED25519,
597 "ipv6-policy" => IPV6_POLICY,
598 "master-key-ed25519" => MASTER_KEY_ED25519,
599 "ntor-onion-key" => NTOR_ONION_KEY,
600 "ntor-onion-key-crosscert" => NTOR_ONION_KEY_CROSSCERT,
601 "or-address" => OR_ADDRESS,
602 "platform" => PLATFORM,
603 "proto" => PROTO,
604 "published" => PUBLISHED,
605 "router" => ROUTER,
606 "router-sig-ed25519" => ROUTER_SIG_ED25519,
607 "router-signature" => ROUTER_SIGNATURE,
608 "signing-key" => SIGNING_KEY,
609 "tunnelled_dir_server" => TUNNELLED_DIR_SERVER,
610 "uptime" => UPTIME,
611 }
615}
616
617static ROUTER_ANNOTATIONS: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
619 use RouterKwd::*;
620
621 let mut rules = SectionRules::builder();
622 rules.add(ANN_SOURCE.rule());
623 rules.add(ANN_DOWNLOADED_AT.rule().args(1..));
624 rules.add(ANN_PURPOSE.rule().args(1..));
625 rules.add(ANN_UNRECOGNIZED.rule().may_repeat().obj_optional());
626 rules.reject_unrecognized();
629 rules.build()
630});
631static ROUTER_HEADER_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
634 use RouterKwd::*;
635
636 let mut rules = SectionRules::builder();
637 rules.add(ROUTER.rule().required().args(5..));
638 rules.add(IDENTITY_ED25519.rule().required().no_args().obj_required());
639 rules.reject_unrecognized();
641 rules.build()
642});
643static ROUTER_BODY_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
646 use RouterKwd::*;
647
648 let mut rules = SectionRules::builder();
649 rules.add(MASTER_KEY_ED25519.rule().required().args(1..));
650 rules.add(PLATFORM.rule());
651 rules.add(PUBLISHED.rule().required());
652 rules.add(FINGERPRINT.rule());
653 rules.add(UPTIME.rule().args(1..));
654 rules.add(NTOR_ONION_KEY.rule().required().args(1..));
655 rules.add(
656 NTOR_ONION_KEY_CROSSCERT
657 .rule()
658 .required()
659 .args(1..=1)
660 .obj_required(),
661 );
662 rules.add(SIGNING_KEY.rule().no_args().required().obj_required());
663 rules.add(POLICY.rule().may_repeat().args(1..));
664 rules.add(IPV6_POLICY.rule().args(2..));
665 rules.add(FAMILY.rule().args(1..));
666 rules.add(FAMILY_CERT.rule().obj_required().may_repeat());
667 rules.add(CACHES_EXTRA_INFO.rule().no_args());
668 rules.add(OR_ADDRESS.rule().may_repeat().args(1..));
669 rules.add(TUNNELLED_DIR_SERVER.rule());
670 rules.add(PROTO.rule().required().args(1..));
671 rules.add(UNRECOGNIZED.rule().may_repeat().obj_optional());
672 {
674 rules.add(BANDWIDTH.rule().required().args(3..));
675 rules.add(BRIDGE_DISTRIBUTION_REQUEST.rule().args(1..));
676 rules.add(HIBERNATING.rule().args(1..));
677 rules.add(CONTACT.rule());
678 }
679 {
681 rules.add(EXTRA_INFO_DIGEST.rule().args(1..));
682 }
683 rules.build()
684});
685
686static ROUTER_SIG_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
688 use RouterKwd::*;
689
690 let mut rules = SectionRules::builder();
691 rules.add(ROUTER_SIG_ED25519.rule().required().args(1..));
692 rules.add(ROUTER_SIGNATURE.rule().required().no_args().obj_required());
693 rules.reject_unrecognized();
695 rules.build()
696});
697
698impl RouterAnnotation {
699 fn take_from_reader(reader: &mut NetDocReader<'_, RouterKwd>) -> Result<RouterAnnotation> {
701 use RouterKwd::*;
702 let mut items = reader.pause_at(|item| item.is_ok_with_non_annotation());
703
704 let body = ROUTER_ANNOTATIONS.parse(&mut items)?;
705
706 let source = body.maybe(ANN_SOURCE).args_as_str().map(String::from);
707 let purpose = body.maybe(ANN_PURPOSE).args_as_str().map(String::from);
708 let downloaded = body
709 .maybe(ANN_DOWNLOADED_AT)
710 .parse_args_as_str::<Iso8601TimeSp>()?
711 .map(|t| t.into());
712 Ok(RouterAnnotation {
713 source,
714 downloaded,
715 purpose,
716 })
717 }
718}
719
720pub type UncheckedRouterDesc = signed::SignatureGated<timed::TimeRangeBound<RouterDesc>>;
723
724const ROUTER_EXPIRY_SECONDS: u64 = 5 * 86400;
727
728const ROUTER_PRE_VALIDITY_SECONDS: u64 = 86400;
734
735impl RouterDesc {
736 pub fn rsa_identity(&self) -> RsaIdentity {
738 self.signing_key.to_rsa_identity()
739 }
740
741 pub fn ed_identity(&self) -> &Ed25519Identity {
743 &self
744 .identity_ed25519
745 .get()
746 .expect("ed25519 identity cert should be verified")
747 .id_ed25519
748 }
749
750 pub fn protocols(&self) -> &tor_protover::Protocols {
753 &self.proto
754 }
755
756 pub fn ntor_onion_key(&self) -> &ll::pk::curve25519::PublicKey {
758 &self.ntor_onion_key.0
759 }
760
761 pub fn published(&self) -> time::SystemTime {
763 self.published.0
764 }
765
766 pub fn or_ports(&self) -> impl Iterator<Item = net::SocketAddr> + '_ {
769 iter::once(net::SocketAddr::new(
770 self.router.address.into(),
771 self.router.orport,
772 ))
773 .chain(self.or_address.iter().copied())
774 }
775
776 pub fn family(&self) -> Intern<RelayFamily> {
778 Intern::clone(&self.family)
779 }
780
781 pub fn family_ids(&self) -> RelayFamilyIds {
783 RelayFamilyIds::from_iter(
784 self.family_cert
785 .iter()
786 .map(|cert| cert.get().expect("unverified family cert?"))
787 .map(|cert| cert.family_ed25519.into()),
788 )
789 }
790
791 fn parse_sections<'a>(
793 reader: &mut NetDocReader<'a, RouterKwd>,
794 ) -> Result<(
795 Section<'a, RouterKwd>,
796 Section<'a, RouterKwd>,
797 Section<'a, RouterKwd>,
798 )> {
799 use RouterKwd::*;
800
801 let header = ROUTER_HEADER_RULES.parse(
803 reader.pause_at(|item| item.is_ok_with_kwd_not_in(&[ROUTER, IDENTITY_ED25519])),
804 )?;
805
806 let body =
808 ROUTER_BODY_RULES.parse(reader.pause_at(|item| {
809 item.is_ok_with_kwd_in(&[ROUTER_SIGNATURE, ROUTER_SIG_ED25519])
810 }))?;
811
812 let sig = ROUTER_SIG_RULES.parse(reader.pause_at(|item| {
814 item.is_ok_with_annotation() || item.is_ok_with_kwd(ROUTER) || item.is_empty_line()
815 }))?;
816
817 Ok((header, body, sig))
818 }
819
820 pub fn parse(s: &str) -> Result<UncheckedRouterDesc> {
837 let mut reader = crate::parse::tokenize::NetDocReader::new(s)?;
838 let result = Self::parse_internal(&mut reader).map_err(|e| e.within(s))?;
839 reader
842 .should_be_exhausted_but_for_empty_lines()
843 .map_err(|e| e.within(s))?;
844 Ok(result)
845 }
846
847 fn parse_internal(r: &mut NetDocReader<'_, RouterKwd>) -> Result<UncheckedRouterDesc> {
853 use RouterKwd::*;
856
857 let s = r.str();
858 let (header, body, sig) = RouterDesc::parse_sections(r)?;
859
860 #[allow(clippy::unwrap_used)]
863 let start_offset = header.required(ROUTER)?.offset_in(s).unwrap();
864
865 let (ku_identity_cert, identity_cert, ed25519_signing_key) = {
879 let cert_tok = header.required(IDENTITY_ED25519)?;
880 #[allow(clippy::unwrap_used)]
883 if cert_tok.offset_in(s).unwrap() < start_offset {
884 return Err(EK::MisplacedToken
885 .with_msg("identity-ed25519")
886 .at_pos(cert_tok.pos()));
887 }
888 let ku_cert = cert_tok
889 .parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
890 .check_cert_type(tor_cert::CertType::IDENTITY_V_SIGNING)?
891 .into_unchecked();
892 let cert = ku_cert.clone().should_have_signing_key().map_err(|err| {
893 EK::BadObjectVal
894 .err()
895 .with_source(err)
896 .at_pos(cert_tok.pos())
897 })?;
898 let sk = *cert.peek_subject_key().as_ed25519().ok_or_else(|| {
899 EK::BadObjectVal
900 .at_pos(cert_tok.pos())
901 .with_msg("wrong type for signing key in cert")
902 })?;
903 let sk: ll::pk::ed25519::PublicKey = sk.try_into().map_err(|_| {
904 EK::BadObjectVal
905 .at_pos(cert_tok.pos())
906 .with_msg("invalid ed25519 signing key")
907 })?;
908 (ku_cert, cert, sk)
909 };
910
911 #[allow(unexpected_cfgs)]
913 let ed25519_identity_key = {
914 let master_key_tok = body.required(MASTER_KEY_ED25519)?;
915 let ed_id: Ed25519Public = master_key_tok.parse_arg(0)?;
916 let ed_id: ll::pk::ed25519::Ed25519Identity = ed_id.into();
917 if ed_id != *identity_cert.peek_signing_key() {
918 #[cfg(not(fuzzing))] return Err(EK::BadObjectVal
920 .at_pos(master_key_tok.pos())
921 .with_msg("master-key-ed25519 does not match key in identity-ed25519"));
922 }
923 ed_id
924 };
925
926 let rsa_identity_key: ll::pk::rsa::PublicKey = body
928 .required(SIGNING_KEY)?
929 .parse_obj::<RsaPublicParse1Helper>("RSA PUBLIC KEY")?
930 .check_len_eq(1024)?
931 .check_exponent(65537)?
932 .into();
933 let rsa_identity = rsa_identity_key.to_rsa_identity();
934
935 let ed_sig = sig.required(ROUTER_SIG_ED25519)?;
936 let rsa_sig = sig.required(ROUTER_SIGNATURE)?;
937 #[allow(clippy::unwrap_used)]
940 let ed_sig_pos = ed_sig.offset_in(s).unwrap();
941 #[allow(clippy::unwrap_used)]
942 let rsa_sig_pos = rsa_sig.offset_in(s).unwrap();
943
944 if ed_sig_pos > rsa_sig_pos {
945 return Err(EK::UnexpectedToken
946 .with_msg(ROUTER_SIG_ED25519.to_str())
947 .at_pos(ed_sig.pos()));
948 }
949
950 let ed_signature: ll::pk::ed25519::ValidatableEd25519Signature = {
952 let mut d = ll::d::Sha256::new();
953 d.update(&b"Tor router descriptor signature v1"[..]);
954 let signed_end = ed_sig_pos + b"router-sig-ed25519 ".len();
955 d.update(
956 s.get(start_offset..signed_end)
957 .ok_or(internal!("chopped utf8"))?,
958 );
959 let d = d.finalize();
960 let sig: [u8; 64] = ed_sig
961 .parse_arg::<B64>(0)?
962 .into_array()
963 .map_err(|_| EK::BadSignature.at_pos(ed_sig.pos()))?;
964 let sig = ll::pk::ed25519::Signature::from(sig);
965 ll::pk::ed25519::ValidatableEd25519Signature::new(ed25519_signing_key, sig, &d)
966 };
967
968 let rsa_signature: ll::pk::rsa::ValidatableRsaSignature = {
970 let mut d = ll::d::Sha1::new();
971 let signed_end = rsa_sig_pos + b"router-signature\n".len();
972 d.update(
973 s.get(start_offset..signed_end)
974 .ok_or(internal!("chopped utf8"))?,
975 );
976 let d = d.finalize();
977 let sig = rsa_sig.obj("SIGNATURE")?;
978 ll::pk::rsa::ValidatableRsaSignature::new(&rsa_identity_key, &sig, &d)
981 };
982
983 let (nickname, ipv4addr, orport, dirport) = {
985 let rtrline = header.required(ROUTER)?;
986 (
987 rtrline.required_arg(0)?.parse::<Nickname>().map_err(|e| {
988 EK::BadArgument
989 .with_msg(e.to_string())
990 .at_pos(rtrline.pos())
991 })?,
992 rtrline.parse_arg::<net::Ipv4Addr>(1)?,
993 rtrline.parse_arg(2)?,
994 rtrline.parse_arg(4)?,
996 )
997 };
998
999 let uptime = body.maybe(UPTIME).parse_arg(0)?;
1001
1002 let published = body
1004 .required(PUBLISHED)?
1005 .args_as_str()
1006 .parse::<Iso8601TimeSp>()?;
1007
1008 let ntor_onion_key: Curve25519Public = body.required(NTOR_ONION_KEY)?.parse_arg(0)?;
1010 let (cc_sig, cc_expiry, cc_cert) = {
1012 let cc = body.required(NTOR_ONION_KEY_CROSSCERT)?;
1013 let sign: u8 = cc.parse_arg(0)?;
1014 if sign != 0 && sign != 1 {
1015 return Err(EK::BadArgument.at_pos(cc.arg_pos(0)).with_msg("not 0 or 1"));
1016 }
1017 let ntor_as_ed: ll::pk::ed25519::PublicKey =
1018 ll::pk::keymanip::convert_curve25519_to_ed25519_public(&ntor_onion_key.0, sign)
1019 .ok_or_else(|| {
1020 EK::BadArgument
1021 .at_pos(cc.pos())
1022 .with_msg("Uncheckable crosscert")
1023 })?;
1024
1025 let cert = cc
1026 .parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
1027 .into_unchecked();
1028 let (_, sig, expiry) = Ed25519NtorCrossCert::verify_inner(
1029 ntor_as_ed.into(),
1030 ed25519_identity_key,
1031 cert.clone(),
1032 )
1033 .map_err(|_| EK::BadSignature.err())?;
1034
1035 let cert = NtorOnionKeyCrossCert {
1036 bit: NumericBoolean(sign != 0),
1037 cert: EmbeddedCert::new(Ed25519NtorCrossCert::dangerous_new_unverified(), cert),
1039 };
1040
1041 (sig, expiry, cert)
1042 };
1043
1044 let proto = {
1046 let proto_tok = body.required(PROTO)?;
1047 proto_tok
1048 .args_as_str()
1049 .parse::<tor_protover::Protocols>()
1050 .map_err(|e| EK::BadArgument.at_pos(proto_tok.pos()).with_source(e))?
1051 };
1052
1053 let is_dircache = ((dirport != 0) || body.get(TUNNELLED_DIR_SERVER).is_some())
1055 .then_some(ItemPresent::default());
1056
1057 let is_extrainfo_cache = body.get(CACHES_EXTRA_INFO).map(|_| ItemPresent::default());
1059
1060 if let Some(fp_tok) = body.get(FINGERPRINT) {
1062 let fp: RsaIdentity = fp_tok.args_as_str().parse::<SpFingerprint>()?.into();
1063 if fp != rsa_identity {
1064 return Err(EK::BadArgument
1065 .at_pos(fp_tok.pos())
1066 .with_msg("fingerprint does not match RSA identity"));
1067 }
1068 }
1069
1070 let family = {
1072 let mut family = body
1073 .maybe(FAMILY)
1074 .parse_args_as_str::<RelayFamily>()?
1075 .unwrap_or_else(RelayFamily::new);
1076 if !family.is_empty() {
1077 family.push(rsa_identity);
1083 }
1084 family.intern()
1085 };
1086
1087 let family_certs = body
1095 .slice(FAMILY_CERT)
1096 .iter()
1097 .map(|ent| {
1098 let ku = ent
1099 .parse_obj::<UnvalidatedEdCert>("FAMILY CERT")?
1100 .check_cert_type(CertType::FAMILY_V_IDENTITY)?
1101 .check_subject_key_is(identity_cert.peek_signing_key())?
1102 .into_unchecked();
1103 let unchecked = ku.clone().should_have_signing_key().map_err(|e| {
1104 EK::BadObjectVal
1105 .with_msg("missing public key")
1106 .at_pos(ent.pos())
1107 .with_source(e)
1108 })?;
1109 Ok((ku, unchecked))
1110 })
1111 .collect::<Result<Vec<_>>>()?;
1112
1113 let mut ipv6addr = Vec::with_capacity(1);
1117 for tok in body.slice(OR_ADDRESS) {
1118 if let Ok(net::SocketAddr::V6(a)) = tok.parse_arg::<net::SocketAddr>(0) {
1119 ipv6addr.push(a.into());
1120 break;
1121 }
1122 }
1124
1125 let platform = body.maybe(PLATFORM).parse_args_as_str::<RelayPlatform>()?;
1127
1128 let ipv4_policy = {
1130 let mut pol = AddrPolicy::new();
1131 for ruletok in body.slice(POLICY).iter() {
1132 let accept = match ruletok.kwd_str() {
1133 "accept" => RuleKind::Accept,
1134 "reject" => RuleKind::Reject,
1135 _ => {
1136 return Err(Error::from(internal!(
1137 "tried to parse a strange line as a policy"
1138 ))
1139 .at_pos(ruletok.pos()));
1140 }
1141 };
1142 let pat: AddrPortPattern = ruletok
1143 .args_as_str()
1144 .parse()
1145 .map_err(|e| EK::BadPolicy.at_pos(ruletok.pos()).with_source(e))?;
1146 pol.push(accept, pat);
1147 }
1148 pol
1149 };
1150
1151 let ipv6_policy = match body.get(IPV6_POLICY) {
1153 Some(p) => p
1154 .args_as_str()
1155 .parse()
1156 .map_err(|e| EK::BadPolicy.at_pos(p.pos()).with_source(e))?,
1157 #[allow(clippy::unwrap_used)]
1159 None => "reject 1-65535".parse::<PortPolicy>().unwrap(),
1160 };
1161
1162 let (identity_cert, identity_sig) = identity_cert.dangerously_split().map_err(|err| {
1164 EK::BadObjectVal
1165 .with_msg("missing public key")
1166 .with_source(err)
1167 })?;
1168 let mut signatures: Vec<Box<dyn ll::pk::ValidatableSignature>> = vec![
1169 Box::new(rsa_signature),
1170 Box::new(ed_signature),
1171 Box::new(identity_sig),
1172 Box::new(cc_sig),
1173 ];
1174
1175 let identity_cert = identity_cert.dangerously_assume_timely();
1176 let mut expirations = vec![
1177 published
1178 .0
1179 .saturating_add(time::Duration::new(ROUTER_EXPIRY_SECONDS, 0)),
1180 identity_cert.expiry(),
1181 cc_expiry,
1182 ];
1183
1184 let mut embedded_family_certs = Vec::with_capacity(family_certs.len());
1190 for (ku_cert, cert) in family_certs {
1191 let family_ed25519 = *cert.peek_signing_key();
1192 let (inner, sig) = cert.dangerously_split().map_err(into_internal!(
1193 "Missing a public key that was previously there."
1194 ))?;
1195 let embedded_cert = EmbeddedCert::new(Ed25519FamilyCert { family_ed25519 }, ku_cert);
1196 signatures.push(Box::new(sig));
1197 expirations.push(inner.dangerously_assume_timely().expiry());
1198 embedded_family_certs.push(embedded_cert);
1199 }
1200
1201 #[allow(clippy::unwrap_used)]
1203 let expiry = *expirations.iter().min().unwrap();
1204
1205 let start_time = published
1206 .0
1207 .saturating_sub(time::Duration::new(ROUTER_PRE_VALIDITY_SECONDS, 0));
1208
1209 let desc = RouterDesc {
1210 router: RouterDescIntroItem {
1211 nickname,
1212 address: ipv4addr,
1213 orport,
1214 socksport: 0,
1215 dirport,
1216 },
1217 identity_ed25519: EmbeddedCert::new(
1218 Ed25519IdentityCert {
1219 id_ed25519: ed25519_identity_key,
1220 sign_ed25519: ed25519_signing_key.into(),
1221 },
1222 ku_identity_cert,
1223 ),
1224 master_key_ed25519: ed25519_identity_key.into(),
1225 bandwidth: Default::default(),
1226 platform,
1227 published,
1228 fingerprint: Some(rsa_identity.into()),
1229 hibernating: Default::default(),
1230 uptime,
1231 ntor_onion_key,
1232 ntor_onion_key_crosscert: cc_cert,
1233 signing_key: rsa_identity_key,
1234 ipv4_policy,
1235 ipv6_policy: ipv6_policy.intern(),
1236 overload_general: Default::default(),
1237 contact: Default::default(),
1238 family,
1239 family_cert: embedded_family_certs.into(),
1240 caches_extra_info: is_extrainfo_cache,
1241 extra_info_digest: Default::default(),
1242 hidden_service_dir: Default::default(),
1243 or_address: ipv6addr,
1244 tunnelled_dir_server: is_dircache,
1245 proto,
1246 __non_exhaustive: (),
1247 };
1248
1249 let time_gated = timed::TimeRangeBound::new(desc, start_time..expiry);
1250 let sig_gated = signed::SignatureGated::new(time_gated, signatures);
1251
1252 Ok(sig_gated)
1253 }
1254}
1255
1256pub struct RouterReader<'a> {
1262 annotated: bool,
1264 reader: NetDocReader<'a, RouterKwd>,
1266}
1267
1268fn advance_to_next_routerdesc(reader: &mut NetDocReader<'_, RouterKwd>, annotated: bool) {
1273 use RouterKwd::*;
1274 loop {
1275 let item = reader.peek();
1276 match item {
1277 Some(Ok(t)) => {
1278 let kwd = t.kwd();
1279 if (annotated && kwd.is_annotation()) || kwd == ROUTER {
1280 return;
1281 }
1282 }
1283 Some(Err(_)) => {
1284 }
1286 None => {
1287 return;
1288 }
1289 }
1290 let _ = reader.next();
1291 }
1292}
1293
1294impl<'a> RouterReader<'a> {
1295 pub fn new(s: &'a str, allow: &AllowAnnotations) -> Result<Self> {
1297 let reader = NetDocReader::new(s)?;
1298 let annotated = allow == &AllowAnnotations::AnnotationsAllowed;
1299 Ok(RouterReader { annotated, reader })
1300 }
1301
1302 fn take_annotation(&mut self) -> Result<RouterAnnotation> {
1304 if self.annotated {
1305 RouterAnnotation::take_from_reader(&mut self.reader)
1306 } else {
1307 Ok(RouterAnnotation::default())
1308 }
1309 }
1310
1311 fn take_annotated_routerdesc_raw(&mut self) -> Result<AnnotatedRouterDesc> {
1315 let ann = self.take_annotation()?;
1316 let router = RouterDesc::parse_internal(&mut self.reader)?;
1317 Ok(AnnotatedRouterDesc { ann, router })
1318 }
1319
1320 fn take_annotated_routerdesc(&mut self) -> Result<AnnotatedRouterDesc> {
1324 let pos_orig = self.reader.pos();
1325 let result = self.take_annotated_routerdesc_raw();
1326 if result.is_err() {
1327 if self.reader.pos() == pos_orig {
1328 let _ = self.reader.next();
1336 }
1337 advance_to_next_routerdesc(&mut self.reader, self.annotated);
1338 }
1339 result
1340 }
1341}
1342
1343impl<'a> Iterator for RouterReader<'a> {
1344 type Item = Result<AnnotatedRouterDesc>;
1345 fn next(&mut self) -> Option<Self::Item> {
1346 self.reader.peek()?;
1348
1349 Some(
1350 self.take_annotated_routerdesc()
1351 .map_err(|e| e.within(self.reader.str())),
1352 )
1353 }
1354}
1355
1356#[cfg(test)]
1357mod test {
1358 #![allow(clippy::bool_assert_comparison)]
1360 #![allow(clippy::clone_on_copy)]
1361 #![allow(clippy::dbg_macro)]
1362 #![allow(clippy::mixed_attributes_style)]
1363 #![allow(clippy::print_stderr)]
1364 #![allow(clippy::print_stdout)]
1365 #![allow(clippy::single_char_pattern)]
1366 #![allow(clippy::unwrap_used)]
1367 #![allow(clippy::unchecked_time_subtraction)]
1368 #![allow(clippy::useless_vec)]
1369 #![allow(clippy::needless_pass_by_value)]
1370 #![allow(clippy::string_slice)] use std::{net::Ipv4Addr, str::FromStr, time::Duration};
1373
1374 use crate::{
1375 encode::{NetdocEncodable, NetdocEncoder},
1376 parse2::{self, NetdocParseableUnverified, ParseInput},
1377 };
1378 use tor_basic_utils::test_rng::testing_rng;
1379 use tor_checkable::TimeValidityError;
1380 use tor_llcrypto::pk::{curve25519, ed25519::Ed25519PublicKey, rsa};
1381
1382 use super::*;
1383 const TESTDATA: &str = include_str!("../../testdata/routerdesc1.txt");
1384 const TESTDATA2: &str = include_str!("../../testdata/routerdesc2.txt");
1385 const TESTDATA3: &str = include_str!("../../testdata/routerdesc3.txt");
1387
1388 fn read_bad(fname: &str) -> String {
1389 use std::fs;
1390 use std::path::PathBuf;
1391 let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
1392 path.push("testdata");
1393 path.push("bad-routerdesc");
1394 path.push(fname);
1395
1396 fs::read_to_string(path).unwrap()
1397 }
1398
1399 #[test]
1400 fn parse_arbitrary() -> Result<()> {
1401 use std::str::FromStr;
1402 use tor_checkable::{SelfSigned, TimeBound};
1403 let rd = RouterDesc::parse(TESTDATA)?
1404 .check_signature()?
1405 .dangerously_assume_timely();
1406
1407 assert_eq!(rd.router.nickname.as_str(), "Akka");
1408 assert_eq!(rd.router.orport, 443);
1409 assert_eq!(rd.router.dirport, 0);
1410 assert_eq!(rd.uptime, Some(1036923));
1411 assert_eq!(
1412 rd.family.as_ref(),
1413 &RelayFamily::from_str(
1414 "$303509ab910ef207b7438c27435c4a2fd579f1b1 \
1415 $56927e61b51e6f363fb55498150a6ddfcf7077f2"
1416 )
1417 .unwrap()
1418 );
1419
1420 assert_eq!(
1421 rd.rsa_identity().to_string(),
1422 "$56927e61b51e6f363fb55498150a6ddfcf7077f2"
1423 );
1424 assert_eq!(
1425 rd.ed_identity().to_string(),
1426 "CVTjf1oeaL616hH+1+UvYZ8OgkwF3z7UMITvJzm5r7A"
1427 );
1428 assert_eq!(
1429 rd.protocols().to_string(),
1430 "Cons=1-2 Desc=1-2 DirCache=2 FlowCtrl=1-2 HSDir=2 \
1431 HSIntro=4-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 \
1432 Padding=2 Relay=1-4"
1433 );
1434
1435 assert_eq!(
1436 hex::encode(rd.ntor_onion_key().to_bytes()),
1437 "329b3b52991613392e35d1a821dd6753e1210458ecc3337f7b7d39bfcf5da273"
1438 );
1439 assert_eq!(
1440 rd.published(),
1441 humantime::parse_rfc3339("2022-11-14T19:58:52Z").unwrap()
1442 );
1443 assert_eq!(
1444 rd.or_ports().collect::<Vec<_>>(),
1445 vec![
1446 "95.216.33.58:443".parse().unwrap(),
1447 "[2a01:4f9:2a:2145::2]:443".parse().unwrap(),
1448 ]
1449 );
1450
1451 Ok(())
1452 }
1453
1454 #[test]
1455 fn parse_no_tap_key() -> Result<()> {
1456 use tor_checkable::{SelfSigned, TimeBound};
1457 let _rd = RouterDesc::parse(TESTDATA2)?
1458 .check_signature()?
1459 .dangerously_assume_timely();
1460
1461 Ok(())
1462 }
1463
1464 #[test]
1465 fn test_bad() {
1466 use crate::Pos;
1467 use crate::types::policy::PolicyError;
1468 fn check(fname: &str, e: &Error) {
1469 let text = read_bad(fname);
1470 let rd = RouterDesc::parse(&text);
1471 assert!(rd.is_err());
1472 assert_eq!(&rd.err().unwrap(), e);
1473 }
1474
1475 check(
1476 "bad-sig-order",
1477 &EK::UnexpectedToken
1478 .with_msg("router-sig-ed25519")
1479 .at_pos(Pos::from_line(50, 1)),
1480 );
1481 check(
1482 "bad-start1",
1483 &EK::MisplacedToken
1484 .with_msg("identity-ed25519")
1485 .at_pos(Pos::from_line(1, 1)),
1486 );
1487 check("bad-start2", &EK::MissingToken.with_msg("identity-ed25519"));
1488 check(
1489 "mismatched-fp",
1490 &EK::BadArgument
1491 .at_pos(Pos::from_line(12, 1))
1492 .with_msg("fingerprint does not match RSA identity"),
1493 );
1494 check("no-ed-sk", &EK::MissingToken.with_msg("identity-ed25519"));
1495
1496 check(
1497 "bad-cc-sign",
1498 &EK::BadArgument
1499 .at_pos(Pos::from_line(34, 26))
1500 .with_msg("not 0 or 1"),
1501 );
1502 check(
1503 "bad-ipv6policy",
1504 &EK::BadPolicy
1505 .at_pos(Pos::from_line(43, 1))
1506 .with_source(PolicyError::InvalidPolicy),
1507 );
1508 check(
1509 "no-ed-id-key-in-cert",
1510 &EK::BadObjectVal
1511 .at_pos(Pos::from_line(2, 1))
1512 .with_source(tor_cert::CertError::MissingPubKey),
1513 );
1514 check(
1515 "non-ed-sk-in-cert",
1516 &EK::BadObjectVal
1517 .at_pos(Pos::from_line(2, 1))
1518 .with_msg("wrong type for signing key in cert"),
1519 );
1520 check(
1521 "bad-ed-sk-in-cert",
1522 &EK::BadObjectVal
1523 .at_pos(Pos::from_line(2, 1))
1524 .with_msg("invalid ed25519 signing key"),
1525 );
1526 check(
1527 "mismatched-ed-sk-in-cert",
1528 &EK::BadObjectVal
1529 .at_pos(Pos::from_line(8, 1))
1530 .with_msg("master-key-ed25519 does not match key in identity-ed25519"),
1531 );
1532 }
1533
1534 #[test]
1535 fn parse_multiple_annotated() {
1536 use crate::AllowAnnotations;
1537 let mut s = read_bad("bad-cc-sign");
1538 s += "\
1539@uploaded-at 2020-09-26 18:15:41
1540@source \"127.0.0.1\"
1541";
1542 s += TESTDATA;
1543 s += "\
1544@uploaded-at 2020-09-26 18:15:41
1545@source \"127.0.0.1\"
1546";
1547 s += &read_bad("mismatched-fp");
1548
1549 let rd = RouterReader::new(&s, &AllowAnnotations::AnnotationsAllowed).unwrap();
1550 let v: Vec<_> = rd.collect();
1551 assert!(v[0].is_err());
1552 assert!(v[1].is_ok());
1553 assert_eq!(
1554 v[1].as_ref().unwrap().ann.source,
1555 Some("\"127.0.0.1\"".to_string())
1556 );
1557 assert!(v[2].is_err());
1558 }
1559
1560 #[test]
1561 fn test_platform() {
1562 let tests = [
1563 (
1565 "Tor 0.4.4.4-alpha on a flying bison",
1566 RelayPlatform::Tor(
1567 "0.4.4.4-alpha".parse().unwrap(),
1568 Some("a flying bison".to_string()),
1569 ),
1570 ),
1571 (
1573 "Tor 0.4.4.4-alpha on",
1574 RelayPlatform::Tor("0.4.4.4-alpha".parse().unwrap(), None),
1575 ),
1576 (
1577 "Tor 0.4.4.4-alpha ",
1578 RelayPlatform::Tor("0.4.4.4-alpha".parse().unwrap(), None),
1579 ),
1580 (
1581 "Tor 0.4.4.4-alpha",
1582 RelayPlatform::Tor("0.4.4.4-alpha".parse().unwrap(), None),
1583 ),
1584 ("arti 0.0.0", RelayPlatform::Other("arti 0.0.0".to_string())),
1586 ];
1587 for (input, output) in tests {
1588 assert_eq!(input.parse::<RelayPlatform>().unwrap(), output);
1589
1590 let input = input.strip_suffix(" on").unwrap_or(input);
1594 let input = input.trim();
1595 assert_eq!(output.to_string(), input);
1596 }
1597 }
1598
1599 #[test]
1600 fn test_family_ids() -> Result<()> {
1601 use tor_checkable::{SelfSigned, TimeBound};
1602 let rd = RouterDesc::parse(TESTDATA3)?
1603 .check_signature()?
1604 .dangerously_assume_timely();
1605
1606 assert_eq!(
1607 rd.family_ids().as_ref(),
1608 &[
1609 "ed25519:7sToQRuge1bU2hS0CG0ViMndc4m82JhO4B4kdrQey80"
1610 .parse()
1611 .unwrap(),
1612 "ed25519:szHUS3ItRd9uk85b1UVnOZx1gg4B0266jCpbuIMNjcM"
1613 .parse()
1614 .unwrap(),
1615 ]
1616 );
1617
1618 Ok(())
1619 }
1620
1621 #[test]
1625 fn test_parse2_simple() {
1626 let input = ParseInput::new(
1627 include_str!("../../testdata2/cached-descriptors.new"),
1628 "cached-descriptors.new",
1629 );
1630 let rd = parse2::parse_netdoc_multiple::<RouterDescUnverified>(&input)
1631 .unwrap()
1632 .into_iter()
1633 .map(|rd| {
1634 rd.clone().verify().unwrap();
1635 rd.unwrap_unverified()
1636 })
1637 .map(|(body, sig)| (body, sig.sigs))
1638 .collect::<Vec<(RouterDesc, RouterDescSignatures)>>();
1639 assert_eq!(rd.len(), 20);
1640 assert_eq!(
1641 rd[0].0.router,
1642 RouterDescIntroItem {
1643 nickname: "test002a".parse().unwrap(),
1644 address: net::Ipv4Addr::LOCALHOST,
1645 orport: 5102,
1646 socksport: 0,
1647 dirport: 7102
1648 }
1649 );
1650 assert_eq!(
1651 rd[0].0.fingerprint.unwrap(),
1652 "257D 06F0 360B B224 6388 724F 109E C089 5A1D 41FB"
1653 .parse()
1654 .unwrap()
1655 );
1656
1657 let mut out = NetdocEncoder::new();
1666 for (body, sig) in &rd {
1667 body.encode_unsigned(&mut out).unwrap();
1668 sig.encode_unsigned(&mut out).unwrap();
1669 }
1670 let out = out.finish().unwrap();
1671 let input2 = ParseInput::new(out.as_str(), "<router descriptor encoding>");
1672 let rd2 = parse2::parse_netdoc_multiple::<RouterDescUnverified>(&input2)
1673 .unwrap()
1674 .into_iter()
1675 .map(|rd| rd.unwrap_unverified())
1676 .map(|(body, sig)| (body, sig.sigs))
1677 .collect::<Vec<(RouterDesc, _)>>();
1678 assert_eq!(rd, rd2);
1679 }
1680
1681 fn rd_encode_sign(doc: &RouterDesc, rsa: &rsa::KeyPair, ed25519: &ed25519::Keypair) -> String {
1684 #[derive(Deftly)]
1686 #[derive_deftly(NetdocEncodable)]
1687 struct Ed25519Writer {
1688 router_sig_ed25519: RouterSigEd25519,
1689 }
1690
1691 #[derive(Deftly)]
1693 #[derive_deftly(NetdocEncodable)]
1694 struct RsaWriter {
1695 router_signature: RouterSignature,
1696 }
1697
1698 let mut out = NetdocEncoder::new();
1700 doc.encode_unsigned(&mut out).unwrap();
1701 Ed25519Writer {
1702 router_sig_ed25519: RouterSigEd25519::new_sign_netdoc(
1703 ed25519,
1704 &out,
1705 "router-sig-ed25519",
1706 )
1707 .unwrap(),
1708 }
1709 .encode_unsigned(&mut out)
1710 .unwrap();
1711
1712 RsaWriter {
1714 router_signature: RouterSignature(
1715 RsaSha1Signature::new_sign_netdoc(rsa, &out, "router-signature")
1716 .unwrap()
1717 .signature,
1718 ),
1719 }
1720 .encode_unsigned(&mut out)
1721 .unwrap();
1722
1723 out.finish().unwrap()
1724 }
1725
1726 #[test]
1728 fn test_verify() {
1729 let rng = &mut testing_rng();
1731 let rsa_id = rsa::KeyPair::generate(rng).unwrap();
1732 let ed25519_id = ed25519::Keypair::generate(rng);
1733 let ed25519_sign = ed25519::Keypair::generate(rng);
1734 let curve25519_ntor = curve25519::StaticSecret::random_from_rng(&mut *rng);
1735 let curve25519_ntor = curve25519::StaticKeypair {
1736 secret: curve25519_ntor.clone(),
1737 public: (&curve25519_ntor).into(),
1738 };
1739 let ed25519_ntor = tor_llcrypto::pk::keymanip::convert_curve25519_to_ed25519_private(
1740 &curve25519_ntor.secret,
1741 )
1742 .unwrap();
1743
1744 let too_early = Iso8601TimeSp::from_str("2026-05-01 03:00:00").unwrap().0;
1746 let published = Iso8601TimeSp::from_str("2026-06-01 03:00:00").unwrap().0;
1747 let now = Iso8601TimeSp::from_str("2026-06-10 15:30:12").unwrap().0;
1748 let expiration = Iso8601TimeSp::from_str("2026-06-20 03:00:00").unwrap().0;
1749 let expired = expiration + Duration::from_secs(60 * 60 * 24);
1750
1751 let mut rd = RouterDesc {
1754 router: RouterDescIntroItem {
1755 nickname: "foo".parse().unwrap(),
1756 address: Ipv4Addr::LOCALHOST,
1757 orport: 9000,
1758 socksport: 0,
1759 dirport: 0,
1760 },
1761 identity_ed25519: Ed25519IdentityCert::new_signed(
1762 &ed25519_id,
1763 Ed25519Identity::from(ed25519_sign.public_key()),
1764 expiration,
1765 )
1766 .unwrap(),
1767 master_key_ed25519: Ed25519Identity::from(ed25519_id.public_key()).into(),
1768 bandwidth: Bandwidth {
1769 average: 0,
1770 burst: 0,
1771 observed: 0,
1772 },
1773 platform: None,
1774 published: published.into(),
1775 fingerprint: Some(rsa_id.to_public_key().to_rsa_identity().into()),
1776 hibernating: NumericBoolean(false),
1777 uptime: None,
1778 ntor_onion_key: Curve25519Public(curve25519_ntor.public),
1779 ntor_onion_key_crosscert: NtorOnionKeyCrossCert {
1780 bit: NumericBoolean(ed25519_ntor.1 == 1),
1781 cert: Ed25519NtorCrossCert::new_signed(
1782 &ed25519_ntor.0,
1783 ed25519_id.public_key().into(),
1784 expiration,
1785 )
1786 .unwrap(),
1787 },
1788 signing_key: rsa_id.to_public_key(),
1789 ipv4_policy: AddrPolicy::default(),
1790 ipv6_policy: Default::default(),
1791 overload_general: None,
1792 contact: None,
1793 family: Default::default(),
1794 family_cert: Default::default(),
1795 caches_extra_info: Some(Default::default()),
1796 extra_info_digest: None,
1797 hidden_service_dir: Some(Default::default()),
1798 or_address: Default::default(),
1799 tunnelled_dir_server: Some(Default::default()),
1800 proto: tor_protover::Protocols::new(),
1801 __non_exhaustive: (),
1802 };
1803 let rd_original = rd.clone();
1804
1805 let verify =
1806 |rd: &RouterDesc| -> std::result::Result<TimeRangeBound<RouterDesc>, VerifyFailed> {
1807 let encoded = rd_encode_sign(rd, &rsa_id, &ed25519_sign);
1808 let decoded = parse2::parse_netdoc::<RouterDescUnverified>(&ParseInput::new(
1809 &encoded,
1810 "<test_invalid>",
1811 ))
1812 .unwrap();
1813 decoded.verify()
1814 };
1815
1816 assert_eq!(
1818 verify(&rd).unwrap().if_valid_at(&too_early).unwrap_err(),
1819 TimeValidityError::NotYetValid(published.duration_since(too_early).unwrap())
1820 );
1821 verify(&rd).unwrap().if_valid_at(&published).unwrap();
1822 verify(&rd).unwrap().if_valid_at(&now).unwrap();
1824 verify(&rd).unwrap().if_valid_at(&expiration).unwrap();
1825 assert_eq!(
1826 verify(&rd).unwrap().if_valid_at(&expired).unwrap_err(),
1827 TimeValidityError::Expired(expired.duration_since(expiration).unwrap())
1828 );
1829
1830 rd.master_key_ed25519 = Ed25519Public(Ed25519Identity::from([0x12; 32]));
1832 assert_eq!(verify(&rd).unwrap_err(), VerifyFailed::Inconsistent);
1833 rd = rd_original.clone();
1834
1835 rd.published = expired.into();
1837 assert_eq!(
1838 verify(&rd).unwrap().if_valid_at(&now).unwrap_err(),
1839 TimeValidityError::NotYetValid(expired.duration_since(now).unwrap())
1840 );
1841 rd = rd_original.clone();
1842
1843 let other_rsa_key = rsa::KeyPair::generate(rng).unwrap();
1845 rd.fingerprint = Some(other_rsa_key.to_public_key().to_rsa_identity().into());
1846 assert_eq!(verify(&rd).unwrap_err(), VerifyFailed::Inconsistent);
1847 rd.signing_key = other_rsa_key.to_public_key();
1850 assert_eq!(verify(&rd).unwrap_err(), VerifyFailed::VerifyFailed);
1851 rd.signing_key = rd_original.signing_key.clone();
1853 rd.fingerprint = None;
1854 verify(&rd).unwrap().if_valid_at(&now).unwrap();
1855 rd = rd_original.clone();
1856
1857 let other_curve25519 = curve25519::StaticSecret::random_from_rng(&mut *rng);
1861 let other_curve25519 = (&other_curve25519).into();
1862 rd.ntor_onion_key = Curve25519Public(other_curve25519);
1863 assert_eq!(verify(&rd).unwrap_err(), VerifyFailed::VerifyFailed);
1864 rd = rd_original.clone();
1865
1866 let different_ed25519_sign = ed25519::Keypair::generate(rng);
1875 rd.identity_ed25519 = Ed25519IdentityCert::new_signed(
1876 &ed25519_id,
1877 Ed25519Identity::from(different_ed25519_sign.public_key()),
1878 expiration,
1879 )
1880 .unwrap();
1881 assert_eq!(verify(&rd).unwrap_err(), VerifyFailed::VerifyFailed);
1882 rd = rd_original.clone();
1883
1884 let different_rsa_id = rsa::KeyPair::generate(rng).unwrap();
1887 rd.signing_key = different_rsa_id.to_public_key();
1888 rd.fingerprint = None;
1889 assert_eq!(verify(&rd).unwrap_err(), VerifyFailed::VerifyFailed);
1890 }
1891
1892 #[test]
1893 fn ntor_onion_key_cross_cert() {
1894 #[derive(Debug, Deftly)]
1896 #[derive_deftly(NetdocParseable)]
1897 #[allow(unused)]
1898 struct TestDoc {
1899 router: RouterDescIntroItem,
1901
1902 #[deftly(netdoc(single_arg))]
1904 published: Iso8601TimeSp,
1905
1906 #[deftly(netdoc(single_arg))]
1908 master_key_ed25519: Ed25519Public,
1909
1910 #[deftly(netdoc(single_arg))]
1912 ntor_onion_key: Curve25519Public,
1913
1914 ntor_onion_key_crosscert: NtorOnionKeyCrossCert,
1916 }
1917
1918 impl TestDoc {
1919 fn verify(&self, now: time::SystemTime) {
1921 Ed25519NtorCrossCert::verify(
1922 tor_llcrypto::pk::keymanip::convert_curve25519_to_ed25519_public(
1924 &self.ntor_onion_key.0,
1925 self.ntor_onion_key_crosscert.bit.0.into(),
1926 )
1927 .unwrap()
1928 .into(),
1929 self.master_key_ed25519.0,
1930 self.ntor_onion_key_crosscert.cert.raw_unverified().clone(),
1931 )
1932 .unwrap()
1933 .check_valid_at(&now)
1934 .unwrap();
1935 }
1936 }
1937
1938 let descs = include_str!("../../testdata2/cached-descriptors.new");
1939 let descs = parse2::parse_netdoc_multiple::<TestDoc>(&ParseInput::new(
1940 descs,
1941 "cached-descriptors.new",
1942 ))
1943 .unwrap();
1944
1945 let negative_rd = descs
1947 .iter()
1948 .find(|rd| rd.ntor_onion_key_crosscert.bit.0)
1949 .unwrap();
1950 let positive_rd = descs
1951 .iter()
1952 .find(|rd| !rd.ntor_onion_key_crosscert.bit.0)
1953 .unwrap();
1954
1955 negative_rd.verify(negative_rd.published.0);
1956 positive_rd.verify(positive_rd.published.0);
1957 }
1958}