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