Skip to main content

tor_netdoc/doc/
routerdesc.rs

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