1use crate::{
2 Certificate, CertificateError,
3 cert::{CT_POISON, SCT_V1},
4 utils::codec::CodecError,
5 v1,
6};
7use itertools::Itertools;
8use sha2::{Digest, Sha256};
9use x509_cert::{
10 Certificate as Cert,
11 der::{Decode, Encode},
12};
13use x509_verify::VerifyingKey;
14
15#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct CertificateChain(Vec<Certificate>);
22
23impl From<Vec<Certificate>> for CertificateChain {
24 fn from(value: Vec<Certificate>) -> Self {
25 Self(value)
26 }
27}
28
29impl CertificateChain {
30 pub fn from_pem_chain(input: &str) -> Result<Self, CertificateError> {
31 let chain = Cert::load_pem_chain(input.as_bytes()).map_err(CodecError::DerError)?;
32
33 if chain.len() < 2 {
36 return Err(CertificateError::InvalidChain);
37 }
38
39 let chain = Self(chain.into_iter().map(Certificate).collect());
40 Ok(chain)
41 }
42
43 pub fn as_pem_chain(&self) -> String {
44 self.0.iter().map(|cert| cert.as_pem()).join("")
45 }
46
47 pub fn from_der_chain(input: &[Vec<u8>]) -> Result<Self, CertificateError> {
48 let chain = input
49 .iter()
50 .map(|bytes| Cert::from_der(bytes))
51 .collect::<Result<Vec<_>, _>>()
52 .map_err(CodecError::DerError)?;
53
54 if chain.len() < 2 {
57 return Err(CertificateError::InvalidChain);
58 }
59
60 let chain = Self(chain.into_iter().map(Certificate).collect());
61 Ok(chain)
62 }
63
64 pub fn verify_chain(&self) -> Result<(), CertificateError> {
65 self.verify_chain_inner(None)
66 }
67
68 pub fn verify_chain_against_root(&self, root: &Certificate) -> Result<(), CertificateError> {
69 self.verify_chain_inner(Some(root))
70 }
71
72 fn verify_chain_inner(&self, maybe_root: Option<&Certificate>) -> Result<(), CertificateError> {
73 for idx in 1..self.0.len() {
74 let key = VerifyingKey::try_from(&self.0[idx].0)?;
75 key.verify(&self.0[idx - 1].0)?;
76 }
77
78 if let Some(root) = maybe_root {
79 let key = VerifyingKey::try_from(&self.0.last().unwrap().0)?;
80 key.verify(&root.0)?;
81 }
82
83 Ok(())
84 }
85
86 pub fn cert(&self) -> &Certificate {
87 &self.0[0]
88 }
89
90 pub fn root(&self) -> &Certificate {
91 self.0.last().unwrap()
92 }
93
94 pub(crate) fn as_log_entry_v1(&self, as_precert: bool) -> Result<v1::LogEntry, CodecError> {
95 if !as_precert {
96 return Ok(v1::LogEntry::X509(self.cert().0.clone()));
97 }
98
99 let mut subject_public_key_bytes = vec![];
101 self.0[1]
105 .0
106 .tbs_certificate
107 .subject_public_key_info
108 .encode_to_vec(&mut subject_public_key_bytes)
109 .map_err(CodecError::DerError)?;
110 let issuer_key_hash: [u8; 32] = Sha256::digest(&subject_public_key_bytes).into();
111
112 let mut tbs_certificate = self.cert().0.tbs_certificate.clone();
113 tbs_certificate.extensions = tbs_certificate.extensions.map(|extensions| {
114 extensions
115 .into_iter()
116 .filter(|extension| extension.extn_id != SCT_V1 && extension.extn_id != CT_POISON)
118 .collect::<Vec<_>>()
119 });
120
121 Ok(v1::LogEntry::PreCert(v1::PreCert {
122 issuer_key_hash,
123 tbs_certificate,
124 }))
125 }
126
127 pub fn as_leaf_v1(
138 &self,
139 sct: &v1::SignedCertificateTimestamp,
140 as_precert: bool,
141 ) -> Result<v1::MerkleTreeLeaf, CodecError> {
142 Ok(v1::MerkleTreeLeaf {
143 version: sct.sct_version.clone(),
144 leaf: v1::tree::Leaf::TimestampedEntry(v1::tree::TimestampedEntry {
145 timestamp: sct.timestamp,
146 log_entry: self.as_log_entry_v1(as_precert)?,
147 extensions: sct.extensions.clone(),
148 }),
149 })
150 }
151}