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.
35
use crate::parse::keyword::Keyword;
36
use crate::parse::parser::{Section, SectionRules};
37
use crate::parse::tokenize::{ItemResult, NetDocReader};
38
use crate::parse2::{ArgumentError, ArgumentStream, ItemArgumentParseable};
39
use crate::types::family::{RelayFamily, RelayFamilyId};
40
use crate::types::misc::*;
41
use crate::types::policy::*;
42
use crate::types::routerdesc::*;
43
use crate::types::version::TorVersion;
44
use crate::util::PeekableIterator;
45
use crate::{AllowAnnotations, Error, KeywordEncodable, NetdocErrorKind as EK, Result};
46

            
47
use derive_deftly::Deftly;
48
use ll::pk::ed25519::Ed25519Identity;
49
use std::sync::Arc;
50
use std::sync::LazyLock;
51
use std::{net, time};
52
use tor_cert::CertType;
53
use tor_checkable::{Timebound, signed, timed};
54
use tor_error::{internal, into_internal};
55
use tor_llcrypto as ll;
56
use tor_llcrypto::pk::rsa::RsaIdentity;
57

            
58
use digest::Digest;
59

            
60
/// Length of a router descriptor digest
61
pub const DOC_DIGEST_LEN: usize = 20;
62

            
63
/// The digest of a RouterDesc document, as reported in a NS consensus.
64
pub type RdDigest = [u8; DOC_DIGEST_LEN];
65

            
66
/// The digest of an ExtraInfo document, as reported in a RouterDesc.
67
pub type ExtraInfoDigest = [u8; DOC_DIGEST_LEN];
68

            
69
/// A router descriptor, with possible annotations.
70
#[non_exhaustive]
71
pub struct AnnotatedRouterDesc {
72
    /// Annotation for this router descriptor; possibly empty.
73
    pub ann: RouterAnnotation,
74
    /// Underlying router descriptor; signatures not checked yet.
75
    pub router: UncheckedRouterDesc,
76
}
77

            
78
/// Annotations about a router descriptor, as stored on disc.
79
#[derive(Default)]
80
#[non_exhaustive]
81
pub struct RouterAnnotation {
82
    /// Description of where we got this router descriptor
83
    pub source: Option<String>,
84
    /// When this descriptor was first downloaded.
85
    pub downloaded: Option<time::SystemTime>,
86
    /// Description of what we're willing to use this descriptor for.
87
    pub purpose: Option<String>,
88
}
89

            
90
/// Information about a relay, parsed from a router descriptor.
91
///
92
/// This type does not hold all the information in the router descriptor
93
///
94
/// # Limitations
95
///
96
/// See module documentation.
97
///
98
/// Additionally, some fields that from router descriptors are not yet
99
/// parsed: see the comments in ROUTER_BODY_RULES for information about those.
100
///
101
/// Before using this type to connect to a relay, you MUST check that
102
/// it is valid, using is_expired_at().
103
///
104
/// # Specification
105
///
106
/// <https://spec.torproject.org/dir-spec/server-descriptor-format.html>
107
#[derive(Clone, Debug)]
108
#[non_exhaustive]
109
pub struct RouterDesc {
110
    // === Virtual items ===
111
    // These items do not correspond to any actual item within the router
112
    // descriptor from a netdoc point of view.  They cannot persist this way
113
    // in parse2 and are already grouped together this way to indicate this
114
    // change.  For example, `family_ids` is computed on the fly and is not
115
    // present in normal router descriptors.  Although `orport`, `nickname`
116
    // and other members are present in a router descriptor, they are only
117
    // present as arguments, not as independent items.
118
    //
119
    //
120
    /// Human-readable nickname for this relay.
121
    ///
122
    /// This is not secure, and not guaranteed to be unique.
123
    pub nickname: Nickname,
124

            
125
    /// IPv4 address for this relay.
126
    pub ipv4addr: Option<net::Ipv4Addr>,
127

            
128
    /// IPv4 ORPort for this relay.
129
    pub orport: u16,
130

            
131
    /// Directory port for contacting this relay for direct HTTP
132
    /// directory downloads.
133
    pub dirport: u16,
134

            
135
    /// Declared (and proven) family IDs for this relay. If two relays
136
    /// share a family ID, they shouldn't be used in the same circuit.
137
    family_ids: Vec<RelayFamilyId>,
138

            
139
    // === Real items ===
140
    // These items are real and correspond to actual items found in router
141
    // descriptors, although potentially not under the same name.
142
    //
143
    //
144
    /// `identity-ed25519` --- Specify the router's ed25519 identity.
145
    ///
146
    /// * `identity-ed25519\n<certificate object>`
147
    /// * Exactly once, in second position in document.
148
    pub identity_ed25519: tor_cert::Ed25519Cert,
149

            
150
    /// `platform` --- Describe the platform on which this relay is running.
151
    ///
152
    /// * `platform <rest of line>`
153
    /// * At most once.
154
    pub platform: Option<RelayPlatform>,
155

            
156
    /// `published` --- Time this descriptor (and extra-info) was generated.
157
    ///
158
    /// * `published <date> <time>`
159
    /// * Exactly once.
160
    pub published: time::SystemTime,
161

            
162
    /// `fingerprint` --- Redundant hash of ASN-1 encoding of router identity key.
163
    ///
164
    /// * `fingerprint <spaced fingerprint>`
165
    /// * At most once.
166
    pub fingerprint: Option<SpFingerprint>,
167

            
168
    /// `uptime` --- How long this relay has been continously running
169
    ///
170
    /// * `uptime <number>`
171
    /// * At most once.
172
    pub uptime: Option<u64>,
173

            
174
    /// `onion-key` --- Relay's obsolete RSA tap key.
175
    ///
176
    /// * `onion-key\n<rsa public key>`
177
    /// * At most once.
178
    /// * No extra arguments.
179
    pub onion_key: Option<ll::pk::rsa::PublicKey>,
180

            
181
    /// `ntor-onion-key` --- The circuit extension key.
182
    ///
183
    /// * `ntor-onion-key <base64 padded key>`
184
    /// * Exactly once.
185
    pub ntor_onion_key: ll::pk::curve25519::PublicKey,
186

            
187
    /// `signing-key` --- Obsolete RSA identity key.
188
    ///
189
    /// * `signing-key\n<rsa public key>`
190
    pub signing_key: ll::pk::rsa::PublicKey,
191

            
192
    /// `accept, reject` --- Exit policy.
193
    ///
194
    /// * `accept exitpattern`
195
    /// * `reject exitpattern`
196
    /// * Any number of times.
197
    // TODO: these polices can get bulky too. Perhaps we should
198
    // de-duplicate them too.
199
    pub ipv4_policy: AddrPolicy,
200

            
201
    /// `ipv6-policy` --- Exit plicy summary for IPv6
202
    ///
203
    /// * `ipv6-policy <accept/reject> PortList`
204
    /// * At most once.
205
    pub ipv6_policy: Arc<PortPolicy>,
206

            
207
    /// `family` --- Group relays for the purpose of path selection.
208
    ///
209
    /// * `family <LongIdent> ...`
210
    /// * One or more `LongIdent` arguments.
211
    /// * At most once.
212
    pub family: Arc<RelayFamily>,
213

            
214
    /// `caches-extra-info` --- Router provides extra-info as a dirmirror.
215
    ///
216
    /// * `caches-extra-info`
217
    /// * At most once.
218
    /// * No extra arguments.
219
    pub caches_extra_info: bool,
220

            
221
    /// `or-address` --- Alternative ORport address and port
222
    ///
223
    /// * `or-address <address>:<port>`.
224
    /// * Any number of times.
225
    // TODO: we don't use a socketaddrv6 because we don't care about
226
    // the flow and scope fields.  We should decide whether that's a
227
    // good idea.
228
    pub or_address: Option<(net::Ipv6Addr, u16)>,
229

            
230
    /// `tunnelled-dir-server` --- Accepts a `BEGIN_DIR` relay message.
231
    ///
232
    /// * `tunnelled-dir-server`
233
    /// * At most once.
234
    /// * No extra arguments.
235
    pub tunnelled_dir_server: bool,
236

            
237
    /// `proto` --- Subprotocol capabilities supported.
238
    ///
239
    /// * `proto <entries>`
240
    /// * Exactly once.
241
    pub proto: tor_protover::Protocols,
242
}
243

            
244
/// Signatures of a [`RouterDesc`].
245
///
246
/// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:router-sig-ed25519>
247
#[derive(Clone, Debug, Deftly)]
248
#[derive_deftly(NetdocParseableSignatures)]
249
#[deftly(netdoc(signatures(hashes_accu = "RouterHashAccu")))]
250
#[non_exhaustive]
251
pub struct RouterDescSignatures {
252
    /// `router-sig-ed25519` --- Ed25519 signature
253
    ///
254
    /// Ed25519 signature by the Ed25519 signing key on the SHA-256 digest of
255
    /// the document prefixed by a magic up until and including the
256
    /// `router-sig-ed25519` keyword plus space.
257
    pub router_sig_ed25519: RouterSigEd25519,
258

            
259
    /// `router-signature` --- RSA signature
260
    ///
261
    /// * At end, exactly once.
262
    /// * RSA signature of the document, including `router-sig-ed25519`.
263
    pub router_signature: RouterSignature,
264
}
265

            
266
/// Description of the software a relay is running.
267
// TODO: Move this to types/misc.rs.
268
#[derive(Debug, Clone, PartialEq, Eq)]
269
#[non_exhaustive]
270
pub enum RelayPlatform {
271
    /// Software advertised to be some version of Tor, on some platform.
272
    Tor(TorVersion, String),
273
    /// Software not advertised to be Tor.
274
    Other(String),
275
}
276

            
277
impl std::str::FromStr for RelayPlatform {
278
    type Err = Error;
279
2288
    fn from_str(args: &str) -> Result<Self> {
280
2288
        if args.starts_with("Tor ") {
281
2286
            let v: Vec<_> = args.splitn(4, ' ').collect();
282
2286
            match &v[..] {
283
2280
                ["Tor", ver, "on", p] => Ok(RelayPlatform::Tor(ver.parse()?, (*p).to_string())),
284
6
                ["Tor", ver, ..] => Ok(RelayPlatform::Tor(ver.parse()?, "".to_string())),
285
                _ => unreachable!(),
286
            }
287
        } else {
288
2
            Ok(RelayPlatform::Other(args.to_string()))
289
        }
290
2288
    }
291
}
292

            
293
impl ItemArgumentParseable for RelayPlatform {
294
    fn from_args<'s>(args: &mut ArgumentStream<'s>) -> std::result::Result<Self, ArgumentError> {
295
        args.into_remaining()
296
            .parse()
297
            .map_err(|_| ArgumentError::Invalid)
298
    }
299
}
300

            
301
decl_keyword! {
302
    /// RouterKwd is an instance of Keyword, used to denote the different
303
    /// Items that are recognized as appearing in a router descriptor.
304
    RouterKwd {
305
        annotation "@source" => ANN_SOURCE,
306
        annotation "@downloaded-at" => ANN_DOWNLOADED_AT,
307
        annotation "@purpose" => ANN_PURPOSE,
308
        "accept" | "reject" => POLICY,
309
        "bandwidth" => BANDWIDTH,
310
        "bridge-distribution-request" => BRIDGE_DISTRIBUTION_REQUEST,
311
        "caches-extra-info" => CACHES_EXTRA_INFO,
312
        "contact" => CONTACT,
313
        "extra-info-digest" => EXTRA_INFO_DIGEST,
314
        "family" => FAMILY,
315
        "family-cert" => FAMILY_CERT,
316
        "fingerprint" => FINGERPRINT,
317
        "hibernating" => HIBERNATING,
318
        "identity-ed25519" => IDENTITY_ED25519,
319
        "ipv6-policy" => IPV6_POLICY,
320
        "master-key-ed25519" => MASTER_KEY_ED25519,
321
        "ntor-onion-key" => NTOR_ONION_KEY,
322
        "ntor-onion-key-crosscert" => NTOR_ONION_KEY_CROSSCERT,
323
        "onion-key" => ONION_KEY,
324
        "onion-key-crosscert" => ONION_KEY_CROSSCERT,
325
        "or-address" => OR_ADDRESS,
326
        "platform" => PLATFORM,
327
        "proto" => PROTO,
328
        "published" => PUBLISHED,
329
        "router" => ROUTER,
330
        "router-sig-ed25519" => ROUTER_SIG_ED25519,
331
        "router-signature" => ROUTER_SIGNATURE,
332
        "signing-key" => SIGNING_KEY,
333
        "tunnelled_dir_server" => TUNNELLED_DIR_SERVER,
334
        "uptime" => UPTIME,
335
        // "protocols" once existed, but is obsolete
336
        // "eventdns" once existed, but is obsolete
337
        // "allow-single-hop-exits" is also obsolete.
338
    }
339
}
340

            
341
/// Rules for parsing a set of router descriptor annotations.
342
2
static ROUTER_ANNOTATIONS: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
343
    use RouterKwd::*;
344

            
345
2
    let mut rules = SectionRules::builder();
346
2
    rules.add(ANN_SOURCE.rule());
347
2
    rules.add(ANN_DOWNLOADED_AT.rule().args(1..));
348
2
    rules.add(ANN_PURPOSE.rule().args(1..));
349
2
    rules.add(ANN_UNRECOGNIZED.rule().may_repeat().obj_optional());
350
    // Unrecognized annotations are fine; anything else is an error in this
351
    // context.
352
2
    rules.reject_unrecognized();
353
2
    rules.build()
354
2
});
355
/// Rules for tokens that are allowed in the first part of a
356
/// router descriptor.
357
56
static ROUTER_HEADER_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
358
    use RouterKwd::*;
359

            
360
56
    let mut rules = SectionRules::builder();
361
56
    rules.add(ROUTER.rule().required().args(5..));
362
56
    rules.add(IDENTITY_ED25519.rule().required().no_args().obj_required());
363
    // No other intervening tokens are permitted in the header.
364
56
    rules.reject_unrecognized();
365
56
    rules.build()
366
56
});
367
/// Rules for  tokens that are allowed in the first part of a
368
/// router descriptor.
369
56
static ROUTER_BODY_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
370
    use RouterKwd::*;
371

            
372
56
    let mut rules = SectionRules::builder();
373
56
    rules.add(MASTER_KEY_ED25519.rule().required().args(1..));
374
56
    rules.add(PLATFORM.rule());
375
56
    rules.add(PUBLISHED.rule().required());
376
56
    rules.add(FINGERPRINT.rule());
377
56
    rules.add(UPTIME.rule().args(1..));
378
56
    rules.add(ONION_KEY.rule().no_args().obj_required());
379
56
    rules.add(ONION_KEY_CROSSCERT.rule().no_args().obj_required());
380
56
    rules.add(NTOR_ONION_KEY.rule().required().args(1..));
381
56
    rules.add(
382
56
        NTOR_ONION_KEY_CROSSCERT
383
56
            .rule()
384
56
            .required()
385
56
            .args(1..=1)
386
56
            .obj_required(),
387
    );
388
56
    rules.add(SIGNING_KEY.rule().no_args().required().obj_required());
389
56
    rules.add(POLICY.rule().may_repeat().args(1..));
390
56
    rules.add(IPV6_POLICY.rule().args(2..));
391
56
    rules.add(FAMILY.rule().args(1..));
392
56
    rules.add(FAMILY_CERT.rule().obj_required().may_repeat());
393
56
    rules.add(CACHES_EXTRA_INFO.rule().no_args());
394
56
    rules.add(OR_ADDRESS.rule().may_repeat().args(1..));
395
56
    rules.add(TUNNELLED_DIR_SERVER.rule());
396
56
    rules.add(PROTO.rule().required().args(1..));
397
56
    rules.add(UNRECOGNIZED.rule().may_repeat().obj_optional());
398
    // TODO: these aren't parsed yet.  Only authorities use them.
399
56
    {
400
56
        rules.add(BANDWIDTH.rule().required().args(3..));
401
56
        rules.add(BRIDGE_DISTRIBUTION_REQUEST.rule().args(1..));
402
56
        rules.add(HIBERNATING.rule().args(1..));
403
56
        rules.add(CONTACT.rule());
404
56
    }
405
    // TODO: this is ignored for now.
406
56
    {
407
56
        rules.add(EXTRA_INFO_DIGEST.rule().args(1..));
408
56
    }
409
56
    rules.build()
410
56
});
411

            
412
/// Rules for items that appear at the end of a router descriptor.
413
56
static ROUTER_SIG_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
414
    use RouterKwd::*;
415

            
416
56
    let mut rules = SectionRules::builder();
417
56
    rules.add(ROUTER_SIG_ED25519.rule().required().args(1..));
418
56
    rules.add(ROUTER_SIGNATURE.rule().required().no_args().obj_required());
419
    // No intervening tokens are allowed in the footer.
420
56
    rules.reject_unrecognized();
421
56
    rules.build()
422
56
});
423

            
424
impl RouterAnnotation {
425
    /// Extract a single RouterAnnotation (possibly empty) from a reader.
426
8
    fn take_from_reader(reader: &mut NetDocReader<'_, RouterKwd>) -> Result<RouterAnnotation> {
427
        use RouterKwd::*;
428
20
        let mut items = reader.pause_at(|item| item.is_ok_with_non_annotation());
429

            
430
8
        let body = ROUTER_ANNOTATIONS.parse(&mut items)?;
431

            
432
6
        let source = body.maybe(ANN_SOURCE).args_as_str().map(String::from);
433
6
        let purpose = body.maybe(ANN_PURPOSE).args_as_str().map(String::from);
434
6
        let downloaded = body
435
6
            .maybe(ANN_DOWNLOADED_AT)
436
6
            .parse_args_as_str::<Iso8601TimeSp>()?
437
6
            .map(|t| t.into());
438
6
        Ok(RouterAnnotation {
439
6
            source,
440
6
            downloaded,
441
6
            purpose,
442
6
        })
443
8
    }
444
}
445

            
446
/// A parsed router descriptor whose signatures and/or validity times
447
/// may or may not be invalid.
448
pub type UncheckedRouterDesc = signed::SignatureGated<timed::TimerangeBound<RouterDesc>>;
449

            
450
/// How long after its published time is a router descriptor officially
451
/// supposed to be usable?
452
const ROUTER_EXPIRY_SECONDS: u64 = 5 * 86400;
453

            
454
/// How long before its published time is a router descriptor usable?
455
// TODO(nickm): This valid doesn't match C tor, which only enforces this rule
456
// ("routers should not some from the future") at directory authorities, and
457
// there only enforces a 12-hour limit (`ROUTER_ALLOW_SKEW`).  Eventually we
458
// should probably harmonize these cutoffs.
459
const ROUTER_PRE_VALIDITY_SECONDS: u64 = 86400;
460

            
461
impl RouterDesc {
462
    /// Return a reference to this relay's RSA identity.
463
1298
    pub fn rsa_identity(&self) -> RsaIdentity {
464
1298
        self.signing_key.to_rsa_identity()
465
1298
    }
466

            
467
    /// Return a reference to this relay's Ed25519 identity.
468
2
    pub fn ed_identity(&self) -> &Ed25519Identity {
469
2
        self.identity_ed25519
470
2
            .signing_key()
471
2
            .expect("No ed25519 identity key on identity cert")
472
2
    }
473

            
474
    /// Return a reference to the list of subprotocol versions supported by this
475
    /// relay.
476
2
    pub fn protocols(&self) -> &tor_protover::Protocols {
477
2
        &self.proto
478
2
    }
479

            
480
    /// Return a reference to this relay's Ntor onion key.
481
2
    pub fn ntor_onion_key(&self) -> &ll::pk::curve25519::PublicKey {
482
2
        &self.ntor_onion_key
483
2
    }
484

            
485
    /// Return the publication
486
326
    pub fn published(&self) -> time::SystemTime {
487
326
        self.published
488
326
    }
489

            
490
    /// Return an iterator of every `SocketAddr` at which this descriptor says
491
    /// its relay can be reached.
492
2
    pub fn or_ports(&self) -> impl Iterator<Item = net::SocketAddr> + '_ {
493
2
        self.ipv4addr
494
3
            .map(|a| net::SocketAddr::new(a.into(), self.orport))
495
2
            .into_iter()
496
2
            .chain(self.or_address.map(net::SocketAddr::from))
497
2
    }
498

            
499
    /// Return the declared family of this descriptor.
500
    pub fn family(&self) -> Arc<RelayFamily> {
501
        Arc::clone(&self.family)
502
    }
503

            
504
    /// Return the authenticated family IDs of this descriptor.
505
2
    pub fn family_ids(&self) -> &[RelayFamilyId] {
506
2
        &self.family_ids[..]
507
2
    }
508

            
509
    /// Helper: tokenize `s`, and divide it into three validated sections.
510
2410
    fn parse_sections<'a>(
511
2410
        reader: &mut NetDocReader<'a, RouterKwd>,
512
2410
    ) -> Result<(
513
2410
        Section<'a, RouterKwd>,
514
2410
        Section<'a, RouterKwd>,
515
2410
        Section<'a, RouterKwd>,
516
2410
    )> {
517
        use RouterKwd::*;
518

            
519
        // Parse everything up through the header.
520
2410
        let header = ROUTER_HEADER_RULES.parse(
521
7069
            reader.pause_at(|item| item.is_ok_with_kwd_not_in(&[ROUTER, IDENTITY_ED25519])),
522
112
        )?;
523

            
524
        // Parse everything up to but not including the signature.
525
2298
        let body =
526
39167
            ROUTER_BODY_RULES.parse(reader.pause_at(|item| {
527
39110
                item.is_ok_with_kwd_in(&[ROUTER_SIGNATURE, ROUTER_SIG_ED25519])
528
39110
            }))?;
529

            
530
        // Parse the signature.
531
4667
        let sig = ROUTER_SIG_RULES.parse(reader.pause_at(|item| {
532
4610
            item.is_ok_with_annotation() || item.is_ok_with_kwd(ROUTER) || item.is_empty_line()
533
4610
        }))?;
534

            
535
2298
        Ok((header, body, sig))
536
2410
    }
537

            
538
    /// Try to parse `s` as a router descriptor.
539
    ///
540
    /// Does not actually check liveness or signatures; you need to do that
541
    /// yourself before you can do the output.
542
2404
    pub fn parse(s: &str) -> Result<UncheckedRouterDesc> {
543
2404
        let mut reader = crate::parse::tokenize::NetDocReader::new(s)?;
544
2417
        let result = Self::parse_internal(&mut reader).map_err(|e| e.within(s))?;
545
        // We permit empty lines at the end of router descriptors, since there's
546
        // a known issue in Tor relays that causes them to return them this way.
547
2274
        reader
548
2274
            .should_be_exhausted_but_for_empty_lines()
549
2274
            .map_err(|e| e.within(s))?;
550
2274
        Ok(result)
551
2404
    }
552

            
553
    /// Helper: parse a router descriptor from `s`.
554
    ///
555
    /// This function does the same as parse(), but returns errors based on
556
    /// byte-wise positions.  The parse() function converts such errors
557
    /// into line-and-byte positions.
558
2410
    fn parse_internal(r: &mut NetDocReader<'_, RouterKwd>) -> Result<UncheckedRouterDesc> {
559
        // TODO: This function is too long!  The little "paragraphs" here
560
        // that parse one item at a time should be made into sub-functions.
561
        use RouterKwd::*;
562

            
563
2410
        let s = r.str();
564
2410
        let (header, body, sig) = RouterDesc::parse_sections(r)?;
565

            
566
        // Unwrap should be safe because inline `required` call should return
567
        // `Error::MissingToken` if `ROUTER` is not `Ok`
568
        #[allow(clippy::unwrap_used)]
569
2298
        let start_offset = header.required(ROUTER)?.offset_in(s).unwrap();
570

            
571
        // ed25519 identity and signing key.
572
2290
        let (identity_cert, ed25519_signing_key) = {
573
2298
            let cert_tok = header.required(IDENTITY_ED25519)?;
574
            // Unwrap should be safe because above `required` call should
575
            // return `Error::MissingToken` if `IDENTITY_ED25519` is not `Ok`
576
            #[allow(clippy::unwrap_used)]
577
2298
            if cert_tok.offset_in(s).unwrap() < start_offset {
578
2
                return Err(EK::MisplacedToken
579
2
                    .with_msg("identity-ed25519")
580
2
                    .at_pos(cert_tok.pos()));
581
2296
            }
582
2296
            let cert: tor_cert::UncheckedCert = cert_tok
583
2296
                .parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
584
2296
                .check_cert_type(tor_cert::CertType::IDENTITY_V_SIGNING)?
585
2296
                .into_unchecked()
586
2296
                .should_have_signing_key()
587
2297
                .map_err(|err| {
588
2
                    EK::BadObjectVal
589
2
                        .err()
590
2
                        .with_source(err)
591
2
                        .at_pos(cert_tok.pos())
592
3
                })?;
593
2295
            let sk = *cert.peek_subject_key().as_ed25519().ok_or_else(|| {
594
2
                EK::BadObjectVal
595
2
                    .at_pos(cert_tok.pos())
596
2
                    .with_msg("wrong type for signing key in cert")
597
3
            })?;
598
2293
            let sk: ll::pk::ed25519::PublicKey = sk.try_into().map_err(|_| {
599
2
                EK::BadObjectVal
600
2
                    .at_pos(cert_tok.pos())
601
2
                    .with_msg("invalid ed25519 signing key")
602
3
            })?;
603
2290
            (cert, sk)
604
        };
605

            
606
        // master-key-ed25519: required, and should match certificate.
607
        #[allow(unexpected_cfgs)]
608
        {
609
2290
            let master_key_tok = body.required(MASTER_KEY_ED25519)?;
610
2290
            let ed_id: Ed25519Public = master_key_tok.parse_arg(0)?;
611
2290
            let ed_id: ll::pk::ed25519::Ed25519Identity = ed_id.into();
612
2290
            if ed_id != *identity_cert.peek_signing_key() {
613
                #[cfg(not(fuzzing))] // No feature here; never omit in production.
614
2
                return Err(EK::BadObjectVal
615
2
                    .at_pos(master_key_tok.pos())
616
2
                    .with_msg("master-key-ed25519 does not match key in identity-ed25519"));
617
2288
            }
618
        }
619

            
620
        // Legacy RSA identity
621
2288
        let rsa_identity_key: ll::pk::rsa::PublicKey = body
622
2288
            .required(SIGNING_KEY)?
623
2288
            .parse_obj::<RsaPublicParse1Helper>("RSA PUBLIC KEY")?
624
2288
            .check_len_eq(1024)?
625
2288
            .check_exponent(65537)?
626
2288
            .into();
627
2288
        let rsa_identity = rsa_identity_key.to_rsa_identity();
628

            
629
2288
        let ed_sig = sig.required(ROUTER_SIG_ED25519)?;
630
2288
        let rsa_sig = sig.required(ROUTER_SIGNATURE)?;
631
        // Unwrap should be safe because above `required` calls should return
632
        // an `Error::MissingToken` if `ROUTER_...` is not `Ok`
633
        #[allow(clippy::unwrap_used)]
634
2288
        let ed_sig_pos = ed_sig.offset_in(s).unwrap();
635
        #[allow(clippy::unwrap_used)]
636
2288
        let rsa_sig_pos = rsa_sig.offset_in(s).unwrap();
637

            
638
2288
        if ed_sig_pos > rsa_sig_pos {
639
2
            return Err(EK::UnexpectedToken
640
2
                .with_msg(ROUTER_SIG_ED25519.to_str())
641
2
                .at_pos(ed_sig.pos()));
642
2286
        }
643

            
644
        // Extract ed25519 signature.
645
2286
        let ed_signature: ll::pk::ed25519::ValidatableEd25519Signature = {
646
2286
            let mut d = ll::d::Sha256::new();
647
2286
            d.update(&b"Tor router descriptor signature v1"[..]);
648
2286
            let signed_end = ed_sig_pos + b"router-sig-ed25519 ".len();
649
2286
            d.update(&s[start_offset..signed_end]);
650
2286
            let d = d.finalize();
651
2286
            let sig: [u8; 64] = ed_sig
652
2286
                .parse_arg::<B64>(0)?
653
2286
                .into_array()
654
2286
                .map_err(|_| EK::BadSignature.at_pos(ed_sig.pos()))?;
655
2286
            let sig = ll::pk::ed25519::Signature::from(sig);
656
2286
            ll::pk::ed25519::ValidatableEd25519Signature::new(ed25519_signing_key, sig, &d)
657
        };
658

            
659
        // Extract legacy RSA signature.
660
2286
        let rsa_signature: ll::pk::rsa::ValidatableRsaSignature = {
661
2286
            let mut d = ll::d::Sha1::new();
662
2286
            let signed_end = rsa_sig_pos + b"router-signature\n".len();
663
2286
            d.update(&s[start_offset..signed_end]);
664
2286
            let d = d.finalize();
665
2286
            let sig = rsa_sig.obj("SIGNATURE")?;
666
            // TODO: we need to accept prefixes here. COMPAT BLOCKER.
667

            
668
2286
            ll::pk::rsa::ValidatableRsaSignature::new(&rsa_identity_key, &sig, &d)
669
        };
670

            
671
        // router nickname ipv4addr orport socksport dirport
672
2286
        let (nickname, ipv4addr, orport, dirport) = {
673
2286
            let rtrline = header.required(ROUTER)?;
674
            (
675
2286
                rtrline.required_arg(0)?.parse::<Nickname>().map_err(|e| {
676
                    EK::BadArgument
677
                        .with_msg(e.to_string())
678
                        .at_pos(rtrline.pos())
679
                })?,
680
2286
                Some(rtrline.parse_arg::<net::Ipv4Addr>(1)?),
681
2286
                rtrline.parse_arg(2)?,
682
                // Skipping socksport.
683
2286
                rtrline.parse_arg(4)?,
684
            )
685
        };
686

            
687
        // uptime
688
2286
        let uptime = body.maybe(UPTIME).parse_arg(0)?;
689

            
690
        // published time.
691
2286
        let published = body
692
2286
            .required(PUBLISHED)?
693
2286
            .args_as_str()
694
2286
            .parse::<Iso8601TimeSp>()?
695
2286
            .into();
696

            
697
        // ntor key
698
2286
        let ntor_onion_key: Curve25519Public = body.required(NTOR_ONION_KEY)?.parse_arg(0)?;
699
2286
        let ntor_onion_key: ll::pk::curve25519::PublicKey = ntor_onion_key.into();
700
        // ntor crosscert
701
2282
        let crosscert_cert: tor_cert::UncheckedCert = {
702
2286
            let cc = body.required(NTOR_ONION_KEY_CROSSCERT)?;
703
2286
            let sign: u8 = cc.parse_arg(0)?;
704
2286
            if sign != 0 && sign != 1 {
705
4
                return Err(EK::BadArgument.at_pos(cc.arg_pos(0)).with_msg("not 0 or 1"));
706
2282
            }
707
2282
            let ntor_as_ed: ll::pk::ed25519::PublicKey =
708
2282
                ll::pk::keymanip::convert_curve25519_to_ed25519_public(&ntor_onion_key, sign)
709
2282
                    .ok_or_else(|| {
710
                        EK::BadArgument
711
                            .at_pos(cc.pos())
712
                            .with_msg("Uncheckable crosscert")
713
                    })?;
714

            
715
2282
            cc.parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
716
2282
                .check_cert_type(tor_cert::CertType::NTOR_CC_IDENTITY)?
717
2282
                .check_subject_key_is(identity_cert.peek_signing_key())?
718
2282
                .into_unchecked()
719
2282
                .should_be_signed_with(&ntor_as_ed.into())
720
2282
                .map_err(|err| EK::BadSignature.err().with_source(err))?
721
        };
722

            
723
        // TAP key
724
2282
        let tap_onion_key: Option<ll::pk::rsa::PublicKey> = if let Some(tok) = body.get(ONION_KEY) {
725
            Some(
726
2280
                tok.parse_obj::<RsaPublicParse1Helper>("RSA PUBLIC KEY")?
727
2280
                    .check_len_eq(1024)?
728
2280
                    .check_exponent(65537)?
729
2280
                    .into(),
730
            )
731
        } else {
732
2
            None
733
        };
734

            
735
        // TAP crosscert
736
2282
        let tap_crosscert_sig = if let Some(cc_tok) = body.get(ONION_KEY_CROSSCERT) {
737
2280
            let cc_val = cc_tok.obj("CROSSCERT")?;
738
2280
            let mut signed = Vec::new();
739
2280
            signed.extend(rsa_identity.as_bytes());
740
2280
            signed.extend(identity_cert.peek_signing_key().as_bytes());
741
2280
            Some(ll::pk::rsa::ValidatableRsaSignature::new(
742
2280
                tap_onion_key.as_ref().ok_or_else(|| {
743
                    EK::MissingToken.with_msg("onion-key-crosscert without onion-key")
744
                })?,
745
2280
                &cc_val,
746
2280
                &signed,
747
            ))
748
2
        } else if tap_onion_key.is_some() {
749
            return Err(EK::MissingToken.with_msg("onion-key without onion-key-crosscert"));
750
        } else {
751
2
            None
752
        };
753

            
754
        // List of subprotocol versions
755
2282
        let proto = {
756
2282
            let proto_tok = body.required(PROTO)?;
757
2282
            proto_tok
758
2282
                .args_as_str()
759
2282
                .parse::<tor_protover::Protocols>()
760
2282
                .map_err(|e| EK::BadArgument.at_pos(proto_tok.pos()).with_source(e))?
761
        };
762

            
763
        // tunneled-dir-server
764
2282
        let is_dircache = (dirport != 0) || body.get(TUNNELLED_DIR_SERVER).is_some();
765

            
766
        // caches-extra-info
767
2282
        let is_extrainfo_cache = body.get(CACHES_EXTRA_INFO).is_some();
768

            
769
        // fingerprint: check for consistency with RSA identity.
770
2282
        if let Some(fp_tok) = body.get(FINGERPRINT) {
771
2282
            let fp: RsaIdentity = fp_tok.args_as_str().parse::<SpFingerprint>()?.into();
772
2282
            if fp != rsa_identity {
773
4
                return Err(EK::BadArgument
774
4
                    .at_pos(fp_tok.pos())
775
4
                    .with_msg("fingerprint does not match RSA identity"));
776
2278
            }
777
        }
778

            
779
        // Family
780
2278
        let family = {
781
2278
            let mut family = body
782
2278
                .maybe(FAMILY)
783
2278
                .parse_args_as_str::<RelayFamily>()?
784
2278
                .unwrap_or_else(RelayFamily::new);
785
2278
            if !family.is_empty() {
786
4
                // If this family is nonempty, we add our own RSA id to it, on
787
4
                // the theory that doing so will improve the odds of having a
788
4
                // canonical family shared by all of the members of this family.
789
4
                // If the family is empty, there's no point in adding our own ID
790
4
                // to it, and doing so would only waste memory.
791
4
                family.push(rsa_identity);
792
2274
            }
793
2278
            family.intern()
794
        };
795

            
796
        // Family ids (for "happy families")
797
2278
        let family_certs: Vec<tor_cert::UncheckedCert> = body
798
2278
            .slice(FAMILY_CERT)
799
2278
            .iter()
800
2280
            .map(|ent| {
801
4
                ent.parse_obj::<UnvalidatedEdCert>("FAMILY CERT")?
802
4
                    .check_cert_type(CertType::FAMILY_V_IDENTITY)?
803
4
                    .check_subject_key_is(identity_cert.peek_signing_key())?
804
4
                    .into_unchecked()
805
4
                    .should_have_signing_key()
806
4
                    .map_err(|e| {
807
                        EK::BadObjectVal
808
                            .with_msg("missing public key")
809
                            .at_pos(ent.pos())
810
                            .with_source(e)
811
                    })
812
4
            })
813
2278
            .collect::<Result<_>>()?;
814

            
815
2278
        let mut family_ids: Vec<_> = family_certs
816
2278
            .iter()
817
2280
            .map(|cert| RelayFamilyId::Ed25519(*cert.peek_signing_key()))
818
2278
            .collect();
819
2278
        family_ids.sort();
820
2278
        family_ids.dedup();
821

            
822
        // or-address
823
        // Extract at most one ipv6 address from the list.  It's not great,
824
        // but it's what Tor does.
825
2278
        let mut ipv6addr = None;
826
2278
        for tok in body.slice(OR_ADDRESS) {
827
6
            if let Ok(net::SocketAddr::V6(a)) = tok.parse_arg::<net::SocketAddr>(0) {
828
6
                ipv6addr = Some((*a.ip(), a.port()));
829
6
                break;
830
            }
831
            // We skip over unparsable addresses. Is that right?
832
        }
833

            
834
        // platform
835
2278
        let platform = body.maybe(PLATFORM).parse_args_as_str::<RelayPlatform>()?;
836

            
837
        // ipv4_policy
838
2278
        let ipv4_policy = {
839
2278
            let mut pol = AddrPolicy::new();
840
2280
            for ruletok in body.slice(POLICY).iter() {
841
2280
                let accept = match ruletok.kwd_str() {
842
2280
                    "accept" => RuleKind::Accept,
843
2278
                    "reject" => RuleKind::Reject,
844
                    _ => {
845
                        return Err(Error::from(internal!(
846
                            "tried to parse a strange line as a policy"
847
                        ))
848
                        .at_pos(ruletok.pos()));
849
                    }
850
                };
851
2280
                let pat: AddrPortPattern = ruletok
852
2280
                    .args_as_str()
853
2280
                    .parse()
854
2280
                    .map_err(|e| EK::BadPolicy.at_pos(ruletok.pos()).with_source(e))?;
855
2280
                pol.push(accept, pat);
856
            }
857
2278
            pol
858
        };
859

            
860
        // ipv6 policy
861
2278
        let ipv6_policy = match body.get(IPV6_POLICY) {
862
2
            Some(p) => p
863
2
                .args_as_str()
864
2
                .parse()
865
3
                .map_err(|e| EK::BadPolicy.at_pos(p.pos()).with_source(e))?,
866
            // Unwrap is safe here because str is not empty
867
            #[allow(clippy::unwrap_used)]
868
2276
            None => "reject 1-65535".parse::<PortPolicy>().unwrap(),
869
        };
870

            
871
        // Now we're going to collect signatures and expiration times.
872
2276
        let (identity_cert, identity_sig) = identity_cert.dangerously_split().map_err(|err| {
873
            EK::BadObjectVal
874
                .with_msg("missing public key")
875
                .with_source(err)
876
        })?;
877
2276
        let (crosscert_cert, cc_sig) = crosscert_cert.dangerously_split().map_err(|err| {
878
            EK::BadObjectVal
879
                .with_msg("missing public key")
880
                .with_source(err)
881
        })?;
882
2276
        let mut signatures: Vec<Box<dyn ll::pk::ValidatableSignature>> = vec![
883
2276
            Box::new(rsa_signature),
884
2276
            Box::new(ed_signature),
885
2276
            Box::new(identity_sig),
886
2276
            Box::new(cc_sig),
887
        ];
888
2276
        if let Some(s) = tap_crosscert_sig {
889
2274
            signatures.push(Box::new(s));
890
2274
        }
891

            
892
2276
        let identity_cert = identity_cert.dangerously_assume_timely();
893
2276
        let crosscert_cert = crosscert_cert.dangerously_assume_timely();
894
2276
        let mut expirations = vec![
895
2276
            published + time::Duration::new(ROUTER_EXPIRY_SECONDS, 0),
896
2276
            identity_cert.expiry(),
897
2276
            crosscert_cert.expiry(),
898
        ];
899

            
900
2276
        for cert in family_certs {
901
4
            let (inner, sig) = cert.dangerously_split().map_err(into_internal!(
902
                "Missing a public key that was previously there."
903
            ))?;
904
4
            signatures.push(Box::new(sig));
905
4
            expirations.push(inner.dangerously_assume_timely().expiry());
906
        }
907

            
908
        // Unwrap is safe here because `expirations` array is not empty
909
        #[allow(clippy::unwrap_used)]
910
2276
        let expiry = *expirations.iter().min().unwrap();
911

            
912
2276
        let start_time = published - time::Duration::new(ROUTER_PRE_VALIDITY_SECONDS, 0);
913

            
914
2276
        let desc = RouterDesc {
915
2276
            nickname,
916
2276
            ipv4addr,
917
2276
            orport,
918
2276
            dirport,
919
2276
            family_ids,
920
2276

            
921
2276
            identity_ed25519: identity_cert,
922
2276
            platform,
923
2276
            published,
924
2276
            fingerprint: Some(rsa_identity.into()),
925
2276
            uptime,
926
2276
            onion_key: tap_onion_key,
927
2276
            ntor_onion_key,
928
2276
            signing_key: rsa_identity_key,
929
2276
            ipv4_policy,
930
2276
            ipv6_policy: ipv6_policy.intern(),
931
2276
            family,
932
2276
            caches_extra_info: is_extrainfo_cache,
933
2276
            or_address: ipv6addr,
934
2276
            tunnelled_dir_server: is_dircache,
935
2276
            proto,
936
2276
        };
937

            
938
2276
        let time_gated = timed::TimerangeBound::new(desc, start_time..expiry);
939
2276
        let sig_gated = signed::SignatureGated::new(time_gated, signatures);
940

            
941
2276
        Ok(sig_gated)
942
2410
    }
943
}
944

            
945
/// An iterator that parses one or more (possibly annotated
946
/// router descriptors from a string.
947
//
948
// TODO: This is largely copy-pasted from MicrodescReader. Can/should they
949
// be merged?
950
pub struct RouterReader<'a> {
951
    /// True iff we accept annotations
952
    annotated: bool,
953
    /// Reader that we're extracting items from.
954
    reader: NetDocReader<'a, RouterKwd>,
955
}
956

            
957
/// Skip this reader forward until the next thing it reads looks like the
958
/// start of a router descriptor.
959
///
960
/// Used to recover from errors.
961
6
fn advance_to_next_routerdesc(reader: &mut NetDocReader<'_, RouterKwd>, annotated: bool) {
962
    use RouterKwd::*;
963
    loop {
964
6
        let item = reader.peek();
965
4
        match item {
966
4
            Some(Ok(t)) => {
967
4
                let kwd = t.kwd();
968
4
                if (annotated && kwd.is_annotation()) || kwd == ROUTER {
969
4
                    return;
970
                }
971
            }
972
            Some(Err(_)) => {
973
                // Skip over broken tokens.
974
            }
975
            None => {
976
2
                return;
977
            }
978
        }
979
        let _ = reader.next();
980
    }
981
6
}
982

            
983
impl<'a> RouterReader<'a> {
984
    /// Construct a RouterReader to take router descriptors from a string.
985
2
    pub fn new(s: &'a str, allow: &AllowAnnotations) -> Result<Self> {
986
2
        let reader = NetDocReader::new(s)?;
987
2
        let annotated = allow == &AllowAnnotations::AnnotationsAllowed;
988
2
        Ok(RouterReader { annotated, reader })
989
2
    }
990

            
991
    /// Extract an annotation from this reader.
992
8
    fn take_annotation(&mut self) -> Result<RouterAnnotation> {
993
8
        if self.annotated {
994
8
            RouterAnnotation::take_from_reader(&mut self.reader)
995
        } else {
996
            Ok(RouterAnnotation::default())
997
        }
998
8
    }
999

            
    /// Extract an annotated router descriptor from this reader
    ///
    /// (internal helper; does not clean up on failures.)
8
    fn take_annotated_routerdesc_raw(&mut self) -> Result<AnnotatedRouterDesc> {
8
        let ann = self.take_annotation()?;
6
        let router = RouterDesc::parse_internal(&mut self.reader)?;
2
        Ok(AnnotatedRouterDesc { ann, router })
8
    }
    /// Extract an annotated router descriptor from this reader
    ///
    /// Ensure that at least one token is consumed
8
    fn take_annotated_routerdesc(&mut self) -> Result<AnnotatedRouterDesc> {
8
        let pos_orig = self.reader.pos();
8
        let result = self.take_annotated_routerdesc_raw();
8
        if result.is_err() {
6
            if self.reader.pos() == pos_orig {
                // No tokens were consumed from the reader.  We need
                // to drop at least one token to ensure we aren't in
                // an infinite loop.
                //
                // (This might not be able to happen, but it's easier to
                // explicitly catch this case than it is to prove that
                // it's impossible.)
                let _ = self.reader.next();
6
            }
6
            advance_to_next_routerdesc(&mut self.reader, self.annotated);
2
        }
8
        result
8
    }
}
impl<'a> Iterator for RouterReader<'a> {
    type Item = Result<AnnotatedRouterDesc>;
10
    fn next(&mut self) -> Option<Self::Item> {
        // Is there a next token? If not, we're done.
10
        self.reader.peek()?;
        Some(
8
            self.take_annotated_routerdesc()
11
                .map_err(|e| e.within(self.reader.str())),
        )
10
    }
}
#[cfg(test)]
mod test {
    // @@ begin test lint list maintained by maint/add_warning @@
    #![allow(clippy::bool_assert_comparison)]
    #![allow(clippy::clone_on_copy)]
    #![allow(clippy::dbg_macro)]
    #![allow(clippy::mixed_attributes_style)]
    #![allow(clippy::print_stderr)]
    #![allow(clippy::print_stdout)]
    #![allow(clippy::single_char_pattern)]
    #![allow(clippy::unwrap_used)]
    #![allow(clippy::unchecked_time_subtraction)]
    #![allow(clippy::useless_vec)]
    #![allow(clippy::needless_pass_by_value)]
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
    use super::*;
    const TESTDATA: &str = include_str!("../../testdata/routerdesc1.txt");
    const TESTDATA2: &str = include_str!("../../testdata/routerdesc2.txt");
    // Generated with a patched C tor to include "happy family" IDs.
    const TESTDATA3: &str = include_str!("../../testdata/routerdesc3.txt");
    fn read_bad(fname: &str) -> String {
        use std::fs;
        use std::path::PathBuf;
        let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        path.push("testdata");
        path.push("bad-routerdesc");
        path.push(fname);
        fs::read_to_string(path).unwrap()
    }
    #[test]
    fn parse_arbitrary() -> Result<()> {
        use std::str::FromStr;
        use tor_checkable::{SelfSigned, Timebound};
        let rd = RouterDesc::parse(TESTDATA)?
            .check_signature()?
            .dangerously_assume_timely();
        assert_eq!(rd.nickname.as_str(), "Akka");
        assert_eq!(rd.orport, 443);
        assert_eq!(rd.dirport, 0);
        assert_eq!(rd.uptime, Some(1036923));
        assert_eq!(
            rd.family.as_ref(),
            &RelayFamily::from_str(
                "$303509ab910ef207b7438c27435c4a2fd579f1b1 \
                 $56927e61b51e6f363fb55498150a6ddfcf7077f2"
            )
            .unwrap()
        );
        assert_eq!(
            rd.rsa_identity().to_string(),
            "$56927e61b51e6f363fb55498150a6ddfcf7077f2"
        );
        assert_eq!(
            rd.ed_identity().to_string(),
            "CVTjf1oeaL616hH+1+UvYZ8OgkwF3z7UMITvJzm5r7A"
        );
        assert_eq!(
            rd.protocols().to_string(),
            "Cons=1-2 Desc=1-2 DirCache=2 FlowCtrl=1-2 HSDir=2 \
             HSIntro=4-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 \
             Padding=2 Relay=1-4"
        );
        assert_eq!(
            hex::encode(rd.ntor_onion_key().to_bytes()),
            "329b3b52991613392e35d1a821dd6753e1210458ecc3337f7b7d39bfcf5da273"
        );
        assert_eq!(
            rd.published(),
            humantime::parse_rfc3339("2022-11-14T19:58:52Z").unwrap()
        );
        assert_eq!(
            rd.or_ports().collect::<Vec<_>>(),
            vec![
                "95.216.33.58:443".parse().unwrap(),
                "[2a01:4f9:2a:2145::2]:443".parse().unwrap(),
            ]
        );
        assert!(rd.onion_key.is_some());
        Ok(())
    }
    #[test]
    fn parse_no_tap_key() -> Result<()> {
        use tor_checkable::{SelfSigned, Timebound};
        let rd = RouterDesc::parse(TESTDATA2)?
            .check_signature()?
            .dangerously_assume_timely();
        assert!(rd.onion_key.is_none());
        Ok(())
    }
    #[test]
    fn test_bad() {
        use crate::Pos;
        use crate::types::policy::PolicyError;
        fn check(fname: &str, e: &Error) {
            let text = read_bad(fname);
            let rd = RouterDesc::parse(&text);
            assert!(rd.is_err());
            assert_eq!(&rd.err().unwrap(), e);
        }
        check(
            "bad-sig-order",
            &EK::UnexpectedToken
                .with_msg("router-sig-ed25519")
                .at_pos(Pos::from_line(50, 1)),
        );
        check(
            "bad-start1",
            &EK::MisplacedToken
                .with_msg("identity-ed25519")
                .at_pos(Pos::from_line(1, 1)),
        );
        check("bad-start2", &EK::MissingToken.with_msg("identity-ed25519"));
        check(
            "mismatched-fp",
            &EK::BadArgument
                .at_pos(Pos::from_line(12, 1))
                .with_msg("fingerprint does not match RSA identity"),
        );
        check("no-ed-sk", &EK::MissingToken.with_msg("identity-ed25519"));
        check(
            "bad-cc-sign",
            &EK::BadArgument
                .at_pos(Pos::from_line(34, 26))
                .with_msg("not 0 or 1"),
        );
        check(
            "bad-ipv6policy",
            &EK::BadPolicy
                .at_pos(Pos::from_line(43, 1))
                .with_source(PolicyError::InvalidPolicy),
        );
        check(
            "no-ed-id-key-in-cert",
            &EK::BadObjectVal
                .at_pos(Pos::from_line(2, 1))
                .with_source(tor_cert::CertError::MissingPubKey),
        );
        check(
            "non-ed-sk-in-cert",
            &EK::BadObjectVal
                .at_pos(Pos::from_line(2, 1))
                .with_msg("wrong type for signing key in cert"),
        );
        check(
            "bad-ed-sk-in-cert",
            &EK::BadObjectVal
                .at_pos(Pos::from_line(2, 1))
                .with_msg("invalid ed25519 signing key"),
        );
        check(
            "mismatched-ed-sk-in-cert",
            &EK::BadObjectVal
                .at_pos(Pos::from_line(8, 1))
                .with_msg("master-key-ed25519 does not match key in identity-ed25519"),
        );
    }
    #[test]
    fn parse_multiple_annotated() {
        use crate::AllowAnnotations;
        let mut s = read_bad("bad-cc-sign");
        s += "\
@uploaded-at 2020-09-26 18:15:41
@source \"127.0.0.1\"
";
        s += TESTDATA;
        s += "\
@uploaded-at 2020-09-26 18:15:41
@source \"127.0.0.1\"
";
        s += &read_bad("mismatched-fp");
        let rd = RouterReader::new(&s, &AllowAnnotations::AnnotationsAllowed).unwrap();
        let v: Vec<_> = rd.collect();
        assert!(v[0].is_err());
        assert!(v[1].is_ok());
        assert_eq!(
            v[1].as_ref().unwrap().ann.source,
            Some("\"127.0.0.1\"".to_string())
        );
        assert!(v[2].is_err());
    }
    #[test]
    fn test_platform() {
        let p = "Tor 0.4.4.4-alpha on a flying bison".parse::<RelayPlatform>();
        assert!(p.is_ok());
        assert_eq!(
            p.unwrap(),
            RelayPlatform::Tor(
                "0.4.4.4-alpha".parse().unwrap(),
                "a flying bison".to_string()
            )
        );
        let p = "Tor 0.4.4.4-alpha on".parse::<RelayPlatform>();
        assert!(p.is_ok());
        let p = "Tor 0.4.4.4-alpha ".parse::<RelayPlatform>();
        assert!(p.is_ok());
        let p = "Tor 0.4.4.4-alpha".parse::<RelayPlatform>();
        assert!(p.is_ok());
        let p = "arti 0.0.0".parse::<RelayPlatform>();
        assert!(p.is_ok());
        assert_eq!(p.unwrap(), RelayPlatform::Other("arti 0.0.0".to_string()));
    }
    #[test]
    fn test_family_ids() -> Result<()> {
        use tor_checkable::{SelfSigned, Timebound};
        let rd = RouterDesc::parse(TESTDATA3)?
            .check_signature()?
            .dangerously_assume_timely();
        assert_eq!(
            rd.family_ids(),
            &[
                "ed25519:7sToQRuge1bU2hS0CG0ViMndc4m82JhO4B4kdrQey80"
                    .parse()
                    .unwrap(),
                "ed25519:szHUS3ItRd9uk85b1UVnOZx1gg4B0266jCpbuIMNjcM"
                    .parse()
                    .unwrap(),
            ]
        );
        Ok(())
    }
}