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_error::internal;
9
use tor_llcrypto::pk::rsa::RsaIdentity;
10
use tor_netdoc::{
11
    doc::{
12
        authcert::{AuthCert, AuthCertKeyIds},
13
        microdesc::Microdesc,
14
        netstatus::{
15
            ConsensusFlavor, ConsensusVerifiabilityError, ConsensusVerifyFailed, Lifetime, md,
16
            plain,
17
        },
18
        routerdesc::{ExtraInfoDigests, RouterDesc, RouterDescUnverified},
19
    },
20
    parse2::{NetdocParseable, NetdocParseableUnverified, SignaturesData},
21
};
22

            
23
use crate::database::{Sha1, Sha256};
24

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

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

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

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

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

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

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

            
96
impl FlavoredConsensusBody for plain::NetworkStatus {
97
13
    fn lifetime(&self) -> &Lifetime {
98
13
        &self.preamble.lifetime
99
13
    }
100

            
101
13
    fn doc_digests(&self) -> impl Iterator<Item = (Option<Sha1>, Option<Sha256>)> {
102
13
        self.routers
103
13
            .iter()
104
91
            .map(|r| (Some(Sha1::from(*r.doc_digest())), None))
105
13
    }
106
}
107

            
108
impl FlavoredConsensusBody for md::NetworkStatus {
109
11
    fn lifetime(&self) -> &Lifetime {
110
11
        &self.preamble.lifetime
111
11
    }
112

            
113
11
    fn doc_digests(&self) -> impl Iterator<Item = (Option<Sha1>, Option<Sha256>)> {
114
11
        self.routers
115
11
            .iter()
116
77
            .map(|r| (None, Some(Sha256::from(*r.doc_digest()))))
117
11
    }
118
}
119

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

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

            
138
impl FlavoredConsensusUnverified for plain::NetworkStatusUnverified {
139
45
    fn flavor() -> ConsensusFlavor {
140
45
        ConsensusFlavor::Plain
141
45
    }
142

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

            
151
6
    fn verify(
152
6
        self,
153
6
        trusted_authorities: &[RsaIdentity],
154
6
        certs_already: &[AuthCert],
155
6
    ) -> Result<TimeRangeBound<Self::Body>, ConsensusVerifyFailed> {
156
6
        self.verify(trusted_authorities, certs_already)
157
6
    }
158
}
159

            
160
impl FlavoredConsensusUnverified for md::NetworkStatusUnverified {
161
14
    fn flavor() -> ConsensusFlavor {
162
14
        ConsensusFlavor::Microdesc
163
14
    }
164

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

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

            
182
/// Generic trait representing a (verified) descriptor.
183
///
184
/// Only implemented in combination with an accompanying data type from which
185
/// the hashes can be derived.
186
// TODO DIRMIRROR: Make the names align with DescriptorMeta and additionally
187
// change the database column names.
188
// TODO DIRMIRROR: How about we implement this for a unit token type instead
189
// because the tuple implementation may not be ideal?
190
pub(crate) trait FlavoredDescriptor: Clone {
191
    /// Returns the [`ConsensusFlavor`] this descriptor is associated with.
192
    fn flavor() -> ConsensusFlavor;
193

            
194
    /// Returns the [`RsaIdentity`] of this descriptor, if present.
195
    fn id_rsa(&self) -> Option<RsaIdentity>;
196

            
197
    /// Returns the [`ExtraInfoDigests`] of this descriptor, if present.
198
    fn extra_info_sha1(&self) -> Option<ExtraInfoDigests>;
199

            
200
    /// Returns the SHA-1 of the signed part of the consensus.
201
    ///
202
    /// Failures are considered a bug and should never happen.
203
    fn sha1(&self) -> Result<Sha1, tor_error::Bug>;
204

            
205
    /// Returns the SHA-256 of the signed part of the consensus.
206
    ///
207
    /// Failures are considered a bug and should never happen.
208
    fn sha256(&self) -> Result<Sha256, tor_error::Bug>;
209
}
210

            
211
/// Wrapper for [`RouterDesc`] with it's associated type.
212
pub(crate) type FlavoredDescriptorPlain = (RouterDesc, SignaturesData<RouterDescUnverified>);
213

            
214
impl FlavoredDescriptor for FlavoredDescriptorPlain {
215
7
    fn flavor() -> ConsensusFlavor {
216
7
        ConsensusFlavor::Plain
217
7
    }
218

            
219
7
    fn id_rsa(&self) -> Option<RsaIdentity> {
220
7
        Some(self.0.signing_key.to_rsa_identity())
221
7
    }
222

            
223
7
    fn extra_info_sha1(&self) -> Option<ExtraInfoDigests> {
224
7
        self.0.extra_info_digest.clone()
225
7
    }
226

            
227
7
    fn sha1(&self) -> Result<Sha1, tor_error::Bug> {
228
7
        Ok(Sha1(self.1.hashes.sha1.ok_or_else(|| {
229
            internal!("router-signature should be present")
230
        })?))
231
7
    }
232

            
233
7
    fn sha256(&self) -> Result<Sha256, tor_error::Bug> {
234
7
        Ok(Sha256(self.1.hashes.sha256.ok_or_else(|| {
235
            internal!("router-sig-ed25519 should be present")
236
        })?))
237
7
    }
238
}
239

            
240
/// Wrapper for [`Microdesc`] with it's associated type.
241
pub(crate) type FlavoredDescriptorMd = (Microdesc, String);
242

            
243
impl FlavoredDescriptor for FlavoredDescriptorMd {
244
    fn flavor() -> ConsensusFlavor {
245
        ConsensusFlavor::Microdesc
246
    }
247

            
248
    fn id_rsa(&self) -> Option<RsaIdentity> {
249
        None
250
    }
251

            
252
    fn extra_info_sha1(&self) -> Option<ExtraInfoDigests> {
253
        None
254
    }
255

            
256
    fn sha1(&self) -> Result<Sha1, tor_error::Bug> {
257
        Ok(Sha1::digest(self.1.as_bytes()))
258
    }
259

            
260
    fn sha256(&self) -> Result<Sha256, tor_error::Bug> {
261
        Ok(Sha256::digest(self.1.as_bytes()))
262
    }
263
}