1
//! Types to describe information about other downloaded directory
2
//! documents, without necessarily having the full document.
3
//!
4
//! These types are all local within tor-dirmgr.  They're used so that
5
//! the storage code doesn't need to know about all of the parsed
6
//! types from tor-netdoc.
7

            
8
use digest::Digest;
9
use tor_llcrypto as ll;
10
use tor_netdoc::doc::{
11
    authcert::{AuthCert, AuthCertKeyIds},
12
    netstatus::{Lifetime, MdConsensus, UnvalidatedMdConsensus},
13
};
14

            
15
use std::time::SystemTime;
16

            
17
/// Information about a consensus that we have in storage.
18
///
19
/// This information is ordinarily derived from the consensus, but doesn't
20
/// have to be.
21
#[derive(Debug, Clone)]
22
pub(crate) struct ConsensusMeta {
23
    /// The time over which the consensus is valid.
24
    lifetime: Lifetime,
25
    /// A sha3-256 digest of the signed portion of the consensus: used for
26
    /// fetching diffs.
27
    sha3_256_of_signed: [u8; 32],
28
    /// A sha3-256 digest of the entirety of the consensus: used for
29
    /// naming the file.
30
    sha3_256_of_whole: [u8; 32],
31
}
32

            
33
impl ConsensusMeta {
34
    /// Create a new ConsensusMeta
35
40
    pub(crate) fn new(
36
40
        lifetime: Lifetime,
37
40
        sha3_256_of_signed: [u8; 32],
38
40
        sha3_256_of_whole: [u8; 32],
39
40
    ) -> Self {
40
40
        ConsensusMeta {
41
40
            lifetime,
42
40
            sha3_256_of_signed,
43
40
            sha3_256_of_whole,
44
40
        }
45
40
    }
46
    /// Derive a new ConsensusMeta from an UnvalidatedMdConsensus and the
47
    /// text of its signed portion.
48
10
    pub(crate) fn from_unvalidated(
49
10
        signed_part: &str,
50
10
        remainder: &str,
51
10
        con: &UnvalidatedMdConsensus,
52
10
    ) -> Self {
53
10
        let lifetime = con.peek_lifetime().clone();
54
10
        let (sd, wd) = sha3_dual(signed_part, remainder);
55
10
        ConsensusMeta::new(lifetime, sd, wd)
56
10
    }
57
    /// Derive a new ConsensusMeta from a MdConsensus and the text of its
58
    /// signed portion.
59
    #[allow(unused)]
60
4
    pub(crate) fn from_consensus(signed_part: &str, remainder: &str, con: &MdConsensus) -> Self {
61
4
        let lifetime = con.lifetime().clone();
62
4
        let (sd, wd) = sha3_dual(signed_part, remainder);
63
4
        ConsensusMeta::new(lifetime, sd, wd)
64
4
    }
65
    /// Return the lifetime of this ConsensusMeta
66
38
    pub(crate) fn lifetime(&self) -> &Lifetime {
67
38
        &self.lifetime
68
38
    }
69
    /// Return the sha3-256 of the signed portion of this consensus.
70
22
    pub(crate) fn sha3_256_of_signed(&self) -> &[u8; 32] {
71
22
        &self.sha3_256_of_signed
72
22
    }
73
    /// Return the sha3-256 of the entirety of this consensus.
74
14
    pub(crate) fn sha3_256_of_whole(&self) -> &[u8; 32] {
75
14
        &self.sha3_256_of_whole
76
14
    }
77
}
78

            
79
/// Compute the sha3-256 digests of signed_part on its own, and of
80
/// signed_part concatenated with remainder.
81
712
fn sha3_dual(signed_part: impl AsRef<[u8]>, remainder: impl AsRef<[u8]>) -> ([u8; 32], [u8; 32]) {
82
712
    let mut d = ll::d::Sha3_256::new();
83
712
    d.update(signed_part.as_ref());
84
712
    let sha3_of_signed = d.clone().finalize().into();
85
712
    d.update(remainder.as_ref());
86
712
    let sha3_of_whole = d.finalize().into();
87
712
    (sha3_of_signed, sha3_of_whole)
88
712
}
89

            
90
/// Information about an authority certificate that we have in storage.
91
///
92
/// This information is ordinarily derived from the authority cert, but it
93
/// doesn't have to be.
94
#[derive(Clone, Debug)]
95
pub(crate) struct AuthCertMeta {
96
    /// Key IDs (identity and signing) for the certificate.
97
    ids: AuthCertKeyIds,
98
    /// Time of publication.
99
    published: SystemTime,
100
    /// Expiration time.
101
    expires: SystemTime,
102
}
103

            
104
impl AuthCertMeta {
105
    /// Construct a new AuthCertMeta from its components
106
8
    pub(crate) fn new(ids: AuthCertKeyIds, published: SystemTime, expires: SystemTime) -> Self {
107
8
        AuthCertMeta {
108
8
            ids,
109
8
            published,
110
8
            expires,
111
8
        }
112
8
    }
113

            
114
    /// Construct a new AuthCertMeta from a certificate.
115
2
    pub(crate) fn from_authcert(cert: &AuthCert) -> Self {
116
2
        AuthCertMeta::new(*cert.key_ids(), cert.published(), cert.expires())
117
2
    }
118

            
119
    /// Return the key IDs for this certificate
120
8
    pub(crate) fn key_ids(&self) -> &AuthCertKeyIds {
121
8
        &self.ids
122
8
    }
123
    /// Return the published time for this certificate
124
8
    pub(crate) fn published(&self) -> SystemTime {
125
8
        self.published
126
8
    }
127
    /// Return the expiration time for this certificate
128
8
    pub(crate) fn expires(&self) -> SystemTime {
129
8
        self.expires
130
8
    }
131
}
132

            
133
#[cfg(test)]
134
mod test {
135
    // @@ begin test lint list maintained by maint/add_warning @@
136
    #![allow(clippy::bool_assert_comparison)]
137
    #![allow(clippy::clone_on_copy)]
138
    #![allow(clippy::dbg_macro)]
139
    #![allow(clippy::mixed_attributes_style)]
140
    #![allow(clippy::print_stderr)]
141
    #![allow(clippy::print_stdout)]
142
    #![allow(clippy::single_char_pattern)]
143
    #![allow(clippy::unwrap_used)]
144
    #![allow(clippy::unchecked_duration_subtraction)]
145
    #![allow(clippy::useless_vec)]
146
    #![allow(clippy::needless_pass_by_value)]
147
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
148
    use super::*;
149

            
150
    #[test]
151
    fn t_sha3_dual() {
152
        let s = b"Loarax ipsum gruvvulus thneed amet, snergelly once-ler lerkim, sed do barbaloot tempor gluppitus ut labore et truffula magna aliqua. Ut enim ad grickle-grass veniam, quis miff-muffered ga-zumpco laboris nisi ut cruffulus ex ea schloppity consequat. Duis aute snarggle in swomeeswans in voluptate axe-hacker esse rippulus crummii eu moof nulla snuvv.";
153

            
154
        let sha3_of_whole: [u8; 32] = ll::d::Sha3_256::digest(s).into();
155

            
156
        for idx in 0..s.len() {
157
            let sha3_of_part: [u8; 32] = ll::d::Sha3_256::digest(&s[..idx]).into();
158
            let (a, b) = sha3_dual(&s[..idx], &s[idx..]);
159
            assert_eq!(a, sha3_of_part);
160
            assert_eq!(b, sha3_of_whole);
161
        }
162
    }
163
}