ct-rs/tests/log_entry_parsing.rs

94 lines
2.9 KiB
Rust
Raw Normal View History

use std::sync::Arc;
use base64ct::Encoding;
use ct::{
2024-10-28 17:42:42 -06:00
api::{responses::GetEntriesResponseEntry, CtApiClient},
merkle::{
2024-10-26 17:41:49 -06:00
consts::EXTRA_DATA_BASE64_BUFFER_SIZE,
types::{MerkleLeafType, Version}
2024-10-28 17:42:42 -06:00
},
parsing::entry::{parse_entry_extra_data_precert, parse_entry_extra_data_x509}
};
use tokio::task::JoinSet;
async fn fetch_entries() -> impl Iterator<Item = GetEntriesResponseEntry> {
2024-10-28 17:42:42 -06:00
let client = Arc::new(CtApiClient::new_with_client(
"https://oak.ct.letsencrypt.org/2024h2/ct/v1/get-entries",
Arc::new(reqwest::Client::new())
));
let mut join_set: JoinSet<_> = JoinSet::new();
for i in 0..12u64 {
let client = client.clone();
join_set.spawn(async move {
client
2024-10-28 17:42:42 -06:00
.get_log_entries(i * 256, (i + 1) * 256 - 1)
.await
.expect("Request should succeed")
});
}
join_set
.join_all()
.await
.into_iter()
.flat_map(|e| e.entries)
}
#[tokio::test]
async fn test_letsencrypt_2024h2_parsing() {
let mut buffer = [0u8; EXTRA_DATA_BASE64_BUFFER_SIZE];
2024-10-26 17:41:49 -06:00
for entry in fetch_entries().await {
// Parse leaf_input
buffer[..entry.leaf_input.len()].copy_from_slice(entry.leaf_input.as_bytes());
let parsed =
base64ct::Base64::decode_in_place(&mut buffer[..entry.leaf_input.len()])
.expect("leaf_input should parse as base64 properly");
let (input, merkle_tree_leaf) =
ct::parsing::entry::parse_merkle_tree_leaf(parsed)
.expect("leaf_input should parse properly");
// leaf_input Assertions
assert_eq!(input.len(), 0, "All input should be parsed");
let MerkleLeafType::TimeStampedEntry { entry_type, .. } =
merkle_tree_leaf.leaf_type
else {
panic!("Merkle tree leaf should be TimestampedEntry");
};
let Version::V1 = merkle_tree_leaf.version else {
panic!("Merkle tree leaf should be Version::V1");
};
// Calculate this before we have to mutably borrow the buffer again to avoid
// multiple mutable references
let parse_entry_extra_data = match entry_type {
ct::merkle::types::LogEntryType::X509Entry(..) => parse_entry_extra_data_x509,
ct::merkle::types::LogEntryType::PrecertEntry { .. } =>
parse_entry_extra_data_precert,
};
// Parse extra_data
buffer[..entry.extra_data.len()].copy_from_slice(entry.extra_data.as_bytes());
let parsed =
base64ct::Base64::decode_in_place(&mut buffer[..entry.extra_data.len()])
.expect("extra_data should parse as base64 properly");
let (input, parsed) =
parse_entry_extra_data(parsed).expect("extra_data should parse properly");
// extra_data assertions
2024-10-26 17:41:49 -06:00
assert_eq!(input.len(), 0, "All input should be parsed");
match parsed {
ct::merkle::types::EntryExtraData::X509Certificate(chain) =>
assert_ne!(chain.len(), 0, "x509 chain should not be 0 length"),
// TODO: Verify main_certificate against the tbs certificate loaded from
// leaf_entry
ct::merkle::types::EntryExtraData::Precertificate(chain_entry) => assert_ne!(
chain_entry.certificate_chain.len(),
0,
"precert chain should not be 0 length"
)
}
}
}