1use std::convert::TryInto;
2
3use openssl::pkey::PKey;
4use openssl::sha::sha256;
5use openssl::x509::X509Ref;
6
7use crate::Error;
8use crate::internal::leaf_hash_constructors;
9use crate::internal::openssl_ffi::{
10 SCTVersion, SignatureAlgorithm, sct_list_from_x509, x509_clone, x509_remove_sct_list,
11 x509_to_tbs,
12};
13use crate::internal::verify_dss_raw;
14
15fn to_unknown_err(openssl_err: openssl::error::ErrorStack) -> Error {
16 Error::Unknown(format!("{}", openssl_err))
17}
18
19#[derive(Debug, Clone)]
21pub struct SignedCertificateTimestamp {
22 pub log_id: [u8; 32],
23 pub timestamp: u64,
24 pub extensions_data: Vec<u8>,
25 pub entry: SctEntry,
26 pub signature_algorithm: SignatureAlgorithm,
27 pub raw_signature: Vec<u8>,
29}
30
31#[derive(Debug, Clone)]
35pub enum SctEntry {
36 X509(Vec<u8>),
37 PreCert {
38 tbs: Vec<u8>,
39 issuer_key_hash: [u8; 32],
40 },
41}
42
43impl SignedCertificateTimestamp {
44 pub fn from_cert_sct_extension(
51 cert: &X509Ref,
52 issuer: &X509Ref,
53 ) -> Result<Vec<SignedCertificateTimestamp>, Error> {
54 let sctlist = sct_list_from_x509(cert)?;
55 if sctlist.is_none() {
56 return Ok(Vec::new());
57 }
58 let sctlist = sctlist.unwrap();
59 let tbs = {
60 let mut cert_clone = x509_clone(cert).map_err(to_unknown_err)?;
61 x509_remove_sct_list(&mut cert_clone).map_err(to_unknown_err)?;
62 x509_to_tbs(&cert_clone).map_err(to_unknown_err)?
63 };
64 let issuer_key_hash = {
65 let k = issuer
66 .public_key()
67 .map_err(|e| {
68 Error::BadCertificate(format!("Can't parse public key from issuer: {}", e))
69 })?
70 .public_key_to_der()
71 .map_err(to_unknown_err)?;
72 sha256(&k)
73 };
74 let mut scts = Vec::with_capacity(sctlist.len());
75 for raw_sct in sctlist.into_iter() {
76 if raw_sct.version() != Some(SCTVersion::V1) {
77 return Err(Error::BadCertificate("Invalid SCT version.".to_owned()));
78 }
79 scts.push(SignedCertificateTimestamp {
80 log_id: raw_sct.log_id().try_into().map_err(|_| {
81 Error::BadCertificate("Expected log_id to have len 32".to_owned())
82 })?,
83 timestamp: raw_sct.timestamp(),
84 extensions_data: raw_sct.extensions().to_vec(),
85 entry: SctEntry::PreCert {
86 tbs: tbs.clone(),
87 issuer_key_hash,
88 },
89 signature_algorithm: raw_sct
90 .signature_algorithm()
91 .ok_or_else(|| Error::BadSct("Unknown signature algorithm.".to_owned()))?,
92 raw_signature: raw_sct.raw_signature().to_vec(),
93 });
94 }
95 Ok(scts)
96 }
97
98 pub fn derive_leaf_hash(&self) -> [u8; 32] {
102 match &self.entry {
103 SctEntry::PreCert {
104 tbs,
105 issuer_key_hash,
106 } => leaf_hash_constructors::with_precert(
107 &tbs[..],
108 &issuer_key_hash[..],
109 self.timestamp,
110 &self.extensions_data,
111 ),
112 SctEntry::X509(x509) => {
113 leaf_hash_constructors::with_x509(x509, self.timestamp, &self.extensions_data)
114 }
115 }
116 }
117
118 pub fn verify(&self, log_public_key: &PKey<openssl::pkey::Public>) -> Result<(), Error> {
122 let mut signed_data: Vec<u8> = Vec::new();
124 signed_data.push(0u8);
126 signed_data.push(0u8);
128 signed_data.extend_from_slice(&self.timestamp.to_be_bytes());
130 signed_data.extend_from_slice(
132 &match &self.entry {
133 SctEntry::X509(_) => 0u16,
134 SctEntry::PreCert {
135 tbs: _,
136 issuer_key_hash: _,
137 } => 1u16,
138 }
139 .to_be_bytes(),
140 );
141 match &self.entry {
142 SctEntry::X509(cert) => {
144 let len = cert.len();
145 if len > 1 << 24 {
146 return Err(Error::BadSct("Certificate too long.".to_owned()));
147 }
148 signed_data.extend_from_slice(&u32::to_be_bytes(len as u32)[1..4]);
149 signed_data.extend_from_slice(cert);
150 }
151 SctEntry::PreCert {
153 tbs,
154 issuer_key_hash,
155 } => {
156 signed_data.extend_from_slice(issuer_key_hash);
157 let len = tbs.len();
158 if len > 1 << 24 {
159 return Err(Error::BadSct("TBS certificate too long.".to_owned()));
160 }
161 signed_data.extend_from_slice(&u32::to_be_bytes(len as u32)[1..4]);
162 signed_data.extend_from_slice(tbs);
163 }
164 }
165 let ext_len = self.extensions_data.len();
167 if ext_len > 1 << 16 {
168 return Err(Error::BadSct("extension data too long.".to_owned()));
169 }
170 signed_data.extend_from_slice(&u16::to_be_bytes(ext_len as u16));
171 signed_data.extend_from_slice(&self.extensions_data);
172 verify_dss_raw(
174 self.signature_algorithm,
175 log_public_key,
176 &self.raw_signature,
177 &signed_data,
178 )
179 }
180}