1use base64::{Engine, prelude::BASE64_STANDARD};
2use std::fmt;
3
4use ouroboros::self_referencing;
5use x509_parser::prelude::*;
6
7use crate::error::{BinaryParsingError, CtLogError};
8
9use super::{
10 model::Entry,
11 util::{read_exact_bytes, read_u8, read_u16_be, read_u24_be, read_u64_be, read_vec},
12};
13
14#[cfg(feature = "debug-fmt")]
15use chrono::TimeZone;
16
17#[cfg(feature = "debug-fmt")]
18use oid_registry::{OidRegistry, format_oid};
19
20#[cfg(feature = "debug-fmt")]
21use super::util::{print_x509_extension, print_x509_ski};
22
23#[self_referencing(pub_extras)]
24#[derive(Debug)]
25pub struct WrapX509Certificate {
26 raw: Vec<u8>,
27 #[borrows(raw)]
28 #[covariant]
29 pub certificate: X509Certificate<'this>,
30}
31
32impl WrapX509Certificate {
33 pub fn try_from_der(v: &[u8]) -> Result<Self, BinaryParsingError> {
34 Ok(WrapX509CertificateBuilder {
35 raw: v.to_vec(),
36 certificate_builder: |raw: &Vec<u8>| X509Certificate::from_der(raw).unwrap().1,
37 }
38 .build())
39 }
40}
41
42#[cfg(feature = "debug-fmt")]
43impl fmt::Display for WrapX509Certificate {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 let certificate = self.borrow_certificate();
46 writeln!(f, "Certificate:")?;
47 writeln!(f, " Data:")?;
48 writeln!(f, " Version: {}", certificate.version())?;
49 writeln!(
50 f,
51 " Serial Number: {} ({})",
52 certificate.serial,
53 certificate.raw_serial_as_string()
54 )?;
55 writeln!(
56 f,
57 " Signature Algorithm: {}",
58 format_oid(
59 certificate.signature_algorithm.oid(),
60 &OidRegistry::default().with_all_crypto()
61 )
62 )?;
63 writeln!(f, " Issuer: {}", certificate.issuer())?;
64 writeln!(f, " Validity:")?;
65 writeln!(f, " Not Before: {}", certificate.validity().not_before)?;
66 writeln!(f, " Not After : {}", certificate.validity().not_after)?;
67 writeln!(f, " Subject: {}", certificate.subject())?;
68 writeln!(f, " Subject Public Key Info:")?;
69 print_x509_ski(f, certificate.public_key(), 6)?;
70
71 if !certificate.extensions().is_empty() {
72 writeln!(f, " X509v3 extensions:")?;
73 for extension in certificate.extensions() {
74 print_x509_extension(f, &extension.oid, extension, 6)?;
75 }
76 }
77
78 Ok(())
79 }
80}
81
82#[self_referencing(pub_extras)]
83#[derive(Debug)]
84pub struct WrapTbsCertificate {
85 raw: Vec<u8>,
86 #[borrows(raw)]
87 #[covariant]
88 pub certificate: TbsCertificate<'this>,
89}
90
91impl WrapTbsCertificate {
92 pub fn try_from_der(v: &[u8]) -> Result<Self, BinaryParsingError> {
93 Ok(WrapTbsCertificateBuilder {
94 raw: v.to_vec(),
95 certificate_builder: |raw: &Vec<u8>| TbsCertificate::from_der(raw).unwrap().1,
96 }
97 .build())
98 }
99}
100
101#[cfg(feature = "debug-fmt")]
102impl fmt::Display for WrapTbsCertificate {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 let certificate = self.borrow_certificate();
105
106 writeln!(f, "Certificate:")?;
107 writeln!(f, " Data:")?;
108 writeln!(f, " Version: {}", certificate.version())?;
109 writeln!(
110 f,
111 " Serial Number: {} ({})",
112 certificate.serial,
113 certificate.raw_serial_as_string()
114 )?;
115 writeln!(
116 f,
117 " Signature Algorithm: {}",
118 format_oid(
119 certificate.signature.oid(),
120 &OidRegistry::default().with_all_crypto()
121 )
122 )?;
123 writeln!(f, " Issuer: {}", certificate.issuer())?;
124 writeln!(f, " Validity:")?;
125 writeln!(f, " Not Before: {}", certificate.validity().not_before)?;
126 writeln!(f, " Not After : {}", certificate.validity().not_after)?;
127 writeln!(f, " Subject: {}", certificate.subject())?;
128 writeln!(f, " Subject Public Key Info:")?;
129 print_x509_ski(f, certificate.public_key(), 6)?;
130
131 if !certificate.extensions().is_empty() {
132 writeln!(f, " X509v3 extensions:")?;
133 for extension in certificate.extensions() {
134 print_x509_extension(f, &extension.oid, extension, 6)?;
135 }
136 }
137
138 Ok(())
139 }
140}
141
142#[derive(Debug, PartialEq, Eq, Clone)]
143pub enum LogEntryType {
144 X509Entry = 0,
145 PrecertEntry = 1,
146}
147
148impl LogEntryType {
149 pub fn parse(input: &mut &[u8]) -> Result<Self, BinaryParsingError> {
150 let id = read_u16_be(input)?;
151 match id {
152 0 => Ok(LogEntryType::X509Entry),
153 1 => Ok(LogEntryType::PrecertEntry),
154 _ => Err(BinaryParsingError::InvalidSequence(format!(
155 "Invalid LogEntryType id: {}",
156 id
157 ))),
158 }
159 }
160}
161
162#[derive(Debug)]
163#[allow(dead_code)]
164pub struct ASN1Cert {
165 pub length: u32,
166 pub certificate: Box<WrapX509Certificate>,
167}
168
169impl ASN1Cert {
170 pub fn parse(input: &mut &[u8]) -> Result<Self, BinaryParsingError> {
171 let length = read_u24_be(input)?;
172 let cert_data = read_exact_bytes(input, length as usize)?;
173
174 let wrapped_cert = WrapX509Certificate::try_from_der(cert_data)?;
175
176 Ok(ASN1Cert {
177 length,
178 certificate: Box::new(wrapped_cert),
179 })
180 }
181}
182
183#[cfg(feature = "debug-fmt")]
184impl fmt::Display for ASN1Cert {
185 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186 self.certificate.fmt(f)
187 }
188}
189
190#[derive(Debug)]
191pub struct ASN1CertChain {
192 pub length: u32,
193 pub certificates: Vec<ASN1Cert>,
194}
195
196impl ASN1CertChain {
197 pub fn parse(input: &mut &[u8]) -> Result<Self, BinaryParsingError> {
198 let total_chain_length = read_u24_be(input)?;
199 let mut certs_data_slice = read_exact_bytes(input, total_chain_length as usize)?;
200 let mut certificates = Vec::new();
201
202 let mut consumed_len = 0;
203 while consumed_len < total_chain_length {
204 let init_len = certs_data_slice.len();
205 if init_len == 0 {
206 if consumed_len < total_chain_length {
207 return Err(BinaryParsingError::InsufficientData);
208 }
209
210 break;
211 }
212
213 let cert = ASN1Cert::parse(&mut certs_data_slice)?;
214 consumed_len += (init_len - certs_data_slice.len()) as u32;
215 certificates.push(cert);
216 }
217 if consumed_len != total_chain_length {
218 return Err(BinaryParsingError::InvalidSequence(format!(
219 "Invalid ASN1CertChain length: {}",
220 consumed_len
221 )));
222 }
223
224 Ok(ASN1CertChain {
225 length: total_chain_length,
226 certificates,
227 })
228 }
229}
230
231#[derive(Debug)]
232pub struct PrecertChainEntry {
233 pub pre_certificate: ASN1Cert,
234 pub precertificate_chain: ASN1CertChain,
235}
236
237impl PrecertChainEntry {
238 pub fn parse(input: &mut &[u8]) -> Result<Self, BinaryParsingError> {
239 let pre_cert = ASN1Cert::parse(input)?;
240 let pre_cert_chain = ASN1CertChain::parse(input)?;
241 Ok(PrecertChainEntry {
242 pre_certificate: pre_cert,
243 precertificate_chain: pre_cert_chain,
244 })
245 }
246}
247
248#[derive(Debug, PartialEq, Eq, Clone)]
249pub enum Version {
250 V1 = 0,
251}
252
253impl Version {
254 pub fn parse(input: &mut &[u8]) -> Result<Self, BinaryParsingError> {
255 let id = read_u8(input)?;
256 match id {
257 0 => Ok(Version::V1),
258 _ => Err(BinaryParsingError::InvalidSequence(format!(
259 "Unknown Version id: {}",
260 id
261 ))),
262 }
263 }
264}
265
266#[derive(Debug)]
267pub struct IssuerKeyHash([u8; 32]);
268
269impl IssuerKeyHash {
270 pub fn parse(input: &mut &[u8]) -> Result<Self, BinaryParsingError> {
271 let bytes = read_exact_bytes(input, 32)?;
272 let mut arr = [0u8; 32];
273 arr.copy_from_slice(bytes);
274 Ok(IssuerKeyHash(arr))
275 }
276}
277
278impl fmt::LowerHex for IssuerKeyHash {
279 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
280 for byte in &self.0 {
281 write!(f, "{:02x}", byte)?;
282 }
283 Ok(())
284 }
285}
286
287#[derive(Debug)]
288pub struct PreCert {
289 pub issuer_key_hash: IssuerKeyHash,
290 pub length: u32,
291 pub tbs_certificate: Box<WrapTbsCertificate>,
292}
293
294impl PreCert {
295 pub fn parse(input: &mut &[u8]) -> Result<Self, BinaryParsingError> {
296 let iss_key_hash = IssuerKeyHash::parse(input)?;
297 let length = read_u24_be(input)?;
298 let tbs_data = read_exact_bytes(input, length as usize)?;
299
300 let wrapped_tbs_cert = WrapTbsCertificate::try_from_der(tbs_data)?;
301
302 Ok(PreCert {
303 issuer_key_hash: iss_key_hash,
304 length,
305 tbs_certificate: Box::new(wrapped_tbs_cert),
306 })
307 }
308}
309
310#[cfg(feature = "debug-fmt")]
311impl fmt::Display for PreCert {
312 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
313 self.tbs_certificate.fmt(f)
314 }
315}
316
317#[derive(Debug, Clone)]
318pub struct CtExtensions {
319 pub length: u16,
320 pub extensions: Vec<u8>,
321}
322
323impl CtExtensions {
324 pub fn parse(input: &mut &[u8]) -> Result<Self, BinaryParsingError> {
325 let length = read_u16_be(input)?;
326 let ext_data = read_vec(input, length as usize)?;
327 Ok(CtExtensions {
328 length,
329 extensions: ext_data.to_vec(),
330 })
331 }
332}
333
334#[derive(Debug, PartialEq, Eq, Clone)]
335pub enum MerkleLeafType {
336 TimestampedEntry = 0,
337}
338
339impl MerkleLeafType {
340 pub fn parse(input: &mut &[u8]) -> Result<Self, BinaryParsingError> {
341 let id = read_u8(input)?;
342 match id {
343 0 => Ok(MerkleLeafType::TimestampedEntry),
344 _ => Err(BinaryParsingError::InvalidSequence(format!(
345 "Unknown MerkleLeafType id: {}",
346 id
347 ))),
348 }
349 }
350}
351
352#[derive(Debug)]
353pub enum TimestampedEntrySignedInner {
354 X509(ASN1Cert),
355 Precert(PreCert),
356}
357
358impl TimestampedEntrySignedInner {
359 pub fn parse(input: &mut &[u8], entry_type: &LogEntryType) -> Result<Self, BinaryParsingError> {
360 match entry_type {
361 LogEntryType::X509Entry => {
362 ASN1Cert::parse(input).map(TimestampedEntrySignedInner::X509)
363 }
364 LogEntryType::PrecertEntry => {
365 PreCert::parse(input).map(TimestampedEntrySignedInner::Precert)
366 }
367 }
368 }
369}
370
371#[derive(Debug)]
372pub struct TimestampedEntry {
373 pub timestamp: u64,
374 pub entry_type: LogEntryType,
375 pub signed_entry: TimestampedEntrySignedInner,
376 pub extensions: CtExtensions,
377}
378
379impl TimestampedEntry {
380 pub fn parse(input: &mut &[u8]) -> Result<Self, BinaryParsingError> {
381 let timestamp = read_u64_be(input)?;
382 let entry_type = LogEntryType::parse(input)?;
383
384 let signed_entry = TimestampedEntrySignedInner::parse(input, &entry_type)?;
385 let ext = CtExtensions::parse(input)?;
386
387 Ok(TimestampedEntry {
388 timestamp,
389 entry_type,
390 signed_entry,
391 extensions: ext,
392 })
393 }
394}
395
396#[derive(Debug)]
397pub struct MerkleTreeLeaf {
398 pub version: Version,
399 pub leaf_type: MerkleLeafType,
400 pub timestamped_entry: TimestampedEntry,
401}
402
403impl MerkleTreeLeaf {
404 pub fn parse(input: &mut &[u8]) -> Result<Self, BinaryParsingError> {
405 let ver = Version::parse(input)?;
406 let leaf_type = MerkleLeafType::parse(input)?;
407 let timestamped_entry = TimestampedEntry::parse(input)?;
408
409 Ok(MerkleTreeLeaf {
410 version: ver,
411 leaf_type,
412 timestamped_entry,
413 })
414 }
415}
416
417#[derive(Debug)]
418pub enum DecodedEntryInner {
419 X509(ASN1CertChain),
420 Precert(PrecertChainEntry),
421}
422
423#[derive(Debug)]
425pub struct DecodedEntry {
426 pub leaf: MerkleTreeLeaf,
427 pub extra_data: DecodedEntryInner,
428 pub raw_leaf: Vec<u8>,
429}
430
431impl TryFrom<&Entry> for DecodedEntry {
432 type Error = CtLogError;
433
434 fn try_from(entry: &Entry) -> Result<Self, CtLogError> {
435 let decoded_leaf_bytes: Vec<u8> = BASE64_STANDARD.decode(entry.leaf_input.clone())?;
436
437 let mut leaf_in_slice = decoded_leaf_bytes.as_slice();
438 let leaf = MerkleTreeLeaf::parse(&mut leaf_in_slice)?;
439
440 if !leaf_in_slice.is_empty() {
441 return Err(BinaryParsingError::InvalidSequence(format!(
442 "Trailing data after parsing MerkleTreeLeaf: {} bytes left",
443 leaf_in_slice.len()
444 ))
445 .into());
446 }
447
448 let extra_data_decoded = BASE64_STANDARD.decode(&entry.extra_data)?;
449 let mut extra_data_slice = extra_data_decoded.as_slice();
450
451 let extra_data = match leaf.timestamped_entry.entry_type {
452 LogEntryType::X509Entry => {
453 let cert_chain = ASN1CertChain::parse(&mut extra_data_slice)?;
454 DecodedEntryInner::X509(cert_chain)
455 }
456 LogEntryType::PrecertEntry => {
457 let precert_chain = PrecertChainEntry::parse(&mut extra_data_slice)?;
458 DecodedEntryInner::Precert(precert_chain)
459 }
460 };
461
462 if !extra_data_slice.is_empty() {
463 return Err(BinaryParsingError::InvalidSequence(format!(
464 "Trailing data after parsing extra_data: {} bytes left",
465 extra_data_slice.len()
466 ))
467 .into());
468 }
469
470 Ok(Self {
471 leaf,
472 extra_data,
473 raw_leaf: decoded_leaf_bytes,
474 })
475 }
476}
477
478#[cfg(feature = "debug-fmt")]
479impl fmt::Display for DecodedEntry {
480 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
481 write!(
482 f,
483 "Timestamp={} ({}) ",
484 self.leaf.timestamped_entry.timestamp,
485 chrono::Utc
486 .timestamp_millis_opt(self.leaf.timestamped_entry.timestamp as i64)
487 .unwrap()
488 )?;
489
490 match (
491 &self.leaf.timestamped_entry.entry_type,
492 &self.leaf.timestamped_entry.signed_entry,
493 ) {
494 (LogEntryType::X509Entry, TimestampedEntrySignedInner::X509(certificate)) => {
495 writeln!(f, "X.509 certificate:")?;
496 writeln!(f, "{certificate}")?;
497
498 }
500 (LogEntryType::PrecertEntry, TimestampedEntrySignedInner::Precert(certificate)) => {
501 writeln!(
502 f,
503 "pre-certificate from issuer with keyhash {:x}:",
504 certificate.issuer_key_hash
505 )?;
506 writeln!(f, "{certificate}")?;
507
508 }
510 _ => unreachable!(),
511 }
512
513 Ok(())
514 }
515}