Skip to main content

tor_netdoc/doc/netstatus/
vote.rs

1//! Implementation for plain consensus documents.
2//
3// Read this file in conjunction with `each_variety.rs`.
4// See "module scope" ns_variety_definition_macros.rs.
5
6use super::*;
7
8// Import `each_variety.rs`, appropriately variegated
9ns_do_variety_vote! {}
10
11/// Used for reporting errors when parsing this document type
12const NETSTATUS_DOCTYPE_FOR_ERROR: &str = "network status vote";
13
14/// The forbidden flavor keyword in a vote consensus heading line
15///
16/// This type is one of the fields in `NetworkStatusVersionItem`.
17///
18/// Votes start with `network-status-version 3`
19/// and aren't allowed to have a variety.
20///
21/// So in *this* variety, we insist that there are no more arguments.
22///
23/// See also torspec#359.
24pub type VarietyKeyword = NoMoreArguments;
25
26impl NetworkStatusUnverified {
27    /// Verify the signatures
28    ///
29    /// Doesn't check the validity period:
30    /// the document is wrapped in [`TimeRangeBound`],
31    /// ensuring that the caller does that check.
32    pub fn verify(
33        self,
34        trusted: &[RsaIdentity],
35    ) -> Result<TimeRangeBound<NetworkStatus>, VoteVerifyFailed> {
36        use VoteVerifyFailed as VVF;
37
38        let (mut body, sigs) = self.unwrap_unverified();
39
40        let authcert = {
41            let input = parse2::ParseInput::new(
42                body.authority.cert.raw_unverified().as_ref(),
43                "<authcert>",
44            );
45            let authcert = parse2::parse_netdoc::<AuthCertUnverified>(&input)
46                .map_err(VVF::AuthCertParseError)?;
47            let authcert = authcert.verify(trusted).map_err(VVF::InvalidSignature)?;
48
49            // We do the authcert validity time check here, with reference to
50            // the vote's declared validity period, not the current time or whatever.
51            let test_validity_at = |t| {
52                authcert
53                    .check_valid_at(&t)
54                    .map_err(VVF::AuthCertWrongValidity)
55            };
56
57            // test at all relevant times, in a uniform way so we can break out check
58            test_validity_at(*body.preamble.lifetime.valid_after)?;
59            test_validity_at(*body.preamble.lifetime.fresh_until)?;
60            test_validity_at(*body.preamble.lifetime.valid_until)?;
61            authcert.dangerously_assume_timely() // we just checked it ^ there
62        };
63
64        if body.authority.authority.dir_source.identity != authcert.fingerprint {
65            return Err(VVF::AuthCertWrongAuthority);
66        }
67
68        SignatureGroup {
69            hashes: sigs.hashes,
70            signatures: vec![sigs.sigs.directory_signature],
71        }
72        .verify_general(
73            VerifyGeneralTrustedAuthorities::AnyOneOfThese { trusted },
74            slice::from_ref(&authcert),
75            |tv| tv.verify().map_err(VVF::InvalidSignature),
76        )?;
77
78        body.authority.cert.set_verified(authcert);
79
80        let time_range = body.preamble.validity_time_range();
81        Ok(TimeRangeBound::new(body, time_range))
82    }
83
84    /// Look at the declared directory authority identity KHP_auth_id_rsa
85    ///
86    /// This tells you what the vote says the issuing authority is,
87    /// but note that the signatures haven't been checked,
88    /// so this information should be used with care.
89    pub fn peek_alleged_authority(&self) -> RsaIdentity {
90        *self
91            .inspect_unverified()
92            .0
93            .authority
94            .authority
95            .dir_source
96            .identity
97    }
98}
99
100impl From<ConsensusVerifiabilityError> for VoteVerifyFailed {
101    fn from(cve: ConsensusVerifiabilityError) -> VoteVerifyFailed {
102        use ConsensusVerifiabilityError as CVE;
103        use VerifyFailed as VF;
104        use VoteVerifyFailed as VVF;
105
106        match cve {
107            CVE::InsufficientTrustedSigners => {
108                VVF::InvalidSignature(VF::InsufficientTrustedSigners)
109            }
110            CVE::MissingAuthCerts { .. } => {
111                // this should be impossible, because we checked the authcert was right
112                VVF::AuthCertWrongAuthority
113            }
114        }
115    }
116}