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