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

            
6
use super::*;
7

            
8
// Import `each_variety.rs`, appropriately variegated
9
ns_do_variety_vote! {}
10

            
11
/// Used for reporting errors when parsing this document type
12
const 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.
24
pub type VarietyKeyword = NoMoreArguments;
25

            
26
impl 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
16
    pub fn verify(
35
16
        self,
36
16
        trusted: &[RsaIdentity],
37
16
    ) -> Result<TimerangeBound<NetworkStatus>, VoteVerifyFailed> {
38
        use VoteVerifyFailed as VVF;
39

            
40
16
        let (mut body, sigs) = self.unwrap_unverified();
41

            
42
6
        let authcert = {
43
16
            let input = parse2::ParseInput::new(
44
16
                body.authority.cert.raw_unverified().as_ref(),
45
16
                "<authcert>",
46
            );
47
16
            let authcert = parse2::parse_netdoc::<AuthCertUnverified>(&input)
48
16
                .map_err(VVF::AuthCertParseError)?;
49
14
            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
36
            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
12
            test_validity_at(*body.preamble.lifetime.valid_after)?;
57
10
            test_validity_at(*body.preamble.lifetime.fresh_until)?;
58
8
            test_validity_at(*body.preamble.lifetime.valid_until)?;
59
6
            authcert.dangerously_assume_timely() // we just checked it ^ there
60
        };
61

            
62
6
        if body.authority.authority.dir_source.identity != authcert.fingerprint {
63
2
            return Err(VVF::AuthCertWrongAuthority);
64
4
        }
65

            
66
4
        SignatureGroup {
67
4
            hashes: sigs.hashes,
68
4
            signatures: vec![sigs.sigs.directory_signature],
69
4
        }
70
4
        .verify_general(
71
4
            VerifyGeneralTrustedAuthorities::AnyOneOfThese { trusted },
72
4
            slice::from_ref(&authcert),
73
4
            |tv| tv.verify().map_err(VVF::InvalidSignature),
74
2
        )?;
75

            
76
2
        body.authority.cert.set_verified(authcert);
77

            
78
2
        let time_range = body.preamble.validity_time_range();
79
2
        Ok(TimerangeBound::new(body, time_range))
80
16
    }
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
2
    pub fn peek_alleged_authority(&self) -> RsaIdentity {
88
2
        *self
89
2
            .inspect_unverified()
90
2
            .0
91
2
            .authority
92
2
            .authority
93
2
            .dir_source
94
2
            .identity
95
2
    }
96
}
97

            
98
impl 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
}