1use crate::parse::keyword::Keyword;
36use crate::parse::parser::{Section, SectionRules};
37use crate::parse::tokenize::{ItemResult, NetDocReader};
38use crate::types::family::{RelayFamily, RelayFamilyId};
39use crate::types::misc::*;
40use crate::types::policy::*;
41use crate::types::version::TorVersion;
42use crate::util::PeekableIterator;
43use crate::{AllowAnnotations, Error, KeywordEncodable, NetdocErrorKind as EK, Result};
44
45use ll::pk::ed25519::Ed25519Identity;
46use std::sync::Arc;
47use std::sync::LazyLock;
48use std::{net, time};
49use tor_cert::CertType;
50use tor_checkable::{Timebound, signed, timed};
51use tor_error::{internal, into_internal};
52use tor_llcrypto as ll;
53use tor_llcrypto::pk::rsa::RsaIdentity;
54
55use digest::Digest;
56
57pub const DOC_DIGEST_LEN: usize = 20;
59
60pub type RdDigest = [u8; DOC_DIGEST_LEN];
62
63#[non_exhaustive]
65pub struct AnnotatedRouterDesc {
66 pub ann: RouterAnnotation,
68 pub router: UncheckedRouterDesc,
70}
71
72#[derive(Default)]
74#[non_exhaustive]
75pub struct RouterAnnotation {
76 pub source: Option<String>,
78 pub downloaded: Option<time::SystemTime>,
80 pub purpose: Option<String>,
82}
83
84#[derive(Clone, Debug)]
98#[non_exhaustive]
99pub struct RouterDesc {
100 pub nickname: Nickname,
104 pub ipv4addr: Option<net::Ipv4Addr>,
106 pub orport: u16,
108 pub ipv6addr: Option<(net::Ipv6Addr, u16)>,
113 pub dirport: u16,
116 pub uptime: Option<u64>,
118 pub published: time::SystemTime,
120 pub identity_cert: tor_cert::Ed25519Cert,
123 pub rsa_identity_key: ll::pk::rsa::PublicKey,
126 pub rsa_identity: ll::pk::rsa::RsaIdentity,
129 pub ntor_onion_key: ll::pk::curve25519::PublicKey,
131 pub tap_onion_key: Option<ll::pk::rsa::PublicKey>,
134 pub proto: tor_protover::Protocols,
136 pub is_dircache: bool,
138 pub is_extrainfo_cache: bool,
140 pub family: Arc<RelayFamily>,
143 family_ids: Vec<RelayFamilyId>,
146 pub platform: Option<RelayPlatform>,
148 pub ipv4_policy: AddrPolicy,
153 pub ipv6_policy: Arc<PortPolicy>,
156}
157
158#[derive(Debug, Clone, PartialEq, Eq)]
160#[non_exhaustive]
161pub enum RelayPlatform {
162 Tor(TorVersion, String),
164 Other(String),
166}
167
168impl std::str::FromStr for RelayPlatform {
169 type Err = Error;
170 fn from_str(args: &str) -> Result<Self> {
171 if args.starts_with("Tor ") {
172 let v: Vec<_> = args.splitn(4, ' ').collect();
173 match &v[..] {
174 ["Tor", ver, "on", p] => Ok(RelayPlatform::Tor(ver.parse()?, (*p).to_string())),
175 ["Tor", ver, ..] => Ok(RelayPlatform::Tor(ver.parse()?, "".to_string())),
176 _ => unreachable!(),
177 }
178 } else {
179 Ok(RelayPlatform::Other(args.to_string()))
180 }
181 }
182}
183
184decl_keyword! {
185 RouterKwd {
188 annotation "@source" => ANN_SOURCE,
189 annotation "@downloaded-at" => ANN_DOWNLOADED_AT,
190 annotation "@purpose" => ANN_PURPOSE,
191 "accept" | "reject" => POLICY,
192 "bandwidth" => BANDWIDTH,
193 "bridge-distribution-request" => BRIDGE_DISTRIBUTION_REQUEST,
194 "caches-extra-info" => CACHES_EXTRA_INFO,
195 "contact" => CONTACT,
196 "extra-info-digest" => EXTRA_INFO_DIGEST,
197 "family" => FAMILY,
198 "family-cert" => FAMILY_CERT,
199 "fingerprint" => FINGERPRINT,
200 "hibernating" => HIBERNATING,
201 "identity-ed25519" => IDENTITY_ED25519,
202 "ipv6-policy" => IPV6_POLICY,
203 "master-key-ed25519" => MASTER_KEY_ED25519,
204 "ntor-onion-key" => NTOR_ONION_KEY,
205 "ntor-onion-key-crosscert" => NTOR_ONION_KEY_CROSSCERT,
206 "onion-key" => ONION_KEY,
207 "onion-key-crosscert" => ONION_KEY_CROSSCERT,
208 "or-address" => OR_ADDRESS,
209 "platform" => PLATFORM,
210 "proto" => PROTO,
211 "published" => PUBLISHED,
212 "router" => ROUTER,
213 "router-sig-ed25519" => ROUTER_SIG_ED25519,
214 "router-signature" => ROUTER_SIGNATURE,
215 "signing-key" => SIGNING_KEY,
216 "tunnelled_dir_server" => TUNNELLED_DIR_SERVER,
217 "uptime" => UPTIME,
218 }
222}
223
224static ROUTER_ANNOTATIONS: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
226 use RouterKwd::*;
227
228 let mut rules = SectionRules::builder();
229 rules.add(ANN_SOURCE.rule());
230 rules.add(ANN_DOWNLOADED_AT.rule().args(1..));
231 rules.add(ANN_PURPOSE.rule().args(1..));
232 rules.add(ANN_UNRECOGNIZED.rule().may_repeat().obj_optional());
233 rules.reject_unrecognized();
236 rules.build()
237});
238static ROUTER_HEADER_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
241 use RouterKwd::*;
242
243 let mut rules = SectionRules::builder();
244 rules.add(ROUTER.rule().required().args(5..));
245 rules.add(IDENTITY_ED25519.rule().required().no_args().obj_required());
246 rules.reject_unrecognized();
248 rules.build()
249});
250static ROUTER_BODY_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
253 use RouterKwd::*;
254
255 let mut rules = SectionRules::builder();
256 rules.add(MASTER_KEY_ED25519.rule().required().args(1..));
257 rules.add(PLATFORM.rule());
258 rules.add(PUBLISHED.rule().required());
259 rules.add(FINGERPRINT.rule());
260 rules.add(UPTIME.rule().args(1..));
261 rules.add(ONION_KEY.rule().no_args().obj_required());
262 rules.add(ONION_KEY_CROSSCERT.rule().no_args().obj_required());
263 rules.add(NTOR_ONION_KEY.rule().required().args(1..));
264 rules.add(
265 NTOR_ONION_KEY_CROSSCERT
266 .rule()
267 .required()
268 .args(1..=1)
269 .obj_required(),
270 );
271 rules.add(SIGNING_KEY.rule().no_args().required().obj_required());
272 rules.add(POLICY.rule().may_repeat().args(1..));
273 rules.add(IPV6_POLICY.rule().args(2..));
274 rules.add(FAMILY.rule().args(1..));
275 rules.add(FAMILY_CERT.rule().obj_required().may_repeat());
276 rules.add(CACHES_EXTRA_INFO.rule().no_args());
277 rules.add(OR_ADDRESS.rule().may_repeat().args(1..));
278 rules.add(TUNNELLED_DIR_SERVER.rule());
279 rules.add(PROTO.rule().required().args(1..));
280 rules.add(UNRECOGNIZED.rule().may_repeat().obj_optional());
281 {
283 rules.add(BANDWIDTH.rule().required().args(3..));
284 rules.add(BRIDGE_DISTRIBUTION_REQUEST.rule().args(1..));
285 rules.add(HIBERNATING.rule().args(1..));
286 rules.add(CONTACT.rule());
287 }
288 {
290 rules.add(EXTRA_INFO_DIGEST.rule().args(1..));
291 }
292 rules.build()
293});
294
295static ROUTER_SIG_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
297 use RouterKwd::*;
298
299 let mut rules = SectionRules::builder();
300 rules.add(ROUTER_SIG_ED25519.rule().required().args(1..));
301 rules.add(ROUTER_SIGNATURE.rule().required().no_args().obj_required());
302 rules.reject_unrecognized();
304 rules.build()
305});
306
307impl RouterAnnotation {
308 fn take_from_reader(reader: &mut NetDocReader<'_, RouterKwd>) -> Result<RouterAnnotation> {
310 use RouterKwd::*;
311 let mut items = reader.pause_at(|item| item.is_ok_with_non_annotation());
312
313 let body = ROUTER_ANNOTATIONS.parse(&mut items)?;
314
315 let source = body.maybe(ANN_SOURCE).args_as_str().map(String::from);
316 let purpose = body.maybe(ANN_PURPOSE).args_as_str().map(String::from);
317 let downloaded = body
318 .maybe(ANN_DOWNLOADED_AT)
319 .parse_args_as_str::<Iso8601TimeSp>()?
320 .map(|t| t.into());
321 Ok(RouterAnnotation {
322 source,
323 downloaded,
324 purpose,
325 })
326 }
327}
328
329pub type UncheckedRouterDesc = signed::SignatureGated<timed::TimerangeBound<RouterDesc>>;
332
333const ROUTER_EXPIRY_SECONDS: u64 = 5 * 86400;
336
337const ROUTER_PRE_VALIDITY_SECONDS: u64 = 86400;
343
344impl RouterDesc {
345 pub fn rsa_identity(&self) -> &RsaIdentity {
347 &self.rsa_identity
348 }
349
350 pub fn ed_identity(&self) -> &Ed25519Identity {
352 self.identity_cert
353 .signing_key()
354 .expect("No ed25519 identity key on identity cert")
355 }
356
357 pub fn protocols(&self) -> &tor_protover::Protocols {
360 &self.proto
361 }
362
363 pub fn ntor_onion_key(&self) -> &ll::pk::curve25519::PublicKey {
365 &self.ntor_onion_key
366 }
367
368 pub fn published(&self) -> time::SystemTime {
370 self.published
371 }
372
373 pub fn or_ports(&self) -> impl Iterator<Item = net::SocketAddr> + '_ {
376 self.ipv4addr
377 .map(|a| net::SocketAddr::new(a.into(), self.orport))
378 .into_iter()
379 .chain(self.ipv6addr.map(net::SocketAddr::from))
380 }
381
382 pub fn family(&self) -> Arc<RelayFamily> {
384 Arc::clone(&self.family)
385 }
386
387 pub fn family_ids(&self) -> &[RelayFamilyId] {
389 &self.family_ids[..]
390 }
391
392 fn parse_sections<'a>(
394 reader: &mut NetDocReader<'a, RouterKwd>,
395 ) -> Result<(
396 Section<'a, RouterKwd>,
397 Section<'a, RouterKwd>,
398 Section<'a, RouterKwd>,
399 )> {
400 use RouterKwd::*;
401
402 let header = ROUTER_HEADER_RULES.parse(
404 reader.pause_at(|item| item.is_ok_with_kwd_not_in(&[ROUTER, IDENTITY_ED25519])),
405 )?;
406
407 let body =
409 ROUTER_BODY_RULES.parse(reader.pause_at(|item| {
410 item.is_ok_with_kwd_in(&[ROUTER_SIGNATURE, ROUTER_SIG_ED25519])
411 }))?;
412
413 let sig = ROUTER_SIG_RULES.parse(reader.pause_at(|item| {
415 item.is_ok_with_annotation() || item.is_ok_with_kwd(ROUTER) || item.is_empty_line()
416 }))?;
417
418 Ok((header, body, sig))
419 }
420
421 pub fn parse(s: &str) -> Result<UncheckedRouterDesc> {
426 let mut reader = crate::parse::tokenize::NetDocReader::new(s)?;
427 let result = Self::parse_internal(&mut reader).map_err(|e| e.within(s))?;
428 reader
431 .should_be_exhausted_but_for_empty_lines()
432 .map_err(|e| e.within(s))?;
433 Ok(result)
434 }
435
436 fn parse_internal(r: &mut NetDocReader<'_, RouterKwd>) -> Result<UncheckedRouterDesc> {
442 use RouterKwd::*;
445
446 let s = r.str();
447 let (header, body, sig) = RouterDesc::parse_sections(r)?;
448
449 #[allow(clippy::unwrap_used)]
452 let start_offset = header.required(ROUTER)?.offset_in(s).unwrap();
453
454 let (identity_cert, ed25519_signing_key) = {
456 let cert_tok = header.required(IDENTITY_ED25519)?;
457 #[allow(clippy::unwrap_used)]
460 if cert_tok.offset_in(s).unwrap() < start_offset {
461 return Err(EK::MisplacedToken
462 .with_msg("identity-ed25519")
463 .at_pos(cert_tok.pos()));
464 }
465 let cert: tor_cert::UncheckedCert = cert_tok
466 .parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
467 .check_cert_type(tor_cert::CertType::IDENTITY_V_SIGNING)?
468 .into_unchecked()
469 .should_have_signing_key()
470 .map_err(|err| {
471 EK::BadObjectVal
472 .err()
473 .with_source(err)
474 .at_pos(cert_tok.pos())
475 })?;
476 let sk = *cert.peek_subject_key().as_ed25519().ok_or_else(|| {
477 EK::BadObjectVal
478 .at_pos(cert_tok.pos())
479 .with_msg("wrong type for signing key in cert")
480 })?;
481 let sk: ll::pk::ed25519::PublicKey = sk.try_into().map_err(|_| {
482 EK::BadObjectVal
483 .at_pos(cert_tok.pos())
484 .with_msg("invalid ed25519 signing key")
485 })?;
486 (cert, sk)
487 };
488
489 #[allow(unexpected_cfgs)]
491 {
492 let master_key_tok = body.required(MASTER_KEY_ED25519)?;
493 let ed_id: Ed25519Public = master_key_tok.parse_arg(0)?;
494 let ed_id: ll::pk::ed25519::Ed25519Identity = ed_id.into();
495 if ed_id != *identity_cert.peek_signing_key() {
496 #[cfg(not(fuzzing))] return Err(EK::BadObjectVal
498 .at_pos(master_key_tok.pos())
499 .with_msg("master-key-ed25519 does not match key in identity-ed25519"));
500 }
501 }
502
503 let rsa_identity_key: ll::pk::rsa::PublicKey = body
505 .required(SIGNING_KEY)?
506 .parse_obj::<RsaPublicParse1Helper>("RSA PUBLIC KEY")?
507 .check_len_eq(1024)?
508 .check_exponent(65537)?
509 .into();
510 let rsa_identity = rsa_identity_key.to_rsa_identity();
511
512 let ed_sig = sig.required(ROUTER_SIG_ED25519)?;
513 let rsa_sig = sig.required(ROUTER_SIGNATURE)?;
514 #[allow(clippy::unwrap_used)]
517 let ed_sig_pos = ed_sig.offset_in(s).unwrap();
518 #[allow(clippy::unwrap_used)]
519 let rsa_sig_pos = rsa_sig.offset_in(s).unwrap();
520
521 if ed_sig_pos > rsa_sig_pos {
522 return Err(EK::UnexpectedToken
523 .with_msg(ROUTER_SIG_ED25519.to_str())
524 .at_pos(ed_sig.pos()));
525 }
526
527 let ed_signature: ll::pk::ed25519::ValidatableEd25519Signature = {
529 let mut d = ll::d::Sha256::new();
530 d.update(&b"Tor router descriptor signature v1"[..]);
531 let signed_end = ed_sig_pos + b"router-sig-ed25519 ".len();
532 d.update(&s[start_offset..signed_end]);
533 let d = d.finalize();
534 let sig: [u8; 64] = ed_sig
535 .parse_arg::<B64>(0)?
536 .into_array()
537 .map_err(|_| EK::BadSignature.at_pos(ed_sig.pos()))?;
538 let sig = ll::pk::ed25519::Signature::from(sig);
539 ll::pk::ed25519::ValidatableEd25519Signature::new(ed25519_signing_key, sig, &d)
540 };
541
542 let rsa_signature: ll::pk::rsa::ValidatableRsaSignature = {
544 let mut d = ll::d::Sha1::new();
545 let signed_end = rsa_sig_pos + b"router-signature\n".len();
546 d.update(&s[start_offset..signed_end]);
547 let d = d.finalize();
548 let sig = rsa_sig.obj("SIGNATURE")?;
549 ll::pk::rsa::ValidatableRsaSignature::new(&rsa_identity_key, &sig, &d)
552 };
553
554 let (nickname, ipv4addr, orport, dirport) = {
556 let rtrline = header.required(ROUTER)?;
557 (
558 rtrline.parse_arg::<Nickname>(0)?,
559 Some(rtrline.parse_arg::<net::Ipv4Addr>(1)?),
560 rtrline.parse_arg(2)?,
561 rtrline.parse_arg(4)?,
563 )
564 };
565
566 let uptime = body.maybe(UPTIME).parse_arg(0)?;
568
569 let published = body
571 .required(PUBLISHED)?
572 .args_as_str()
573 .parse::<Iso8601TimeSp>()?
574 .into();
575
576 let ntor_onion_key: Curve25519Public = body.required(NTOR_ONION_KEY)?.parse_arg(0)?;
578 let ntor_onion_key: ll::pk::curve25519::PublicKey = ntor_onion_key.into();
579 let crosscert_cert: tor_cert::UncheckedCert = {
581 let cc = body.required(NTOR_ONION_KEY_CROSSCERT)?;
582 let sign: u8 = cc.parse_arg(0)?;
583 if sign != 0 && sign != 1 {
584 return Err(EK::BadArgument.at_pos(cc.arg_pos(0)).with_msg("not 0 or 1"));
585 }
586 let ntor_as_ed: ll::pk::ed25519::PublicKey =
587 ll::pk::keymanip::convert_curve25519_to_ed25519_public(&ntor_onion_key, sign)
588 .ok_or_else(|| {
589 EK::BadArgument
590 .at_pos(cc.pos())
591 .with_msg("Uncheckable crosscert")
592 })?;
593
594 cc.parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
595 .check_cert_type(tor_cert::CertType::NTOR_CC_IDENTITY)?
596 .check_subject_key_is(identity_cert.peek_signing_key())?
597 .into_unchecked()
598 .should_be_signed_with(&ntor_as_ed.into())
599 .map_err(|err| EK::BadSignature.err().with_source(err))?
600 };
601
602 let tap_onion_key: Option<ll::pk::rsa::PublicKey> = if let Some(tok) = body.get(ONION_KEY) {
604 Some(
605 tok.parse_obj::<RsaPublicParse1Helper>("RSA PUBLIC KEY")?
606 .check_len_eq(1024)?
607 .check_exponent(65537)?
608 .into(),
609 )
610 } else {
611 None
612 };
613
614 let tap_crosscert_sig = if let Some(cc_tok) = body.get(ONION_KEY_CROSSCERT) {
616 let cc_val = cc_tok.obj("CROSSCERT")?;
617 let mut signed = Vec::new();
618 signed.extend(rsa_identity.as_bytes());
619 signed.extend(identity_cert.peek_signing_key().as_bytes());
620 Some(ll::pk::rsa::ValidatableRsaSignature::new(
621 tap_onion_key.as_ref().ok_or_else(|| {
622 EK::MissingToken.with_msg("onion-key-crosscert without onion-key")
623 })?,
624 &cc_val,
625 &signed,
626 ))
627 } else if tap_onion_key.is_some() {
628 return Err(EK::MissingToken.with_msg("onion-key without onion-key-crosscert"));
629 } else {
630 None
631 };
632
633 let proto = {
635 let proto_tok = body.required(PROTO)?;
636 proto_tok
637 .args_as_str()
638 .parse::<tor_protover::Protocols>()
639 .map_err(|e| EK::BadArgument.at_pos(proto_tok.pos()).with_source(e))?
640 };
641
642 let is_dircache = (dirport != 0) || body.get(TUNNELLED_DIR_SERVER).is_some();
644
645 let is_extrainfo_cache = body.get(CACHES_EXTRA_INFO).is_some();
647
648 if let Some(fp_tok) = body.get(FINGERPRINT) {
650 let fp: RsaIdentity = fp_tok.args_as_str().parse::<SpFingerprint>()?.into();
651 if fp != rsa_identity {
652 return Err(EK::BadArgument
653 .at_pos(fp_tok.pos())
654 .with_msg("fingerprint does not match RSA identity"));
655 }
656 }
657
658 let family = {
660 let mut family = body
661 .maybe(FAMILY)
662 .parse_args_as_str::<RelayFamily>()?
663 .unwrap_or_else(RelayFamily::new);
664 if !family.is_empty() {
665 family.push(rsa_identity);
671 }
672 family.intern()
673 };
674
675 let family_certs: Vec<tor_cert::UncheckedCert> = body
677 .slice(FAMILY_CERT)
678 .iter()
679 .map(|ent| {
680 ent.parse_obj::<UnvalidatedEdCert>("FAMILY CERT")?
681 .check_cert_type(CertType::FAMILY_V_IDENTITY)?
682 .check_subject_key_is(identity_cert.peek_signing_key())?
683 .into_unchecked()
684 .should_have_signing_key()
685 .map_err(|e| {
686 EK::BadObjectVal
687 .with_msg("missing public key")
688 .at_pos(ent.pos())
689 .with_source(e)
690 })
691 })
692 .collect::<Result<_>>()?;
693
694 let mut family_ids: Vec<_> = family_certs
695 .iter()
696 .map(|cert| RelayFamilyId::Ed25519(*cert.peek_signing_key()))
697 .collect();
698 family_ids.sort();
699 family_ids.dedup();
700
701 let mut ipv6addr = None;
705 for tok in body.slice(OR_ADDRESS) {
706 if let Ok(net::SocketAddr::V6(a)) = tok.parse_arg::<net::SocketAddr>(0) {
707 ipv6addr = Some((*a.ip(), a.port()));
708 break;
709 }
710 }
712
713 let platform = body.maybe(PLATFORM).parse_args_as_str::<RelayPlatform>()?;
715
716 let ipv4_policy = {
718 let mut pol = AddrPolicy::new();
719 for ruletok in body.slice(POLICY).iter() {
720 let accept = match ruletok.kwd_str() {
721 "accept" => RuleKind::Accept,
722 "reject" => RuleKind::Reject,
723 _ => {
724 return Err(Error::from(internal!(
725 "tried to parse a strange line as a policy"
726 ))
727 .at_pos(ruletok.pos()));
728 }
729 };
730 let pat: AddrPortPattern = ruletok
731 .args_as_str()
732 .parse()
733 .map_err(|e| EK::BadPolicy.at_pos(ruletok.pos()).with_source(e))?;
734 pol.push(accept, pat);
735 }
736 pol
737 };
738
739 let ipv6_policy = match body.get(IPV6_POLICY) {
741 Some(p) => p
742 .args_as_str()
743 .parse()
744 .map_err(|e| EK::BadPolicy.at_pos(p.pos()).with_source(e))?,
745 #[allow(clippy::unwrap_used)]
747 None => "reject 1-65535".parse::<PortPolicy>().unwrap(),
748 };
749
750 let (identity_cert, identity_sig) = identity_cert.dangerously_split().map_err(|err| {
752 EK::BadObjectVal
753 .with_msg("missing public key")
754 .with_source(err)
755 })?;
756 let (crosscert_cert, cc_sig) = crosscert_cert.dangerously_split().map_err(|err| {
757 EK::BadObjectVal
758 .with_msg("missing public key")
759 .with_source(err)
760 })?;
761 let mut signatures: Vec<Box<dyn ll::pk::ValidatableSignature>> = vec![
762 Box::new(rsa_signature),
763 Box::new(ed_signature),
764 Box::new(identity_sig),
765 Box::new(cc_sig),
766 ];
767 if let Some(s) = tap_crosscert_sig {
768 signatures.push(Box::new(s));
769 }
770
771 let identity_cert = identity_cert.dangerously_assume_timely();
772 let crosscert_cert = crosscert_cert.dangerously_assume_timely();
773 let mut expirations = vec![
774 published + time::Duration::new(ROUTER_EXPIRY_SECONDS, 0),
775 identity_cert.expiry(),
776 crosscert_cert.expiry(),
777 ];
778
779 for cert in family_certs {
780 let (inner, sig) = cert.dangerously_split().map_err(into_internal!(
781 "Missing a public key that was previously there."
782 ))?;
783 signatures.push(Box::new(sig));
784 expirations.push(inner.dangerously_assume_timely().expiry());
785 }
786
787 #[allow(clippy::unwrap_used)]
789 let expiry = *expirations.iter().min().unwrap();
790
791 let start_time = published - time::Duration::new(ROUTER_PRE_VALIDITY_SECONDS, 0);
792
793 let desc = RouterDesc {
794 nickname,
795 ipv4addr,
796 orport,
797 ipv6addr,
798 dirport,
799 uptime,
800 published,
801 identity_cert,
802 rsa_identity_key,
803 rsa_identity,
804 ntor_onion_key,
805 tap_onion_key,
806 proto,
807 is_dircache,
808 is_extrainfo_cache,
809 family,
810 family_ids,
811 platform,
812 ipv4_policy,
813 ipv6_policy: ipv6_policy.intern(),
814 };
815
816 let time_gated = timed::TimerangeBound::new(desc, start_time..expiry);
817 let sig_gated = signed::SignatureGated::new(time_gated, signatures);
818
819 Ok(sig_gated)
820 }
821}
822
823pub struct RouterReader<'a> {
829 annotated: bool,
831 reader: NetDocReader<'a, RouterKwd>,
833}
834
835fn advance_to_next_routerdesc(reader: &mut NetDocReader<'_, RouterKwd>, annotated: bool) {
840 use RouterKwd::*;
841 loop {
842 let item = reader.peek();
843 match item {
844 Some(Ok(t)) => {
845 let kwd = t.kwd();
846 if (annotated && kwd.is_annotation()) || kwd == ROUTER {
847 return;
848 }
849 }
850 Some(Err(_)) => {
851 }
853 None => {
854 return;
855 }
856 }
857 let _ = reader.next();
858 }
859}
860
861impl<'a> RouterReader<'a> {
862 pub fn new(s: &'a str, allow: &AllowAnnotations) -> Result<Self> {
864 let reader = NetDocReader::new(s)?;
865 let annotated = allow == &AllowAnnotations::AnnotationsAllowed;
866 Ok(RouterReader { annotated, reader })
867 }
868
869 fn take_annotation(&mut self) -> Result<RouterAnnotation> {
871 if self.annotated {
872 RouterAnnotation::take_from_reader(&mut self.reader)
873 } else {
874 Ok(RouterAnnotation::default())
875 }
876 }
877
878 fn take_annotated_routerdesc_raw(&mut self) -> Result<AnnotatedRouterDesc> {
882 let ann = self.take_annotation()?;
883 let router = RouterDesc::parse_internal(&mut self.reader)?;
884 Ok(AnnotatedRouterDesc { ann, router })
885 }
886
887 fn take_annotated_routerdesc(&mut self) -> Result<AnnotatedRouterDesc> {
891 let pos_orig = self.reader.pos();
892 let result = self.take_annotated_routerdesc_raw();
893 if result.is_err() {
894 if self.reader.pos() == pos_orig {
895 let _ = self.reader.next();
903 }
904 advance_to_next_routerdesc(&mut self.reader, self.annotated);
905 }
906 result
907 }
908}
909
910impl<'a> Iterator for RouterReader<'a> {
911 type Item = Result<AnnotatedRouterDesc>;
912 fn next(&mut self) -> Option<Self::Item> {
913 self.reader.peek()?;
915
916 Some(
917 self.take_annotated_routerdesc()
918 .map_err(|e| e.within(self.reader.str())),
919 )
920 }
921}
922
923#[cfg(test)]
924mod test {
925 #![allow(clippy::bool_assert_comparison)]
927 #![allow(clippy::clone_on_copy)]
928 #![allow(clippy::dbg_macro)]
929 #![allow(clippy::mixed_attributes_style)]
930 #![allow(clippy::print_stderr)]
931 #![allow(clippy::print_stdout)]
932 #![allow(clippy::single_char_pattern)]
933 #![allow(clippy::unwrap_used)]
934 #![allow(clippy::unchecked_time_subtraction)]
935 #![allow(clippy::useless_vec)]
936 #![allow(clippy::needless_pass_by_value)]
937 use super::*;
939 const TESTDATA: &str = include_str!("../../testdata/routerdesc1.txt");
940 const TESTDATA2: &str = include_str!("../../testdata/routerdesc2.txt");
941 const TESTDATA3: &str = include_str!("../../testdata/routerdesc3.txt");
943
944 fn read_bad(fname: &str) -> String {
945 use std::fs;
946 use std::path::PathBuf;
947 let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
948 path.push("testdata");
949 path.push("bad-routerdesc");
950 path.push(fname);
951
952 fs::read_to_string(path).unwrap()
953 }
954
955 #[test]
956 fn parse_arbitrary() -> Result<()> {
957 use std::str::FromStr;
958 use tor_checkable::{SelfSigned, Timebound};
959 let rd = RouterDesc::parse(TESTDATA)?
960 .check_signature()?
961 .dangerously_assume_timely();
962
963 assert_eq!(rd.nickname.as_str(), "Akka");
964 assert_eq!(rd.orport, 443);
965 assert_eq!(rd.dirport, 0);
966 assert_eq!(rd.uptime, Some(1036923));
967 assert_eq!(
968 rd.family.as_ref(),
969 &RelayFamily::from_str(
970 "$303509ab910ef207b7438c27435c4a2fd579f1b1 \
971 $56927e61b51e6f363fb55498150a6ddfcf7077f2"
972 )
973 .unwrap()
974 );
975
976 assert_eq!(
977 rd.rsa_identity().to_string(),
978 "$56927e61b51e6f363fb55498150a6ddfcf7077f2"
979 );
980 assert_eq!(
981 rd.ed_identity().to_string(),
982 "CVTjf1oeaL616hH+1+UvYZ8OgkwF3z7UMITvJzm5r7A"
983 );
984 assert_eq!(
985 rd.protocols().to_string(),
986 "Cons=1-2 Desc=1-2 DirCache=2 FlowCtrl=1-2 HSDir=2 \
987 HSIntro=4-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 \
988 Padding=2 Relay=1-4"
989 );
990
991 assert_eq!(
992 hex::encode(rd.ntor_onion_key().to_bytes()),
993 "329b3b52991613392e35d1a821dd6753e1210458ecc3337f7b7d39bfcf5da273"
994 );
995 assert_eq!(
996 rd.published(),
997 humantime::parse_rfc3339("2022-11-14T19:58:52Z").unwrap()
998 );
999 assert_eq!(
1000 rd.or_ports().collect::<Vec<_>>(),
1001 vec![
1002 "95.216.33.58:443".parse().unwrap(),
1003 "[2a01:4f9:2a:2145::2]:443".parse().unwrap(),
1004 ]
1005 );
1006 assert!(rd.tap_onion_key.is_some());
1007
1008 Ok(())
1009 }
1010
1011 #[test]
1012 fn parse_no_tap_key() -> Result<()> {
1013 use tor_checkable::{SelfSigned, Timebound};
1014 let rd = RouterDesc::parse(TESTDATA2)?
1015 .check_signature()?
1016 .dangerously_assume_timely();
1017 assert!(rd.tap_onion_key.is_none());
1018
1019 Ok(())
1020 }
1021
1022 #[test]
1023 fn test_bad() {
1024 use crate::Pos;
1025 use crate::types::policy::PolicyError;
1026 fn check(fname: &str, e: &Error) {
1027 let text = read_bad(fname);
1028 let rd = RouterDesc::parse(&text);
1029 assert!(rd.is_err());
1030 assert_eq!(&rd.err().unwrap(), e);
1031 }
1032
1033 check(
1034 "bad-sig-order",
1035 &EK::UnexpectedToken
1036 .with_msg("router-sig-ed25519")
1037 .at_pos(Pos::from_line(50, 1)),
1038 );
1039 check(
1040 "bad-start1",
1041 &EK::MisplacedToken
1042 .with_msg("identity-ed25519")
1043 .at_pos(Pos::from_line(1, 1)),
1044 );
1045 check("bad-start2", &EK::MissingToken.with_msg("identity-ed25519"));
1046 check(
1047 "mismatched-fp",
1048 &EK::BadArgument
1049 .at_pos(Pos::from_line(12, 1))
1050 .with_msg("fingerprint does not match RSA identity"),
1051 );
1052 check("no-ed-sk", &EK::MissingToken.with_msg("identity-ed25519"));
1053
1054 check(
1055 "bad-cc-sign",
1056 &EK::BadArgument
1057 .at_pos(Pos::from_line(34, 26))
1058 .with_msg("not 0 or 1"),
1059 );
1060 check(
1061 "bad-ipv6policy",
1062 &EK::BadPolicy
1063 .at_pos(Pos::from_line(43, 1))
1064 .with_source(PolicyError::InvalidPolicy),
1065 );
1066 check(
1067 "no-ed-id-key-in-cert",
1068 &EK::BadObjectVal
1069 .at_pos(Pos::from_line(2, 1))
1070 .with_source(tor_cert::CertError::MissingPubKey),
1071 );
1072 check(
1073 "non-ed-sk-in-cert",
1074 &EK::BadObjectVal
1075 .at_pos(Pos::from_line(2, 1))
1076 .with_msg("wrong type for signing key in cert"),
1077 );
1078 check(
1079 "bad-ed-sk-in-cert",
1080 &EK::BadObjectVal
1081 .at_pos(Pos::from_line(2, 1))
1082 .with_msg("invalid ed25519 signing key"),
1083 );
1084 check(
1085 "mismatched-ed-sk-in-cert",
1086 &EK::BadObjectVal
1087 .at_pos(Pos::from_line(8, 1))
1088 .with_msg("master-key-ed25519 does not match key in identity-ed25519"),
1089 );
1090 }
1091
1092 #[test]
1093 fn parse_multiple_annotated() {
1094 use crate::AllowAnnotations;
1095 let mut s = read_bad("bad-cc-sign");
1096 s += "\
1097@uploaded-at 2020-09-26 18:15:41
1098@source \"127.0.0.1\"
1099";
1100 s += TESTDATA;
1101 s += "\
1102@uploaded-at 2020-09-26 18:15:41
1103@source \"127.0.0.1\"
1104";
1105 s += &read_bad("mismatched-fp");
1106
1107 let rd = RouterReader::new(&s, &AllowAnnotations::AnnotationsAllowed).unwrap();
1108 let v: Vec<_> = rd.collect();
1109 assert!(v[0].is_err());
1110 assert!(v[1].is_ok());
1111 assert_eq!(
1112 v[1].as_ref().unwrap().ann.source,
1113 Some("\"127.0.0.1\"".to_string())
1114 );
1115 assert!(v[2].is_err());
1116 }
1117
1118 #[test]
1119 fn test_platform() {
1120 let p = "Tor 0.4.4.4-alpha on a flying bison".parse::<RelayPlatform>();
1121 assert!(p.is_ok());
1122 assert_eq!(
1123 p.unwrap(),
1124 RelayPlatform::Tor(
1125 "0.4.4.4-alpha".parse().unwrap(),
1126 "a flying bison".to_string()
1127 )
1128 );
1129
1130 let p = "Tor 0.4.4.4-alpha on".parse::<RelayPlatform>();
1131 assert!(p.is_ok());
1132
1133 let p = "Tor 0.4.4.4-alpha ".parse::<RelayPlatform>();
1134 assert!(p.is_ok());
1135 let p = "Tor 0.4.4.4-alpha".parse::<RelayPlatform>();
1136 assert!(p.is_ok());
1137
1138 let p = "arti 0.0.0".parse::<RelayPlatform>();
1139 assert!(p.is_ok());
1140 assert_eq!(p.unwrap(), RelayPlatform::Other("arti 0.0.0".to_string()));
1141 }
1142
1143 #[test]
1144 fn test_family_ids() -> Result<()> {
1145 use tor_checkable::{SelfSigned, Timebound};
1146 let rd = RouterDesc::parse(TESTDATA3)?
1147 .check_signature()?
1148 .dangerously_assume_timely();
1149
1150 assert_eq!(
1151 rd.family_ids(),
1152 &[
1153 "ed25519:7sToQRuge1bU2hS0CG0ViMndc4m82JhO4B4kdrQey80"
1154 .parse()
1155 .unwrap(),
1156 "ed25519:szHUS3ItRd9uk85b1UVnOZx1gg4B0266jCpbuIMNjcM"
1157 .parse()
1158 .unwrap(),
1159 ]
1160 );
1161
1162 Ok(())
1163 }
1164}