Skip to main content

tor_netdoc/doc/
routerdesc.rs

1//!
2//! A "router descriptor" is a signed statement that a relay makes
3//! about itself, explaining its keys, its capabilities, its location,
4//! and its status.
5//!
6//! Relays upload their router descriptors to authorities, which use
7//! them to build consensus documents.  Old clients and relays used to
8//! fetch and use router descriptors for all the relays, but nowadays they use
9//! microdescriptors instead.
10//!
11//! Clients still use router descriptors when communicating with
12//! bridges: since bridges are not passed through an authority,
13//! clients accept their descriptors directly.
14//!
15//! For full information about the router descriptor format, see
16//! [dir-spec.txt](https://spec.torproject.org/dir-spec).
17//!
18//! # Limitations
19//!
20//! TODO: This needs to get tested much more!
21//!
22//! TODO: This implementation can be memory-inefficient.  In practice,
23//! it gets really expensive storing policy entries, family
24//! descriptions, parsed keys, and things like that.  We will probably want to
25//! de-duplicate those.
26//!
27//! TODO: There should be accessor functions for some or all of the
28//! fields in RouterDesc.  I'm deferring those until I know what they
29//! should be.
30//!
31//! # Availability
32//!
33//! Most of this module is only available when this crate is built with the
34//! `routerdesc` feature enabled.
35use crate::encode::{ItemEncoder, ItemValueEncodable};
36use crate::parse::keyword::Keyword;
37use crate::parse::parser::{Section, SectionRules};
38use crate::parse::tokenize::{ItemResult, NetDocReader};
39use crate::parse2::{ArgumentError, ErrorProblem, ItemValueParseable, UnparsedItem};
40use crate::types::family::{RelayFamily, RelayFamilyIds};
41use crate::types::policy::*;
42use crate::types::routerdesc::*;
43use crate::types::version::TorVersion;
44use crate::types::{EmbeddedCert, misc::*};
45use crate::util::PeekableIterator;
46use crate::{AllowAnnotations, Error, KeywordEncodable, NetdocErrorKind as EK, Result};
47
48use derive_deftly::Deftly;
49use ll::pk::ed25519::Ed25519Identity;
50use saturating_time::SaturatingTime;
51use std::fmt::Display;
52use std::sync::LazyLock;
53use std::{iter, net, time};
54use tor_basic_utils::intern::Intern;
55use tor_cert::{CertType, KeyUnknownCert};
56use tor_checkable::{Timebound, signed, timed};
57use tor_error::{internal, into_internal};
58use tor_llcrypto as ll;
59use tor_llcrypto::pk::rsa::RsaIdentity;
60
61use digest::Digest;
62
63/// Length of a router descriptor digest
64pub const DOC_DIGEST_LEN: usize = 20;
65
66/// The digest of a RouterDesc document, as reported in a NS consensus.
67pub type RdDigest = [u8; DOC_DIGEST_LEN];
68
69/// The digest of an ExtraInfo document, as reported in a RouterDesc.
70pub type ExtraInfoDigest = [u8; DOC_DIGEST_LEN];
71
72/// A router descriptor, with possible annotations.
73#[non_exhaustive]
74pub struct AnnotatedRouterDesc {
75    /// Annotation for this router descriptor; possibly empty.
76    pub ann: RouterAnnotation,
77    /// Underlying router descriptor; signatures not checked yet.
78    pub router: UncheckedRouterDesc,
79}
80
81/// Annotations about a router descriptor, as stored on disc.
82#[derive(Default)]
83#[non_exhaustive]
84pub struct RouterAnnotation {
85    /// Description of where we got this router descriptor
86    pub source: Option<String>,
87    /// When this descriptor was first downloaded.
88    pub downloaded: Option<time::SystemTime>,
89    /// Description of what we're willing to use this descriptor for.
90    pub purpose: Option<String>,
91}
92
93/// Information about a relay, parsed from a router descriptor.
94///
95/// This type does not hold all the information in the router descriptor
96///
97/// # Limitations
98///
99/// See module documentation.
100///
101/// Additionally, some fields that from router descriptors are not yet
102/// parsed: see the comments in ROUTER_BODY_RULES for information about those.
103///
104/// Before using this type to connect to a relay, you MUST check that
105/// it is valid, using is_expired_at().
106///
107/// # Specification
108///
109/// <https://spec.torproject.org/dir-spec/server-descriptor-format.html>
110#[derive(Clone, Debug, Deftly, PartialEq, Eq)]
111#[derive_deftly(NetdocParseableUnverified)]
112#[non_exhaustive]
113pub struct RouterDesc {
114    /// `router` --- Introduce a router descriptor.
115    /// * `router <nickname> <address> <orport> <socksport> <dirport>`
116    /// * At start, exactly once.
117    pub router: RouterDescIntroItem,
118
119    /// `identity-ed25519` --- Specify the router's ed25519 identity.
120    ///
121    /// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:identity-ed25519>
122    pub identity_ed25519: EmbeddedCert<Ed25519IdentityCert, KeyUnknownCert>,
123
124    /// `master-key-ed25519` --- Redundantly specify the router's ed25519 identity.
125    ///
126    /// * `master-key-ed25519 <master key>`
127    /// * Exactly once.
128    // TODO DIRAUTH when implementing verification, don't forget to check this!
129    #[deftly(netdoc(single_arg))]
130    pub master_key_ed25519: Ed25519Public,
131
132    /// `bandwidth` --- Report router's network bandwidth.
133    ///
134    /// * `bandwidth <average> <burst> <observed>`
135    /// * Exactly once.
136    pub bandwidth: Bandwidth,
137
138    /// `platform` --- Describe the platform on which this relay is running.
139    ///
140    /// * `platform <rest of line>`
141    /// * At most once.
142    pub platform: Option<RelayPlatform>,
143
144    /// `published` --- Time this descriptor (and extra-info) was generated.
145    ///
146    /// * `published <date> <time>`
147    /// * Exactly once.
148    #[deftly(netdoc(single_arg))]
149    pub published: Iso8601TimeSp,
150
151    /// `fingerprint` --- Redundant hash of ASN-1 encoding of router identity key.
152    ///
153    /// * `fingerprint <spaced fingerprint>`
154    /// * At most once.
155    #[deftly(netdoc(single_arg))]
156    pub fingerprint: Option<SpFingerprint>,
157
158    /// `hibernating` --- Whether the relay is hibernating.
159    ///
160    /// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:hibernating>
161    // TODO DIRAUTH: Mark this as `netdoc(default)` and skip during encoding if false.
162    #[deftly(netdoc(single_arg, default))]
163    pub hibernating: NumericBoolean,
164
165    /// `uptime` --- How long this relay has been continously running
166    ///
167    /// * `uptime <number>`
168    /// * At most once.
169    #[deftly(netdoc(single_arg))]
170    pub uptime: Option<u64>,
171
172    /// `onion-key` --- Relay's obsolete RSA tap key.
173    ///
174    /// * `onion-key\n<rsa public key>`
175    /// * At most once.
176    /// * No extra arguments.
177    pub onion_key: Option<ll::pk::rsa::PublicKey>,
178
179    /// `ntor-onion-key` --- The circuit extension key.
180    ///
181    /// * `ntor-onion-key <base64 padded key>`
182    /// * Exactly once.
183    #[deftly(netdoc(single_arg))]
184    pub ntor_onion_key: Curve25519Public,
185
186    /// `ntor-onion-key-crosscert` --- Reverse cert by K_ntor on KP_relayid_ed
187    ///
188    /// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:ntor-onion-key-crosscert>
189    pub ntor_onion_key_crosscert: NtorOnionKeyCrossCert,
190
191    /// `signing-key` --- Obsolete RSA identity key.
192    ///
193    /// * `signing-key\n<rsa public key>`
194    pub signing_key: ll::pk::rsa::PublicKey,
195
196    /// `accept, reject` --- Exit policy.
197    ///
198    /// * `accept exitpattern`
199    /// * `reject exitpattern`
200    /// * Any number of times.
201    // TODO: these polices can get bulky too. Perhaps we should
202    // de-duplicate them too.
203    #[deftly(netdoc(flatten))]
204    pub ipv4_policy: AddrPolicy,
205
206    /// `ipv6-policy` --- Exit plicy summary for IPv6
207    ///
208    /// * `ipv6-policy <accept/reject> PortList`
209    /// * At most once.
210    #[deftly(netdoc(default))]
211    pub ipv6_policy: Intern<PortPolicy>,
212
213    /// `overload-general` --- Relay is overloaded.
214    ///
215    /// * `overload-general 1 <time>`
216    /// * At most once.
217    // TODO in OverloadGeneral use ConstantString (from !3985) for version
218    pub overload_general: Option<OverloadGeneral>,
219
220    /// `contact` --- Server administrator contact information.
221    ///
222    /// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:contact>
223    pub contact: Option<ContactInfo>,
224
225    /// `family` --- Group relays for the purpose of path selection.
226    ///
227    /// * `family <LongIdent> ...`
228    /// * One or more `LongIdent` arguments.
229    /// * At most once.
230    #[deftly(netdoc(default))]
231    pub family: Intern<RelayFamily>,
232
233    /// `family-cert` --- Prove membership in a relay family.
234    ///
235    /// * `family-cert\n<object>`
236    /// * Any number of times.
237    pub family_cert: RetainedOrderVec<EmbeddedCert<Ed25519FamilyCert, KeyUnknownCert>>,
238
239    /// `caches-extra-info` --- Router provides extra-info as a dirmirror.
240    ///
241    /// * `caches-extra-info`
242    /// * At most once.
243    /// * No extra arguments.
244    pub caches_extra_info: Option<ItemPresent<CachesExtraInfoToken>>,
245
246    /// `extra-info-digest` --- Hash of the extra-info document.
247    ///
248    /// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:extra-info-digest>
249    pub extra_info_digest: Option<ExtraInfoDigests>,
250
251    /// `hidden-service-dir` --- Declares this router to be a hidden service directory
252    ///
253    /// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:hidden-service-dir>
254    pub hidden_service_dir: Option<ItemPresent<HiddenServiceDirToken>>,
255
256    /// `or-address` --- Alternative ORport address and port
257    ///
258    /// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:or-address>
259    #[deftly(netdoc(single_arg))]
260    pub or_address: Vec<net::SocketAddr>,
261
262    /// `tunnelled-dir-server` --- Accepts a `BEGIN_DIR` relay message.
263    ///
264    /// * `tunnelled-dir-server`
265    /// * At most once.
266    /// * No extra arguments.
267    pub tunnelled_dir_server: Option<ItemPresent<TunnelledDirServerToken>>,
268
269    /// `proto` --- Subprotocol capabilities supported.
270    ///
271    /// * `proto <entries>`
272    /// * Exactly once.
273    pub proto: tor_protover::Protocols,
274}
275
276/// Signatures of a [`RouterDesc`].
277///
278/// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:router-sig-ed25519>
279#[derive(Clone, Debug, PartialEq, Eq, Deftly)]
280#[derive_deftly(NetdocParseableSignatures)]
281#[deftly(netdoc(signatures(hashes_accu = "RouterHashAccu")))]
282#[non_exhaustive]
283pub struct RouterDescSignatures {
284    /// `router-sig-ed25519` --- Ed25519 signature
285    ///
286    /// Ed25519 signature by the Ed25519 signing key on the SHA-256 digest of
287    /// the document prefixed by a magic up until and including the
288    /// `router-sig-ed25519` keyword plus space.
289    pub router_sig_ed25519: RouterSigEd25519,
290
291    /// `router-signature` --- RSA signature
292    ///
293    /// * At end, exactly once.
294    /// * RSA signature of the document, including `router-sig-ed25519`.
295    pub router_signature: RouterSignature,
296}
297
298// TODO: Implement a .verify() method.
299impl RouterDescUnverified {}
300
301/// Description of the software a relay is running.
302///
303/// `platform` line in a routerstatus.
304/// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:platform>
305// TODO: Move this to types/misc.rs.
306#[derive(Debug, Clone, PartialEq, Eq)]
307#[non_exhaustive]
308pub enum RelayPlatform {
309    /// Software advertised to be some version of Tor, on some platform.
310    Tor(TorVersion, Option<String>),
311    /// Software not advertised to be Tor.
312    Other(String),
313}
314
315/// Zero-sized token type for use in [`RouterDesc::caches_extra_info`].
316#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
317#[non_exhaustive]
318pub struct CachesExtraInfoToken;
319
320/// Zero-sized token type for use in [`RouterDesc::hidden_service_dir`].
321#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
322#[non_exhaustive]
323pub struct HiddenServiceDirToken;
324
325/// Zero-sized token type for use in [`RouterDesc::tunnelled_dir_server`].
326#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
327#[non_exhaustive]
328pub struct TunnelledDirServerToken;
329
330impl std::str::FromStr for RelayPlatform {
331    type Err = Error;
332    fn from_str(args: &str) -> Result<Self> {
333        if args.starts_with("Tor ") {
334            let v: Vec<_> = args.splitn(4, ' ').collect();
335            match &v[..] {
336                ["Tor", ver, "on", p] => {
337                    Ok(RelayPlatform::Tor(ver.parse()?, Some((*p).to_string())))
338                }
339                ["Tor", ver, ..] => Ok(RelayPlatform::Tor(ver.parse()?, None)),
340                _ => unreachable!(),
341            }
342        } else {
343            Ok(RelayPlatform::Other(args.to_string()))
344        }
345    }
346}
347
348impl Display for RelayPlatform {
349    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
350        match &self {
351            Self::Tor(v, Some(p)) => write!(f, "Tor {v} on {p}"),
352            Self::Tor(v, None) => write!(f, "Tor {v}"),
353            Self::Other(s) => write!(f, "{s}"),
354        }
355    }
356}
357
358impl ItemValueParseable for RelayPlatform {
359    fn from_unparsed(item: UnparsedItem<'_>) -> std::result::Result<Self, ErrorProblem> {
360        let mut args = item.args_copy();
361        item.check_no_object()?;
362        args.into_remaining()
363            .parse()
364            .map_err(|_| args.handle_error("platform", ArgumentError::Invalid))
365    }
366}
367
368impl ItemValueEncodable for RelayPlatform {
369    fn write_item_value_onto(
370        &self,
371        mut out: ItemEncoder,
372    ) -> std::result::Result<(), tor_error::Bug> {
373        // Adding a raw string is fine because this is effectively a free form
374        // field.
375        out.args_raw_string(&self);
376        Ok(())
377    }
378}
379
380decl_keyword! {
381    /// RouterKwd is an instance of Keyword, used to denote the different
382    /// Items that are recognized as appearing in a router descriptor.
383    RouterKwd {
384        annotation "@source" => ANN_SOURCE,
385        annotation "@downloaded-at" => ANN_DOWNLOADED_AT,
386        annotation "@purpose" => ANN_PURPOSE,
387        "accept" | "reject" => POLICY,
388        "bandwidth" => BANDWIDTH,
389        "bridge-distribution-request" => BRIDGE_DISTRIBUTION_REQUEST,
390        "caches-extra-info" => CACHES_EXTRA_INFO,
391        "contact" => CONTACT,
392        "extra-info-digest" => EXTRA_INFO_DIGEST,
393        "family" => FAMILY,
394        "family-cert" => FAMILY_CERT,
395        "fingerprint" => FINGERPRINT,
396        "hibernating" => HIBERNATING,
397        "identity-ed25519" => IDENTITY_ED25519,
398        "ipv6-policy" => IPV6_POLICY,
399        "master-key-ed25519" => MASTER_KEY_ED25519,
400        "ntor-onion-key" => NTOR_ONION_KEY,
401        "ntor-onion-key-crosscert" => NTOR_ONION_KEY_CROSSCERT,
402        "onion-key" => ONION_KEY,
403        "onion-key-crosscert" => ONION_KEY_CROSSCERT,
404        "or-address" => OR_ADDRESS,
405        "platform" => PLATFORM,
406        "proto" => PROTO,
407        "published" => PUBLISHED,
408        "router" => ROUTER,
409        "router-sig-ed25519" => ROUTER_SIG_ED25519,
410        "router-signature" => ROUTER_SIGNATURE,
411        "signing-key" => SIGNING_KEY,
412        "tunnelled_dir_server" => TUNNELLED_DIR_SERVER,
413        "uptime" => UPTIME,
414        // "protocols" once existed, but is obsolete
415        // "eventdns" once existed, but is obsolete
416        // "allow-single-hop-exits" is also obsolete.
417    }
418}
419
420/// Rules for parsing a set of router descriptor annotations.
421static ROUTER_ANNOTATIONS: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
422    use RouterKwd::*;
423
424    let mut rules = SectionRules::builder();
425    rules.add(ANN_SOURCE.rule());
426    rules.add(ANN_DOWNLOADED_AT.rule().args(1..));
427    rules.add(ANN_PURPOSE.rule().args(1..));
428    rules.add(ANN_UNRECOGNIZED.rule().may_repeat().obj_optional());
429    // Unrecognized annotations are fine; anything else is an error in this
430    // context.
431    rules.reject_unrecognized();
432    rules.build()
433});
434/// Rules for tokens that are allowed in the first part of a
435/// router descriptor.
436static ROUTER_HEADER_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
437    use RouterKwd::*;
438
439    let mut rules = SectionRules::builder();
440    rules.add(ROUTER.rule().required().args(5..));
441    rules.add(IDENTITY_ED25519.rule().required().no_args().obj_required());
442    // No other intervening tokens are permitted in the header.
443    rules.reject_unrecognized();
444    rules.build()
445});
446/// Rules for  tokens that are allowed in the first part of a
447/// router descriptor.
448static ROUTER_BODY_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
449    use RouterKwd::*;
450
451    let mut rules = SectionRules::builder();
452    rules.add(MASTER_KEY_ED25519.rule().required().args(1..));
453    rules.add(PLATFORM.rule());
454    rules.add(PUBLISHED.rule().required());
455    rules.add(FINGERPRINT.rule());
456    rules.add(UPTIME.rule().args(1..));
457    rules.add(ONION_KEY.rule().no_args().obj_required());
458    rules.add(ONION_KEY_CROSSCERT.rule().no_args().obj_required());
459    rules.add(NTOR_ONION_KEY.rule().required().args(1..));
460    rules.add(
461        NTOR_ONION_KEY_CROSSCERT
462            .rule()
463            .required()
464            .args(1..=1)
465            .obj_required(),
466    );
467    rules.add(SIGNING_KEY.rule().no_args().required().obj_required());
468    rules.add(POLICY.rule().may_repeat().args(1..));
469    rules.add(IPV6_POLICY.rule().args(2..));
470    rules.add(FAMILY.rule().args(1..));
471    rules.add(FAMILY_CERT.rule().obj_required().may_repeat());
472    rules.add(CACHES_EXTRA_INFO.rule().no_args());
473    rules.add(OR_ADDRESS.rule().may_repeat().args(1..));
474    rules.add(TUNNELLED_DIR_SERVER.rule());
475    rules.add(PROTO.rule().required().args(1..));
476    rules.add(UNRECOGNIZED.rule().may_repeat().obj_optional());
477    // TODO: these aren't parsed yet.  Only authorities use them.
478    {
479        rules.add(BANDWIDTH.rule().required().args(3..));
480        rules.add(BRIDGE_DISTRIBUTION_REQUEST.rule().args(1..));
481        rules.add(HIBERNATING.rule().args(1..));
482        rules.add(CONTACT.rule());
483    }
484    // TODO: this is ignored for now.
485    {
486        rules.add(EXTRA_INFO_DIGEST.rule().args(1..));
487    }
488    rules.build()
489});
490
491/// Rules for items that appear at the end of a router descriptor.
492static ROUTER_SIG_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
493    use RouterKwd::*;
494
495    let mut rules = SectionRules::builder();
496    rules.add(ROUTER_SIG_ED25519.rule().required().args(1..));
497    rules.add(ROUTER_SIGNATURE.rule().required().no_args().obj_required());
498    // No intervening tokens are allowed in the footer.
499    rules.reject_unrecognized();
500    rules.build()
501});
502
503impl RouterAnnotation {
504    /// Extract a single RouterAnnotation (possibly empty) from a reader.
505    fn take_from_reader(reader: &mut NetDocReader<'_, RouterKwd>) -> Result<RouterAnnotation> {
506        use RouterKwd::*;
507        let mut items = reader.pause_at(|item| item.is_ok_with_non_annotation());
508
509        let body = ROUTER_ANNOTATIONS.parse(&mut items)?;
510
511        let source = body.maybe(ANN_SOURCE).args_as_str().map(String::from);
512        let purpose = body.maybe(ANN_PURPOSE).args_as_str().map(String::from);
513        let downloaded = body
514            .maybe(ANN_DOWNLOADED_AT)
515            .parse_args_as_str::<Iso8601TimeSp>()?
516            .map(|t| t.into());
517        Ok(RouterAnnotation {
518            source,
519            downloaded,
520            purpose,
521        })
522    }
523}
524
525/// A parsed router descriptor whose signatures and/or validity times
526/// may or may not be invalid.
527pub type UncheckedRouterDesc = signed::SignatureGated<timed::TimerangeBound<RouterDesc>>;
528
529/// How long after its published time is a router descriptor officially
530/// supposed to be usable?
531const ROUTER_EXPIRY_SECONDS: u64 = 5 * 86400;
532
533/// How long before its published time is a router descriptor usable?
534// TODO(nickm): This valid doesn't match C tor, which only enforces this rule
535// ("routers should not some from the future") at directory authorities, and
536// there only enforces a 12-hour limit (`ROUTER_ALLOW_SKEW`).  Eventually we
537// should probably harmonize these cutoffs.
538const ROUTER_PRE_VALIDITY_SECONDS: u64 = 86400;
539
540impl RouterDesc {
541    /// Return a reference to this relay's RSA identity.
542    pub fn rsa_identity(&self) -> RsaIdentity {
543        self.signing_key.to_rsa_identity()
544    }
545
546    /// Return a reference to this relay's Ed25519 identity.
547    pub fn ed_identity(&self) -> &Ed25519Identity {
548        &self
549            .identity_ed25519
550            .get()
551            .expect("ed25519 identity cert should be verified")
552            .id_ed25519
553    }
554
555    /// Return a reference to the list of subprotocol versions supported by this
556    /// relay.
557    pub fn protocols(&self) -> &tor_protover::Protocols {
558        &self.proto
559    }
560
561    /// Return a reference to this relay's Ntor onion key.
562    pub fn ntor_onion_key(&self) -> &ll::pk::curve25519::PublicKey {
563        &self.ntor_onion_key.0
564    }
565
566    /// Return the publication
567    pub fn published(&self) -> time::SystemTime {
568        self.published.0
569    }
570
571    /// Return an iterator of every `SocketAddr` at which this descriptor says
572    /// its relay can be reached.
573    pub fn or_ports(&self) -> impl Iterator<Item = net::SocketAddr> + '_ {
574        iter::once(net::SocketAddr::new(
575            self.router.address.into(),
576            self.router.orport,
577        ))
578        .chain(self.or_address.iter().copied())
579    }
580
581    /// Return the declared family of this descriptor.
582    pub fn family(&self) -> Intern<RelayFamily> {
583        Intern::clone(&self.family)
584    }
585
586    /// Return the authenticated family IDs of this descriptor.
587    pub fn family_ids(&self) -> RelayFamilyIds {
588        RelayFamilyIds::from_iter(
589            self.family_cert
590                .iter()
591                .map(|cert| cert.get().expect("unverified family cert?"))
592                .map(|cert| cert.family_ed25519.into()),
593        )
594    }
595
596    /// Helper: tokenize `s`, and divide it into three validated sections.
597    fn parse_sections<'a>(
598        reader: &mut NetDocReader<'a, RouterKwd>,
599    ) -> Result<(
600        Section<'a, RouterKwd>,
601        Section<'a, RouterKwd>,
602        Section<'a, RouterKwd>,
603    )> {
604        use RouterKwd::*;
605
606        // Parse everything up through the header.
607        let header = ROUTER_HEADER_RULES.parse(
608            reader.pause_at(|item| item.is_ok_with_kwd_not_in(&[ROUTER, IDENTITY_ED25519])),
609        )?;
610
611        // Parse everything up to but not including the signature.
612        let body =
613            ROUTER_BODY_RULES.parse(reader.pause_at(|item| {
614                item.is_ok_with_kwd_in(&[ROUTER_SIGNATURE, ROUTER_SIG_ED25519])
615            }))?;
616
617        // Parse the signature.
618        let sig = ROUTER_SIG_RULES.parse(reader.pause_at(|item| {
619            item.is_ok_with_annotation() || item.is_ok_with_kwd(ROUTER) || item.is_empty_line()
620        }))?;
621
622        Ok((header, body, sig))
623    }
624
625    /// Try to parse `s` as a router descriptor.
626    ///
627    /// Does not actually check liveness or signatures; you need to do that
628    /// yourself before you can do the output.
629    ///
630    /// The following fields are not parsed with the legacy parser and their
631    /// default value is used instead.
632    /// * [`RouterDescIntroItem::socksport`] in [`RouterDesc::router`]
633    /// * [`RouterDesc::bandwidth`]
634    /// * [`RouterDesc::or_address`]
635    ///     * Extracts only the first IPv6 address.
636    /// * [`RouterDesc::hibernating`]
637    /// * [`RouterDesc::overload_general`]
638    /// * [`RouterDesc::contact`]
639    /// * [`RouterDesc::extra_info_digest`]
640    /// * [`RouterDesc::hidden_service_dir`]
641    pub fn parse(s: &str) -> Result<UncheckedRouterDesc> {
642        let mut reader = crate::parse::tokenize::NetDocReader::new(s)?;
643        let result = Self::parse_internal(&mut reader).map_err(|e| e.within(s))?;
644        // We permit empty lines at the end of router descriptors, since there's
645        // a known issue in Tor relays that causes them to return them this way.
646        reader
647            .should_be_exhausted_but_for_empty_lines()
648            .map_err(|e| e.within(s))?;
649        Ok(result)
650    }
651
652    /// Helper: parse a router descriptor from `s`.
653    ///
654    /// This function does the same as parse(), but returns errors based on
655    /// byte-wise positions.  The parse() function converts such errors
656    /// into line-and-byte positions.
657    fn parse_internal(r: &mut NetDocReader<'_, RouterKwd>) -> Result<UncheckedRouterDesc> {
658        // TODO: This function is too long!  The little "paragraphs" here
659        // that parse one item at a time should be made into sub-functions.
660        use RouterKwd::*;
661
662        let s = r.str();
663        let (header, body, sig) = RouterDesc::parse_sections(r)?;
664
665        // Unwrap should be safe because inline `required` call should return
666        // `Error::MissingToken` if `ROUTER` is not `Ok`
667        #[allow(clippy::unwrap_used)]
668        let start_offset = header.required(ROUTER)?.offset_in(s).unwrap();
669
670        // ed25519 identity and signing key.
671        //
672        // Small digression: This is terrible.  We return a tuple containing
673        // a KeyUnknownCert and an UncheckedCert.  This is because of a parse2
674        // and legacy incongruence.  For parse2, we need the KeyUnknownCert
675        // to properly include it into EmbeddedCert, whereas the legacy parser
676        // will need an UncheckedCert because the verification chain is
677        // performed at the end.  Because tor-cert's method all consume self,
678        // we can not go backwards, meaning we have to store two separate
679        // copies.  It is also not possible to do the conversion to
680        // UncheckedCert later, because then we lose the error context returned
681        // in EK::BadObjectVal if the signed-by extension is missing.
682        //
683        let (ku_identity_cert, identity_cert, ed25519_signing_key) = {
684            let cert_tok = header.required(IDENTITY_ED25519)?;
685            // Unwrap should be safe because above `required` call should
686            // return `Error::MissingToken` if `IDENTITY_ED25519` is not `Ok`
687            #[allow(clippy::unwrap_used)]
688            if cert_tok.offset_in(s).unwrap() < start_offset {
689                return Err(EK::MisplacedToken
690                    .with_msg("identity-ed25519")
691                    .at_pos(cert_tok.pos()));
692            }
693            let ku_cert = cert_tok
694                .parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
695                .check_cert_type(tor_cert::CertType::IDENTITY_V_SIGNING)?
696                .into_unchecked();
697            let cert = ku_cert.clone().should_have_signing_key().map_err(|err| {
698                EK::BadObjectVal
699                    .err()
700                    .with_source(err)
701                    .at_pos(cert_tok.pos())
702            })?;
703            let sk = *cert.peek_subject_key().as_ed25519().ok_or_else(|| {
704                EK::BadObjectVal
705                    .at_pos(cert_tok.pos())
706                    .with_msg("wrong type for signing key in cert")
707            })?;
708            let sk: ll::pk::ed25519::PublicKey = sk.try_into().map_err(|_| {
709                EK::BadObjectVal
710                    .at_pos(cert_tok.pos())
711                    .with_msg("invalid ed25519 signing key")
712            })?;
713            (ku_cert, cert, sk)
714        };
715
716        // master-key-ed25519: required, and should match certificate.
717        #[allow(unexpected_cfgs)]
718        let ed25519_identity_key = {
719            let master_key_tok = body.required(MASTER_KEY_ED25519)?;
720            let ed_id: Ed25519Public = master_key_tok.parse_arg(0)?;
721            let ed_id: ll::pk::ed25519::Ed25519Identity = ed_id.into();
722            if ed_id != *identity_cert.peek_signing_key() {
723                #[cfg(not(fuzzing))] // No feature here; never omit in production.
724                return Err(EK::BadObjectVal
725                    .at_pos(master_key_tok.pos())
726                    .with_msg("master-key-ed25519 does not match key in identity-ed25519"));
727            }
728            ed_id
729        };
730
731        // Legacy RSA identity
732        let rsa_identity_key: ll::pk::rsa::PublicKey = body
733            .required(SIGNING_KEY)?
734            .parse_obj::<RsaPublicParse1Helper>("RSA PUBLIC KEY")?
735            .check_len_eq(1024)?
736            .check_exponent(65537)?
737            .into();
738        let rsa_identity = rsa_identity_key.to_rsa_identity();
739
740        let ed_sig = sig.required(ROUTER_SIG_ED25519)?;
741        let rsa_sig = sig.required(ROUTER_SIGNATURE)?;
742        // Unwrap should be safe because above `required` calls should return
743        // an `Error::MissingToken` if `ROUTER_...` is not `Ok`
744        #[allow(clippy::unwrap_used)]
745        let ed_sig_pos = ed_sig.offset_in(s).unwrap();
746        #[allow(clippy::unwrap_used)]
747        let rsa_sig_pos = rsa_sig.offset_in(s).unwrap();
748
749        if ed_sig_pos > rsa_sig_pos {
750            return Err(EK::UnexpectedToken
751                .with_msg(ROUTER_SIG_ED25519.to_str())
752                .at_pos(ed_sig.pos()));
753        }
754
755        // Extract ed25519 signature.
756        let ed_signature: ll::pk::ed25519::ValidatableEd25519Signature = {
757            let mut d = ll::d::Sha256::new();
758            d.update(&b"Tor router descriptor signature v1"[..]);
759            let signed_end = ed_sig_pos + b"router-sig-ed25519 ".len();
760            d.update(
761                s.get(start_offset..signed_end)
762                    .ok_or(internal!("chopped utf8"))?,
763            );
764            let d = d.finalize();
765            let sig: [u8; 64] = ed_sig
766                .parse_arg::<B64>(0)?
767                .into_array()
768                .map_err(|_| EK::BadSignature.at_pos(ed_sig.pos()))?;
769            let sig = ll::pk::ed25519::Signature::from(sig);
770            ll::pk::ed25519::ValidatableEd25519Signature::new(ed25519_signing_key, sig, &d)
771        };
772
773        // Extract legacy RSA signature.
774        let rsa_signature: ll::pk::rsa::ValidatableRsaSignature = {
775            let mut d = ll::d::Sha1::new();
776            let signed_end = rsa_sig_pos + b"router-signature\n".len();
777            d.update(
778                s.get(start_offset..signed_end)
779                    .ok_or(internal!("chopped utf8"))?,
780            );
781            let d = d.finalize();
782            let sig = rsa_sig.obj("SIGNATURE")?;
783            // TODO: we need to accept prefixes here. COMPAT BLOCKER.
784
785            ll::pk::rsa::ValidatableRsaSignature::new(&rsa_identity_key, &sig, &d)
786        };
787
788        // router nickname ipv4addr orport socksport dirport
789        let (nickname, ipv4addr, orport, dirport) = {
790            let rtrline = header.required(ROUTER)?;
791            (
792                rtrline.required_arg(0)?.parse::<Nickname>().map_err(|e| {
793                    EK::BadArgument
794                        .with_msg(e.to_string())
795                        .at_pos(rtrline.pos())
796                })?,
797                rtrline.parse_arg::<net::Ipv4Addr>(1)?,
798                rtrline.parse_arg(2)?,
799                // Skipping socksport.
800                rtrline.parse_arg(4)?,
801            )
802        };
803
804        // uptime
805        let uptime = body.maybe(UPTIME).parse_arg(0)?;
806
807        // published time.
808        let published = body
809            .required(PUBLISHED)?
810            .args_as_str()
811            .parse::<Iso8601TimeSp>()?;
812
813        // ntor key
814        let ntor_onion_key: Curve25519Public = body.required(NTOR_ONION_KEY)?.parse_arg(0)?;
815        // ntor crosscert
816        let (cc_sig, cc_expiry, cc_cert) = {
817            let cc = body.required(NTOR_ONION_KEY_CROSSCERT)?;
818            let sign: u8 = cc.parse_arg(0)?;
819            if sign != 0 && sign != 1 {
820                return Err(EK::BadArgument.at_pos(cc.arg_pos(0)).with_msg("not 0 or 1"));
821            }
822            let ntor_as_ed: ll::pk::ed25519::PublicKey =
823                ll::pk::keymanip::convert_curve25519_to_ed25519_public(&ntor_onion_key.0, sign)
824                    .ok_or_else(|| {
825                        EK::BadArgument
826                            .at_pos(cc.pos())
827                            .with_msg("Uncheckable crosscert")
828                    })?;
829
830            let cert = cc
831                .parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
832                .into_unchecked();
833            let (_, sig, expiry) = Ed25519NtorCrossCert::verify_inner(
834                ntor_as_ed.into(),
835                ed25519_identity_key,
836                cert.clone(),
837            )
838            .map_err(|_| EK::BadSignature.err())?;
839
840            let cert = NtorOnionKeyCrossCert {
841                bit: NumericBoolean(sign != 0),
842                // Okay to call because we added the signature to the batch.
843                cert: EmbeddedCert::new(Ed25519NtorCrossCert::dangerous_new_unverified(), cert),
844            };
845
846            (sig, expiry, cert)
847        };
848
849        // TAP key
850        let tap_onion_key: Option<ll::pk::rsa::PublicKey> = if let Some(tok) = body.get(ONION_KEY) {
851            Some(
852                tok.parse_obj::<RsaPublicParse1Helper>("RSA PUBLIC KEY")?
853                    .check_len_eq(1024)?
854                    .check_exponent(65537)?
855                    .into(),
856            )
857        } else {
858            None
859        };
860
861        // TAP crosscert
862        let tap_crosscert_sig = if let Some(cc_tok) = body.get(ONION_KEY_CROSSCERT) {
863            let cc_val = cc_tok.obj("CROSSCERT")?;
864            let mut signed = Vec::new();
865            signed.extend(rsa_identity.as_bytes());
866            signed.extend(identity_cert.peek_signing_key().as_bytes());
867            Some(ll::pk::rsa::ValidatableRsaSignature::new(
868                tap_onion_key.as_ref().ok_or_else(|| {
869                    EK::MissingToken.with_msg("onion-key-crosscert without onion-key")
870                })?,
871                &cc_val,
872                &signed,
873            ))
874        } else if tap_onion_key.is_some() {
875            return Err(EK::MissingToken.with_msg("onion-key without onion-key-crosscert"));
876        } else {
877            None
878        };
879
880        // List of subprotocol versions
881        let proto = {
882            let proto_tok = body.required(PROTO)?;
883            proto_tok
884                .args_as_str()
885                .parse::<tor_protover::Protocols>()
886                .map_err(|e| EK::BadArgument.at_pos(proto_tok.pos()).with_source(e))?
887        };
888
889        // tunneled-dir-server
890        let is_dircache = ((dirport != 0) || body.get(TUNNELLED_DIR_SERVER).is_some())
891            .then_some(ItemPresent::default());
892
893        // caches-extra-info
894        let is_extrainfo_cache = body.get(CACHES_EXTRA_INFO).map(|_| ItemPresent::default());
895
896        // fingerprint: check for consistency with RSA identity.
897        if let Some(fp_tok) = body.get(FINGERPRINT) {
898            let fp: RsaIdentity = fp_tok.args_as_str().parse::<SpFingerprint>()?.into();
899            if fp != rsa_identity {
900                return Err(EK::BadArgument
901                    .at_pos(fp_tok.pos())
902                    .with_msg("fingerprint does not match RSA identity"));
903            }
904        }
905
906        // Family
907        let family = {
908            let mut family = body
909                .maybe(FAMILY)
910                .parse_args_as_str::<RelayFamily>()?
911                .unwrap_or_else(RelayFamily::new);
912            if !family.is_empty() {
913                // If this family is nonempty, we add our own RSA id to it, on
914                // the theory that doing so will improve the odds of having a
915                // canonical family shared by all of the members of this family.
916                // If the family is empty, there's no point in adding our own ID
917                // to it, and doing so would only waste memory.
918                family.push(rsa_identity);
919            }
920            family.intern()
921        };
922
923        // Family ids (for "happy families")
924        //
925        // Unfortunately we have to store this as a tuple of KeyUnknownCert and
926        // UncheckedCert due to a parse2/legacy incongruence.  parse2 requires
927        // KeyUnknownCert for EmbeddedCert whereas the legacy parser needs
928        // descendants of it obtained by passing it irreversibly through the
929        // tor_cert verification chain.
930        let family_certs = body
931            .slice(FAMILY_CERT)
932            .iter()
933            .map(|ent| {
934                let ku = ent
935                    .parse_obj::<UnvalidatedEdCert>("FAMILY CERT")?
936                    .check_cert_type(CertType::FAMILY_V_IDENTITY)?
937                    .check_subject_key_is(identity_cert.peek_signing_key())?
938                    .into_unchecked();
939                let unchecked = ku.clone().should_have_signing_key().map_err(|e| {
940                    EK::BadObjectVal
941                        .with_msg("missing public key")
942                        .at_pos(ent.pos())
943                        .with_source(e)
944                })?;
945                Ok((ku, unchecked))
946            })
947            .collect::<Result<Vec<_>>>()?;
948
949        // or-address
950        // Extract at most one ipv6 address from the list.  It's not great,
951        // but it's what the legacy parser does.
952        let mut ipv6addr = Vec::with_capacity(1);
953        for tok in body.slice(OR_ADDRESS) {
954            if let Ok(net::SocketAddr::V6(a)) = tok.parse_arg::<net::SocketAddr>(0) {
955                ipv6addr.push(a.into());
956                break;
957            }
958            // We skip over unparsable addresses. Is that right?
959        }
960
961        // platform
962        let platform = body.maybe(PLATFORM).parse_args_as_str::<RelayPlatform>()?;
963
964        // ipv4_policy
965        let ipv4_policy = {
966            let mut pol = AddrPolicy::new();
967            for ruletok in body.slice(POLICY).iter() {
968                let accept = match ruletok.kwd_str() {
969                    "accept" => RuleKind::Accept,
970                    "reject" => RuleKind::Reject,
971                    _ => {
972                        return Err(Error::from(internal!(
973                            "tried to parse a strange line as a policy"
974                        ))
975                        .at_pos(ruletok.pos()));
976                    }
977                };
978                let pat: AddrPortPattern = ruletok
979                    .args_as_str()
980                    .parse()
981                    .map_err(|e| EK::BadPolicy.at_pos(ruletok.pos()).with_source(e))?;
982                pol.push(accept, pat);
983            }
984            pol
985        };
986
987        // ipv6 policy
988        let ipv6_policy = match body.get(IPV6_POLICY) {
989            Some(p) => p
990                .args_as_str()
991                .parse()
992                .map_err(|e| EK::BadPolicy.at_pos(p.pos()).with_source(e))?,
993            // Unwrap is safe here because str is not empty
994            #[allow(clippy::unwrap_used)]
995            None => "reject 1-65535".parse::<PortPolicy>().unwrap(),
996        };
997
998        // Now we're going to collect signatures and expiration times.
999        let (identity_cert, identity_sig) = identity_cert.dangerously_split().map_err(|err| {
1000            EK::BadObjectVal
1001                .with_msg("missing public key")
1002                .with_source(err)
1003        })?;
1004        let mut signatures: Vec<Box<dyn ll::pk::ValidatableSignature>> = vec![
1005            Box::new(rsa_signature),
1006            Box::new(ed_signature),
1007            Box::new(identity_sig),
1008            Box::new(cc_sig),
1009        ];
1010        if let Some(s) = tap_crosscert_sig {
1011            signatures.push(Box::new(s));
1012        }
1013
1014        let identity_cert = identity_cert.dangerously_assume_timely();
1015        let mut expirations = vec![
1016            published
1017                .0
1018                .saturating_add(time::Duration::new(ROUTER_EXPIRY_SECONDS, 0)),
1019            identity_cert.expiry(),
1020            cc_expiry,
1021        ];
1022
1023        // As outlined above, we have to do this ... :/
1024        //
1025        // Composing the verified part of the EmbeddedCert by just extracting
1026        // the key alone is OK because it gets checked at the end anyways
1027        // due to the push to signatures and expirations.
1028        let mut embedded_family_certs = Vec::with_capacity(family_certs.len());
1029        for (ku_cert, cert) in family_certs {
1030            let family_ed25519 = *cert.peek_signing_key();
1031            let (inner, sig) = cert.dangerously_split().map_err(into_internal!(
1032                "Missing a public key that was previously there."
1033            ))?;
1034            let embedded_cert = EmbeddedCert::new(Ed25519FamilyCert { family_ed25519 }, ku_cert);
1035            signatures.push(Box::new(sig));
1036            expirations.push(inner.dangerously_assume_timely().expiry());
1037            embedded_family_certs.push(embedded_cert);
1038        }
1039
1040        // Unwrap is safe here because `expirations` array is not empty
1041        #[allow(clippy::unwrap_used)]
1042        let expiry = *expirations.iter().min().unwrap();
1043
1044        let start_time = published
1045            .0
1046            .saturating_sub(time::Duration::new(ROUTER_PRE_VALIDITY_SECONDS, 0));
1047
1048        let desc = RouterDesc {
1049            router: RouterDescIntroItem {
1050                nickname,
1051                address: ipv4addr,
1052                orport,
1053                socksport: 0,
1054                dirport,
1055            },
1056            identity_ed25519: EmbeddedCert::new(
1057                Ed25519IdentityCert {
1058                    id_ed25519: ed25519_identity_key,
1059                    sign_ed25519: ed25519_signing_key.into(),
1060                },
1061                ku_identity_cert,
1062            ),
1063            master_key_ed25519: ed25519_identity_key.into(),
1064            bandwidth: Default::default(),
1065            platform,
1066            published,
1067            fingerprint: Some(rsa_identity.into()),
1068            hibernating: Default::default(),
1069            uptime,
1070            onion_key: tap_onion_key,
1071            ntor_onion_key,
1072            ntor_onion_key_crosscert: cc_cert,
1073            signing_key: rsa_identity_key,
1074            ipv4_policy,
1075            ipv6_policy: ipv6_policy.intern(),
1076            overload_general: Default::default(),
1077            contact: Default::default(),
1078            family,
1079            family_cert: embedded_family_certs.into(),
1080            caches_extra_info: is_extrainfo_cache,
1081            extra_info_digest: Default::default(),
1082            hidden_service_dir: Default::default(),
1083            or_address: ipv6addr,
1084            tunnelled_dir_server: is_dircache,
1085            proto,
1086        };
1087
1088        let time_gated = timed::TimerangeBound::new(desc, start_time..expiry);
1089        let sig_gated = signed::SignatureGated::new(time_gated, signatures);
1090
1091        Ok(sig_gated)
1092    }
1093}
1094
1095/// An iterator that parses one or more (possibly annotated
1096/// router descriptors from a string.
1097//
1098// TODO: This is largely copy-pasted from MicrodescReader. Can/should they
1099// be merged?
1100pub struct RouterReader<'a> {
1101    /// True iff we accept annotations
1102    annotated: bool,
1103    /// Reader that we're extracting items from.
1104    reader: NetDocReader<'a, RouterKwd>,
1105}
1106
1107/// Skip this reader forward until the next thing it reads looks like the
1108/// start of a router descriptor.
1109///
1110/// Used to recover from errors.
1111fn advance_to_next_routerdesc(reader: &mut NetDocReader<'_, RouterKwd>, annotated: bool) {
1112    use RouterKwd::*;
1113    loop {
1114        let item = reader.peek();
1115        match item {
1116            Some(Ok(t)) => {
1117                let kwd = t.kwd();
1118                if (annotated && kwd.is_annotation()) || kwd == ROUTER {
1119                    return;
1120                }
1121            }
1122            Some(Err(_)) => {
1123                // Skip over broken tokens.
1124            }
1125            None => {
1126                return;
1127            }
1128        }
1129        let _ = reader.next();
1130    }
1131}
1132
1133impl<'a> RouterReader<'a> {
1134    /// Construct a RouterReader to take router descriptors from a string.
1135    pub fn new(s: &'a str, allow: &AllowAnnotations) -> Result<Self> {
1136        let reader = NetDocReader::new(s)?;
1137        let annotated = allow == &AllowAnnotations::AnnotationsAllowed;
1138        Ok(RouterReader { annotated, reader })
1139    }
1140
1141    /// Extract an annotation from this reader.
1142    fn take_annotation(&mut self) -> Result<RouterAnnotation> {
1143        if self.annotated {
1144            RouterAnnotation::take_from_reader(&mut self.reader)
1145        } else {
1146            Ok(RouterAnnotation::default())
1147        }
1148    }
1149
1150    /// Extract an annotated router descriptor from this reader
1151    ///
1152    /// (internal helper; does not clean up on failures.)
1153    fn take_annotated_routerdesc_raw(&mut self) -> Result<AnnotatedRouterDesc> {
1154        let ann = self.take_annotation()?;
1155        let router = RouterDesc::parse_internal(&mut self.reader)?;
1156        Ok(AnnotatedRouterDesc { ann, router })
1157    }
1158
1159    /// Extract an annotated router descriptor from this reader
1160    ///
1161    /// Ensure that at least one token is consumed
1162    fn take_annotated_routerdesc(&mut self) -> Result<AnnotatedRouterDesc> {
1163        let pos_orig = self.reader.pos();
1164        let result = self.take_annotated_routerdesc_raw();
1165        if result.is_err() {
1166            if self.reader.pos() == pos_orig {
1167                // No tokens were consumed from the reader.  We need
1168                // to drop at least one token to ensure we aren't in
1169                // an infinite loop.
1170                //
1171                // (This might not be able to happen, but it's easier to
1172                // explicitly catch this case than it is to prove that
1173                // it's impossible.)
1174                let _ = self.reader.next();
1175            }
1176            advance_to_next_routerdesc(&mut self.reader, self.annotated);
1177        }
1178        result
1179    }
1180}
1181
1182impl<'a> Iterator for RouterReader<'a> {
1183    type Item = Result<AnnotatedRouterDesc>;
1184    fn next(&mut self) -> Option<Self::Item> {
1185        // Is there a next token? If not, we're done.
1186        self.reader.peek()?;
1187
1188        Some(
1189            self.take_annotated_routerdesc()
1190                .map_err(|e| e.within(self.reader.str())),
1191        )
1192    }
1193}
1194
1195#[cfg(test)]
1196mod test {
1197    // @@ begin test lint list maintained by maint/add_warning @@
1198    #![allow(clippy::bool_assert_comparison)]
1199    #![allow(clippy::clone_on_copy)]
1200    #![allow(clippy::dbg_macro)]
1201    #![allow(clippy::mixed_attributes_style)]
1202    #![allow(clippy::print_stderr)]
1203    #![allow(clippy::print_stdout)]
1204    #![allow(clippy::single_char_pattern)]
1205    #![allow(clippy::unwrap_used)]
1206    #![allow(clippy::unchecked_time_subtraction)]
1207    #![allow(clippy::useless_vec)]
1208    #![allow(clippy::needless_pass_by_value)]
1209    #![allow(clippy::string_slice)] // See arti#2571
1210    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
1211    use crate::parse2::{self, NetdocParseableUnverified, ParseInput};
1212
1213    use super::*;
1214    const TESTDATA: &str = include_str!("../../testdata/routerdesc1.txt");
1215    const TESTDATA2: &str = include_str!("../../testdata/routerdesc2.txt");
1216    // Generated with a patched C tor to include "happy family" IDs.
1217    const TESTDATA3: &str = include_str!("../../testdata/routerdesc3.txt");
1218
1219    fn read_bad(fname: &str) -> String {
1220        use std::fs;
1221        use std::path::PathBuf;
1222        let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
1223        path.push("testdata");
1224        path.push("bad-routerdesc");
1225        path.push(fname);
1226
1227        fs::read_to_string(path).unwrap()
1228    }
1229
1230    #[test]
1231    fn parse_arbitrary() -> Result<()> {
1232        use std::str::FromStr;
1233        use tor_checkable::{SelfSigned, Timebound};
1234        let rd = RouterDesc::parse(TESTDATA)?
1235            .check_signature()?
1236            .dangerously_assume_timely();
1237
1238        assert_eq!(rd.router.nickname.as_str(), "Akka");
1239        assert_eq!(rd.router.orport, 443);
1240        assert_eq!(rd.router.dirport, 0);
1241        assert_eq!(rd.uptime, Some(1036923));
1242        assert_eq!(
1243            rd.family.as_ref(),
1244            &RelayFamily::from_str(
1245                "$303509ab910ef207b7438c27435c4a2fd579f1b1 \
1246                 $56927e61b51e6f363fb55498150a6ddfcf7077f2"
1247            )
1248            .unwrap()
1249        );
1250
1251        assert_eq!(
1252            rd.rsa_identity().to_string(),
1253            "$56927e61b51e6f363fb55498150a6ddfcf7077f2"
1254        );
1255        assert_eq!(
1256            rd.ed_identity().to_string(),
1257            "CVTjf1oeaL616hH+1+UvYZ8OgkwF3z7UMITvJzm5r7A"
1258        );
1259        assert_eq!(
1260            rd.protocols().to_string(),
1261            "Cons=1-2 Desc=1-2 DirCache=2 FlowCtrl=1-2 HSDir=2 \
1262             HSIntro=4-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 \
1263             Padding=2 Relay=1-4"
1264        );
1265
1266        assert_eq!(
1267            hex::encode(rd.ntor_onion_key().to_bytes()),
1268            "329b3b52991613392e35d1a821dd6753e1210458ecc3337f7b7d39bfcf5da273"
1269        );
1270        assert_eq!(
1271            rd.published(),
1272            humantime::parse_rfc3339("2022-11-14T19:58:52Z").unwrap()
1273        );
1274        assert_eq!(
1275            rd.or_ports().collect::<Vec<_>>(),
1276            vec![
1277                "95.216.33.58:443".parse().unwrap(),
1278                "[2a01:4f9:2a:2145::2]:443".parse().unwrap(),
1279            ]
1280        );
1281        assert!(rd.onion_key.is_some());
1282
1283        Ok(())
1284    }
1285
1286    #[test]
1287    fn parse_no_tap_key() -> Result<()> {
1288        use tor_checkable::{SelfSigned, Timebound};
1289        let rd = RouterDesc::parse(TESTDATA2)?
1290            .check_signature()?
1291            .dangerously_assume_timely();
1292        assert!(rd.onion_key.is_none());
1293
1294        Ok(())
1295    }
1296
1297    #[test]
1298    fn test_bad() {
1299        use crate::Pos;
1300        use crate::types::policy::PolicyError;
1301        fn check(fname: &str, e: &Error) {
1302            let text = read_bad(fname);
1303            let rd = RouterDesc::parse(&text);
1304            assert!(rd.is_err());
1305            assert_eq!(&rd.err().unwrap(), e);
1306        }
1307
1308        check(
1309            "bad-sig-order",
1310            &EK::UnexpectedToken
1311                .with_msg("router-sig-ed25519")
1312                .at_pos(Pos::from_line(50, 1)),
1313        );
1314        check(
1315            "bad-start1",
1316            &EK::MisplacedToken
1317                .with_msg("identity-ed25519")
1318                .at_pos(Pos::from_line(1, 1)),
1319        );
1320        check("bad-start2", &EK::MissingToken.with_msg("identity-ed25519"));
1321        check(
1322            "mismatched-fp",
1323            &EK::BadArgument
1324                .at_pos(Pos::from_line(12, 1))
1325                .with_msg("fingerprint does not match RSA identity"),
1326        );
1327        check("no-ed-sk", &EK::MissingToken.with_msg("identity-ed25519"));
1328
1329        check(
1330            "bad-cc-sign",
1331            &EK::BadArgument
1332                .at_pos(Pos::from_line(34, 26))
1333                .with_msg("not 0 or 1"),
1334        );
1335        check(
1336            "bad-ipv6policy",
1337            &EK::BadPolicy
1338                .at_pos(Pos::from_line(43, 1))
1339                .with_source(PolicyError::InvalidPolicy),
1340        );
1341        check(
1342            "no-ed-id-key-in-cert",
1343            &EK::BadObjectVal
1344                .at_pos(Pos::from_line(2, 1))
1345                .with_source(tor_cert::CertError::MissingPubKey),
1346        );
1347        check(
1348            "non-ed-sk-in-cert",
1349            &EK::BadObjectVal
1350                .at_pos(Pos::from_line(2, 1))
1351                .with_msg("wrong type for signing key in cert"),
1352        );
1353        check(
1354            "bad-ed-sk-in-cert",
1355            &EK::BadObjectVal
1356                .at_pos(Pos::from_line(2, 1))
1357                .with_msg("invalid ed25519 signing key"),
1358        );
1359        check(
1360            "mismatched-ed-sk-in-cert",
1361            &EK::BadObjectVal
1362                .at_pos(Pos::from_line(8, 1))
1363                .with_msg("master-key-ed25519 does not match key in identity-ed25519"),
1364        );
1365    }
1366
1367    #[test]
1368    fn parse_multiple_annotated() {
1369        use crate::AllowAnnotations;
1370        let mut s = read_bad("bad-cc-sign");
1371        s += "\
1372@uploaded-at 2020-09-26 18:15:41
1373@source \"127.0.0.1\"
1374";
1375        s += TESTDATA;
1376        s += "\
1377@uploaded-at 2020-09-26 18:15:41
1378@source \"127.0.0.1\"
1379";
1380        s += &read_bad("mismatched-fp");
1381
1382        let rd = RouterReader::new(&s, &AllowAnnotations::AnnotationsAllowed).unwrap();
1383        let v: Vec<_> = rd.collect();
1384        assert!(v[0].is_err());
1385        assert!(v[1].is_ok());
1386        assert_eq!(
1387            v[1].as_ref().unwrap().ann.source,
1388            Some("\"127.0.0.1\"".to_string())
1389        );
1390        assert!(v[2].is_err());
1391    }
1392
1393    #[test]
1394    fn test_platform() {
1395        let tests = [
1396            // Test with platform.
1397            (
1398                "Tor 0.4.4.4-alpha on a flying bison",
1399                RelayPlatform::Tor(
1400                    "0.4.4.4-alpha".parse().unwrap(),
1401                    Some("a flying bison".to_string()),
1402                ),
1403            ),
1404            // Test without platform but potentially weird spacing.
1405            (
1406                "Tor 0.4.4.4-alpha on",
1407                RelayPlatform::Tor("0.4.4.4-alpha".parse().unwrap(), None),
1408            ),
1409            (
1410                "Tor 0.4.4.4-alpha ",
1411                RelayPlatform::Tor("0.4.4.4-alpha".parse().unwrap(), None),
1412            ),
1413            (
1414                "Tor 0.4.4.4-alpha",
1415                RelayPlatform::Tor("0.4.4.4-alpha".parse().unwrap(), None),
1416            ),
1417            // Test other.
1418            ("arti 0.0.0", RelayPlatform::Other("arti 0.0.0".to_string())),
1419        ];
1420        for (input, output) in tests {
1421            assert_eq!(input.parse::<RelayPlatform>().unwrap(), output);
1422
1423            // Round-trip test with input stripped of " on" suffix and trimmed.
1424            // Otherwise we cannot really make this work because certain inputs
1425            // contain redundant data on purpose.
1426            let input = input.strip_suffix(" on").unwrap_or(input);
1427            let input = input.trim();
1428            assert_eq!(output.to_string(), input);
1429        }
1430    }
1431
1432    #[test]
1433    fn test_family_ids() -> Result<()> {
1434        use tor_checkable::{SelfSigned, Timebound};
1435        let rd = RouterDesc::parse(TESTDATA3)?
1436            .check_signature()?
1437            .dangerously_assume_timely();
1438
1439        assert_eq!(
1440            rd.family_ids().as_ref(),
1441            &[
1442                "ed25519:7sToQRuge1bU2hS0CG0ViMndc4m82JhO4B4kdrQey80"
1443                    .parse()
1444                    .unwrap(),
1445                "ed25519:szHUS3ItRd9uk85b1UVnOZx1gg4B0266jCpbuIMNjcM"
1446                    .parse()
1447                    .unwrap(),
1448            ]
1449        );
1450
1451        Ok(())
1452    }
1453
1454    // TODO: For now, this only tests if decoding works with a few field checks.
1455    // It should be extended to a full roundtrip test with failed verification
1456    // at one point eventually ...
1457    #[test]
1458    fn test_parse2() {
1459        let input = ParseInput::new(
1460            include_str!("../../testdata2/cached-descriptors.new"),
1461            "cached-descriptors.new",
1462        );
1463        let rd = parse2::parse_netdoc_multiple::<RouterDescUnverified>(&input)
1464            .unwrap()
1465            .into_iter()
1466            .map(|rd| rd.unwrap_unverified().0)
1467            .collect::<Vec<RouterDesc>>();
1468        assert_eq!(rd.len(), 20);
1469        assert_eq!(
1470            rd[0].router,
1471            RouterDescIntroItem {
1472                nickname: "test002a".parse().unwrap(),
1473                address: net::Ipv4Addr::LOCALHOST,
1474                orport: 5102,
1475                socksport: 0,
1476                dirport: 7102
1477            }
1478        );
1479        assert_eq!(
1480            rd[0].fingerprint.unwrap(),
1481            "257D 06F0 360B B224 6388 724F 109E C089 5A1D 41FB"
1482                .parse()
1483                .unwrap()
1484        );
1485    }
1486}