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