use std::convert::{TryFrom, TryInto};
use std::fmt;
use crate::Error;
use crate::jsons;
use crate::utils;
pub struct Leaf {
pub hash: [u8; 32],
pub timestamp: u64,
pub is_pre_cert: bool,
pub x509_chain: Vec<Vec<u8>>,
pub tbs_cert: Option<Vec<u8>>,
pub issuer_key_hash: Option<Vec<u8>>,
pub extensions: Vec<u8>,
}
impl Leaf {
pub fn from_raw(leaf_input: &[u8], extra_data: &[u8]) -> Result<Self, Error> {
let mut hash_data = Vec::new();
hash_data.reserve(1 + leaf_input.len());
hash_data.push(0);
hash_data.extend_from_slice(leaf_input);
let hash = utils::sha256(&hash_data);
let is_pre_cert;
let mut x509_chain;
let mut tbs = None;
fn err_invalid() -> Result<Leaf, Error> {
Err(Error::MalformedResponseBody("Invalid leaf data.".to_owned()))
}
fn err_invalid_extra() -> Result<Leaf, Error> {
Err(Error::MalformedResponseBody("Invalid extra data.".to_owned()))
}
if leaf_input.len() < 2 {
return err_invalid();
}
let mut leaf_slice = &leaf_input[..];
let version = u8::from_be_bytes([leaf_slice[0]]);
let leaf_type = u8::from_be_bytes([leaf_slice[1]]);
if version != 0 || leaf_type != 0 {
return err_invalid(); }
leaf_slice = &leaf_slice[2..];
if leaf_slice.len() < 8 + 2 {
return err_invalid();
}
let timestamp = u64::from_be_bytes(leaf_slice[0..8].try_into().unwrap());
leaf_slice = &leaf_slice[8..];
let entry_type = u16::from_be_bytes([leaf_slice[0], leaf_slice[1]]);
leaf_slice = &leaf_slice[2..];
let issuer_key_hash;
match entry_type {
0 => { is_pre_cert = false;
issuer_key_hash = None;
if leaf_slice.len() < 3 {
return err_invalid();
}
let len = u32::from_be_bytes([0, leaf_slice[0], leaf_slice[1], leaf_slice[2]]);
leaf_slice = &leaf_slice[3..];
if leaf_slice.len() < len as usize {
return err_invalid();
}
let x509_end = &leaf_slice[..len as usize]; leaf_slice = &leaf_slice[len as usize..];
let mut extra_slice = &extra_data[..];
if extra_slice.len() < 3 {
return err_invalid_extra();
}
let chain_byte_len = u32::from_be_bytes([0, extra_slice[0], extra_slice[1], extra_slice[2]]);
extra_slice = &extra_slice[3..];
if extra_slice.len() != chain_byte_len as usize {
return err_invalid_extra();
}
x509_chain = Vec::new();
x509_chain.push(Vec::from(x509_end));
while !extra_slice.is_empty() {
if extra_slice.len() < 3 {
return err_invalid_extra();
}
let len = u32::from_be_bytes([0, extra_slice[0], extra_slice[1], extra_slice[2]]);
extra_slice = &extra_slice[3..];
if extra_slice.len() < len as usize {
return err_invalid_extra();
}
let data = &extra_slice[..len as usize];
extra_slice = &extra_slice[len as usize..];
x509_chain.push(Vec::from(data));
}
},
1 => {
is_pre_cert = true;
if leaf_slice.len() < 32 {
return err_invalid();
}
issuer_key_hash = Some(leaf_slice[0..32].to_owned());
leaf_slice = &leaf_slice[32..];
if leaf_slice.len() < 3 {
return err_invalid();
}
let len = u32::from_be_bytes([0, leaf_slice[0], leaf_slice[1], leaf_slice[2]]);
leaf_slice = &leaf_slice[3..];
if leaf_slice.len() < len as usize {
return err_invalid();
}
let tbs_data = &leaf_slice[..len as usize];
leaf_slice = &leaf_slice[len as usize..];
tbs = Some(tbs_data.to_vec());
let mut extra_slice = &extra_data[..];
if extra_slice.len() < 3 {
return err_invalid_extra();
}
let pre_cert_len = u32::from_be_bytes([0, extra_slice[0], extra_slice[1], extra_slice[2]]);
extra_slice = &extra_slice[3..];
if extra_slice.len() < pre_cert_len as usize {
return err_invalid_extra();
}
let pre_cert_data = &extra_slice[..pre_cert_len as usize];
extra_slice = &extra_slice[pre_cert_len as usize..];
x509_chain = Vec::new();
x509_chain.push(Vec::from(pre_cert_data));
if extra_slice.len() < 3 {
return err_invalid_extra();
}
let rest_len = u32::from_be_bytes([0, extra_slice[0], extra_slice[1], extra_slice[2]]);
extra_slice = &extra_slice[3..];
if extra_slice.len() != rest_len as usize {
return err_invalid_extra();
}
while !extra_slice.is_empty() {
if extra_slice.len() < 3 {
return err_invalid_extra();
}
let len = u32::from_be_bytes([0, extra_slice[0], extra_slice[1], extra_slice[2]]);
extra_slice = &extra_slice[3..];
if extra_slice.len() < len as usize {
return err_invalid_extra();
}
let data = &extra_slice[..len as usize];
extra_slice = &extra_slice[len as usize..];
x509_chain.push(Vec::from(data));
}
},
_ => {
return err_invalid(); }
}
if leaf_slice.len() < 2 {
return err_invalid();
}
let extension_len = u16::from_be_bytes([leaf_slice[0], leaf_slice[1]]);
leaf_slice = &leaf_slice[2..];
if leaf_slice.len() != extension_len as usize {
return err_invalid();
}
Ok(Leaf{hash, is_pre_cert, x509_chain, tbs_cert: tbs, timestamp, extensions: leaf_slice.to_owned(), issuer_key_hash})
}
}
impl TryFrom<&jsons::LeafEntry> for Leaf {
type Error = Error;
fn try_from(le: &jsons::LeafEntry) -> Result<Self, Error> {
let leaf_input = base64::decode(&le.leaf_input).map_err(|e| Error::MalformedResponseBody(format!("base64 decode leaf_input: {}", &e)))?;
let extra_data = base64::decode(&le.extra_data).map_err(|e| Error::MalformedResponseBody(format!("base64 decode extra_data: {}", &e)))?;
Leaf::from_raw(&leaf_input, &extra_data)
}
}
impl fmt::Debug for Leaf {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Leaf({})", &utils::u8_to_hex(&self.hash))?;
if self.is_pre_cert {
write!(f, " (pre_cert)")?;
}
Ok(())
}
}
pub mod leaf_hash_constructors {
use crate::utils;
pub fn with_x509(x509_endcert: &[u8], timestamp: u64, extensions_data: &[u8]) -> [u8; 32] {
let mut hash_data: Vec<u8> = Vec::new();
hash_data.push(0); hash_data.push(0); hash_data.push(0); hash_data.extend_from_slice(×tamp.to_be_bytes()); hash_data.extend_from_slice(&0u16.to_be_bytes()); assert!(x509_endcert.len() < 1<<24);
hash_data.extend_from_slice(&(x509_endcert.len() as u32).to_be_bytes()[1..4]); hash_data.extend_from_slice(&x509_endcert); assert!(extensions_data.len() < 1<<16);
hash_data.extend_from_slice(&(extensions_data.len() as u16).to_be_bytes()); hash_data.extend_from_slice(&extensions_data); utils::sha256(&hash_data)
}
pub fn with_precert(tbs: &[u8], issuer_key_hash: &[u8], timestamp: u64, extensions_data: &[u8]) -> [u8; 32] {
assert_eq!(issuer_key_hash.len(), 32);
let mut hash_data: Vec<u8> = Vec::new();
hash_data.push(0); hash_data.push(0); hash_data.push(0); hash_data.extend_from_slice(×tamp.to_be_bytes()); hash_data.extend_from_slice(&1u16.to_be_bytes()); hash_data.extend_from_slice(issuer_key_hash); assert!(tbs.len() < 1<<24);
hash_data.extend_from_slice(&(tbs.len() as u32).to_be_bytes()[1..4]); hash_data.extend_from_slice(tbs); assert!(extensions_data.len() < 1<<16);
hash_data.extend_from_slice(&(extensions_data.len() as u16).to_be_bytes()); hash_data.extend_from_slice(&extensions_data); utils::sha256(&hash_data)
}
}