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::encode::{ItemEncoder, ItemValueEncodable};
36
use crate::parse::keyword::Keyword;
37
use crate::parse::parser::{Section, SectionRules};
38
use crate::parse::tokenize::{ItemResult, NetDocReader};
39
use crate::parse2::{ArgumentError, ErrorProblem, ItemValueParseable, UnparsedItem};
40
use crate::types::family::{RelayFamily, RelayFamilyIds};
41
use crate::types::policy::*;
42
use crate::types::routerdesc::*;
43
use crate::types::version::TorVersion;
44
use crate::types::{EmbeddedCert, misc::*};
45
use crate::util::PeekableIterator;
46
use crate::{AllowAnnotations, Error, KeywordEncodable, NetdocErrorKind as EK, Result};
47

            
48
use derive_deftly::Deftly;
49
use ll::pk::ed25519::Ed25519Identity;
50
use saturating_time::SaturatingTime;
51
use std::fmt::Display;
52
use std::sync::LazyLock;
53
use std::{iter, net, time};
54
use tor_basic_utils::intern::Intern;
55
use tor_cert::{CertType, KeyUnknownCert};
56
use tor_checkable::{Timebound, signed, timed};
57
use tor_error::{internal, into_internal};
58
use tor_llcrypto as ll;
59
use tor_llcrypto::pk::rsa::RsaIdentity;
60

            
61
use digest::Digest;
62

            
63
/// Length of a router descriptor digest
64
pub const DOC_DIGEST_LEN: usize = 20;
65

            
66
/// The digest of a RouterDesc document, as reported in a NS consensus.
67
pub type RdDigest = [u8; DOC_DIGEST_LEN];
68

            
69
/// The digest of an ExtraInfo document, as reported in a RouterDesc.
70
pub type ExtraInfoDigest = [u8; DOC_DIGEST_LEN];
71

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

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

            
93
/// Information about a relay, parsed from a router descriptor.
94
///
95
/// This type does not hold all the information in the router descriptor
96
///
97
/// # Limitations
98
///
99
/// See module documentation.
100
///
101
/// Additionally, some fields that from router descriptors are not yet
102
/// parsed: see the comments in ROUTER_BODY_RULES for information about those.
103
///
104
/// Before using this type to connect to a relay, you MUST check that
105
/// it is valid, using is_expired_at().
106
///
107
/// # Specification
108
///
109
/// <https://spec.torproject.org/dir-spec/server-descriptor-format.html>
110
#[derive(Clone, Debug, Deftly)]
111
#[derive_deftly(NetdocParseableUnverified)]
112
#[non_exhaustive]
113
pub struct RouterDesc {
114
    /// `router` --- Introduce a router descriptor.
115
    /// * `router <nickname> <address> <orport> <socksport> <dirport>`
116
    /// * At start, exactly once.
117
    pub router: RouterDescIntroItem,
118

            
119
    /// `identity-ed25519` --- Specify the router's ed25519 identity.
120
    ///
121
    /// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:identity-ed25519>
122
    pub identity_ed25519: EmbeddedCert<Ed25519IdentityCert, KeyUnknownCert>,
123

            
124
    /// `master-key-ed25519` --- Redundantly specify the router's ed25519 identity.
125
    ///
126
    /// * `master-key-ed25519 <master key>`
127
    /// * Exactly once.
128
    // TODO DIRAUTH when implementing verification, don't forget to check this!
129
    #[deftly(netdoc(single_arg))]
130
    pub master_key_ed25519: Ed25519Public,
131

            
132
    /// `bandwidth` --- Report router's network bandwidth.
133
    ///
134
    /// * `bandwidth <average> <burst> <observed>`
135
    /// * Exactly once.
136
    pub bandwidth: Bandwidth,
137

            
138
    /// `platform` --- Describe the platform on which this relay is running.
139
    ///
140
    /// * `platform <rest of line>`
141
    /// * At most once.
142
    pub platform: Option<RelayPlatform>,
143

            
144
    /// `published` --- Time this descriptor (and extra-info) was generated.
145
    ///
146
    /// * `published <date> <time>`
147
    /// * Exactly once.
148
    #[deftly(netdoc(single_arg))]
149
    pub published: Iso8601TimeSp,
150

            
151
    /// `fingerprint` --- Redundant hash of ASN-1 encoding of router identity key.
152
    ///
153
    /// * `fingerprint <spaced fingerprint>`
154
    /// * At most once.
155
    #[deftly(netdoc(single_arg))]
156
    pub fingerprint: Option<SpFingerprint>,
157

            
158
    /// `hibernating` --- Whether the relay is hibernating.
159
    ///
160
    /// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:hibernating>
161
    // TODO DIRAUTH: Mark this as `netdoc(default)` and skip during encoding if false.
162
    #[deftly(netdoc(single_arg, default))]
163
    pub hibernating: NumericBoolean,
164

            
165
    /// `uptime` --- How long this relay has been continously running
166
    ///
167
    /// * `uptime <number>`
168
    /// * At most once.
169
    #[deftly(netdoc(single_arg))]
170
    pub uptime: Option<u64>,
171

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

            
179
    /// `ntor-onion-key` --- The circuit extension key.
180
    ///
181
    /// * `ntor-onion-key <base64 padded key>`
182
    /// * Exactly once.
183
    #[deftly(netdoc(single_arg))]
184
    pub ntor_onion_key: Curve25519Public,
185

            
186
    /// `ntor-onion-key-crosscert` --- Reverse cert by K_ntor on KP_relayid_ed
187
    ///
188
    /// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:ntor-onion-key-crosscert>
189
    pub ntor_onion_key_crosscert: NtorOnionKeyCrossCert,
190

            
191
    /// `signing-key` --- Obsolete RSA identity key.
192
    ///
193
    /// * `signing-key\n<rsa public key>`
194
    pub signing_key: ll::pk::rsa::PublicKey,
195

            
196
    /// `accept, reject` --- Exit policy.
197
    ///
198
    /// * `accept exitpattern`
199
    /// * `reject exitpattern`
200
    /// * Any number of times.
201
    // TODO: these polices can get bulky too. Perhaps we should
202
    // de-duplicate them too.
203
    #[deftly(netdoc(flatten))]
204
    pub ipv4_policy: AddrPolicy,
205

            
206
    /// `ipv6-policy` --- Exit plicy summary for IPv6
207
    ///
208
    /// * `ipv6-policy <accept/reject> PortList`
209
    /// * At most once.
210
    #[deftly(netdoc(default))]
211
    pub ipv6_policy: Intern<PortPolicy>,
212

            
213
    /// `overload-general` --- Relay is overloaded.
214
    ///
215
    /// * `overload-general 1 <time>`
216
    /// * At most once.
217
    // TODO in OverloadGeneral use ConstantString (from !3985) for version
218
    pub overload_general: Option<OverloadGeneral>,
219

            
220
    /// `contact` --- Server administrator contact information.
221
    ///
222
    /// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:contact>
223
    pub contact: Option<ContactInfo>,
224

            
225
    /// `family` --- Group relays for the purpose of path selection.
226
    ///
227
    /// * `family <LongIdent> ...`
228
    /// * One or more `LongIdent` arguments.
229
    /// * At most once.
230
    #[deftly(netdoc(default))]
231
    pub family: Intern<RelayFamily>,
232

            
233
    /// `family-cert` --- Prove membership in a relay family.
234
    ///
235
    /// * `family-cert\n<object>`
236
    /// * Any number of times.
237
    pub family_cert: RetainedOrderVec<EmbeddedCert<Ed25519FamilyCert, KeyUnknownCert>>,
238

            
239
    /// `caches-extra-info` --- Router provides extra-info as a dirmirror.
240
    ///
241
    /// * `caches-extra-info`
242
    /// * At most once.
243
    /// * No extra arguments.
244
    pub caches_extra_info: Option<ItemPresent<CachesExtraInfoToken>>,
245

            
246
    /// `extra-info-digest` --- Hash of the extra-info document.
247
    ///
248
    /// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:extra-info-digest>
249
    pub extra_info_digest: Option<ExtraInfoDigests>,
250

            
251
    /// `hidden-service-dir` --- Declares this router to be a hidden service directory
252
    ///
253
    /// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:hidden-service-dir>
254
    pub hidden_service_dir: Option<ItemPresent<HiddenServiceDirToken>>,
255

            
256
    /// `or-address` --- Alternative ORport address and port
257
    ///
258
    /// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:or-address>
259
    #[deftly(netdoc(single_arg))]
260
    pub or_address: Vec<net::SocketAddr>,
261

            
262
    /// `tunnelled-dir-server` --- Accepts a `BEGIN_DIR` relay message.
263
    ///
264
    /// * `tunnelled-dir-server`
265
    /// * At most once.
266
    /// * No extra arguments.
267
    pub tunnelled_dir_server: Option<ItemPresent<TunnelledDirServerToken>>,
268

            
269
    /// `proto` --- Subprotocol capabilities supported.
270
    ///
271
    /// * `proto <entries>`
272
    /// * Exactly once.
273
    pub proto: tor_protover::Protocols,
274
}
275

            
276
/// Signatures of a [`RouterDesc`].
277
///
278
/// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:router-sig-ed25519>
279
#[derive(Clone, Debug, Deftly)]
280
#[derive_deftly(NetdocParseableSignatures)]
281
#[deftly(netdoc(signatures(hashes_accu = "RouterHashAccu")))]
282
#[non_exhaustive]
283
pub struct RouterDescSignatures {
284
    /// `router-sig-ed25519` --- Ed25519 signature
285
    ///
286
    /// Ed25519 signature by the Ed25519 signing key on the SHA-256 digest of
287
    /// the document prefixed by a magic up until and including the
288
    /// `router-sig-ed25519` keyword plus space.
289
    pub router_sig_ed25519: RouterSigEd25519,
290

            
291
    /// `router-signature` --- RSA signature
292
    ///
293
    /// * At end, exactly once.
294
    /// * RSA signature of the document, including `router-sig-ed25519`.
295
    pub router_signature: RouterSignature,
296
}
297

            
298
// TODO: Implement a .verify() method.
299
impl RouterDescUnverified {}
300

            
301
/// Description of the software a relay is running.
302
///
303
/// `platform` line in a routerstatus.
304
/// <https://spec.torproject.org/dir-spec/server-descriptor-format.html#item:platform>
305
// TODO: Move this to types/misc.rs.
306
#[derive(Debug, Clone, PartialEq, Eq)]
307
#[non_exhaustive]
308
pub enum RelayPlatform {
309
    /// Software advertised to be some version of Tor, on some platform.
310
    Tor(TorVersion, Option<String>),
311
    /// Software not advertised to be Tor.
312
    Other(String),
313
}
314

            
315
/// Zero-sized token type for use in [`RouterDesc::caches_extra_info`].
316
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
317
#[non_exhaustive]
318
pub struct CachesExtraInfoToken;
319

            
320
/// Zero-sized token type for use in [`RouterDesc::hidden_service_dir`].
321
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
322
#[non_exhaustive]
323
pub struct HiddenServiceDirToken;
324

            
325
/// Zero-sized token type for use in [`RouterDesc::tunnelled_dir_server`].
326
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
327
#[non_exhaustive]
328
pub struct TunnelledDirServerToken;
329

            
330
impl std::str::FromStr for RelayPlatform {
331
    type Err = Error;
332
2244
    fn from_str(args: &str) -> Result<Self> {
333
2244
        if args.starts_with("Tor ") {
334
2242
            let v: Vec<_> = args.splitn(4, ' ').collect();
335
2242
            match &v[..] {
336
2236
                ["Tor", ver, "on", p] => {
337
2236
                    Ok(RelayPlatform::Tor(ver.parse()?, Some((*p).to_string())))
338
                }
339
6
                ["Tor", ver, ..] => Ok(RelayPlatform::Tor(ver.parse()?, None)),
340
                _ => unreachable!(),
341
            }
342
        } else {
343
2
            Ok(RelayPlatform::Other(args.to_string()))
344
        }
345
2244
    }
346
}
347

            
348
impl Display for RelayPlatform {
349
10
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
350
8
        match &self {
351
2
            Self::Tor(v, Some(p)) => write!(f, "Tor {v} on {p}"),
352
6
            Self::Tor(v, None) => write!(f, "Tor {v}"),
353
2
            Self::Other(s) => write!(f, "{s}"),
354
        }
355
10
    }
356
}
357

            
358
impl ItemValueParseable for RelayPlatform {
359
40
    fn from_unparsed(item: UnparsedItem<'_>) -> std::result::Result<Self, ErrorProblem> {
360
40
        let mut args = item.args_copy();
361
40
        item.check_no_object()?;
362
40
        args.into_remaining()
363
40
            .parse()
364
40
            .map_err(|_| args.handle_error("platform", ArgumentError::Invalid))
365
40
    }
366
}
367

            
368
impl ItemValueEncodable for RelayPlatform {
369
    fn write_item_value_onto(
370
        &self,
371
        mut out: ItemEncoder,
372
    ) -> std::result::Result<(), tor_error::Bug> {
373
        // Adding a raw string is fine because this is effectively a free form
374
        // field.
375
        out.args_raw_string(&self);
376
        Ok(())
377
    }
378
}
379

            
380
decl_keyword! {
381
    /// RouterKwd is an instance of Keyword, used to denote the different
382
    /// Items that are recognized as appearing in a router descriptor.
383
    RouterKwd {
384
        annotation "@source" => ANN_SOURCE,
385
        annotation "@downloaded-at" => ANN_DOWNLOADED_AT,
386
        annotation "@purpose" => ANN_PURPOSE,
387
        "accept" | "reject" => POLICY,
388
        "bandwidth" => BANDWIDTH,
389
        "bridge-distribution-request" => BRIDGE_DISTRIBUTION_REQUEST,
390
        "caches-extra-info" => CACHES_EXTRA_INFO,
391
        "contact" => CONTACT,
392
        "extra-info-digest" => EXTRA_INFO_DIGEST,
393
        "family" => FAMILY,
394
        "family-cert" => FAMILY_CERT,
395
        "fingerprint" => FINGERPRINT,
396
        "hibernating" => HIBERNATING,
397
        "identity-ed25519" => IDENTITY_ED25519,
398
        "ipv6-policy" => IPV6_POLICY,
399
        "master-key-ed25519" => MASTER_KEY_ED25519,
400
        "ntor-onion-key" => NTOR_ONION_KEY,
401
        "ntor-onion-key-crosscert" => NTOR_ONION_KEY_CROSSCERT,
402
        "onion-key" => ONION_KEY,
403
        "onion-key-crosscert" => ONION_KEY_CROSSCERT,
404
        "or-address" => OR_ADDRESS,
405
        "platform" => PLATFORM,
406
        "proto" => PROTO,
407
        "published" => PUBLISHED,
408
        "router" => ROUTER,
409
        "router-sig-ed25519" => ROUTER_SIG_ED25519,
410
        "router-signature" => ROUTER_SIGNATURE,
411
        "signing-key" => SIGNING_KEY,
412
        "tunnelled_dir_server" => TUNNELLED_DIR_SERVER,
413
        "uptime" => UPTIME,
414
        // "protocols" once existed, but is obsolete
415
        // "eventdns" once existed, but is obsolete
416
        // "allow-single-hop-exits" is also obsolete.
417
    }
418
}
419

            
420
/// Rules for parsing a set of router descriptor annotations.
421
2
static ROUTER_ANNOTATIONS: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
422
    use RouterKwd::*;
423

            
424
2
    let mut rules = SectionRules::builder();
425
2
    rules.add(ANN_SOURCE.rule());
426
2
    rules.add(ANN_DOWNLOADED_AT.rule().args(1..));
427
2
    rules.add(ANN_PURPOSE.rule().args(1..));
428
2
    rules.add(ANN_UNRECOGNIZED.rule().may_repeat().obj_optional());
429
    // Unrecognized annotations are fine; anything else is an error in this
430
    // context.
431
2
    rules.reject_unrecognized();
432
2
    rules.build()
433
2
});
434
/// Rules for tokens that are allowed in the first part of a
435
/// router descriptor.
436
54
static ROUTER_HEADER_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
437
    use RouterKwd::*;
438

            
439
54
    let mut rules = SectionRules::builder();
440
54
    rules.add(ROUTER.rule().required().args(5..));
441
54
    rules.add(IDENTITY_ED25519.rule().required().no_args().obj_required());
442
    // No other intervening tokens are permitted in the header.
443
54
    rules.reject_unrecognized();
444
54
    rules.build()
445
54
});
446
/// Rules for  tokens that are allowed in the first part of a
447
/// router descriptor.
448
54
static ROUTER_BODY_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
449
    use RouterKwd::*;
450

            
451
54
    let mut rules = SectionRules::builder();
452
54
    rules.add(MASTER_KEY_ED25519.rule().required().args(1..));
453
54
    rules.add(PLATFORM.rule());
454
54
    rules.add(PUBLISHED.rule().required());
455
54
    rules.add(FINGERPRINT.rule());
456
54
    rules.add(UPTIME.rule().args(1..));
457
54
    rules.add(ONION_KEY.rule().no_args().obj_required());
458
54
    rules.add(ONION_KEY_CROSSCERT.rule().no_args().obj_required());
459
54
    rules.add(NTOR_ONION_KEY.rule().required().args(1..));
460
54
    rules.add(
461
54
        NTOR_ONION_KEY_CROSSCERT
462
54
            .rule()
463
54
            .required()
464
54
            .args(1..=1)
465
54
            .obj_required(),
466
    );
467
54
    rules.add(SIGNING_KEY.rule().no_args().required().obj_required());
468
54
    rules.add(POLICY.rule().may_repeat().args(1..));
469
54
    rules.add(IPV6_POLICY.rule().args(2..));
470
54
    rules.add(FAMILY.rule().args(1..));
471
54
    rules.add(FAMILY_CERT.rule().obj_required().may_repeat());
472
54
    rules.add(CACHES_EXTRA_INFO.rule().no_args());
473
54
    rules.add(OR_ADDRESS.rule().may_repeat().args(1..));
474
54
    rules.add(TUNNELLED_DIR_SERVER.rule());
475
54
    rules.add(PROTO.rule().required().args(1..));
476
54
    rules.add(UNRECOGNIZED.rule().may_repeat().obj_optional());
477
    // TODO: these aren't parsed yet.  Only authorities use them.
478
54
    {
479
54
        rules.add(BANDWIDTH.rule().required().args(3..));
480
54
        rules.add(BRIDGE_DISTRIBUTION_REQUEST.rule().args(1..));
481
54
        rules.add(HIBERNATING.rule().args(1..));
482
54
        rules.add(CONTACT.rule());
483
54
    }
484
    // TODO: this is ignored for now.
485
54
    {
486
54
        rules.add(EXTRA_INFO_DIGEST.rule().args(1..));
487
54
    }
488
54
    rules.build()
489
54
});
490

            
491
/// Rules for items that appear at the end of a router descriptor.
492
54
static ROUTER_SIG_RULES: LazyLock<SectionRules<RouterKwd>> = LazyLock::new(|| {
493
    use RouterKwd::*;
494

            
495
54
    let mut rules = SectionRules::builder();
496
54
    rules.add(ROUTER_SIG_ED25519.rule().required().args(1..));
497
54
    rules.add(ROUTER_SIGNATURE.rule().required().no_args().obj_required());
498
    // No intervening tokens are allowed in the footer.
499
54
    rules.reject_unrecognized();
500
54
    rules.build()
501
54
});
502

            
503
impl RouterAnnotation {
504
    /// Extract a single RouterAnnotation (possibly empty) from a reader.
505
8
    fn take_from_reader(reader: &mut NetDocReader<'_, RouterKwd>) -> Result<RouterAnnotation> {
506
        use RouterKwd::*;
507
20
        let mut items = reader.pause_at(|item| item.is_ok_with_non_annotation());
508

            
509
8
        let body = ROUTER_ANNOTATIONS.parse(&mut items)?;
510

            
511
6
        let source = body.maybe(ANN_SOURCE).args_as_str().map(String::from);
512
6
        let purpose = body.maybe(ANN_PURPOSE).args_as_str().map(String::from);
513
6
        let downloaded = body
514
6
            .maybe(ANN_DOWNLOADED_AT)
515
6
            .parse_args_as_str::<Iso8601TimeSp>()?
516
6
            .map(|t| t.into());
517
6
        Ok(RouterAnnotation {
518
6
            source,
519
6
            downloaded,
520
6
            purpose,
521
6
        })
522
8
    }
523
}
524

            
525
/// A parsed router descriptor whose signatures and/or validity times
526
/// may or may not be invalid.
527
pub type UncheckedRouterDesc = signed::SignatureGated<timed::TimerangeBound<RouterDesc>>;
528

            
529
/// How long after its published time is a router descriptor officially
530
/// supposed to be usable?
531
const ROUTER_EXPIRY_SECONDS: u64 = 5 * 86400;
532

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

            
540
impl RouterDesc {
541
    /// Return a reference to this relay's RSA identity.
542
1250
    pub fn rsa_identity(&self) -> RsaIdentity {
543
1250
        self.signing_key.to_rsa_identity()
544
1250
    }
545

            
546
    /// Return a reference to this relay's Ed25519 identity.
547
2
    pub fn ed_identity(&self) -> &Ed25519Identity {
548
2
        &self
549
2
            .identity_ed25519
550
2
            .get()
551
2
            .expect("ed25519 identity cert should be verified")
552
2
            .id_ed25519
553
2
    }
554

            
555
    /// Return a reference to the list of subprotocol versions supported by this
556
    /// relay.
557
2
    pub fn protocols(&self) -> &tor_protover::Protocols {
558
2
        &self.proto
559
2
    }
560

            
561
    /// Return a reference to this relay's Ntor onion key.
562
2
    pub fn ntor_onion_key(&self) -> &ll::pk::curve25519::PublicKey {
563
2
        &self.ntor_onion_key.0
564
2
    }
565

            
566
    /// Return the publication
567
314
    pub fn published(&self) -> time::SystemTime {
568
314
        self.published.0
569
314
    }
570

            
571
    /// Return an iterator of every `SocketAddr` at which this descriptor says
572
    /// its relay can be reached.
573
2
    pub fn or_ports(&self) -> impl Iterator<Item = net::SocketAddr> + '_ {
574
2
        iter::once(net::SocketAddr::new(
575
2
            self.router.address.into(),
576
2
            self.router.orport,
577
        ))
578
2
        .chain(self.or_address.iter().copied())
579
2
    }
580

            
581
    /// Return the declared family of this descriptor.
582
    pub fn family(&self) -> Intern<RelayFamily> {
583
        Intern::clone(&self.family)
584
    }
585

            
586
    /// Return the authenticated family IDs of this descriptor.
587
2
    pub fn family_ids(&self) -> RelayFamilyIds {
588
2
        RelayFamilyIds::from_iter(
589
2
            self.family_cert
590
2
                .iter()
591
5
                .map(|cert| cert.get().expect("unverified family cert?"))
592
5
                .map(|cert| cert.family_ed25519.into()),
593
        )
594
2
    }
595

            
596
    /// Helper: tokenize `s`, and divide it into three validated sections.
597
2322
    fn parse_sections<'a>(
598
2322
        reader: &mut NetDocReader<'a, RouterKwd>,
599
2322
    ) -> Result<(
600
2322
        Section<'a, RouterKwd>,
601
2322
        Section<'a, RouterKwd>,
602
2322
        Section<'a, RouterKwd>,
603
2322
    )> {
604
        use RouterKwd::*;
605

            
606
        // Parse everything up through the header.
607
2322
        let header = ROUTER_HEADER_RULES.parse(
608
6813
            reader.pause_at(|item| item.is_ok_with_kwd_not_in(&[ROUTER, IDENTITY_ED25519])),
609
108
        )?;
610

            
611
        // Parse everything up to but not including the signature.
612
2214
        let body =
613
37739
            ROUTER_BODY_RULES.parse(reader.pause_at(|item| {
614
37682
                item.is_ok_with_kwd_in(&[ROUTER_SIGNATURE, ROUTER_SIG_ED25519])
615
37682
            }))?;
616

            
617
        // Parse the signature.
618
4499
        let sig = ROUTER_SIG_RULES.parse(reader.pause_at(|item| {
619
4442
            item.is_ok_with_annotation() || item.is_ok_with_kwd(ROUTER) || item.is_empty_line()
620
4442
        }))?;
621

            
622
2214
        Ok((header, body, sig))
623
2322
    }
624

            
625
    /// Try to parse `s` as a router descriptor.
626
    ///
627
    /// Does not actually check liveness or signatures; you need to do that
628
    /// yourself before you can do the output.
629
    ///
630
    /// The following fields are not parsed with the legacy parser and their
631
    /// default value is used instead.
632
    /// * [`RouterDescIntroItem::socksport`] in [`RouterDesc::router`]
633
    /// * [`RouterDesc::bandwidth`]
634
    /// * [`RouterDesc::or_address`]
635
    ///     * Extracts only the first IPv6 address.
636
    /// * [`RouterDesc::hibernating`]
637
    /// * [`RouterDesc::overload_general`]
638
    /// * [`RouterDesc::contact`]
639
    /// * [`RouterDesc::extra_info_digest`]
640
    /// * [`RouterDesc::hidden_service_dir`]
641
2316
    pub fn parse(s: &str) -> Result<UncheckedRouterDesc> {
642
2316
        let mut reader = crate::parse::tokenize::NetDocReader::new(s)?;
643
2329
        let result = Self::parse_internal(&mut reader).map_err(|e| e.within(s))?;
644
        // We permit empty lines at the end of router descriptors, since there's
645
        // a known issue in Tor relays that causes them to return them this way.
646
2190
        reader
647
2190
            .should_be_exhausted_but_for_empty_lines()
648
2190
            .map_err(|e| e.within(s))?;
649
2190
        Ok(result)
650
2316
    }
651

            
652
    /// Helper: parse a router descriptor from `s`.
653
    ///
654
    /// This function does the same as parse(), but returns errors based on
655
    /// byte-wise positions.  The parse() function converts such errors
656
    /// into line-and-byte positions.
657
2322
    fn parse_internal(r: &mut NetDocReader<'_, RouterKwd>) -> Result<UncheckedRouterDesc> {
658
        // TODO: This function is too long!  The little "paragraphs" here
659
        // that parse one item at a time should be made into sub-functions.
660
        use RouterKwd::*;
661

            
662
2322
        let s = r.str();
663
2322
        let (header, body, sig) = RouterDesc::parse_sections(r)?;
664

            
665
        // Unwrap should be safe because inline `required` call should return
666
        // `Error::MissingToken` if `ROUTER` is not `Ok`
667
        #[allow(clippy::unwrap_used)]
668
2214
        let start_offset = header.required(ROUTER)?.offset_in(s).unwrap();
669

            
670
        // ed25519 identity and signing key.
671
        //
672
        // Small digression: This is terrible.  We return a tuple containing
673
        // a KeyUnknownCert and an UncheckedCert.  This is because of a parse2
674
        // and legacy incongruence.  For parse2, we need the KeyUnknownCert
675
        // to properly include it into EmbeddedCert, whereas the legacy parser
676
        // will need an UncheckedCert because the verification chain is
677
        // performed at the end.  Because tor-cert's method all consume self,
678
        // we can not go backwards, meaning we have to store two separate
679
        // copies.  It is also not possible to do the conversion to
680
        // UncheckedCert later, because then we lose the error context returned
681
        // in EK::BadObjectVal if the signed-by extension is missing.
682
        //
683
2206
        let (ku_identity_cert, identity_cert, ed25519_signing_key) = {
684
2214
            let cert_tok = header.required(IDENTITY_ED25519)?;
685
            // Unwrap should be safe because above `required` call should
686
            // return `Error::MissingToken` if `IDENTITY_ED25519` is not `Ok`
687
            #[allow(clippy::unwrap_used)]
688
2214
            if cert_tok.offset_in(s).unwrap() < start_offset {
689
2
                return Err(EK::MisplacedToken
690
2
                    .with_msg("identity-ed25519")
691
2
                    .at_pos(cert_tok.pos()));
692
2212
            }
693
2212
            let ku_cert = cert_tok
694
2212
                .parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
695
2212
                .check_cert_type(tor_cert::CertType::IDENTITY_V_SIGNING)?
696
2212
                .into_unchecked();
697
2213
            let cert = ku_cert.clone().should_have_signing_key().map_err(|err| {
698
2
                EK::BadObjectVal
699
2
                    .err()
700
2
                    .with_source(err)
701
2
                    .at_pos(cert_tok.pos())
702
3
            })?;
703
2211
            let sk = *cert.peek_subject_key().as_ed25519().ok_or_else(|| {
704
2
                EK::BadObjectVal
705
2
                    .at_pos(cert_tok.pos())
706
2
                    .with_msg("wrong type for signing key in cert")
707
3
            })?;
708
2209
            let sk: ll::pk::ed25519::PublicKey = sk.try_into().map_err(|_| {
709
2
                EK::BadObjectVal
710
2
                    .at_pos(cert_tok.pos())
711
2
                    .with_msg("invalid ed25519 signing key")
712
3
            })?;
713
2206
            (ku_cert, cert, sk)
714
        };
715

            
716
        // master-key-ed25519: required, and should match certificate.
717
        #[allow(unexpected_cfgs)]
718
2204
        let ed25519_identity_key = {
719
2206
            let master_key_tok = body.required(MASTER_KEY_ED25519)?;
720
2206
            let ed_id: Ed25519Public = master_key_tok.parse_arg(0)?;
721
2206
            let ed_id: ll::pk::ed25519::Ed25519Identity = ed_id.into();
722
2206
            if ed_id != *identity_cert.peek_signing_key() {
723
                #[cfg(not(fuzzing))] // No feature here; never omit in production.
724
2
                return Err(EK::BadObjectVal
725
2
                    .at_pos(master_key_tok.pos())
726
2
                    .with_msg("master-key-ed25519 does not match key in identity-ed25519"));
727
2204
            }
728
2204
            ed_id
729
        };
730

            
731
        // Legacy RSA identity
732
2204
        let rsa_identity_key: ll::pk::rsa::PublicKey = body
733
2204
            .required(SIGNING_KEY)?
734
2204
            .parse_obj::<RsaPublicParse1Helper>("RSA PUBLIC KEY")?
735
2204
            .check_len_eq(1024)?
736
2204
            .check_exponent(65537)?
737
2204
            .into();
738
2204
        let rsa_identity = rsa_identity_key.to_rsa_identity();
739

            
740
2204
        let ed_sig = sig.required(ROUTER_SIG_ED25519)?;
741
2204
        let rsa_sig = sig.required(ROUTER_SIGNATURE)?;
742
        // Unwrap should be safe because above `required` calls should return
743
        // an `Error::MissingToken` if `ROUTER_...` is not `Ok`
744
        #[allow(clippy::unwrap_used)]
745
2204
        let ed_sig_pos = ed_sig.offset_in(s).unwrap();
746
        #[allow(clippy::unwrap_used)]
747
2204
        let rsa_sig_pos = rsa_sig.offset_in(s).unwrap();
748

            
749
2204
        if ed_sig_pos > rsa_sig_pos {
750
2
            return Err(EK::UnexpectedToken
751
2
                .with_msg(ROUTER_SIG_ED25519.to_str())
752
2
                .at_pos(ed_sig.pos()));
753
2202
        }
754

            
755
        // Extract ed25519 signature.
756
2202
        let ed_signature: ll::pk::ed25519::ValidatableEd25519Signature = {
757
2202
            let mut d = ll::d::Sha256::new();
758
2202
            d.update(&b"Tor router descriptor signature v1"[..]);
759
2202
            let signed_end = ed_sig_pos + b"router-sig-ed25519 ".len();
760
2202
            d.update(
761
2202
                s.get(start_offset..signed_end)
762
2202
                    .ok_or(internal!("chopped utf8"))?,
763
            );
764
2202
            let d = d.finalize();
765
2202
            let sig: [u8; 64] = ed_sig
766
2202
                .parse_arg::<B64>(0)?
767
2202
                .into_array()
768
2202
                .map_err(|_| EK::BadSignature.at_pos(ed_sig.pos()))?;
769
2202
            let sig = ll::pk::ed25519::Signature::from(sig);
770
2202
            ll::pk::ed25519::ValidatableEd25519Signature::new(ed25519_signing_key, sig, &d)
771
        };
772

            
773
        // Extract legacy RSA signature.
774
2202
        let rsa_signature: ll::pk::rsa::ValidatableRsaSignature = {
775
2202
            let mut d = ll::d::Sha1::new();
776
2202
            let signed_end = rsa_sig_pos + b"router-signature\n".len();
777
2202
            d.update(
778
2202
                s.get(start_offset..signed_end)
779
2202
                    .ok_or(internal!("chopped utf8"))?,
780
            );
781
2202
            let d = d.finalize();
782
2202
            let sig = rsa_sig.obj("SIGNATURE")?;
783
            // TODO: we need to accept prefixes here. COMPAT BLOCKER.
784

            
785
2202
            ll::pk::rsa::ValidatableRsaSignature::new(&rsa_identity_key, &sig, &d)
786
        };
787

            
788
        // router nickname ipv4addr orport socksport dirport
789
2202
        let (nickname, ipv4addr, orport, dirport) = {
790
2202
            let rtrline = header.required(ROUTER)?;
791
            (
792
2202
                rtrline.required_arg(0)?.parse::<Nickname>().map_err(|e| {
793
                    EK::BadArgument
794
                        .with_msg(e.to_string())
795
                        .at_pos(rtrline.pos())
796
                })?,
797
2202
                rtrline.parse_arg::<net::Ipv4Addr>(1)?,
798
2202
                rtrline.parse_arg(2)?,
799
                // Skipping socksport.
800
2202
                rtrline.parse_arg(4)?,
801
            )
802
        };
803

            
804
        // uptime
805
2202
        let uptime = body.maybe(UPTIME).parse_arg(0)?;
806

            
807
        // published time.
808
2202
        let published = body
809
2202
            .required(PUBLISHED)?
810
2202
            .args_as_str()
811
2202
            .parse::<Iso8601TimeSp>()?;
812

            
813
        // ntor key
814
2202
        let ntor_onion_key: Curve25519Public = body.required(NTOR_ONION_KEY)?.parse_arg(0)?;
815
        // ntor crosscert
816
2198
        let (cc_sig, cc_expiry, cc_cert) = {
817
2202
            let cc = body.required(NTOR_ONION_KEY_CROSSCERT)?;
818
2202
            let sign: u8 = cc.parse_arg(0)?;
819
2202
            if sign != 0 && sign != 1 {
820
4
                return Err(EK::BadArgument.at_pos(cc.arg_pos(0)).with_msg("not 0 or 1"));
821
2198
            }
822
2198
            let ntor_as_ed: ll::pk::ed25519::PublicKey =
823
2198
                ll::pk::keymanip::convert_curve25519_to_ed25519_public(&ntor_onion_key.0, sign)
824
2198
                    .ok_or_else(|| {
825
                        EK::BadArgument
826
                            .at_pos(cc.pos())
827
                            .with_msg("Uncheckable crosscert")
828
                    })?;
829

            
830
2198
            let cert = cc
831
2198
                .parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
832
2198
                .into_unchecked();
833
2198
            let (_, sig, expiry) = Ed25519NtorCrossCert::verify_inner(
834
2198
                ntor_as_ed.into(),
835
2198
                ed25519_identity_key,
836
2198
                cert.clone(),
837
            )
838
2198
            .map_err(|_| EK::BadSignature.err())?;
839

            
840
2198
            let cert = NtorOnionKeyCrossCert {
841
2198
                bit: NumericBoolean(sign != 0),
842
2198
                // Okay to call because we added the signature to the batch.
843
2198
                cert: EmbeddedCert::new(Ed25519NtorCrossCert::dangerous_new_unverified(), cert),
844
2198
            };
845

            
846
2198
            (sig, expiry, cert)
847
        };
848

            
849
        // TAP key
850
2198
        let tap_onion_key: Option<ll::pk::rsa::PublicKey> = if let Some(tok) = body.get(ONION_KEY) {
851
            Some(
852
2196
                tok.parse_obj::<RsaPublicParse1Helper>("RSA PUBLIC KEY")?
853
2196
                    .check_len_eq(1024)?
854
2196
                    .check_exponent(65537)?
855
2196
                    .into(),
856
            )
857
        } else {
858
2
            None
859
        };
860

            
861
        // TAP crosscert
862
2198
        let tap_crosscert_sig = if let Some(cc_tok) = body.get(ONION_KEY_CROSSCERT) {
863
2196
            let cc_val = cc_tok.obj("CROSSCERT")?;
864
2196
            let mut signed = Vec::new();
865
2196
            signed.extend(rsa_identity.as_bytes());
866
2196
            signed.extend(identity_cert.peek_signing_key().as_bytes());
867
2196
            Some(ll::pk::rsa::ValidatableRsaSignature::new(
868
2196
                tap_onion_key.as_ref().ok_or_else(|| {
869
                    EK::MissingToken.with_msg("onion-key-crosscert without onion-key")
870
                })?,
871
2196
                &cc_val,
872
2196
                &signed,
873
            ))
874
2
        } else if tap_onion_key.is_some() {
875
            return Err(EK::MissingToken.with_msg("onion-key without onion-key-crosscert"));
876
        } else {
877
2
            None
878
        };
879

            
880
        // List of subprotocol versions
881
2198
        let proto = {
882
2198
            let proto_tok = body.required(PROTO)?;
883
2198
            proto_tok
884
2198
                .args_as_str()
885
2198
                .parse::<tor_protover::Protocols>()
886
2198
                .map_err(|e| EK::BadArgument.at_pos(proto_tok.pos()).with_source(e))?
887
        };
888

            
889
        // tunneled-dir-server
890
2198
        let is_dircache = ((dirport != 0) || body.get(TUNNELLED_DIR_SERVER).is_some())
891
2198
            .then_some(ItemPresent::default());
892

            
893
        // caches-extra-info
894
2199
        let is_extrainfo_cache = body.get(CACHES_EXTRA_INFO).map(|_| ItemPresent::default());
895

            
896
        // fingerprint: check for consistency with RSA identity.
897
2198
        if let Some(fp_tok) = body.get(FINGERPRINT) {
898
2198
            let fp: RsaIdentity = fp_tok.args_as_str().parse::<SpFingerprint>()?.into();
899
2198
            if fp != rsa_identity {
900
4
                return Err(EK::BadArgument
901
4
                    .at_pos(fp_tok.pos())
902
4
                    .with_msg("fingerprint does not match RSA identity"));
903
2194
            }
904
        }
905

            
906
        // Family
907
2194
        let family = {
908
2194
            let mut family = body
909
2194
                .maybe(FAMILY)
910
2194
                .parse_args_as_str::<RelayFamily>()?
911
2194
                .unwrap_or_else(RelayFamily::new);
912
2194
            if !family.is_empty() {
913
4
                // If this family is nonempty, we add our own RSA id to it, on
914
4
                // the theory that doing so will improve the odds of having a
915
4
                // canonical family shared by all of the members of this family.
916
4
                // If the family is empty, there's no point in adding our own ID
917
4
                // to it, and doing so would only waste memory.
918
4
                family.push(rsa_identity);
919
2190
            }
920
2194
            family.intern()
921
        };
922

            
923
        // Family ids (for "happy families")
924
        //
925
        // Unfortunately we have to store this as a tuple of KeyUnknownCert and
926
        // UncheckedCert due to a parse2/legacy incongruence.  parse2 requires
927
        // KeyUnknownCert for EmbeddedCert whereas the legacy parser needs
928
        // descendants of it obtained by passing it irreversibly through the
929
        // tor_cert verification chain.
930
2194
        let family_certs = body
931
2194
            .slice(FAMILY_CERT)
932
2194
            .iter()
933
2196
            .map(|ent| {
934
4
                let ku = ent
935
4
                    .parse_obj::<UnvalidatedEdCert>("FAMILY CERT")?
936
4
                    .check_cert_type(CertType::FAMILY_V_IDENTITY)?
937
4
                    .check_subject_key_is(identity_cert.peek_signing_key())?
938
4
                    .into_unchecked();
939
4
                let unchecked = ku.clone().should_have_signing_key().map_err(|e| {
940
                    EK::BadObjectVal
941
                        .with_msg("missing public key")
942
                        .at_pos(ent.pos())
943
                        .with_source(e)
944
                })?;
945
4
                Ok((ku, unchecked))
946
4
            })
947
2194
            .collect::<Result<Vec<_>>>()?;
948

            
949
        // or-address
950
        // Extract at most one ipv6 address from the list.  It's not great,
951
        // but it's what the legacy parser does.
952
2194
        let mut ipv6addr = Vec::with_capacity(1);
953
2194
        for tok in body.slice(OR_ADDRESS) {
954
6
            if let Ok(net::SocketAddr::V6(a)) = tok.parse_arg::<net::SocketAddr>(0) {
955
6
                ipv6addr.push(a.into());
956
6
                break;
957
            }
958
            // We skip over unparsable addresses. Is that right?
959
        }
960

            
961
        // platform
962
2194
        let platform = body.maybe(PLATFORM).parse_args_as_str::<RelayPlatform>()?;
963

            
964
        // ipv4_policy
965
2194
        let ipv4_policy = {
966
2194
            let mut pol = AddrPolicy::new();
967
2196
            for ruletok in body.slice(POLICY).iter() {
968
2196
                let accept = match ruletok.kwd_str() {
969
2196
                    "accept" => RuleKind::Accept,
970
2194
                    "reject" => RuleKind::Reject,
971
                    _ => {
972
                        return Err(Error::from(internal!(
973
                            "tried to parse a strange line as a policy"
974
                        ))
975
                        .at_pos(ruletok.pos()));
976
                    }
977
                };
978
2196
                let pat: AddrPortPattern = ruletok
979
2196
                    .args_as_str()
980
2196
                    .parse()
981
2196
                    .map_err(|e| EK::BadPolicy.at_pos(ruletok.pos()).with_source(e))?;
982
2196
                pol.push(accept, pat);
983
            }
984
2194
            pol
985
        };
986

            
987
        // ipv6 policy
988
2194
        let ipv6_policy = match body.get(IPV6_POLICY) {
989
2
            Some(p) => p
990
2
                .args_as_str()
991
2
                .parse()
992
3
                .map_err(|e| EK::BadPolicy.at_pos(p.pos()).with_source(e))?,
993
            // Unwrap is safe here because str is not empty
994
            #[allow(clippy::unwrap_used)]
995
2192
            None => "reject 1-65535".parse::<PortPolicy>().unwrap(),
996
        };
997

            
998
        // Now we're going to collect signatures and expiration times.
999
2192
        let (identity_cert, identity_sig) = identity_cert.dangerously_split().map_err(|err| {
            EK::BadObjectVal
                .with_msg("missing public key")
                .with_source(err)
        })?;
2192
        let mut signatures: Vec<Box<dyn ll::pk::ValidatableSignature>> = vec![
2192
            Box::new(rsa_signature),
2192
            Box::new(ed_signature),
2192
            Box::new(identity_sig),
2192
            Box::new(cc_sig),
        ];
2192
        if let Some(s) = tap_crosscert_sig {
2190
            signatures.push(Box::new(s));
2190
        }
2192
        let identity_cert = identity_cert.dangerously_assume_timely();
2192
        let mut expirations = vec![
2192
            published
2192
                .0
2192
                .saturating_add(time::Duration::new(ROUTER_EXPIRY_SECONDS, 0)),
2192
            identity_cert.expiry(),
2192
            cc_expiry,
        ];
        // As outlined above, we have to do this ... :/
        //
        // Composing the verified part of the EmbeddedCert by just extracting
        // the key alone is OK because it gets checked at the end anyways
        // due to the push to signatures and expirations.
2192
        let mut embedded_family_certs = Vec::with_capacity(family_certs.len());
2192
        for (ku_cert, cert) in family_certs {
4
            let family_ed25519 = *cert.peek_signing_key();
4
            let (inner, sig) = cert.dangerously_split().map_err(into_internal!(
                "Missing a public key that was previously there."
            ))?;
4
            let embedded_cert = EmbeddedCert::new(Ed25519FamilyCert { family_ed25519 }, ku_cert);
4
            signatures.push(Box::new(sig));
4
            expirations.push(inner.dangerously_assume_timely().expiry());
4
            embedded_family_certs.push(embedded_cert);
        }
        // Unwrap is safe here because `expirations` array is not empty
        #[allow(clippy::unwrap_used)]
2192
        let expiry = *expirations.iter().min().unwrap();
2192
        let start_time = published
2192
            .0
2192
            .saturating_sub(time::Duration::new(ROUTER_PRE_VALIDITY_SECONDS, 0));
2192
        let desc = RouterDesc {
2192
            router: RouterDescIntroItem {
2192
                nickname,
2192
                address: ipv4addr,
2192
                orport,
2192
                socksport: 0,
2192
                dirport,
2192
            },
2192
            identity_ed25519: EmbeddedCert::new(
2192
                Ed25519IdentityCert {
2192
                    id_ed25519: ed25519_identity_key,
2192
                    sign_ed25519: ed25519_signing_key.into(),
2192
                },
2192
                ku_identity_cert,
2192
            ),
2192
            master_key_ed25519: ed25519_identity_key.into(),
2192
            bandwidth: Default::default(),
2192
            platform,
2192
            published,
2192
            fingerprint: Some(rsa_identity.into()),
2192
            hibernating: Default::default(),
2192
            uptime,
2192
            onion_key: tap_onion_key,
2192
            ntor_onion_key,
2192
            ntor_onion_key_crosscert: cc_cert,
2192
            signing_key: rsa_identity_key,
2192
            ipv4_policy,
2192
            ipv6_policy: ipv6_policy.intern(),
2192
            overload_general: Default::default(),
2192
            contact: Default::default(),
2192
            family,
2192
            family_cert: embedded_family_certs.into(),
2192
            caches_extra_info: is_extrainfo_cache,
2192
            extra_info_digest: Default::default(),
2192
            hidden_service_dir: Default::default(),
2192
            or_address: ipv6addr,
2192
            tunnelled_dir_server: is_dircache,
2192
            proto,
2192
        };
2192
        let time_gated = timed::TimerangeBound::new(desc, start_time..expiry);
2192
        let sig_gated = signed::SignatureGated::new(time_gated, signatures);
2192
        Ok(sig_gated)
2322
    }
}
/// An iterator that parses one or more (possibly annotated
/// router descriptors from a string.
//
// TODO: This is largely copy-pasted from MicrodescReader. Can/should they
// be merged?
pub struct RouterReader<'a> {
    /// True iff we accept annotations
    annotated: bool,
    /// Reader that we're extracting items from.
    reader: NetDocReader<'a, RouterKwd>,
}
/// Skip this reader forward until the next thing it reads looks like the
/// start of a router descriptor.
///
/// Used to recover from errors.
6
fn advance_to_next_routerdesc(reader: &mut NetDocReader<'_, RouterKwd>, annotated: bool) {
    use RouterKwd::*;
    loop {
6
        let item = reader.peek();
4
        match item {
4
            Some(Ok(t)) => {
4
                let kwd = t.kwd();
4
                if (annotated && kwd.is_annotation()) || kwd == ROUTER {
4
                    return;
                }
            }
            Some(Err(_)) => {
                // Skip over broken tokens.
            }
            None => {
2
                return;
            }
        }
        let _ = reader.next();
    }
6
}
impl<'a> RouterReader<'a> {
    /// Construct a RouterReader to take router descriptors from a string.
2
    pub fn new(s: &'a str, allow: &AllowAnnotations) -> Result<Self> {
2
        let reader = NetDocReader::new(s)?;
2
        let annotated = allow == &AllowAnnotations::AnnotationsAllowed;
2
        Ok(RouterReader { annotated, reader })
2
    }
    /// Extract an annotation from this reader.
8
    fn take_annotation(&mut self) -> Result<RouterAnnotation> {
8
        if self.annotated {
8
            RouterAnnotation::take_from_reader(&mut self.reader)
        } else {
            Ok(RouterAnnotation::default())
        }
8
    }
    /// 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)]
    #![allow(clippy::string_slice)] // See arti#2571
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
    use crate::parse2::{self, NetdocParseableUnverified, ParseInput};
    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.router.nickname.as_str(), "Akka");
        assert_eq!(rd.router.orport, 443);
        assert_eq!(rd.router.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 tests = [
            // Test with platform.
            (
                "Tor 0.4.4.4-alpha on a flying bison",
                RelayPlatform::Tor(
                    "0.4.4.4-alpha".parse().unwrap(),
                    Some("a flying bison".to_string()),
                ),
            ),
            // Test without platform but potentially weird spacing.
            (
                "Tor 0.4.4.4-alpha on",
                RelayPlatform::Tor("0.4.4.4-alpha".parse().unwrap(), None),
            ),
            (
                "Tor 0.4.4.4-alpha ",
                RelayPlatform::Tor("0.4.4.4-alpha".parse().unwrap(), None),
            ),
            (
                "Tor 0.4.4.4-alpha",
                RelayPlatform::Tor("0.4.4.4-alpha".parse().unwrap(), None),
            ),
            // Test other.
            ("arti 0.0.0", RelayPlatform::Other("arti 0.0.0".to_string())),
        ];
        for (input, output) in tests {
            assert_eq!(input.parse::<RelayPlatform>().unwrap(), output);
            // Round-trip test with input stripped of " on" suffix and trimmed.
            // Otherwise we cannot really make this work because certain inputs
            // contain redundant data on purpose.
            let input = input.strip_suffix(" on").unwrap_or(input);
            let input = input.trim();
            assert_eq!(output.to_string(), input);
        }
    }
    #[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().as_ref(),
            &[
                "ed25519:7sToQRuge1bU2hS0CG0ViMndc4m82JhO4B4kdrQey80"
                    .parse()
                    .unwrap(),
                "ed25519:szHUS3ItRd9uk85b1UVnOZx1gg4B0266jCpbuIMNjcM"
                    .parse()
                    .unwrap(),
            ]
        );
        Ok(())
    }
    // TODO: For now, this only tests if decoding works with a few field checks.
    // It should be extended to a full roundtrip test with failed verification
    // at one point eventually ...
    #[test]
    fn test_parse2() {
        let input = ParseInput::new(
            include_str!("../../testdata2/cached-descriptors.new"),
            "cached-descriptors.new",
        );
        let rd = parse2::parse_netdoc_multiple::<RouterDescUnverified>(&input)
            .unwrap()
            .into_iter()
            .map(|rd| rd.unwrap_unverified().0)
            .collect::<Vec<RouterDesc>>();
        assert_eq!(rd.len(), 20);
        assert_eq!(
            rd[0].router,
            RouterDescIntroItem {
                nickname: "test002a".parse().unwrap(),
                address: net::Ipv4Addr::LOCALHOST,
                orport: 5102,
                socksport: 0,
                dirport: 7102
            }
        );
        assert_eq!(
            rd[0].fingerprint.unwrap(),
            "257D 06F0 360B B224 6388 724F 109E C089 5A1D 41FB"
                .parse()
                .unwrap()
        );
    }
}