1
//! General collection of types.
2
//!
3
//! This module serves as a collection of types useful for the operation of a
4
//! directory server that are not related to the database, in which case they
5
//! belong to the respective [`crate::database`] module.
6

            
7
use tor_checkable::TimeRangeBound;
8
use tor_llcrypto::pk::rsa::RsaIdentity;
9
use tor_netdoc::{
10
    doc::{
11
        authcert::{AuthCert, AuthCertKeyIds},
12
        netstatus::{
13
            ConsensusFlavor, ConsensusVerifiabilityError, ConsensusVerifyFailed, Lifetime, md,
14
            plain,
15
        },
16
    },
17
    parse2::{NetdocParseable, NetdocParseableUnverified},
18
};
19

            
20
use crate::database::{Sha1, Sha256};
21

            
22
/// Generic trait representing a flavored verified consensus.
23
///
24
/// Similar to [`FlavoredConsensusUnverified`] and obtained from it.
25
pub(crate) trait FlavoredConsensusBody: Clone {
26
    /// Returns the [`Lifetime`] of this body.
27
    fn lifetime(&self) -> &Lifetime;
28

            
29
    /// Returns the doc digests for every router.
30
    ///
31
    /// These may be duplicate so ensure to properly handle conflicts.
32
    // TODO DIRMIRROR: This module should probably be moved into a submodule
33
    // of database.rs alongside other types found in database.rs.
34
    //
35
    // Orginally, the types here had no relation to database implementations,
36
    // but this does not work out long-term, as we see by this signature.
37
    fn doc_digests(&self) -> impl Iterator<Item = (Option<Sha1>, Option<Sha256>)>;
38
}
39

            
40
/// Generic trait representing the signatures of a consensus.
41
///
42
/// Similar to [`FlavoredConsensusUnverified`] and obtained from it.
43
pub(crate) trait FlavoredConsensusSignatures: Clone {
44
    /// Returns the [`AuthCertKeyIds`] of all authority certificates in the signatures.
45
    // TODO DIRMIRROR: Obtain this from the respective error variant returned by
46
    // .can_verify().
47
    // TODO: The respective implementations are repetitive, can we do better?
48
    fn signatories(&self) -> Vec<AuthCertKeyIds>;
49
}
50

            
51
/// Generic trait representing a flavored unverified consensus.
52
///
53
/// Required because in certain parts of the code, the exact flavor of the
54
/// consensus does not matter.
55
///
56
/// See [`FlavoredConsensusBody`] for the verified variant of it.
57
pub(crate) trait FlavoredConsensusUnverified:
58
    NetdocParseableUnverified<Body: FlavoredConsensusBody, Signatures: FlavoredConsensusSignatures>
59
    + NetdocParseable
60
    + Clone
61
{
62
    /// Returns the [`ConsensusFlavor`] of this type.
63
    fn flavor() -> ConsensusFlavor;
64

            
65
    /// Whether or not we have all required authority certificates to verify
66
    /// the consensus.
67
    fn can_verify(
68
        &self,
69
        trusted_authorities: &[RsaIdentity],
70
        certs_already: &[AuthCert],
71
    ) -> Result<(), ConsensusVerifiabilityError>;
72

            
73
    /// Verifies the consensus, returning the body.
74
    fn verify(
75
        self,
76
        trusted_authorities: &[RsaIdentity],
77
        certs_already: &[AuthCert],
78
    ) -> Result<TimeRangeBound<Self::Body>, ConsensusVerifyFailed>;
79

            
80
    /// Returns the signatures contained inside.
81
    ///
82
    /// It corresponds to accessing the publicly available T::sigs which is
83
    /// guaranteed to be present due to derive logic.
84
    ///
85
    /// Functionally equivalent to accessing the signatures through
86
    /// [`NetdocParseableUnverified::inspect_unverified()`], yet it tries to
87
    /// provide a safer semantic around it.
88
5
    fn sigs(&self) -> &Self::Signatures {
89
5
        &self.inspect_unverified().1.sigs
90
5
    }
91
}
92

            
93
impl FlavoredConsensusBody for plain::NetworkStatus {
94
12
    fn lifetime(&self) -> &Lifetime {
95
12
        &self.preamble.lifetime
96
12
    }
97

            
98
12
    fn doc_digests(&self) -> impl Iterator<Item = (Option<Sha1>, Option<Sha256>)> {
99
12
        self.routers
100
12
            .iter()
101
84
            .map(|r| (Some(Sha1::from(*r.doc_digest())), None))
102
12
    }
103
}
104

            
105
impl FlavoredConsensusBody for md::NetworkStatus {
106
10
    fn lifetime(&self) -> &Lifetime {
107
10
        &self.preamble.lifetime
108
10
    }
109

            
110
10
    fn doc_digests(&self) -> impl Iterator<Item = (Option<Sha1>, Option<Sha256>)> {
111
10
        self.routers
112
10
            .iter()
113
70
            .map(|r| (None, Some(Sha256::from(*r.doc_digest()))))
114
10
    }
115
}
116

            
117
impl FlavoredConsensusSignatures for plain::NetworkStatusSignatures {
118
12
    fn signatories(&self) -> Vec<AuthCertKeyIds> {
119
12
        self.directory_signature
120
12
            .iter()
121
12
            .map(|sig| sig.key_ids)
122
12
            .collect()
123
12
    }
124
}
125

            
126
impl FlavoredConsensusSignatures for md::NetworkStatusSignatures {
127
10
    fn signatories(&self) -> Vec<AuthCertKeyIds> {
128
10
        self.directory_signature
129
10
            .iter()
130
10
            .map(|sig| sig.key_ids)
131
10
            .collect()
132
10
    }
133
}
134

            
135
impl FlavoredConsensusUnverified for plain::NetworkStatusUnverified {
136
34
    fn flavor() -> ConsensusFlavor {
137
34
        ConsensusFlavor::Plain
138
34
    }
139

            
140
5
    fn can_verify(
141
5
        &self,
142
5
        trusted_authorities: &[RsaIdentity],
143
5
        certs_already: &[AuthCert],
144
5
    ) -> Result<(), ConsensusVerifiabilityError> {
145
5
        self.can_verify(trusted_authorities, certs_already)
146
5
    }
147

            
148
5
    fn verify(
149
5
        self,
150
5
        trusted_authorities: &[RsaIdentity],
151
5
        certs_already: &[AuthCert],
152
5
    ) -> Result<TimeRangeBound<Self::Body>, ConsensusVerifyFailed> {
153
5
        self.verify(trusted_authorities, certs_already)
154
5
    }
155
}
156

            
157
impl FlavoredConsensusUnverified for md::NetworkStatusUnverified {
158
13
    fn flavor() -> ConsensusFlavor {
159
13
        ConsensusFlavor::Microdesc
160
13
    }
161

            
162
    fn can_verify(
163
        &self,
164
        trusted_authorities: &[RsaIdentity],
165
        certs_already: &[AuthCert],
166
    ) -> Result<(), ConsensusVerifiabilityError> {
167
        self.can_verify(trusted_authorities, certs_already)
168
    }
169

            
170
    fn verify(
171
        self,
172
        trusted_authorities: &[RsaIdentity],
173
        certs_already: &[AuthCert],
174
    ) -> Result<TimeRangeBound<Self::Body>, ConsensusVerifyFailed> {
175
        self.verify(trusted_authorities, certs_already)
176
    }
177
}