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

            
79
/// Compute the sha3-256 digests of signed_part on its own, and of
80
/// signed_part concatenated with remainder.
81
356
fn sha3_dual(signed_part: impl AsRef<[u8]>, remainder: impl AsRef<[u8]>) -> ([u8; 32], [u8; 32]) {
82
356
    let mut d = ll::d::Sha3_256::new();
83
356
    d.update(signed_part.as_ref());
84
356
    let sha3_of_signed = d.clone().finalize().into();
85
356
    d.update(remainder.as_ref());
86
356
    let sha3_of_whole = d.finalize().into();
87
356
    (sha3_of_signed, sha3_of_whole)
88
356
}
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
4
    pub(crate) fn new(ids: AuthCertKeyIds, published: SystemTime, expires: SystemTime) -> Self {
107
4
        AuthCertMeta {
108
4
            ids,
109
4
            published,
110
4
            expires,
111
4
        }
112
4
    }
113

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

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

            
133
#[cfg(test)]
134
mod test {
135
    use super::*;
136

            
137
    #[test]
138
    fn t_sha3_dual() {
139
        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.";
140

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

            
143
        for idx in 0..s.len() {
144
            let sha3_of_part: [u8; 32] = ll::d::Sha3_256::digest(&s[..idx]).into();
145
            let (a, b) = sha3_dual(&s[..idx], &s[idx..]);
146
            assert_eq!(a, sha3_of_part);
147
            assert_eq!(b, sha3_of_whole);
148
        }
149
    }
150
}