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    //
33    // TODO DIRAUTH test this
34    pub fn verify(
35        self,
36        trusted: &[RsaIdentity],
37    ) -> Result<TimerangeBound<NetworkStatus>, VoteVerifyFailed> {
38        use VoteVerifyFailed as VVF;
39
40        let (mut body, sigs) = self.unwrap_unverified();
41
42        let authcert = {
43            let input = parse2::ParseInput::new(
44                body.authority.cert.raw_unverified().as_ref(),
45                "<authcert>",
46            );
47            let authcert = parse2::parse_netdoc::<AuthCertUnverified>(&input)
48                .map_err(VVF::AuthCertParseError)?;
49            let authcert = authcert.verify(trusted).map_err(VVF::InvalidSignature)?;
50
51            // We do the authcert validity time check here, with reference to
52            // the vote's declared validity period, not the current time or whatever.
53            let test_validity_at = |t| authcert.is_valid_at(&t).map_err(VVF::AuthCertWrongValidity);
54
55            // test at all relevant times, in a uniform way so we can break out check
56            test_validity_at(*body.preamble.lifetime.valid_after)?;
57            test_validity_at(*body.preamble.lifetime.fresh_until)?;
58            test_validity_at(*body.preamble.lifetime.valid_until)?;
59            authcert.dangerously_assume_timely() // we just checked it ^ there
60        };
61
62        if body.authority.authority.dir_source.identity != authcert.fingerprint {
63            return Err(VVF::AuthCertWrongAuthority);
64        }
65
66        SignatureGroup {
67            hashes: sigs.hashes,
68            signatures: vec![sigs.sigs.directory_signature],
69        }
70        .verify_general(
71            VerifyGeneralTrustedAuthorities::AnyOneOfThese { trusted },
72            slice::from_ref(&authcert),
73            |tv| tv.verify().map_err(VVF::InvalidSignature),
74        )?;
75
76        body.authority.cert.set_verified(authcert);
77
78        let time_range = body.preamble.validity_time_range();
79        Ok(TimerangeBound::new(body, time_range))
80    }
81
82    /// Look at the declared directory authority identity KHP_auth_id_rsa
83    ///
84    /// This tells you what the vote says the issuing authority is,
85    /// but note that the signatures haven't been checked,
86    /// so this information should be used with care.
87    pub fn peek_alleged_authority(&self) -> RsaIdentity {
88        *self
89            .inspect_unverified()
90            .0
91            .authority
92            .authority
93            .dir_source
94            .identity
95    }
96}
97
98impl From<ConsensusVerifiabilityError> for VoteVerifyFailed {
99    fn from(cve: ConsensusVerifiabilityError) -> VoteVerifyFailed {
100        use ConsensusVerifiabilityError as CVE;
101        use VerifyFailed as VF;
102        use VoteVerifyFailed as VVF;
103
104        match cve {
105            CVE::InsufficientTrustedSigners => {
106                VVF::InvalidSignature(VF::InsufficientTrustedSigners)
107            }
108            CVE::MissingAuthCerts { .. } => {
109                // this should be impossible, because we checked the authcert was right
110                VVF::AuthCertWrongAuthority
111            }
112        }
113    }
114}