ctclient_async/internal/
leaf.rs

1use std::convert::{TryFrom, TryInto};
2use std::fmt;
3
4use crate::Error;
5use crate::jsons;
6use crate::utils;
7
8/// A parsed leaf.
9///
10/// Parse a JSON get-entries response to this with
11/// `TryFrom<&jsons::LeafEntry>::try_from`.
12pub struct Leaf {
13    /// What they call "leaf hash".
14    pub hash: [u8; 32],
15    /// The leaf timestamp provided by the log.
16    pub timestamp: u64,
17    pub is_pre_cert: bool,
18    /// The first cert is the end entity cert (or pre cert, if `is_pre_cert` is
19    /// true), and the last is the root CA.
20    pub x509_chain: Vec<Vec<u8>>,
21    /// When is_pre_cert is true, this contains the tbs certificate found at the leaf input data.
22    /// You should verify that this is the same certificate as x509_chain\[0], except not signed.
23    pub tbs_cert: Option<Vec<u8>>,
24    pub issuer_key_hash: Option<Vec<u8>>,
25    /// Raw extensions data. Ignored. Length not included.
26    pub extensions: Vec<u8>,
27}
28
29impl Leaf {
30    pub fn from_raw(leaf_input: &[u8], extra_data: &[u8]) -> Result<Self, Error> {
31        let mut hash_data = Vec::with_capacity(1 + leaf_input.len());
32        hash_data.push(0);
33        hash_data.extend_from_slice(leaf_input);
34        let hash = utils::sha256(&hash_data);
35        let is_pre_cert;
36        let mut x509_chain;
37        let mut tbs = None;
38        /*
39          type MerkleTreeLeaf struct {
40            Version          Version           `tls:"maxval:255"`
41            LeafType         MerkleLeafType    `tls:"maxval:255"`
42            TimestampedEntry *TimestampedEntry `tls:"selector:LeafType,val:0"`
43          }
44        */
45        fn err_invalid() -> Result<Leaf, Error> {
46            Err(Error::MalformedResponseBody(
47                "Invalid leaf data.".to_owned(),
48            ))
49        }
50        fn err_invalid_extra() -> Result<Leaf, Error> {
51            Err(Error::MalformedResponseBody(
52                "Invalid extra data.".to_owned(),
53            ))
54        }
55        if leaf_input.len() < 2 {
56            return err_invalid();
57        }
58        let mut leaf_slice = leaf_input;
59        let version = u8::from_be_bytes([leaf_slice[0]]);
60        let leaf_type = u8::from_be_bytes([leaf_slice[1]]);
61        if version != 0 || leaf_type != 0 {
62            return err_invalid(); // TODO should ignore.
63        }
64        leaf_slice = &leaf_slice[2..];
65        /*
66          type TimestampedEntry struct {
67            Timestamp    uint64
68            EntryType    LogEntryType   `tls:"maxval:65535"`
69            X509Entry    *ASN1Cert      `tls:"selector:EntryType,val:0"`
70            PrecertEntry *PreCert       `tls:"selector:EntryType,val:1"`
71            JSONEntry    *JSONDataEntry `tls:"selector:EntryType,val:32768"`
72            Extensions   CTExtensions   `tls:"minlen:0,maxlen:65535"`
73          }
74        */
75        if leaf_slice.len() < 8 + 2 {
76            return err_invalid();
77        }
78        let timestamp = u64::from_be_bytes(leaf_slice[0..8].try_into().unwrap());
79        leaf_slice = &leaf_slice[8..];
80        let entry_type = u16::from_be_bytes([leaf_slice[0], leaf_slice[1]]);
81        leaf_slice = &leaf_slice[2..];
82        let issuer_key_hash;
83        match entry_type {
84            0 => {
85                // x509_entry
86                is_pre_cert = false;
87                issuer_key_hash = None;
88                // len is u24
89                if leaf_slice.len() < 3 {
90                    return err_invalid();
91                }
92                let len = u32::from_be_bytes([0, leaf_slice[0], leaf_slice[1], leaf_slice[2]]);
93                leaf_slice = &leaf_slice[3..];
94                if leaf_slice.len() < len as usize {
95                    return err_invalid();
96                }
97                let x509_end = &leaf_slice[..len as usize]; // DER certificate
98                leaf_slice = &leaf_slice[len as usize..];
99                // rest of leaf_slice parsed below this match statement.
100
101                // Extra data is [][]byte with all length u24.
102                let mut extra_slice = extra_data;
103                if extra_slice.len() < 3 {
104                    return err_invalid_extra();
105                }
106                let chain_byte_len =
107                    u32::from_be_bytes([0, extra_slice[0], extra_slice[1], extra_slice[2]]);
108                extra_slice = &extra_slice[3..];
109                if extra_slice.len() != chain_byte_len as usize {
110                    return err_invalid_extra();
111                }
112                x509_chain = Vec::new();
113                x509_chain.push(Vec::from(x509_end));
114                while !extra_slice.is_empty() {
115                    if extra_slice.len() < 3 {
116                        return err_invalid_extra();
117                    }
118                    let len =
119                        u32::from_be_bytes([0, extra_slice[0], extra_slice[1], extra_slice[2]]);
120                    extra_slice = &extra_slice[3..];
121                    if extra_slice.len() < len as usize {
122                        return err_invalid_extra();
123                    }
124                    let data = &extra_slice[..len as usize];
125                    extra_slice = &extra_slice[len as usize..];
126                    x509_chain.push(Vec::from(data));
127                }
128            }
129            1 => {
130                // precert_entry
131                /*
132                  type PreCert struct {
133                    IssuerKeyHash  [sha256.Size]byte
134                    TBSCertificate []byte `tls:"minlen:1,maxlen:16777215"` // DER-encoded TBSCertificate
135                  }
136                */
137                is_pre_cert = true;
138                if leaf_slice.len() < 32 {
139                    return err_invalid();
140                }
141                issuer_key_hash = Some(leaf_slice[0..32].to_owned());
142                leaf_slice = &leaf_slice[32..];
143                if leaf_slice.len() < 3 {
144                    return err_invalid();
145                }
146                let len = u32::from_be_bytes([0, leaf_slice[0], leaf_slice[1], leaf_slice[2]]);
147                leaf_slice = &leaf_slice[3..];
148                if leaf_slice.len() < len as usize {
149                    return err_invalid();
150                }
151                let tbs_data = &leaf_slice[..len as usize];
152                leaf_slice = &leaf_slice[len as usize..];
153                // rest of leaf_slice parsed below this match statement.
154
155                tbs = Some(tbs_data.to_vec());
156
157                /* Extra data:
158                  type PrecertChainEntry struct {
159                    PreCertificate   ASN1Cert   `tls:"minlen:1,maxlen:16777215"`
160                    CertificateChain []ASN1Cert `tls:"minlen:0,maxlen:16777215"`
161                  }
162                */
163
164                let mut extra_slice = extra_data;
165                if extra_slice.len() < 3 {
166                    return err_invalid_extra();
167                }
168                let pre_cert_len =
169                    u32::from_be_bytes([0, extra_slice[0], extra_slice[1], extra_slice[2]]);
170                extra_slice = &extra_slice[3..];
171                if extra_slice.len() < pre_cert_len as usize {
172                    return err_invalid_extra();
173                }
174                let pre_cert_data = &extra_slice[..pre_cert_len as usize];
175                extra_slice = &extra_slice[pre_cert_len as usize..];
176                x509_chain = Vec::new();
177                x509_chain.push(Vec::from(pre_cert_data));
178                if extra_slice.len() < 3 {
179                    return err_invalid_extra();
180                }
181                let rest_len =
182                    u32::from_be_bytes([0, extra_slice[0], extra_slice[1], extra_slice[2]]);
183                extra_slice = &extra_slice[3..];
184                if extra_slice.len() != rest_len as usize {
185                    return err_invalid_extra();
186                }
187                while !extra_slice.is_empty() {
188                    if extra_slice.len() < 3 {
189                        return err_invalid_extra();
190                    }
191                    let len =
192                        u32::from_be_bytes([0, extra_slice[0], extra_slice[1], extra_slice[2]]);
193                    extra_slice = &extra_slice[3..];
194                    if extra_slice.len() < len as usize {
195                        return err_invalid_extra();
196                    }
197                    let data = &extra_slice[..len as usize];
198                    extra_slice = &extra_slice[len as usize..];
199                    x509_chain.push(Vec::from(data));
200                }
201            }
202            _ => {
203                return err_invalid(); // TODO should ignore.
204            }
205        }
206        if leaf_slice.len() < 2 {
207            return err_invalid();
208        }
209        let extension_len = u16::from_be_bytes([leaf_slice[0], leaf_slice[1]]);
210        leaf_slice = &leaf_slice[2..];
211        if leaf_slice.len() != extension_len as usize {
212            return err_invalid();
213        }
214        Ok(Leaf {
215            hash,
216            is_pre_cert,
217            x509_chain,
218            tbs_cert: tbs,
219            timestamp,
220            extensions: leaf_slice.to_owned(),
221            issuer_key_hash,
222        })
223    }
224}
225
226impl TryFrom<&jsons::LeafEntry> for Leaf {
227    type Error = Error;
228    fn try_from(le: &jsons::LeafEntry) -> Result<Self, Error> {
229        let leaf_input = base64::decode(&le.leaf_input).map_err(|e| {
230            Error::MalformedResponseBody(format!("base64 decode leaf_input: {}", &e))
231        })?;
232        let extra_data = base64::decode(&le.extra_data).map_err(|e| {
233            Error::MalformedResponseBody(format!("base64 decode extra_data: {}", &e))
234        })?;
235        Leaf::from_raw(&leaf_input, &extra_data)
236    }
237}
238
239impl fmt::Debug for Leaf {
240    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241        write!(f, "Leaf({})", &utils::u8_to_hex(&self.hash))?;
242        if self.is_pre_cert {
243            write!(f, " (pre_cert)")?;
244        }
245        Ok(())
246    }
247}
248
249/// Turn some raw leaf data into leaf hash.
250///
251/// Used in [`crate::SignedCertificateTimestamp::derive_leaf_hash`].
252pub mod leaf_hash_constructors {
253    use crate::utils;
254
255    pub fn with_x509(x509_endcert: &[u8], timestamp: u64, extensions_data: &[u8]) -> [u8; 32] {
256        let mut hash_data: Vec<u8> = Vec::new();
257        hash_data.push(0); // hash type = leaf data
258        // Merkle tree leaf_input:
259        hash_data.push(0); // version = 0
260        hash_data.push(0); // leaf type = 0
261        hash_data.extend_from_slice(&timestamp.to_be_bytes()); // timestamp
262        hash_data.extend_from_slice(&0u16.to_be_bytes()); // entry type = x509_entry
263        // all there is left is just chain[0].
264        assert!(x509_endcert.len() < 1 << 24);
265        hash_data.extend_from_slice(&(x509_endcert.len() as u32).to_be_bytes()[1..4]); // len of x509
266        hash_data.extend_from_slice(x509_endcert); // x509 data
267        assert!(extensions_data.len() < 1 << 16);
268        hash_data.extend_from_slice(&(extensions_data.len() as u16).to_be_bytes()); // len of extensions
269        hash_data.extend_from_slice(extensions_data); // extensions
270        utils::sha256(&hash_data)
271    }
272
273    pub fn with_precert(
274        tbs: &[u8],
275        issuer_key_hash: &[u8],
276        timestamp: u64,
277        extensions_data: &[u8],
278    ) -> [u8; 32] {
279        assert_eq!(issuer_key_hash.len(), 32);
280        let mut hash_data: Vec<u8> = Vec::new();
281        hash_data.push(0); // hash type = leaf data
282        // Merkle tree leaf_input:
283        hash_data.push(0); // version = 0
284        hash_data.push(0); // leaf type = 0
285        hash_data.extend_from_slice(&timestamp.to_be_bytes()); // timestamp
286        hash_data.extend_from_slice(&1u16.to_be_bytes()); // entry type = precert_entry
287        hash_data.extend_from_slice(issuer_key_hash); // issuer_key_hash
288        assert!(tbs.len() < 1 << 24);
289        hash_data.extend_from_slice(&(tbs.len() as u32).to_be_bytes()[1..4]); // len of tbs
290        hash_data.extend_from_slice(tbs); // tbs
291        assert!(extensions_data.len() < 1 << 16);
292        hash_data.extend_from_slice(&(extensions_data.len() as u16).to_be_bytes()); // len of extensions
293        hash_data.extend_from_slice(extensions_data); // extensions
294        utils::sha256(&hash_data)
295    }
296}