1use crate::encode::{ItemEncoder, ItemValueEncodable};
36use crate::parse::keyword::Keyword;
37use crate::parse::parser::{Section, SectionRules};
38use crate::parse::tokenize::{ItemResult, NetDocReader};
39use crate::parse2::{
40 ArgumentError, ErrorProblem, ItemValueParseable, SignaturesData, UnparsedItem, VerifyFailed,
41};
42use crate::types::family::{RelayFamily, RelayFamilyIds};
43use crate::types::policy::*;
44use crate::types::routerdesc::*;
45use crate::types::version::TorVersion;
46use crate::types::{EmbeddedCert, misc::*};
47use crate::util::PeekableIterator;
48use crate::{AllowAnnotations, Error, KeywordEncodable, NetdocErrorKind as EK, Result};
49
50use derive_deftly::Deftly;
51use ll::pk::ed25519::Ed25519Identity;
52use saturating_time::SaturatingTime;
53use std::fmt::Display;
54use std::sync::LazyLock;
55use std::{iter, net, time};
56use tor_basic_utils::intern::Intern;
57use tor_cert::{CertType, KeyUnknownCert};
58use tor_checkable::timed::TimeRangeBound;
59use tor_checkable::{Timebound, signed, timed};
60use tor_error::{internal, into_internal};
61use tor_llcrypto as ll;
62use tor_llcrypto::pk::ed25519;
63use tor_llcrypto::pk::keymanip::convert_curve25519_to_ed25519_public;
64use tor_llcrypto::pk::rsa::RsaIdentity;
65
66use digest::Digest;
67
68pub const DOC_DIGEST_LEN: usize = 20;
70
71pub type RdDigest = [u8; DOC_DIGEST_LEN];
73
74pub type ExtraInfoDigest = [u8; DOC_DIGEST_LEN];
76
77#[non_exhaustive]
79pub struct AnnotatedRouterDesc {
80 pub ann: RouterAnnotation,
82 pub router: UncheckedRouterDesc,
84}
85
86#[derive(Default)]
88#[non_exhaustive]
89pub struct RouterAnnotation {
90 pub source: Option<String>,
92 pub downloaded: Option<time::SystemTime>,
94 pub purpose: Option<String>,
96}
97
98#[derive(Clone, Debug, Deftly, PartialEq)]
116#[derive_deftly(NetdocParseableUnverified, NetdocEncodable)]
117#[non_exhaustive]
118pub struct RouterDesc {
119 pub router: RouterDescIntroItem,
123
124 pub identity_ed25519: EmbeddedCert<Ed25519IdentityCert, KeyUnknownCert>,
128
129 #[deftly(netdoc(single_arg))]
134 pub master_key_ed25519: Ed25519Public,
135
136 pub bandwidth: Bandwidth,
141
142 pub platform: Option<RelayPlatform>,
147
148 #[deftly(netdoc(single_arg))]
153 pub published: Iso8601TimeSp,
154
155 #[deftly(netdoc(single_arg))]
160 pub fingerprint: Option<SpFingerprint>,
161
162 #[deftly(netdoc(single_arg, default(skip)))]
166 pub hibernating: NumericBoolean,
167
168 #[deftly(netdoc(single_arg))]
173 pub uptime: Option<u64>,
174
175 #[deftly(netdoc(single_arg))]
180 pub ntor_onion_key: Curve25519Public,
181
182 pub ntor_onion_key_crosscert: NtorOnionKeyCrossCert,
186
187 pub signing_key: ll::pk::rsa::PublicKey,
191
192 #[deftly(netdoc(flatten))]
203 pub ipv4_policy: AddrPolicy,
204
205 #[deftly(netdoc(default(skip)))]
210 pub ipv6_policy: Intern<PortPolicy>,
211
212 pub overload_general: Option<OverloadGeneral>,
218
219 pub contact: Option<ContactInfo>,
223
224 #[deftly(netdoc(default(skip)))]
230 pub family: Intern<RelayFamily>,
231
232 pub family_cert: RetainedOrderVec<EmbeddedCert<Ed25519FamilyCert, KeyUnknownCert>>,
237
238 pub caches_extra_info: Option<ItemPresent<CachesExtraInfoToken>>,
244
245 pub extra_info_digest: Option<ExtraInfoDigests>,
249
250 pub hidden_service_dir: Option<ItemPresent<HiddenServiceDirToken>>,
254
255 #[deftly(netdoc(single_arg))]
259 pub or_address: Vec<net::SocketAddr>,
260
261 pub tunnelled_dir_server: Option<ItemPresent<TunnelledDirServerToken>>,
267
268 pub proto: tor_protover::Protocols,
273}
274
275#[derive(Clone, Debug, PartialEq, Deftly)]
279#[derive_deftly(NetdocParseableSignatures, NetdocEncodable)]
280#[deftly(netdoc(signatures(hashes_accu = "RouterHashAccu")))]
281#[non_exhaustive]
282pub struct RouterDescSignatures {
283 pub router_sig_ed25519: RouterSigEd25519,
289
290 pub router_signature: RouterSignature,
295}
296
297impl RouterDescUnverified {
299 #[deny(unused_variables)]
318 #[cfg(feature = "incomplete")]
319 pub fn verify(self) -> std::result::Result<TimeRangeBound<RouterDesc>, VerifyFailed> {
320 let (mut body, sigs): (RouterDesc, SignaturesData<_>) = (self.body, self.sigs);
322
323 let mut timebounds = Vec::new();
325
326 let (identity_ed25519, identity_ed25519_bounds) =
329 Ed25519IdentityCert::verify(body.identity_ed25519.raw_unverified().clone())?
330 .dangerously_into_parts(); let Ed25519IdentityCert {
332 id_ed25519,
333 sign_ed25519,
334 } = identity_ed25519;
335 if id_ed25519 != body.master_key_ed25519.0 {
336 return Err(VerifyFailed::Inconsistent);
337 }
338 body.identity_ed25519.set_verified(identity_ed25519);
339 timebounds.push(identity_ed25519_bounds);
340
341 timebounds.push(TimeRangeBound::new_from_start_end(
343 (),
344 Some(body.published.0),
345 None,
346 ));
347
348 if body
350 .fingerprint
351 .is_some_and(|fp| fp.0 != body.signing_key.to_rsa_identity())
352 {
353 return Err(VerifyFailed::Inconsistent);
354 }
355
356 let ntor_pk = convert_curve25519_to_ed25519_public(
360 &body.ntor_onion_key.0,
361 body.ntor_onion_key_crosscert.bit.0.into(),
363 )
364 .ok_or(VerifyFailed::Other)?;
365 let (ntor_cc, ntor_cc_bounds) = Ed25519NtorCrossCert::verify(
366 ntor_pk.into(),
367 id_ed25519,
368 body.ntor_onion_key_crosscert.cert.raw_unverified().clone(),
369 )?
370 .dangerously_into_parts(); body.ntor_onion_key_crosscert.cert.set_verified(ntor_cc);
372 timebounds.push(ntor_cc_bounds);
373
374 if body.signing_key.bits() != 1024 || !body.signing_key.exponent_is(65537) {
377 return Err(VerifyFailed::Other);
378 }
379
380 for cert in body.family_cert.0.iter_mut() {
382 let (cert_verified, cert_bounds) =
383 Ed25519FamilyCert::verify(id_ed25519, cert.raw_unverified().clone())?
384 .dangerously_into_parts(); cert.set_verified(cert_verified);
386 timebounds.push(cert_bounds);
387 }
388
389 ed25519::PublicKey::try_from(sign_ed25519)
394 .map_err(|_| VerifyFailed::Other)?
395 .verify(
396 &sigs.hashes.sha256.ok_or(VerifyFailed::VerifyFailed)?,
397 &sigs.sigs.router_sig_ed25519.0,
398 )?;
399 body.signing_key.verify(
400 sigs.hashes.sha1.ok_or(VerifyFailed::VerifyFailed)?.as_ref(),
401 sigs.sigs.router_signature.0.as_ref(),
402 )?;
403
404 let start_time = timebounds
409 .iter()
410 .filter_map(|x| x.bounds_start_end().0)
411 .max();
412 let end_time = timebounds
413 .iter()
414 .filter_map(|x| x.bounds_start_end().1)
415 .min();
416 debug_assert!(start_time.is_some()); debug_assert!(end_time.is_some()); Ok(TimeRangeBound::new_from_start_end(
420 body, start_time, end_time,
421 ))
422 }
423}
424
425#[derive(Debug, Clone, PartialEq, Eq)]
431#[non_exhaustive]
432pub enum RelayPlatform {
433 Tor(TorVersion, Option<String>),
435 Other(String),
437}
438
439#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
441#[non_exhaustive]
442pub struct CachesExtraInfoToken;
443
444#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
446#[non_exhaustive]
447pub struct HiddenServiceDirToken;
448
449#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
451#[non_exhaustive]
452pub struct TunnelledDirServerToken;
453
454impl std::str::FromStr for RelayPlatform {
455 type Err = Error;
456 fn from_str(args: &str) -> Result<Self> {
457 if args.starts_with("Tor ") {
458 let v: Vec<_> = args.splitn(4, ' ').collect();
459 match &v[..] {
460 ["Tor", ver, "on", p] => {
461 Ok(RelayPlatform::Tor(ver.parse()?, Some((*p).to_string())))
462 }
463 ["Tor", ver, ..] => Ok(RelayPlatform::Tor(ver.parse()?, None)),
464 _ => unreachable!(),
465 }
466 } else {
467 Ok(RelayPlatform::Other(args.to_string()))
468 }
469 }
470}
471
472impl Display for RelayPlatform {
473 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
474 match &self {
475 Self::Tor(v, Some(p)) => write!(f, "Tor {v} on {p}"),
476 Self::Tor(v, None) => write!(f, "Tor {v}"),
477 Self::Other(s) => write!(f, "{s}"),
478 }
479 }
480}
481
482impl ItemValueParseable for RelayPlatform {
483 fn from_unparsed(item: UnparsedItem<'_>) -> std::result::Result<Self, ErrorProblem> {
484 let mut args = item.args_copy();
485 item.check_no_object()?;
486 args.into_remaining()
487 .parse()
488 .map_err(|_| args.handle_error("platform", ArgumentError::Invalid))
489 }
490}
491
492impl ItemValueEncodable for RelayPlatform {
493 fn write_item_value_onto(
494 &self,
495 mut out: ItemEncoder,
496 ) -> std::result::Result<(), tor_error::Bug> {
497 out.args_raw_string(&self);
500 Ok(())
501 }
502}
503
504decl_keyword! {
505 RouterKwd {
508 annotation "@source" => ANN_SOURCE,
509 annotation "@downloaded-at" => ANN_DOWNLOADED_AT,
510 annotation "@purpose" => ANN_PURPOSE,
511 "accept" | "reject" => POLICY,
512 "bandwidth" => BANDWIDTH,
513 "bridge-distribution-request" => BRIDGE_DISTRIBUTION_REQUEST,
514 "caches-extra-info" => CACHES_EXTRA_INFO,
515 "contact" => CONTACT,
516 "extra-info-digest" => EXTRA_INFO_DIGEST,
517 "family" => FAMILY,
518 "family-cert" => FAMILY_CERT,
519 "fingerprint" => FINGERPRINT,
520 "hibernating" => HIBERNATING,
521 "identity-ed25519" => IDENTITY_ED25519,
522 "ipv6-policy" => IPV6_POLICY,
523 "master-key-ed25519" => MASTER_KEY_ED25519,
524 "ntor-onion-key" => NTOR_ONION_KEY,
525 "ntor-onion-key-crosscert" => NTOR_ONION_KEY_CROSSCERT,
526 "or-address" => OR_ADDRESS,
527 "platform" => PLATFORM,
528 "proto" => PROTO,
529 "published" => PUBLISHED,
530 "router" => ROUTER,
531 "router-sig-ed25519" => ROUTER_SIG_ED25519,
532 "router-signature" => ROUTER_SIGNATURE,
533 "signing-key" => SIGNING_KEY,
534 "tunnelled_dir_server" => TUNNELLED_DIR_SERVER,
535 "uptime" => UPTIME,
536 }
540}
541
542static ROUTER_ANNOTATIONS: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
544 use RouterKwd::*;
545
546 let mut rules = SectionRules::builder();
547 rules.add(ANN_SOURCE.rule());
548 rules.add(ANN_DOWNLOADED_AT.rule().args(1..));
549 rules.add(ANN_PURPOSE.rule().args(1..));
550 rules.add(ANN_UNRECOGNIZED.rule().may_repeat().obj_optional());
551 rules.reject_unrecognized();
554 rules.build()
555});
556static ROUTER_HEADER_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
559 use RouterKwd::*;
560
561 let mut rules = SectionRules::builder();
562 rules.add(ROUTER.rule().required().args(5..));
563 rules.add(IDENTITY_ED25519.rule().required().no_args().obj_required());
564 rules.reject_unrecognized();
566 rules.build()
567});
568static ROUTER_BODY_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
571 use RouterKwd::*;
572
573 let mut rules = SectionRules::builder();
574 rules.add(MASTER_KEY_ED25519.rule().required().args(1..));
575 rules.add(PLATFORM.rule());
576 rules.add(PUBLISHED.rule().required());
577 rules.add(FINGERPRINT.rule());
578 rules.add(UPTIME.rule().args(1..));
579 rules.add(NTOR_ONION_KEY.rule().required().args(1..));
580 rules.add(
581 NTOR_ONION_KEY_CROSSCERT
582 .rule()
583 .required()
584 .args(1..=1)
585 .obj_required(),
586 );
587 rules.add(SIGNING_KEY.rule().no_args().required().obj_required());
588 rules.add(POLICY.rule().may_repeat().args(1..));
589 rules.add(IPV6_POLICY.rule().args(2..));
590 rules.add(FAMILY.rule().args(1..));
591 rules.add(FAMILY_CERT.rule().obj_required().may_repeat());
592 rules.add(CACHES_EXTRA_INFO.rule().no_args());
593 rules.add(OR_ADDRESS.rule().may_repeat().args(1..));
594 rules.add(TUNNELLED_DIR_SERVER.rule());
595 rules.add(PROTO.rule().required().args(1..));
596 rules.add(UNRECOGNIZED.rule().may_repeat().obj_optional());
597 {
599 rules.add(BANDWIDTH.rule().required().args(3..));
600 rules.add(BRIDGE_DISTRIBUTION_REQUEST.rule().args(1..));
601 rules.add(HIBERNATING.rule().args(1..));
602 rules.add(CONTACT.rule());
603 }
604 {
606 rules.add(EXTRA_INFO_DIGEST.rule().args(1..));
607 }
608 rules.build()
609});
610
611static ROUTER_SIG_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
613 use RouterKwd::*;
614
615 let mut rules = SectionRules::builder();
616 rules.add(ROUTER_SIG_ED25519.rule().required().args(1..));
617 rules.add(ROUTER_SIGNATURE.rule().required().no_args().obj_required());
618 rules.reject_unrecognized();
620 rules.build()
621});
622
623impl RouterAnnotation {
624 fn take_from_reader(reader: &mut NetDocReader<'_, RouterKwd>) -> Result<RouterAnnotation> {
626 use RouterKwd::*;
627 let mut items = reader.pause_at(|item| item.is_ok_with_non_annotation());
628
629 let body = ROUTER_ANNOTATIONS.parse(&mut items)?;
630
631 let source = body.maybe(ANN_SOURCE).args_as_str().map(String::from);
632 let purpose = body.maybe(ANN_PURPOSE).args_as_str().map(String::from);
633 let downloaded = body
634 .maybe(ANN_DOWNLOADED_AT)
635 .parse_args_as_str::<Iso8601TimeSp>()?
636 .map(|t| t.into());
637 Ok(RouterAnnotation {
638 source,
639 downloaded,
640 purpose,
641 })
642 }
643}
644
645pub type UncheckedRouterDesc = signed::SignatureGated<timed::TimeRangeBound<RouterDesc>>;
648
649const ROUTER_EXPIRY_SECONDS: u64 = 5 * 86400;
652
653const ROUTER_PRE_VALIDITY_SECONDS: u64 = 86400;
659
660impl RouterDesc {
661 pub fn rsa_identity(&self) -> RsaIdentity {
663 self.signing_key.to_rsa_identity()
664 }
665
666 pub fn ed_identity(&self) -> &Ed25519Identity {
668 &self
669 .identity_ed25519
670 .get()
671 .expect("ed25519 identity cert should be verified")
672 .id_ed25519
673 }
674
675 pub fn protocols(&self) -> &tor_protover::Protocols {
678 &self.proto
679 }
680
681 pub fn ntor_onion_key(&self) -> &ll::pk::curve25519::PublicKey {
683 &self.ntor_onion_key.0
684 }
685
686 pub fn published(&self) -> time::SystemTime {
688 self.published.0
689 }
690
691 pub fn or_ports(&self) -> impl Iterator<Item = net::SocketAddr> + '_ {
694 iter::once(net::SocketAddr::new(
695 self.router.address.into(),
696 self.router.orport,
697 ))
698 .chain(self.or_address.iter().copied())
699 }
700
701 pub fn family(&self) -> Intern<RelayFamily> {
703 Intern::clone(&self.family)
704 }
705
706 pub fn family_ids(&self) -> RelayFamilyIds {
708 RelayFamilyIds::from_iter(
709 self.family_cert
710 .iter()
711 .map(|cert| cert.get().expect("unverified family cert?"))
712 .map(|cert| cert.family_ed25519.into()),
713 )
714 }
715
716 fn parse_sections<'a>(
718 reader: &mut NetDocReader<'a, RouterKwd>,
719 ) -> Result<(
720 Section<'a, RouterKwd>,
721 Section<'a, RouterKwd>,
722 Section<'a, RouterKwd>,
723 )> {
724 use RouterKwd::*;
725
726 let header = ROUTER_HEADER_RULES.parse(
728 reader.pause_at(|item| item.is_ok_with_kwd_not_in(&[ROUTER, IDENTITY_ED25519])),
729 )?;
730
731 let body =
733 ROUTER_BODY_RULES.parse(reader.pause_at(|item| {
734 item.is_ok_with_kwd_in(&[ROUTER_SIGNATURE, ROUTER_SIG_ED25519])
735 }))?;
736
737 let sig = ROUTER_SIG_RULES.parse(reader.pause_at(|item| {
739 item.is_ok_with_annotation() || item.is_ok_with_kwd(ROUTER) || item.is_empty_line()
740 }))?;
741
742 Ok((header, body, sig))
743 }
744
745 pub fn parse(s: &str) -> Result<UncheckedRouterDesc> {
762 let mut reader = crate::parse::tokenize::NetDocReader::new(s)?;
763 let result = Self::parse_internal(&mut reader).map_err(|e| e.within(s))?;
764 reader
767 .should_be_exhausted_but_for_empty_lines()
768 .map_err(|e| e.within(s))?;
769 Ok(result)
770 }
771
772 fn parse_internal(r: &mut NetDocReader<'_, RouterKwd>) -> Result<UncheckedRouterDesc> {
778 use RouterKwd::*;
781
782 let s = r.str();
783 let (header, body, sig) = RouterDesc::parse_sections(r)?;
784
785 #[allow(clippy::unwrap_used)]
788 let start_offset = header.required(ROUTER)?.offset_in(s).unwrap();
789
790 let (ku_identity_cert, identity_cert, ed25519_signing_key) = {
804 let cert_tok = header.required(IDENTITY_ED25519)?;
805 #[allow(clippy::unwrap_used)]
808 if cert_tok.offset_in(s).unwrap() < start_offset {
809 return Err(EK::MisplacedToken
810 .with_msg("identity-ed25519")
811 .at_pos(cert_tok.pos()));
812 }
813 let ku_cert = cert_tok
814 .parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
815 .check_cert_type(tor_cert::CertType::IDENTITY_V_SIGNING)?
816 .into_unchecked();
817 let cert = ku_cert.clone().should_have_signing_key().map_err(|err| {
818 EK::BadObjectVal
819 .err()
820 .with_source(err)
821 .at_pos(cert_tok.pos())
822 })?;
823 let sk = *cert.peek_subject_key().as_ed25519().ok_or_else(|| {
824 EK::BadObjectVal
825 .at_pos(cert_tok.pos())
826 .with_msg("wrong type for signing key in cert")
827 })?;
828 let sk: ll::pk::ed25519::PublicKey = sk.try_into().map_err(|_| {
829 EK::BadObjectVal
830 .at_pos(cert_tok.pos())
831 .with_msg("invalid ed25519 signing key")
832 })?;
833 (ku_cert, cert, sk)
834 };
835
836 #[allow(unexpected_cfgs)]
838 let ed25519_identity_key = {
839 let master_key_tok = body.required(MASTER_KEY_ED25519)?;
840 let ed_id: Ed25519Public = master_key_tok.parse_arg(0)?;
841 let ed_id: ll::pk::ed25519::Ed25519Identity = ed_id.into();
842 if ed_id != *identity_cert.peek_signing_key() {
843 #[cfg(not(fuzzing))] return Err(EK::BadObjectVal
845 .at_pos(master_key_tok.pos())
846 .with_msg("master-key-ed25519 does not match key in identity-ed25519"));
847 }
848 ed_id
849 };
850
851 let rsa_identity_key: ll::pk::rsa::PublicKey = body
853 .required(SIGNING_KEY)?
854 .parse_obj::<RsaPublicParse1Helper>("RSA PUBLIC KEY")?
855 .check_len_eq(1024)?
856 .check_exponent(65537)?
857 .into();
858 let rsa_identity = rsa_identity_key.to_rsa_identity();
859
860 let ed_sig = sig.required(ROUTER_SIG_ED25519)?;
861 let rsa_sig = sig.required(ROUTER_SIGNATURE)?;
862 #[allow(clippy::unwrap_used)]
865 let ed_sig_pos = ed_sig.offset_in(s).unwrap();
866 #[allow(clippy::unwrap_used)]
867 let rsa_sig_pos = rsa_sig.offset_in(s).unwrap();
868
869 if ed_sig_pos > rsa_sig_pos {
870 return Err(EK::UnexpectedToken
871 .with_msg(ROUTER_SIG_ED25519.to_str())
872 .at_pos(ed_sig.pos()));
873 }
874
875 let ed_signature: ll::pk::ed25519::ValidatableEd25519Signature = {
877 let mut d = ll::d::Sha256::new();
878 d.update(&b"Tor router descriptor signature v1"[..]);
879 let signed_end = ed_sig_pos + b"router-sig-ed25519 ".len();
880 d.update(
881 s.get(start_offset..signed_end)
882 .ok_or(internal!("chopped utf8"))?,
883 );
884 let d = d.finalize();
885 let sig: [u8; 64] = ed_sig
886 .parse_arg::<B64>(0)?
887 .into_array()
888 .map_err(|_| EK::BadSignature.at_pos(ed_sig.pos()))?;
889 let sig = ll::pk::ed25519::Signature::from(sig);
890 ll::pk::ed25519::ValidatableEd25519Signature::new(ed25519_signing_key, sig, &d)
891 };
892
893 let rsa_signature: ll::pk::rsa::ValidatableRsaSignature = {
895 let mut d = ll::d::Sha1::new();
896 let signed_end = rsa_sig_pos + b"router-signature\n".len();
897 d.update(
898 s.get(start_offset..signed_end)
899 .ok_or(internal!("chopped utf8"))?,
900 );
901 let d = d.finalize();
902 let sig = rsa_sig.obj("SIGNATURE")?;
903 ll::pk::rsa::ValidatableRsaSignature::new(&rsa_identity_key, &sig, &d)
906 };
907
908 let (nickname, ipv4addr, orport, dirport) = {
910 let rtrline = header.required(ROUTER)?;
911 (
912 rtrline.required_arg(0)?.parse::<Nickname>().map_err(|e| {
913 EK::BadArgument
914 .with_msg(e.to_string())
915 .at_pos(rtrline.pos())
916 })?,
917 rtrline.parse_arg::<net::Ipv4Addr>(1)?,
918 rtrline.parse_arg(2)?,
919 rtrline.parse_arg(4)?,
921 )
922 };
923
924 let uptime = body.maybe(UPTIME).parse_arg(0)?;
926
927 let published = body
929 .required(PUBLISHED)?
930 .args_as_str()
931 .parse::<Iso8601TimeSp>()?;
932
933 let ntor_onion_key: Curve25519Public = body.required(NTOR_ONION_KEY)?.parse_arg(0)?;
935 let (cc_sig, cc_expiry, cc_cert) = {
937 let cc = body.required(NTOR_ONION_KEY_CROSSCERT)?;
938 let sign: u8 = cc.parse_arg(0)?;
939 if sign != 0 && sign != 1 {
940 return Err(EK::BadArgument.at_pos(cc.arg_pos(0)).with_msg("not 0 or 1"));
941 }
942 let ntor_as_ed: ll::pk::ed25519::PublicKey =
943 ll::pk::keymanip::convert_curve25519_to_ed25519_public(&ntor_onion_key.0, sign)
944 .ok_or_else(|| {
945 EK::BadArgument
946 .at_pos(cc.pos())
947 .with_msg("Uncheckable crosscert")
948 })?;
949
950 let cert = cc
951 .parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
952 .into_unchecked();
953 let (_, sig, expiry) = Ed25519NtorCrossCert::verify_inner(
954 ntor_as_ed.into(),
955 ed25519_identity_key,
956 cert.clone(),
957 )
958 .map_err(|_| EK::BadSignature.err())?;
959
960 let cert = NtorOnionKeyCrossCert {
961 bit: NumericBoolean(sign != 0),
962 cert: EmbeddedCert::new(Ed25519NtorCrossCert::dangerous_new_unverified(), cert),
964 };
965
966 (sig, expiry, cert)
967 };
968
969 let proto = {
971 let proto_tok = body.required(PROTO)?;
972 proto_tok
973 .args_as_str()
974 .parse::<tor_protover::Protocols>()
975 .map_err(|e| EK::BadArgument.at_pos(proto_tok.pos()).with_source(e))?
976 };
977
978 let is_dircache = ((dirport != 0) || body.get(TUNNELLED_DIR_SERVER).is_some())
980 .then_some(ItemPresent::default());
981
982 let is_extrainfo_cache = body.get(CACHES_EXTRA_INFO).map(|_| ItemPresent::default());
984
985 if let Some(fp_tok) = body.get(FINGERPRINT) {
987 let fp: RsaIdentity = fp_tok.args_as_str().parse::<SpFingerprint>()?.into();
988 if fp != rsa_identity {
989 return Err(EK::BadArgument
990 .at_pos(fp_tok.pos())
991 .with_msg("fingerprint does not match RSA identity"));
992 }
993 }
994
995 let family = {
997 let mut family = body
998 .maybe(FAMILY)
999 .parse_args_as_str::<RelayFamily>()?
1000 .unwrap_or_else(RelayFamily::new);
1001 if !family.is_empty() {
1002 family.push(rsa_identity);
1008 }
1009 family.intern()
1010 };
1011
1012 let family_certs = body
1020 .slice(FAMILY_CERT)
1021 .iter()
1022 .map(|ent| {
1023 let ku = ent
1024 .parse_obj::<UnvalidatedEdCert>("FAMILY CERT")?
1025 .check_cert_type(CertType::FAMILY_V_IDENTITY)?
1026 .check_subject_key_is(identity_cert.peek_signing_key())?
1027 .into_unchecked();
1028 let unchecked = ku.clone().should_have_signing_key().map_err(|e| {
1029 EK::BadObjectVal
1030 .with_msg("missing public key")
1031 .at_pos(ent.pos())
1032 .with_source(e)
1033 })?;
1034 Ok((ku, unchecked))
1035 })
1036 .collect::<Result<Vec<_>>>()?;
1037
1038 let mut ipv6addr = Vec::with_capacity(1);
1042 for tok in body.slice(OR_ADDRESS) {
1043 if let Ok(net::SocketAddr::V6(a)) = tok.parse_arg::<net::SocketAddr>(0) {
1044 ipv6addr.push(a.into());
1045 break;
1046 }
1047 }
1049
1050 let platform = body.maybe(PLATFORM).parse_args_as_str::<RelayPlatform>()?;
1052
1053 let ipv4_policy = {
1055 let mut pol = AddrPolicy::new();
1056 for ruletok in body.slice(POLICY).iter() {
1057 let accept = match ruletok.kwd_str() {
1058 "accept" => RuleKind::Accept,
1059 "reject" => RuleKind::Reject,
1060 _ => {
1061 return Err(Error::from(internal!(
1062 "tried to parse a strange line as a policy"
1063 ))
1064 .at_pos(ruletok.pos()));
1065 }
1066 };
1067 let pat: AddrPortPattern = ruletok
1068 .args_as_str()
1069 .parse()
1070 .map_err(|e| EK::BadPolicy.at_pos(ruletok.pos()).with_source(e))?;
1071 pol.push(accept, pat);
1072 }
1073 pol
1074 };
1075
1076 let ipv6_policy = match body.get(IPV6_POLICY) {
1078 Some(p) => p
1079 .args_as_str()
1080 .parse()
1081 .map_err(|e| EK::BadPolicy.at_pos(p.pos()).with_source(e))?,
1082 #[allow(clippy::unwrap_used)]
1084 None => "reject 1-65535".parse::<PortPolicy>().unwrap(),
1085 };
1086
1087 let (identity_cert, identity_sig) = identity_cert.dangerously_split().map_err(|err| {
1089 EK::BadObjectVal
1090 .with_msg("missing public key")
1091 .with_source(err)
1092 })?;
1093 let mut signatures: Vec<Box<dyn ll::pk::ValidatableSignature>> = vec![
1094 Box::new(rsa_signature),
1095 Box::new(ed_signature),
1096 Box::new(identity_sig),
1097 Box::new(cc_sig),
1098 ];
1099
1100 let identity_cert = identity_cert.dangerously_assume_timely();
1101 let mut expirations = vec![
1102 published
1103 .0
1104 .saturating_add(time::Duration::new(ROUTER_EXPIRY_SECONDS, 0)),
1105 identity_cert.expiry(),
1106 cc_expiry,
1107 ];
1108
1109 let mut embedded_family_certs = Vec::with_capacity(family_certs.len());
1115 for (ku_cert, cert) in family_certs {
1116 let family_ed25519 = *cert.peek_signing_key();
1117 let (inner, sig) = cert.dangerously_split().map_err(into_internal!(
1118 "Missing a public key that was previously there."
1119 ))?;
1120 let embedded_cert = EmbeddedCert::new(Ed25519FamilyCert { family_ed25519 }, ku_cert);
1121 signatures.push(Box::new(sig));
1122 expirations.push(inner.dangerously_assume_timely().expiry());
1123 embedded_family_certs.push(embedded_cert);
1124 }
1125
1126 #[allow(clippy::unwrap_used)]
1128 let expiry = *expirations.iter().min().unwrap();
1129
1130 let start_time = published
1131 .0
1132 .saturating_sub(time::Duration::new(ROUTER_PRE_VALIDITY_SECONDS, 0));
1133
1134 let desc = RouterDesc {
1135 router: RouterDescIntroItem {
1136 nickname,
1137 address: ipv4addr,
1138 orport,
1139 socksport: 0,
1140 dirport,
1141 },
1142 identity_ed25519: EmbeddedCert::new(
1143 Ed25519IdentityCert {
1144 id_ed25519: ed25519_identity_key,
1145 sign_ed25519: ed25519_signing_key.into(),
1146 },
1147 ku_identity_cert,
1148 ),
1149 master_key_ed25519: ed25519_identity_key.into(),
1150 bandwidth: Default::default(),
1151 platform,
1152 published,
1153 fingerprint: Some(rsa_identity.into()),
1154 hibernating: Default::default(),
1155 uptime,
1156 ntor_onion_key,
1157 ntor_onion_key_crosscert: cc_cert,
1158 signing_key: rsa_identity_key,
1159 ipv4_policy,
1160 ipv6_policy: ipv6_policy.intern(),
1161 overload_general: Default::default(),
1162 contact: Default::default(),
1163 family,
1164 family_cert: embedded_family_certs.into(),
1165 caches_extra_info: is_extrainfo_cache,
1166 extra_info_digest: Default::default(),
1167 hidden_service_dir: Default::default(),
1168 or_address: ipv6addr,
1169 tunnelled_dir_server: is_dircache,
1170 proto,
1171 };
1172
1173 let time_gated = timed::TimeRangeBound::new(desc, start_time..expiry);
1174 let sig_gated = signed::SignatureGated::new(time_gated, signatures);
1175
1176 Ok(sig_gated)
1177 }
1178}
1179
1180pub struct RouterReader<'a> {
1186 annotated: bool,
1188 reader: NetDocReader<'a, RouterKwd>,
1190}
1191
1192fn advance_to_next_routerdesc(reader: &mut NetDocReader<'_, RouterKwd>, annotated: bool) {
1197 use RouterKwd::*;
1198 loop {
1199 let item = reader.peek();
1200 match item {
1201 Some(Ok(t)) => {
1202 let kwd = t.kwd();
1203 if (annotated && kwd.is_annotation()) || kwd == ROUTER {
1204 return;
1205 }
1206 }
1207 Some(Err(_)) => {
1208 }
1210 None => {
1211 return;
1212 }
1213 }
1214 let _ = reader.next();
1215 }
1216}
1217
1218impl<'a> RouterReader<'a> {
1219 pub fn new(s: &'a str, allow: &AllowAnnotations) -> Result<Self> {
1221 let reader = NetDocReader::new(s)?;
1222 let annotated = allow == &AllowAnnotations::AnnotationsAllowed;
1223 Ok(RouterReader { annotated, reader })
1224 }
1225
1226 fn take_annotation(&mut self) -> Result<RouterAnnotation> {
1228 if self.annotated {
1229 RouterAnnotation::take_from_reader(&mut self.reader)
1230 } else {
1231 Ok(RouterAnnotation::default())
1232 }
1233 }
1234
1235 fn take_annotated_routerdesc_raw(&mut self) -> Result<AnnotatedRouterDesc> {
1239 let ann = self.take_annotation()?;
1240 let router = RouterDesc::parse_internal(&mut self.reader)?;
1241 Ok(AnnotatedRouterDesc { ann, router })
1242 }
1243
1244 fn take_annotated_routerdesc(&mut self) -> Result<AnnotatedRouterDesc> {
1248 let pos_orig = self.reader.pos();
1249 let result = self.take_annotated_routerdesc_raw();
1250 if result.is_err() {
1251 if self.reader.pos() == pos_orig {
1252 let _ = self.reader.next();
1260 }
1261 advance_to_next_routerdesc(&mut self.reader, self.annotated);
1262 }
1263 result
1264 }
1265}
1266
1267impl<'a> Iterator for RouterReader<'a> {
1268 type Item = Result<AnnotatedRouterDesc>;
1269 fn next(&mut self) -> Option<Self::Item> {
1270 self.reader.peek()?;
1272
1273 Some(
1274 self.take_annotated_routerdesc()
1275 .map_err(|e| e.within(self.reader.str())),
1276 )
1277 }
1278}
1279
1280#[cfg(test)]
1281mod test {
1282 #![allow(clippy::bool_assert_comparison)]
1284 #![allow(clippy::clone_on_copy)]
1285 #![allow(clippy::dbg_macro)]
1286 #![allow(clippy::mixed_attributes_style)]
1287 #![allow(clippy::print_stderr)]
1288 #![allow(clippy::print_stdout)]
1289 #![allow(clippy::single_char_pattern)]
1290 #![allow(clippy::unwrap_used)]
1291 #![allow(clippy::unchecked_time_subtraction)]
1292 #![allow(clippy::useless_vec)]
1293 #![allow(clippy::needless_pass_by_value)]
1294 #![allow(clippy::string_slice)] use std::{net::Ipv4Addr, str::FromStr, time::Duration};
1297
1298 use crate::{
1299 encode::{NetdocEncodable, NetdocEncoder},
1300 parse2::{self, NetdocParseableUnverified, ParseInput},
1301 };
1302 use tor_basic_utils::test_rng::testing_rng;
1303 use tor_checkable::TimeValidityError;
1304 use tor_llcrypto::pk::{curve25519, ed25519::Ed25519PublicKey, rsa};
1305
1306 use super::*;
1307 const TESTDATA: &str = include_str!("../../testdata/routerdesc1.txt");
1308 const TESTDATA2: &str = include_str!("../../testdata/routerdesc2.txt");
1309 const TESTDATA3: &str = include_str!("../../testdata/routerdesc3.txt");
1311
1312 fn read_bad(fname: &str) -> String {
1313 use std::fs;
1314 use std::path::PathBuf;
1315 let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
1316 path.push("testdata");
1317 path.push("bad-routerdesc");
1318 path.push(fname);
1319
1320 fs::read_to_string(path).unwrap()
1321 }
1322
1323 #[test]
1324 fn parse_arbitrary() -> Result<()> {
1325 use std::str::FromStr;
1326 use tor_checkable::{SelfSigned, TimeBound};
1327 let rd = RouterDesc::parse(TESTDATA)?
1328 .check_signature()?
1329 .dangerously_assume_timely();
1330
1331 assert_eq!(rd.router.nickname.as_str(), "Akka");
1332 assert_eq!(rd.router.orport, 443);
1333 assert_eq!(rd.router.dirport, 0);
1334 assert_eq!(rd.uptime, Some(1036923));
1335 assert_eq!(
1336 rd.family.as_ref(),
1337 &RelayFamily::from_str(
1338 "$303509ab910ef207b7438c27435c4a2fd579f1b1 \
1339 $56927e61b51e6f363fb55498150a6ddfcf7077f2"
1340 )
1341 .unwrap()
1342 );
1343
1344 assert_eq!(
1345 rd.rsa_identity().to_string(),
1346 "$56927e61b51e6f363fb55498150a6ddfcf7077f2"
1347 );
1348 assert_eq!(
1349 rd.ed_identity().to_string(),
1350 "CVTjf1oeaL616hH+1+UvYZ8OgkwF3z7UMITvJzm5r7A"
1351 );
1352 assert_eq!(
1353 rd.protocols().to_string(),
1354 "Cons=1-2 Desc=1-2 DirCache=2 FlowCtrl=1-2 HSDir=2 \
1355 HSIntro=4-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 \
1356 Padding=2 Relay=1-4"
1357 );
1358
1359 assert_eq!(
1360 hex::encode(rd.ntor_onion_key().to_bytes()),
1361 "329b3b52991613392e35d1a821dd6753e1210458ecc3337f7b7d39bfcf5da273"
1362 );
1363 assert_eq!(
1364 rd.published(),
1365 humantime::parse_rfc3339("2022-11-14T19:58:52Z").unwrap()
1366 );
1367 assert_eq!(
1368 rd.or_ports().collect::<Vec<_>>(),
1369 vec![
1370 "95.216.33.58:443".parse().unwrap(),
1371 "[2a01:4f9:2a:2145::2]:443".parse().unwrap(),
1372 ]
1373 );
1374
1375 Ok(())
1376 }
1377
1378 #[test]
1379 fn parse_no_tap_key() -> Result<()> {
1380 use tor_checkable::{SelfSigned, TimeBound};
1381 let _rd = RouterDesc::parse(TESTDATA2)?
1382 .check_signature()?
1383 .dangerously_assume_timely();
1384
1385 Ok(())
1386 }
1387
1388 #[test]
1389 fn test_bad() {
1390 use crate::Pos;
1391 use crate::types::policy::PolicyError;
1392 fn check(fname: &str, e: &Error) {
1393 let text = read_bad(fname);
1394 let rd = RouterDesc::parse(&text);
1395 assert!(rd.is_err());
1396 assert_eq!(&rd.err().unwrap(), e);
1397 }
1398
1399 check(
1400 "bad-sig-order",
1401 &EK::UnexpectedToken
1402 .with_msg("router-sig-ed25519")
1403 .at_pos(Pos::from_line(50, 1)),
1404 );
1405 check(
1406 "bad-start1",
1407 &EK::MisplacedToken
1408 .with_msg("identity-ed25519")
1409 .at_pos(Pos::from_line(1, 1)),
1410 );
1411 check("bad-start2", &EK::MissingToken.with_msg("identity-ed25519"));
1412 check(
1413 "mismatched-fp",
1414 &EK::BadArgument
1415 .at_pos(Pos::from_line(12, 1))
1416 .with_msg("fingerprint does not match RSA identity"),
1417 );
1418 check("no-ed-sk", &EK::MissingToken.with_msg("identity-ed25519"));
1419
1420 check(
1421 "bad-cc-sign",
1422 &EK::BadArgument
1423 .at_pos(Pos::from_line(34, 26))
1424 .with_msg("not 0 or 1"),
1425 );
1426 check(
1427 "bad-ipv6policy",
1428 &EK::BadPolicy
1429 .at_pos(Pos::from_line(43, 1))
1430 .with_source(PolicyError::InvalidPolicy),
1431 );
1432 check(
1433 "no-ed-id-key-in-cert",
1434 &EK::BadObjectVal
1435 .at_pos(Pos::from_line(2, 1))
1436 .with_source(tor_cert::CertError::MissingPubKey),
1437 );
1438 check(
1439 "non-ed-sk-in-cert",
1440 &EK::BadObjectVal
1441 .at_pos(Pos::from_line(2, 1))
1442 .with_msg("wrong type for signing key in cert"),
1443 );
1444 check(
1445 "bad-ed-sk-in-cert",
1446 &EK::BadObjectVal
1447 .at_pos(Pos::from_line(2, 1))
1448 .with_msg("invalid ed25519 signing key"),
1449 );
1450 check(
1451 "mismatched-ed-sk-in-cert",
1452 &EK::BadObjectVal
1453 .at_pos(Pos::from_line(8, 1))
1454 .with_msg("master-key-ed25519 does not match key in identity-ed25519"),
1455 );
1456 }
1457
1458 #[test]
1459 fn parse_multiple_annotated() {
1460 use crate::AllowAnnotations;
1461 let mut s = read_bad("bad-cc-sign");
1462 s += "\
1463@uploaded-at 2020-09-26 18:15:41
1464@source \"127.0.0.1\"
1465";
1466 s += TESTDATA;
1467 s += "\
1468@uploaded-at 2020-09-26 18:15:41
1469@source \"127.0.0.1\"
1470";
1471 s += &read_bad("mismatched-fp");
1472
1473 let rd = RouterReader::new(&s, &AllowAnnotations::AnnotationsAllowed).unwrap();
1474 let v: Vec<_> = rd.collect();
1475 assert!(v[0].is_err());
1476 assert!(v[1].is_ok());
1477 assert_eq!(
1478 v[1].as_ref().unwrap().ann.source,
1479 Some("\"127.0.0.1\"".to_string())
1480 );
1481 assert!(v[2].is_err());
1482 }
1483
1484 #[test]
1485 fn test_platform() {
1486 let tests = [
1487 (
1489 "Tor 0.4.4.4-alpha on a flying bison",
1490 RelayPlatform::Tor(
1491 "0.4.4.4-alpha".parse().unwrap(),
1492 Some("a flying bison".to_string()),
1493 ),
1494 ),
1495 (
1497 "Tor 0.4.4.4-alpha on",
1498 RelayPlatform::Tor("0.4.4.4-alpha".parse().unwrap(), None),
1499 ),
1500 (
1501 "Tor 0.4.4.4-alpha ",
1502 RelayPlatform::Tor("0.4.4.4-alpha".parse().unwrap(), None),
1503 ),
1504 (
1505 "Tor 0.4.4.4-alpha",
1506 RelayPlatform::Tor("0.4.4.4-alpha".parse().unwrap(), None),
1507 ),
1508 ("arti 0.0.0", RelayPlatform::Other("arti 0.0.0".to_string())),
1510 ];
1511 for (input, output) in tests {
1512 assert_eq!(input.parse::<RelayPlatform>().unwrap(), output);
1513
1514 let input = input.strip_suffix(" on").unwrap_or(input);
1518 let input = input.trim();
1519 assert_eq!(output.to_string(), input);
1520 }
1521 }
1522
1523 #[test]
1524 fn test_family_ids() -> Result<()> {
1525 use tor_checkable::{SelfSigned, TimeBound};
1526 let rd = RouterDesc::parse(TESTDATA3)?
1527 .check_signature()?
1528 .dangerously_assume_timely();
1529
1530 assert_eq!(
1531 rd.family_ids().as_ref(),
1532 &[
1533 "ed25519:7sToQRuge1bU2hS0CG0ViMndc4m82JhO4B4kdrQey80"
1534 .parse()
1535 .unwrap(),
1536 "ed25519:szHUS3ItRd9uk85b1UVnOZx1gg4B0266jCpbuIMNjcM"
1537 .parse()
1538 .unwrap(),
1539 ]
1540 );
1541
1542 Ok(())
1543 }
1544
1545 #[test]
1549 fn test_parse2_simple() {
1550 let input = ParseInput::new(
1551 include_str!("../../testdata2/cached-descriptors.new"),
1552 "cached-descriptors.new",
1553 );
1554 let rd = parse2::parse_netdoc_multiple::<RouterDescUnverified>(&input)
1555 .unwrap()
1556 .into_iter()
1557 .map(|rd| {
1558 #[cfg(feature = "incomplete")]
1559 rd.clone().verify().unwrap();
1560 rd.unwrap_unverified()
1561 })
1562 .map(|(body, sig)| (body, sig.sigs))
1563 .collect::<Vec<(RouterDesc, RouterDescSignatures)>>();
1564 assert_eq!(rd.len(), 20);
1565 assert_eq!(
1566 rd[0].0.router,
1567 RouterDescIntroItem {
1568 nickname: "test002a".parse().unwrap(),
1569 address: net::Ipv4Addr::LOCALHOST,
1570 orport: 5102,
1571 socksport: 0,
1572 dirport: 7102
1573 }
1574 );
1575 assert_eq!(
1576 rd[0].0.fingerprint.unwrap(),
1577 "257D 06F0 360B B224 6388 724F 109E C089 5A1D 41FB"
1578 .parse()
1579 .unwrap()
1580 );
1581
1582 let mut out = NetdocEncoder::new();
1591 for (body, sig) in &rd {
1592 body.encode_unsigned(&mut out).unwrap();
1593 sig.encode_unsigned(&mut out).unwrap();
1594 }
1595 let out = out.finish().unwrap();
1596 let input2 = ParseInput::new(out.as_str(), "<router descriptor encoding>");
1597 let rd2 = parse2::parse_netdoc_multiple::<RouterDescUnverified>(&input2)
1598 .unwrap()
1599 .into_iter()
1600 .map(|rd| rd.unwrap_unverified())
1601 .map(|(body, sig)| (body, sig.sigs))
1602 .collect::<Vec<(RouterDesc, _)>>();
1603 assert_eq!(rd, rd2);
1604 }
1605
1606 fn rd_encode_sign(doc: &RouterDesc, rsa: &rsa::KeyPair, ed25519: &ed25519::Keypair) -> String {
1609 #[derive(Deftly)]
1611 #[derive_deftly(NetdocEncodable)]
1612 struct Ed25519Writer {
1613 router_sig_ed25519: RouterSigEd25519,
1614 }
1615
1616 #[derive(Deftly)]
1618 #[derive_deftly(NetdocEncodable)]
1619 struct RsaWriter {
1620 router_signature: RouterSignature,
1621 }
1622
1623 let mut out = NetdocEncoder::new();
1625 doc.encode_unsigned(&mut out).unwrap();
1626 Ed25519Writer {
1627 router_sig_ed25519: RouterSigEd25519::new_sign_netdoc(
1628 ed25519,
1629 &out,
1630 "router-sig-ed25519",
1631 )
1632 .unwrap(),
1633 }
1634 .encode_unsigned(&mut out)
1635 .unwrap();
1636
1637 RsaWriter {
1639 router_signature: RouterSignature(
1640 RsaSha1Signature::new_sign_netdoc(rsa, &out, "router-signature")
1641 .unwrap()
1642 .signature,
1643 ),
1644 }
1645 .encode_unsigned(&mut out)
1646 .unwrap();
1647
1648 out.finish().unwrap()
1649 }
1650
1651 #[test]
1653 #[cfg(feature = "incomplete")]
1654 fn test_verify() {
1655 let rng = &mut testing_rng();
1657 let rsa_id = rsa::KeyPair::generate(rng).unwrap();
1658 let ed25519_id = ed25519::Keypair::generate(rng);
1659 let ed25519_sign = ed25519::Keypair::generate(rng);
1660 let curve25519_ntor = curve25519::StaticSecret::random_from_rng(&mut *rng);
1661 let curve25519_ntor = curve25519::StaticKeypair {
1662 secret: curve25519_ntor.clone(),
1663 public: (&curve25519_ntor).into(),
1664 };
1665 let ed25519_ntor = tor_llcrypto::pk::keymanip::convert_curve25519_to_ed25519_private(
1666 &curve25519_ntor.secret,
1667 )
1668 .unwrap();
1669
1670 let too_early = Iso8601TimeSp::from_str("2026-05-01 03:00:00").unwrap().0;
1672 let published = Iso8601TimeSp::from_str("2026-06-01 03:00:00").unwrap().0;
1673 let now = Iso8601TimeSp::from_str("2026-06-10 15:30:12").unwrap().0;
1674 let expiration = Iso8601TimeSp::from_str("2026-06-20 03:00:00").unwrap().0;
1675 let expired = expiration + Duration::from_secs(60 * 60 * 24);
1676
1677 let mut rd = RouterDesc {
1679 router: RouterDescIntroItem {
1680 nickname: "foo".parse().unwrap(),
1681 address: Ipv4Addr::LOCALHOST,
1682 orport: 9000,
1683 socksport: 0,
1684 dirport: 0,
1685 },
1686 identity_ed25519: Ed25519IdentityCert::new_signed(
1687 &ed25519_id,
1688 Ed25519Identity::from(ed25519_sign.public_key()),
1689 expiration,
1690 )
1691 .unwrap(),
1692 master_key_ed25519: Ed25519Identity::from(ed25519_id.public_key()).into(),
1693 bandwidth: Bandwidth {
1694 average: 0,
1695 burst: 0,
1696 observed: 0,
1697 },
1698 platform: None,
1699 published: published.into(),
1700 fingerprint: Some(rsa_id.to_public_key().to_rsa_identity().into()),
1701 hibernating: NumericBoolean(false),
1702 uptime: None,
1703 ntor_onion_key: Curve25519Public(curve25519_ntor.public),
1704 ntor_onion_key_crosscert: NtorOnionKeyCrossCert {
1705 bit: NumericBoolean(ed25519_ntor.1 == 1),
1706 cert: Ed25519NtorCrossCert::new_signed(
1707 &ed25519_ntor.0,
1708 ed25519_id.public_key().into(),
1709 expiration,
1710 )
1711 .unwrap(),
1712 },
1713 signing_key: rsa_id.to_public_key(),
1714 ipv4_policy: AddrPolicy::default(),
1715 ipv6_policy: Default::default(),
1716 overload_general: None,
1717 contact: None,
1718 family: Default::default(),
1719 family_cert: Default::default(),
1720 caches_extra_info: Some(Default::default()),
1721 extra_info_digest: None,
1722 hidden_service_dir: Some(Default::default()),
1723 or_address: Default::default(),
1724 tunnelled_dir_server: Some(Default::default()),
1725 proto: tor_protover::Protocols::new(),
1726 };
1727 let rd_original = rd.clone();
1728
1729 let verify =
1730 |rd: &RouterDesc| -> std::result::Result<TimeRangeBound<RouterDesc>, VerifyFailed> {
1731 let encoded = rd_encode_sign(rd, &rsa_id, &ed25519_sign);
1732 let decoded = parse2::parse_netdoc::<RouterDescUnverified>(&ParseInput::new(
1733 &encoded,
1734 "<test_invalid>",
1735 ))
1736 .unwrap();
1737 decoded.verify()
1738 };
1739
1740 assert_eq!(
1742 verify(&rd).unwrap().if_valid_at(&too_early).unwrap_err(),
1743 TimeValidityError::NotYetValid(published.duration_since(too_early).unwrap())
1744 );
1745 verify(&rd).unwrap().if_valid_at(&published).unwrap();
1746 verify(&rd).unwrap().if_valid_at(&now).unwrap();
1748 verify(&rd).unwrap().if_valid_at(&expiration).unwrap();
1749 assert_eq!(
1750 verify(&rd).unwrap().if_valid_at(&expired).unwrap_err(),
1751 TimeValidityError::Expired(expired.duration_since(expiration).unwrap())
1752 );
1753
1754 rd.master_key_ed25519 = Ed25519Public(Ed25519Identity::from([0x12; 32]));
1756 assert_eq!(verify(&rd).unwrap_err(), VerifyFailed::Inconsistent);
1757 rd = rd_original.clone();
1758
1759 rd.published = expired.into();
1761 assert_eq!(
1762 verify(&rd).unwrap().if_valid_at(&now).unwrap_err(),
1763 TimeValidityError::NotYetValid(expired.duration_since(now).unwrap())
1764 );
1765 rd = rd_original.clone();
1766
1767 let other_rsa_key = rsa::KeyPair::generate(rng).unwrap();
1769 rd.fingerprint = Some(other_rsa_key.to_public_key().to_rsa_identity().into());
1770 assert_eq!(verify(&rd).unwrap_err(), VerifyFailed::Inconsistent);
1771 rd.signing_key = other_rsa_key.to_public_key();
1774 assert_eq!(verify(&rd).unwrap_err(), VerifyFailed::VerifyFailed);
1775 rd.signing_key = rd_original.signing_key.clone();
1777 rd.fingerprint = None;
1778 verify(&rd).unwrap().if_valid_at(&now).unwrap();
1779 rd = rd_original.clone();
1780
1781 let other_curve25519 = curve25519::StaticSecret::random_from_rng(&mut *rng);
1785 let other_curve25519 = (&other_curve25519).into();
1786 rd.ntor_onion_key = Curve25519Public(other_curve25519);
1787 assert_eq!(verify(&rd).unwrap_err(), VerifyFailed::VerifyFailed);
1788 rd = rd_original.clone();
1789
1790 let different_ed25519_sign = ed25519::Keypair::generate(rng);
1799 rd.identity_ed25519 = Ed25519IdentityCert::new_signed(
1800 &ed25519_id,
1801 Ed25519Identity::from(different_ed25519_sign.public_key()),
1802 expiration,
1803 )
1804 .unwrap();
1805 assert_eq!(verify(&rd).unwrap_err(), VerifyFailed::VerifyFailed);
1806 rd = rd_original.clone();
1807
1808 let different_rsa_id = rsa::KeyPair::generate(rng).unwrap();
1811 rd.signing_key = different_rsa_id.to_public_key();
1812 rd.fingerprint = None;
1813 assert_eq!(verify(&rd).unwrap_err(), VerifyFailed::VerifyFailed);
1814 }
1815}