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, NetdocErrorKind as EK, Result, doc};
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#[allow(dead_code)]
65#[cfg_attr(
66 feature = "dangerous-expose-struct-fields",
67 visible::StructFields(pub),
68 non_exhaustive
69)]
70pub struct AnnotatedRouterDesc {
71 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
73 ann: RouterAnnotation,
74 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
76 router: UncheckedRouterDesc,
77}
78
79#[allow(dead_code)] #[cfg_attr(
82 feature = "dangerous-expose-struct-fields",
83 visible::StructFields(pub),
84 non_exhaustive
85)]
86#[derive(Default)]
87pub struct RouterAnnotation {
88 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
90 source: Option<String>,
91 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
93 downloaded: Option<time::SystemTime>,
94 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
96 purpose: Option<String>,
97}
98
99#[allow(dead_code)] #[cfg_attr(
114 feature = "dangerous-expose-struct-fields",
115 visible::StructFields(pub),
116 non_exhaustive
117)]
118#[derive(Clone, Debug)]
119pub struct RouterDesc {
120 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
124 nickname: Nickname,
125 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
127 ipv4addr: Option<net::Ipv4Addr>,
128 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
130 orport: u16,
131 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
136 ipv6addr: Option<(net::Ipv6Addr, u16)>,
137 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
140 dirport: u16,
141 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
143 uptime: Option<u64>,
144 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
146 published: time::SystemTime,
147 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
150 identity_cert: tor_cert::Ed25519Cert,
151 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
154 rsa_identity_key: ll::pk::rsa::PublicKey,
155 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
158 rsa_identity: ll::pk::rsa::RsaIdentity,
159 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
161 ntor_onion_key: ll::pk::curve25519::PublicKey,
162 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
165 tap_onion_key: Option<ll::pk::rsa::PublicKey>,
166 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
168 proto: Arc<tor_protover::Protocols>,
169 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
171 is_dircache: bool,
172 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
174 is_extrainfo_cache: bool,
175 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
178 family: Arc<RelayFamily>,
179 family_ids: Vec<RelayFamilyId>,
182 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
184 platform: Option<RelayPlatform>,
185 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
190 ipv4_policy: AddrPolicy,
191 #[cfg_attr(docsrs, doc(cfg(feature = "dangerous-expose-struct-fields")))]
194 ipv6_policy: Arc<PortPolicy>,
195}
196
197#[derive(Debug, Clone, PartialEq, Eq)]
199#[non_exhaustive]
200pub enum RelayPlatform {
201 Tor(TorVersion, String),
203 Other(String),
205}
206
207impl std::str::FromStr for RelayPlatform {
208 type Err = Error;
209 fn from_str(args: &str) -> Result<Self> {
210 if args.starts_with("Tor ") {
211 let v: Vec<_> = args.splitn(4, ' ').collect();
212 match &v[..] {
213 ["Tor", ver, "on", p] => Ok(RelayPlatform::Tor(ver.parse()?, (*p).to_string())),
214 ["Tor", ver, ..] => Ok(RelayPlatform::Tor(ver.parse()?, "".to_string())),
215 _ => unreachable!(),
216 }
217 } else {
218 Ok(RelayPlatform::Other(args.to_string()))
219 }
220 }
221}
222
223decl_keyword! {
224 RouterKwd {
227 annotation "@source" => ANN_SOURCE,
228 annotation "@downloaded-at" => ANN_DOWNLOADED_AT,
229 annotation "@purpose" => ANN_PURPOSE,
230 "accept" | "reject" => POLICY,
231 "bandwidth" => BANDWIDTH,
232 "bridge-distribution-request" => BRIDGE_DISTRIBUTION_REQUEST,
233 "caches-extra-info" => CACHES_EXTRA_INFO,
234 "contact" => CONTACT,
235 "extra-info-digest" => EXTRA_INFO_DIGEST,
236 "family" => FAMILY,
237 "family-cert" => FAMILY_CERT,
238 "fingerprint" => FINGERPRINT,
239 "hibernating" => HIBERNATING,
240 "identity-ed25519" => IDENTITY_ED25519,
241 "ipv6-policy" => IPV6_POLICY,
242 "master-key-ed25519" => MASTER_KEY_ED25519,
243 "ntor-onion-key" => NTOR_ONION_KEY,
244 "ntor-onion-key-crosscert" => NTOR_ONION_KEY_CROSSCERT,
245 "onion-key" => ONION_KEY,
246 "onion-key-crosscert" => ONION_KEY_CROSSCERT,
247 "or-address" => OR_ADDRESS,
248 "platform" => PLATFORM,
249 "proto" => PROTO,
250 "published" => PUBLISHED,
251 "router" => ROUTER,
252 "router-sig-ed25519" => ROUTER_SIG_ED25519,
253 "router-signature" => ROUTER_SIGNATURE,
254 "signing-key" => SIGNING_KEY,
255 "tunnelled_dir_server" => TUNNELLED_DIR_SERVER,
256 "uptime" => UPTIME,
257 }
261}
262
263static ROUTER_ANNOTATIONS: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
265 use RouterKwd::*;
266
267 let mut rules = SectionRules::builder();
268 rules.add(ANN_SOURCE.rule());
269 rules.add(ANN_DOWNLOADED_AT.rule().args(1..));
270 rules.add(ANN_PURPOSE.rule().args(1..));
271 rules.add(ANN_UNRECOGNIZED.rule().may_repeat().obj_optional());
272 rules.reject_unrecognized();
275 rules.build()
276});
277static ROUTER_HEADER_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
280 use RouterKwd::*;
281
282 let mut rules = SectionRules::builder();
283 rules.add(ROUTER.rule().required().args(5..));
284 rules.add(IDENTITY_ED25519.rule().required().no_args().obj_required());
285 rules.reject_unrecognized();
287 rules.build()
288});
289static ROUTER_BODY_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
292 use RouterKwd::*;
293
294 let mut rules = SectionRules::builder();
295 rules.add(MASTER_KEY_ED25519.rule().required().args(1..));
296 rules.add(PLATFORM.rule());
297 rules.add(PUBLISHED.rule().required());
298 rules.add(FINGERPRINT.rule());
299 rules.add(UPTIME.rule().args(1..));
300 rules.add(ONION_KEY.rule().no_args().obj_required());
301 rules.add(ONION_KEY_CROSSCERT.rule().no_args().obj_required());
302 rules.add(NTOR_ONION_KEY.rule().required().args(1..));
303 rules.add(
304 NTOR_ONION_KEY_CROSSCERT
305 .rule()
306 .required()
307 .args(1..=1)
308 .obj_required(),
309 );
310 rules.add(SIGNING_KEY.rule().no_args().required().obj_required());
311 rules.add(POLICY.rule().may_repeat().args(1..));
312 rules.add(IPV6_POLICY.rule().args(2..));
313 rules.add(FAMILY.rule().args(1..));
314 rules.add(FAMILY_CERT.rule().obj_required().may_repeat());
315 rules.add(CACHES_EXTRA_INFO.rule().no_args());
316 rules.add(OR_ADDRESS.rule().may_repeat().args(1..));
317 rules.add(TUNNELLED_DIR_SERVER.rule());
318 rules.add(PROTO.rule().required().args(1..));
319 rules.add(UNRECOGNIZED.rule().may_repeat().obj_optional());
320 {
322 rules.add(BANDWIDTH.rule().required().args(3..));
323 rules.add(BRIDGE_DISTRIBUTION_REQUEST.rule().args(1..));
324 rules.add(HIBERNATING.rule().args(1..));
325 rules.add(CONTACT.rule());
326 }
327 {
329 rules.add(EXTRA_INFO_DIGEST.rule().args(1..));
330 }
331 rules.build()
332});
333
334static ROUTER_SIG_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
336 use RouterKwd::*;
337
338 let mut rules = SectionRules::builder();
339 rules.add(ROUTER_SIG_ED25519.rule().required().args(1..));
340 rules.add(ROUTER_SIGNATURE.rule().required().no_args().obj_required());
341 rules.reject_unrecognized();
343 rules.build()
344});
345
346impl RouterAnnotation {
347 fn take_from_reader(reader: &mut NetDocReader<'_, RouterKwd>) -> Result<RouterAnnotation> {
349 use RouterKwd::*;
350 let mut items = reader.pause_at(|item| item.is_ok_with_non_annotation());
351
352 let body = ROUTER_ANNOTATIONS.parse(&mut items)?;
353
354 let source = body.maybe(ANN_SOURCE).args_as_str().map(String::from);
355 let purpose = body.maybe(ANN_PURPOSE).args_as_str().map(String::from);
356 let downloaded = body
357 .maybe(ANN_DOWNLOADED_AT)
358 .parse_args_as_str::<Iso8601TimeSp>()?
359 .map(|t| t.into());
360 Ok(RouterAnnotation {
361 source,
362 downloaded,
363 purpose,
364 })
365 }
366}
367
368pub type UncheckedRouterDesc = signed::SignatureGated<timed::TimerangeBound<RouterDesc>>;
371
372const ROUTER_EXPIRY_SECONDS: u64 = 5 * 86400;
375
376const ROUTER_PRE_VALIDITY_SECONDS: u64 = 86400;
382
383impl RouterDesc {
384 pub fn rsa_identity(&self) -> &RsaIdentity {
386 &self.rsa_identity
387 }
388
389 pub fn ed_identity(&self) -> &Ed25519Identity {
391 self.identity_cert
392 .signing_key()
393 .expect("No ed25519 identity key on identity cert")
394 }
395
396 pub fn protocols(&self) -> &tor_protover::Protocols {
399 self.proto.as_ref()
400 }
401
402 pub fn ntor_onion_key(&self) -> &ll::pk::curve25519::PublicKey {
404 &self.ntor_onion_key
405 }
406
407 pub fn published(&self) -> time::SystemTime {
409 self.published
410 }
411
412 pub fn or_ports(&self) -> impl Iterator<Item = net::SocketAddr> + '_ {
415 self.ipv4addr
416 .map(|a| net::SocketAddr::new(a.into(), self.orport))
417 .into_iter()
418 .chain(self.ipv6addr.map(net::SocketAddr::from))
419 }
420
421 pub fn family(&self) -> Arc<RelayFamily> {
423 Arc::clone(&self.family)
424 }
425
426 pub fn family_ids(&self) -> &[RelayFamilyId] {
428 &self.family_ids[..]
429 }
430
431 fn parse_sections<'a>(
433 reader: &mut NetDocReader<'a, RouterKwd>,
434 ) -> Result<(
435 Section<'a, RouterKwd>,
436 Section<'a, RouterKwd>,
437 Section<'a, RouterKwd>,
438 )> {
439 use RouterKwd::*;
440
441 let header = ROUTER_HEADER_RULES.parse(
443 reader.pause_at(|item| item.is_ok_with_kwd_not_in(&[ROUTER, IDENTITY_ED25519])),
444 )?;
445
446 let body =
448 ROUTER_BODY_RULES.parse(reader.pause_at(|item| {
449 item.is_ok_with_kwd_in(&[ROUTER_SIGNATURE, ROUTER_SIG_ED25519])
450 }))?;
451
452 let sig = ROUTER_SIG_RULES.parse(reader.pause_at(|item| {
454 item.is_ok_with_annotation() || item.is_ok_with_kwd(ROUTER) || item.is_empty_line()
455 }))?;
456
457 Ok((header, body, sig))
458 }
459
460 pub fn parse(s: &str) -> Result<UncheckedRouterDesc> {
465 let mut reader = crate::parse::tokenize::NetDocReader::new(s)?;
466 let result = Self::parse_internal(&mut reader).map_err(|e| e.within(s))?;
467 reader
470 .should_be_exhausted_but_for_empty_lines()
471 .map_err(|e| e.within(s))?;
472 Ok(result)
473 }
474
475 fn parse_internal(r: &mut NetDocReader<'_, RouterKwd>) -> Result<UncheckedRouterDesc> {
481 use RouterKwd::*;
484
485 let s = r.str();
486 let (header, body, sig) = RouterDesc::parse_sections(r)?;
487
488 #[allow(clippy::unwrap_used)]
491 let start_offset = header.required(ROUTER)?.offset_in(s).unwrap();
492
493 let (identity_cert, ed25519_signing_key) = {
495 let cert_tok = header.required(IDENTITY_ED25519)?;
496 #[allow(clippy::unwrap_used)]
499 if cert_tok.offset_in(s).unwrap() < start_offset {
500 return Err(EK::MisplacedToken
501 .with_msg("identity-ed25519")
502 .at_pos(cert_tok.pos()));
503 }
504 let cert: tor_cert::UncheckedCert = cert_tok
505 .parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
506 .check_cert_type(tor_cert::CertType::IDENTITY_V_SIGNING)?
507 .into_unchecked()
508 .should_have_signing_key()
509 .map_err(|err| {
510 EK::BadObjectVal
511 .err()
512 .with_source(err)
513 .at_pos(cert_tok.pos())
514 })?;
515 let sk = *cert.peek_subject_key().as_ed25519().ok_or_else(|| {
516 EK::BadObjectVal
517 .at_pos(cert_tok.pos())
518 .with_msg("wrong type for signing key in cert")
519 })?;
520 let sk: ll::pk::ed25519::PublicKey = sk.try_into().map_err(|_| {
521 EK::BadObjectVal
522 .at_pos(cert_tok.pos())
523 .with_msg("invalid ed25519 signing key")
524 })?;
525 (cert, sk)
526 };
527
528 #[allow(unexpected_cfgs)]
530 {
531 let master_key_tok = body.required(MASTER_KEY_ED25519)?;
532 let ed_id: Ed25519Public = master_key_tok.parse_arg(0)?;
533 let ed_id: ll::pk::ed25519::Ed25519Identity = ed_id.into();
534 if ed_id != *identity_cert.peek_signing_key() {
535 #[cfg(not(fuzzing))] return Err(EK::BadObjectVal
537 .at_pos(master_key_tok.pos())
538 .with_msg("master-key-ed25519 does not match key in identity-ed25519"));
539 }
540 }
541
542 let rsa_identity_key: ll::pk::rsa::PublicKey = body
544 .required(SIGNING_KEY)?
545 .parse_obj::<RsaPublic>("RSA PUBLIC KEY")?
546 .check_len_eq(1024)?
547 .check_exponent(65537)?
548 .into();
549 let rsa_identity = rsa_identity_key.to_rsa_identity();
550
551 let ed_sig = sig.required(ROUTER_SIG_ED25519)?;
552 let rsa_sig = sig.required(ROUTER_SIGNATURE)?;
553 #[allow(clippy::unwrap_used)]
556 let ed_sig_pos = ed_sig.offset_in(s).unwrap();
557 #[allow(clippy::unwrap_used)]
558 let rsa_sig_pos = rsa_sig.offset_in(s).unwrap();
559
560 if ed_sig_pos > rsa_sig_pos {
561 return Err(EK::UnexpectedToken
562 .with_msg(ROUTER_SIG_ED25519.to_str())
563 .at_pos(ed_sig.pos()));
564 }
565
566 let ed_signature: ll::pk::ed25519::ValidatableEd25519Signature = {
568 let mut d = ll::d::Sha256::new();
569 d.update(&b"Tor router descriptor signature v1"[..]);
570 let signed_end = ed_sig_pos + b"router-sig-ed25519 ".len();
571 d.update(&s[start_offset..signed_end]);
572 let d = d.finalize();
573 let sig: [u8; 64] = ed_sig
574 .parse_arg::<B64>(0)?
575 .into_array()
576 .map_err(|_| EK::BadSignature.at_pos(ed_sig.pos()))?;
577 let sig = ll::pk::ed25519::Signature::from(sig);
578 ll::pk::ed25519::ValidatableEd25519Signature::new(ed25519_signing_key, sig, &d)
579 };
580
581 let rsa_signature: ll::pk::rsa::ValidatableRsaSignature = {
583 let mut d = ll::d::Sha1::new();
584 let signed_end = rsa_sig_pos + b"router-signature\n".len();
585 d.update(&s[start_offset..signed_end]);
586 let d = d.finalize();
587 let sig = rsa_sig.obj("SIGNATURE")?;
588 ll::pk::rsa::ValidatableRsaSignature::new(&rsa_identity_key, &sig, &d)
591 };
592
593 let (nickname, ipv4addr, orport, dirport) = {
595 let rtrline = header.required(ROUTER)?;
596 (
597 rtrline.parse_arg::<Nickname>(0)?,
598 Some(rtrline.parse_arg::<net::Ipv4Addr>(1)?),
599 rtrline.parse_arg(2)?,
600 rtrline.parse_arg(4)?,
602 )
603 };
604
605 let uptime = body.maybe(UPTIME).parse_arg(0)?;
607
608 let published = body
610 .required(PUBLISHED)?
611 .args_as_str()
612 .parse::<Iso8601TimeSp>()?
613 .into();
614
615 let ntor_onion_key: Curve25519Public = body.required(NTOR_ONION_KEY)?.parse_arg(0)?;
617 let ntor_onion_key: ll::pk::curve25519::PublicKey = ntor_onion_key.into();
618 let crosscert_cert: tor_cert::UncheckedCert = {
620 let cc = body.required(NTOR_ONION_KEY_CROSSCERT)?;
621 let sign: u8 = cc.parse_arg(0)?;
622 if sign != 0 && sign != 1 {
623 return Err(EK::BadArgument.at_pos(cc.arg_pos(0)).with_msg("not 0 or 1"));
624 }
625 let ntor_as_ed: ll::pk::ed25519::PublicKey =
626 ll::pk::keymanip::convert_curve25519_to_ed25519_public(&ntor_onion_key, sign)
627 .ok_or_else(|| {
628 EK::BadArgument
629 .at_pos(cc.pos())
630 .with_msg("Uncheckable crosscert")
631 })?;
632
633 cc.parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
634 .check_cert_type(tor_cert::CertType::NTOR_CC_IDENTITY)?
635 .check_subject_key_is(identity_cert.peek_signing_key())?
636 .into_unchecked()
637 .should_be_signed_with(&ntor_as_ed.into())
638 .map_err(|err| EK::BadSignature.err().with_source(err))?
639 };
640
641 let tap_onion_key: Option<ll::pk::rsa::PublicKey> = if let Some(tok) = body.get(ONION_KEY) {
643 Some(
644 tok.parse_obj::<RsaPublic>("RSA PUBLIC KEY")?
645 .check_len_eq(1024)?
646 .check_exponent(65537)?
647 .into(),
648 )
649 } else {
650 None
651 };
652
653 let tap_crosscert_sig = if let Some(cc_tok) = body.get(ONION_KEY_CROSSCERT) {
655 let cc_val = cc_tok.obj("CROSSCERT")?;
656 let mut signed = Vec::new();
657 signed.extend(rsa_identity.as_bytes());
658 signed.extend(identity_cert.peek_signing_key().as_bytes());
659 Some(ll::pk::rsa::ValidatableRsaSignature::new(
660 tap_onion_key.as_ref().ok_or_else(|| {
661 EK::MissingToken.with_msg("onion-key-crosscert without onion-key")
662 })?,
663 &cc_val,
664 &signed,
665 ))
666 } else if tap_onion_key.is_some() {
667 return Err(EK::MissingToken.with_msg("onion-key without onion-key-crosscert"));
668 } else {
669 None
670 };
671
672 let proto = {
674 let proto_tok = body.required(PROTO)?;
675 doc::PROTOVERS_CACHE.intern(
676 proto_tok
677 .args_as_str()
678 .parse::<tor_protover::Protocols>()
679 .map_err(|e| EK::BadArgument.at_pos(proto_tok.pos()).with_source(e))?,
680 )
681 };
682
683 let is_dircache = (dirport != 0) || body.get(TUNNELLED_DIR_SERVER).is_some();
685
686 let is_extrainfo_cache = body.get(CACHES_EXTRA_INFO).is_some();
688
689 if let Some(fp_tok) = body.get(FINGERPRINT) {
691 let fp: RsaIdentity = fp_tok.args_as_str().parse::<SpFingerprint>()?.into();
692 if fp != rsa_identity {
693 return Err(EK::BadArgument
694 .at_pos(fp_tok.pos())
695 .with_msg("fingerprint does not match RSA identity"));
696 }
697 }
698
699 let family = {
701 let mut family = body
702 .maybe(FAMILY)
703 .parse_args_as_str::<RelayFamily>()?
704 .unwrap_or_else(RelayFamily::new);
705 if !family.is_empty() {
706 family.push(rsa_identity);
712 }
713 family.intern()
714 };
715
716 let family_certs: Vec<tor_cert::UncheckedCert> = body
718 .slice(FAMILY_CERT)
719 .iter()
720 .map(|ent| {
721 ent.parse_obj::<UnvalidatedEdCert>("FAMILY CERT")?
722 .check_cert_type(CertType::FAMILY_V_IDENTITY)?
723 .check_subject_key_is(identity_cert.peek_signing_key())?
724 .into_unchecked()
725 .should_have_signing_key()
726 .map_err(|e| {
727 EK::BadObjectVal
728 .with_msg("missing public key")
729 .at_pos(ent.pos())
730 .with_source(e)
731 })
732 })
733 .collect::<Result<_>>()?;
734
735 let mut family_ids: Vec<_> = family_certs
736 .iter()
737 .map(|cert| RelayFamilyId::Ed25519(*cert.peek_signing_key()))
738 .collect();
739 family_ids.sort();
740 family_ids.dedup();
741
742 let mut ipv6addr = None;
746 for tok in body.slice(OR_ADDRESS) {
747 if let Ok(net::SocketAddr::V6(a)) = tok.parse_arg::<net::SocketAddr>(0) {
748 ipv6addr = Some((*a.ip(), a.port()));
749 break;
750 }
751 }
753
754 let platform = body.maybe(PLATFORM).parse_args_as_str::<RelayPlatform>()?;
756
757 let ipv4_policy = {
759 let mut pol = AddrPolicy::new();
760 for ruletok in body.slice(POLICY).iter() {
761 let accept = match ruletok.kwd_str() {
762 "accept" => RuleKind::Accept,
763 "reject" => RuleKind::Reject,
764 _ => {
765 return Err(Error::from(internal!(
766 "tried to parse a strange line as a policy"
767 ))
768 .at_pos(ruletok.pos()));
769 }
770 };
771 let pat: AddrPortPattern = ruletok
772 .args_as_str()
773 .parse()
774 .map_err(|e| EK::BadPolicy.at_pos(ruletok.pos()).with_source(e))?;
775 pol.push(accept, pat);
776 }
777 pol
778 };
779
780 let ipv6_policy = match body.get(IPV6_POLICY) {
782 Some(p) => p
783 .args_as_str()
784 .parse()
785 .map_err(|e| EK::BadPolicy.at_pos(p.pos()).with_source(e))?,
786 #[allow(clippy::unwrap_used)]
788 None => "reject 1-65535".parse::<PortPolicy>().unwrap(),
789 };
790
791 let (identity_cert, identity_sig) = identity_cert.dangerously_split().map_err(|err| {
793 EK::BadObjectVal
794 .with_msg("missing public key")
795 .with_source(err)
796 })?;
797 let (crosscert_cert, cc_sig) = crosscert_cert.dangerously_split().map_err(|err| {
798 EK::BadObjectVal
799 .with_msg("missing public key")
800 .with_source(err)
801 })?;
802 let mut signatures: Vec<Box<dyn ll::pk::ValidatableSignature>> = vec![
803 Box::new(rsa_signature),
804 Box::new(ed_signature),
805 Box::new(identity_sig),
806 Box::new(cc_sig),
807 ];
808 if let Some(s) = tap_crosscert_sig {
809 signatures.push(Box::new(s));
810 }
811
812 let identity_cert = identity_cert.dangerously_assume_timely();
813 let crosscert_cert = crosscert_cert.dangerously_assume_timely();
814 let mut expirations = vec![
815 published + time::Duration::new(ROUTER_EXPIRY_SECONDS, 0),
816 identity_cert.expiry(),
817 crosscert_cert.expiry(),
818 ];
819
820 for cert in family_certs {
821 let (inner, sig) = cert.dangerously_split().map_err(into_internal!(
822 "Missing a public key that was previously there."
823 ))?;
824 signatures.push(Box::new(sig));
825 expirations.push(inner.dangerously_assume_timely().expiry());
826 }
827
828 #[allow(clippy::unwrap_used)]
830 let expiry = *expirations.iter().min().unwrap();
831
832 let start_time = published - time::Duration::new(ROUTER_PRE_VALIDITY_SECONDS, 0);
833
834 let desc = RouterDesc {
835 nickname,
836 ipv4addr,
837 orport,
838 ipv6addr,
839 dirport,
840 uptime,
841 published,
842 identity_cert,
843 rsa_identity_key,
844 rsa_identity,
845 ntor_onion_key,
846 tap_onion_key,
847 proto,
848 is_dircache,
849 is_extrainfo_cache,
850 family,
851 family_ids,
852 platform,
853 ipv4_policy,
854 ipv6_policy: ipv6_policy.intern(),
855 };
856
857 let time_gated = timed::TimerangeBound::new(desc, start_time..expiry);
858 let sig_gated = signed::SignatureGated::new(time_gated, signatures);
859
860 Ok(sig_gated)
861 }
862}
863
864pub struct RouterReader<'a> {
870 annotated: bool,
872 reader: NetDocReader<'a, RouterKwd>,
874}
875
876fn advance_to_next_routerdesc(reader: &mut NetDocReader<'_, RouterKwd>, annotated: bool) {
881 use RouterKwd::*;
882 loop {
883 let item = reader.peek();
884 match item {
885 Some(Ok(t)) => {
886 let kwd = t.kwd();
887 if (annotated && kwd.is_annotation()) || kwd == ROUTER {
888 return;
889 }
890 }
891 Some(Err(_)) => {
892 }
894 None => {
895 return;
896 }
897 }
898 let _ = reader.next();
899 }
900}
901
902impl<'a> RouterReader<'a> {
903 pub fn new(s: &'a str, allow: &AllowAnnotations) -> Result<Self> {
905 let reader = NetDocReader::new(s)?;
906 let annotated = allow == &AllowAnnotations::AnnotationsAllowed;
907 Ok(RouterReader { annotated, reader })
908 }
909
910 fn take_annotation(&mut self) -> Result<RouterAnnotation> {
912 if self.annotated {
913 RouterAnnotation::take_from_reader(&mut self.reader)
914 } else {
915 Ok(RouterAnnotation::default())
916 }
917 }
918
919 fn take_annotated_routerdesc_raw(&mut self) -> Result<AnnotatedRouterDesc> {
923 let ann = self.take_annotation()?;
924 let router = RouterDesc::parse_internal(&mut self.reader)?;
925 Ok(AnnotatedRouterDesc { ann, router })
926 }
927
928 fn take_annotated_routerdesc(&mut self) -> Result<AnnotatedRouterDesc> {
932 let pos_orig = self.reader.pos();
933 let result = self.take_annotated_routerdesc_raw();
934 if result.is_err() {
935 if self.reader.pos() == pos_orig {
936 let _ = self.reader.next();
944 }
945 advance_to_next_routerdesc(&mut self.reader, self.annotated);
946 }
947 result
948 }
949}
950
951impl<'a> Iterator for RouterReader<'a> {
952 type Item = Result<AnnotatedRouterDesc>;
953 fn next(&mut self) -> Option<Self::Item> {
954 self.reader.peek()?;
956
957 Some(
958 self.take_annotated_routerdesc()
959 .map_err(|e| e.within(self.reader.str())),
960 )
961 }
962}
963
964#[cfg(test)]
965mod test {
966 #![allow(clippy::bool_assert_comparison)]
968 #![allow(clippy::clone_on_copy)]
969 #![allow(clippy::dbg_macro)]
970 #![allow(clippy::mixed_attributes_style)]
971 #![allow(clippy::print_stderr)]
972 #![allow(clippy::print_stdout)]
973 #![allow(clippy::single_char_pattern)]
974 #![allow(clippy::unwrap_used)]
975 #![allow(clippy::unchecked_duration_subtraction)]
976 #![allow(clippy::useless_vec)]
977 #![allow(clippy::needless_pass_by_value)]
978 use super::*;
980 const TESTDATA: &str = include_str!("../../testdata/routerdesc1.txt");
981 const TESTDATA2: &str = include_str!("../../testdata/routerdesc2.txt");
982 const TESTDATA3: &str = include_str!("../../testdata/routerdesc3.txt");
984
985 fn read_bad(fname: &str) -> String {
986 use std::fs;
987 use std::path::PathBuf;
988 let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
989 path.push("testdata");
990 path.push("bad-routerdesc");
991 path.push(fname);
992
993 fs::read_to_string(path).unwrap()
994 }
995
996 #[test]
997 fn parse_arbitrary() -> Result<()> {
998 use std::str::FromStr;
999 use tor_checkable::{SelfSigned, Timebound};
1000 let rd = RouterDesc::parse(TESTDATA)?
1001 .check_signature()?
1002 .dangerously_assume_timely();
1003
1004 assert_eq!(rd.nickname.as_str(), "Akka");
1005 assert_eq!(rd.orport, 443);
1006 assert_eq!(rd.dirport, 0);
1007 assert_eq!(rd.uptime, Some(1036923));
1008 assert_eq!(
1009 rd.family.as_ref(),
1010 &RelayFamily::from_str(
1011 "$303509ab910ef207b7438c27435c4a2fd579f1b1 \
1012 $56927e61b51e6f363fb55498150a6ddfcf7077f2"
1013 )
1014 .unwrap()
1015 );
1016
1017 assert_eq!(
1018 rd.rsa_identity().to_string(),
1019 "$56927e61b51e6f363fb55498150a6ddfcf7077f2"
1020 );
1021 assert_eq!(
1022 rd.ed_identity().to_string(),
1023 "CVTjf1oeaL616hH+1+UvYZ8OgkwF3z7UMITvJzm5r7A"
1024 );
1025 assert_eq!(
1026 rd.protocols().to_string(),
1027 "Cons=1-2 Desc=1-2 DirCache=2 FlowCtrl=1-2 HSDir=2 \
1028 HSIntro=4-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 \
1029 Padding=2 Relay=1-4"
1030 );
1031
1032 assert_eq!(
1033 hex::encode(rd.ntor_onion_key().to_bytes()),
1034 "329b3b52991613392e35d1a821dd6753e1210458ecc3337f7b7d39bfcf5da273"
1035 );
1036 assert_eq!(
1037 rd.published(),
1038 humantime::parse_rfc3339("2022-11-14T19:58:52Z").unwrap()
1039 );
1040 assert_eq!(
1041 rd.or_ports().collect::<Vec<_>>(),
1042 vec![
1043 "95.216.33.58:443".parse().unwrap(),
1044 "[2a01:4f9:2a:2145::2]:443".parse().unwrap(),
1045 ]
1046 );
1047 assert!(rd.tap_onion_key.is_some());
1048
1049 Ok(())
1050 }
1051
1052 #[test]
1053 fn parse_no_tap_key() -> Result<()> {
1054 use tor_checkable::{SelfSigned, Timebound};
1055 let rd = RouterDesc::parse(TESTDATA2)?
1056 .check_signature()?
1057 .dangerously_assume_timely();
1058 assert!(rd.tap_onion_key.is_none());
1059
1060 Ok(())
1061 }
1062
1063 #[test]
1064 fn test_bad() {
1065 use crate::Pos;
1066 use crate::types::policy::PolicyError;
1067 fn check(fname: &str, e: &Error) {
1068 let text = read_bad(fname);
1069 let rd = RouterDesc::parse(&text);
1070 assert!(rd.is_err());
1071 assert_eq!(&rd.err().unwrap(), e);
1072 }
1073
1074 check(
1075 "bad-sig-order",
1076 &EK::UnexpectedToken
1077 .with_msg("router-sig-ed25519")
1078 .at_pos(Pos::from_line(50, 1)),
1079 );
1080 check(
1081 "bad-start1",
1082 &EK::MisplacedToken
1083 .with_msg("identity-ed25519")
1084 .at_pos(Pos::from_line(1, 1)),
1085 );
1086 check("bad-start2", &EK::MissingToken.with_msg("identity-ed25519"));
1087 check(
1088 "mismatched-fp",
1089 &EK::BadArgument
1090 .at_pos(Pos::from_line(12, 1))
1091 .with_msg("fingerprint does not match RSA identity"),
1092 );
1093 check("no-ed-sk", &EK::MissingToken.with_msg("identity-ed25519"));
1094
1095 check(
1096 "bad-cc-sign",
1097 &EK::BadArgument
1098 .at_pos(Pos::from_line(34, 26))
1099 .with_msg("not 0 or 1"),
1100 );
1101 check(
1102 "bad-ipv6policy",
1103 &EK::BadPolicy
1104 .at_pos(Pos::from_line(43, 1))
1105 .with_source(PolicyError::InvalidPolicy),
1106 );
1107 check(
1108 "no-ed-id-key-in-cert",
1109 &EK::BadObjectVal
1110 .at_pos(Pos::from_line(2, 1))
1111 .with_source(tor_cert::CertError::MissingPubKey),
1112 );
1113 check(
1114 "non-ed-sk-in-cert",
1115 &EK::BadObjectVal
1116 .at_pos(Pos::from_line(2, 1))
1117 .with_msg("wrong type for signing key in cert"),
1118 );
1119 check(
1120 "bad-ed-sk-in-cert",
1121 &EK::BadObjectVal
1122 .at_pos(Pos::from_line(2, 1))
1123 .with_msg("invalid ed25519 signing key"),
1124 );
1125 check(
1126 "mismatched-ed-sk-in-cert",
1127 &EK::BadObjectVal
1128 .at_pos(Pos::from_line(8, 1))
1129 .with_msg("master-key-ed25519 does not match key in identity-ed25519"),
1130 );
1131 }
1132
1133 #[test]
1134 fn parse_multiple_annotated() {
1135 use crate::AllowAnnotations;
1136 let mut s = read_bad("bad-cc-sign");
1137 s += "\
1138@uploaded-at 2020-09-26 18:15:41
1139@source \"127.0.0.1\"
1140";
1141 s += TESTDATA;
1142 s += "\
1143@uploaded-at 2020-09-26 18:15:41
1144@source \"127.0.0.1\"
1145";
1146 s += &read_bad("mismatched-fp");
1147
1148 let rd = RouterReader::new(&s, &AllowAnnotations::AnnotationsAllowed).unwrap();
1149 let v: Vec<_> = rd.collect();
1150 assert!(v[0].is_err());
1151 assert!(v[1].is_ok());
1152 assert_eq!(
1153 v[1].as_ref().unwrap().ann.source,
1154 Some("\"127.0.0.1\"".to_string())
1155 );
1156 assert!(v[2].is_err());
1157 }
1158
1159 #[test]
1160 fn test_platform() {
1161 let p = "Tor 0.4.4.4-alpha on a flying bison".parse::<RelayPlatform>();
1162 assert!(p.is_ok());
1163 assert_eq!(
1164 p.unwrap(),
1165 RelayPlatform::Tor(
1166 "0.4.4.4-alpha".parse().unwrap(),
1167 "a flying bison".to_string()
1168 )
1169 );
1170
1171 let p = "Tor 0.4.4.4-alpha on".parse::<RelayPlatform>();
1172 assert!(p.is_ok());
1173
1174 let p = "Tor 0.4.4.4-alpha ".parse::<RelayPlatform>();
1175 assert!(p.is_ok());
1176 let p = "Tor 0.4.4.4-alpha".parse::<RelayPlatform>();
1177 assert!(p.is_ok());
1178
1179 let p = "arti 0.0.0".parse::<RelayPlatform>();
1180 assert!(p.is_ok());
1181 assert_eq!(p.unwrap(), RelayPlatform::Other("arti 0.0.0".to_string()));
1182 }
1183
1184 #[test]
1185 fn test_family_ids() -> Result<()> {
1186 use tor_checkable::{SelfSigned, Timebound};
1187 let rd = RouterDesc::parse(TESTDATA3)?
1188 .check_signature()?
1189 .dangerously_assume_timely();
1190
1191 assert_eq!(
1192 rd.family_ids(),
1193 &[
1194 "ed25519:7sToQRuge1bU2hS0CG0ViMndc4m82JhO4B4kdrQey80"
1195 .parse()
1196 .unwrap(),
1197 "ed25519:szHUS3ItRd9uk85b1UVnOZx1gg4B0266jCpbuIMNjcM"
1198 .parse()
1199 .unwrap(),
1200 ]
1201 );
1202
1203 Ok(())
1204 }
1205}