1use std::{fmt::Display, time::Duration};
3
4use const_oid::{AssociatedOid, ObjectIdentifier};
5use der::asn1::{GeneralizedTime, OctetString, UtcTime};
6use x509_cert::{ext::AsExtension, impl_newtype, time::Time};
7
8pub const CT_PRECERT_SCTS: ObjectIdentifier =
12 ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11129.2.4.2");
13
14pub struct SctList(pub OctetString);
16
17impl AssociatedOid for SctList {
18 const OID: ObjectIdentifier = CT_PRECERT_SCTS;
19}
20
21impl_newtype!(SctList, OctetString);
22
23impl AsExtension for SctList {
24 fn critical(
25 &self,
26 _subject: &x509_cert::name::Name,
27 _extensions: &[x509_cert::ext::Extension],
28 ) -> bool {
29 false
30 }
31}
32
33#[derive(Debug)]
35pub enum Error {
36 DecodeTlsSctListError,
38 DecodeTlsSctError,
40 DecodeVersionError,
42 DecodeIntError,
44 DecodeLogIdError,
46 DecodeTimestampError,
48 DecodeExtensionsError,
50 DecodeDigitallySignedError,
52 DecodeHashAlgoError,
54 DecodeSignAlgoError,
56}
57
58fn decode_u8_be(bytes: &[u8]) -> Result<(u8, &[u8]), Error> {
60 if bytes.is_empty() {
61 return Err(Error::DecodeIntError);
62 }
63 let result = u8::from_be_bytes(bytes[..1].try_into().unwrap());
64
65 Ok((result, &bytes[1..]))
66}
67
68fn decode_u16_be(bytes: &[u8]) -> Result<(u16, &[u8]), Error> {
70 if bytes.len() < 2 {
71 return Err(Error::DecodeIntError);
72 }
73 let result = u16::from_be_bytes(bytes[..2].try_into().unwrap());
74
75 Ok((result, &bytes[2..]))
76}
77
78fn decode_u64_be(bytes: &[u8]) -> Result<(u64, &[u8]), Error> {
80 if bytes.len() < 8 {
81 return Err(Error::DecodeIntError);
82 }
83 let result = u64::from_be_bytes(bytes[..8].try_into().unwrap());
84
85 Ok((result, &bytes[8..]))
86}
87
88pub struct TlsSctList {
90 pub scts: Vec<TlsSct>,
92}
93
94impl TlsSctList {
95 pub fn from_sct_list(sct_list: &SctList) -> Result<Self, Error> {
97 let bytes = sct_list.0.as_bytes();
98 TlsSctList::decode(bytes)
99 }
100
101 fn decode(bytes: &[u8]) -> Result<Self, Error>
103 where
104 Self: Sized,
105 {
106 let (len, bytes) = decode_u16_be(bytes)?;
107 let len = len as usize;
108 if len != bytes.len() {
109 return Err(Error::DecodeTlsSctListError);
110 }
111 let mut scts = Vec::new();
112 let mut bytes = bytes;
113 while !bytes.is_empty() {
114 let (sct, rest) = TlsSct::decode(bytes)?;
115 bytes = rest;
116 scts.push(sct);
117 }
118 Ok(Self { scts })
119 }
120}
121
122pub struct TlsSct {
124 pub version: Version,
126 pub log_id: [u8; 32],
128 pub timestamp: Time,
130 pub extensions: Vec<u8>,
132 pub sign: DigitallySigned,
134}
135
136impl TlsSct {
137 fn decode(bytes: &[u8]) -> Result<(Self, &[u8]), Error>
139 where
140 Self: Sized,
141 {
142 let (len, bytes) = decode_u16_be(bytes)?;
143 let len = len as usize;
144 if len > bytes.len() {
145 return Err(Error::DecodeTlsSctError);
146 }
147 let (version, bytes) = Version::decode(bytes)?;
148 let (log_id, bytes) = Self::decode_log_id(bytes)?;
149 let (timestamp, bytes) = Self::decode_timestamp(bytes)?;
150 let (extensions, bytes) = Self::decode_extensions(bytes)?;
151 let (sign, bytes) = DigitallySigned::decode(bytes)?;
152
153 Ok((
154 Self {
155 version,
156 log_id,
157 timestamp,
158 extensions,
159 sign,
160 },
161 bytes,
162 ))
163 }
164
165 fn decode_log_id(bytes: &[u8]) -> Result<([u8; 32], &[u8]), Error> {
167 if bytes.len() < 32 {
168 return Err(Error::DecodeLogIdError);
169 }
170 let result = bytes[..32].try_into().unwrap();
171
172 Ok((result, &bytes[32..]))
173 }
174
175 fn decode_timestamp(bytes: &[u8]) -> Result<(Time, &[u8]), Error> {
177 let (timestamp, bytes) = decode_u64_be(bytes)?;
178 let timestamp = Duration::from_millis(timestamp);
179 let generalized_time = GeneralizedTime::from_unix_duration(timestamp);
180 if let Ok(generalized_time) = generalized_time {
181 Ok((generalized_time.into(), bytes))
182 } else {
183 let utc_time = UtcTime::from_unix_duration(timestamp);
184 if let Ok(utc_time) = utc_time {
185 Ok((utc_time.into(), bytes))
186 } else {
187 Err(Error::DecodeTimestampError)
188 }
189 }
190 }
191
192 fn decode_extensions(bytes: &[u8]) -> Result<(Vec<u8>, &[u8]), Error> {
194 let (len, rest) = decode_u16_be(bytes)?;
195 let len = len as usize;
196 if len > bytes.len() {
197 return Err(Error::DecodeExtensionsError);
198 }
199 let mut vec = Vec::with_capacity(len);
200 vec.extend_from_slice(&rest[..len]);
201 Ok((vec, &rest[len..]))
202 }
203}
204
205#[derive(Debug)]
207pub enum Version {
208 V1 = 0,
210}
211
212impl Version {
213 fn decode(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
215 let (version, bytes) = decode_u8_be(bytes)?;
216 Ok((version.try_into()?, bytes))
217 }
218}
219
220impl TryFrom<u8> for Version {
221 type Error = Error;
222
223 fn try_from(value: u8) -> Result<Self, Self::Error> {
224 match value {
225 0 => Ok(Version::V1),
226 _ => Err(Error::DecodeVersionError),
227 }
228 }
229}
230
231impl Display for Version {
232 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233 match self {
234 Version::V1 => write!(f, "v1"),
235 }
236 }
237}
238
239#[derive(Debug)]
241pub struct DigitallySigned {
242 pub sign_and_hash_algo: SignAndHashAlgo,
244 pub sign: Vec<u8>,
246}
247
248impl DigitallySigned {
249 fn decode(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
251 let (sign_and_hash_algo, bytes) = SignAndHashAlgo::decode(bytes)?;
252
253 let (len, rest) = decode_u16_be(bytes)?;
254 let len = len as usize;
255 if len > bytes.len() {
256 return Err(Error::DecodeDigitallySignedError);
257 }
258 let mut sign = Vec::with_capacity(len);
259 sign.extend_from_slice(&rest[..len]);
260 Ok((
261 Self {
262 sign_and_hash_algo,
263 sign,
264 },
265 &rest[len..],
266 ))
267 }
268}
269
270#[derive(Debug)]
272pub struct SignAndHashAlgo {
273 pub sign: SignatureAlgo,
275 pub hash: HashAlgo,
277}
278
279impl SignAndHashAlgo {
280 fn decode(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
282 let (hash, bytes) = HashAlgo::decode(bytes)?;
283 let (sign, bytes) = SignatureAlgo::decode(bytes)?;
284 Ok((Self { sign, hash }, bytes))
285 }
286}
287
288impl Display for SignAndHashAlgo {
289 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290 write!(f, "{}-with-{}", self.sign, self.hash)
291 }
292}
293
294#[derive(Debug)]
296pub enum SignatureAlgo {
297 Anonymous = 0,
299 Rsa = 1,
301 Dsa = 2,
303 Ecdsa = 3,
305 Ed25519 = 7,
307 Ed448 = 8,
309}
310
311impl SignatureAlgo {
312 fn decode(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
314 let (algo, bytes) = decode_u8_be(bytes)?;
315 Ok((algo.try_into()?, bytes))
316 }
317}
318
319impl TryFrom<u8> for SignatureAlgo {
320 type Error = Error;
321
322 fn try_from(value: u8) -> Result<Self, Self::Error> {
323 match value {
324 0 => Ok(SignatureAlgo::Anonymous),
325 1 => Ok(SignatureAlgo::Rsa),
326 2 => Ok(SignatureAlgo::Dsa),
327 3 => Ok(SignatureAlgo::Ecdsa),
328 7 => Ok(SignatureAlgo::Ed25519),
329 8 => Ok(SignatureAlgo::Ed448),
330 _ => Err(Error::DecodeSignAlgoError),
331 }
332 }
333}
334
335impl Display for SignatureAlgo {
336 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
337 match self {
338 SignatureAlgo::Anonymous => write!(f, "anonymous"),
339 SignatureAlgo::Rsa => write!(f, "rsa"),
340 SignatureAlgo::Dsa => write!(f, "dsa"),
341 SignatureAlgo::Ecdsa => write!(f, "ecdsa"),
342 SignatureAlgo::Ed25519 => write!(f, "ed25519"),
343 SignatureAlgo::Ed448 => write!(f, "ed448"),
344 }
345 }
346}
347
348#[derive(Debug)]
350pub enum HashAlgo {
351 None = 0,
353 Md5 = 1,
355 Sha1 = 2,
357 Sha224 = 3,
359 Sha256 = 4,
361 Sha384 = 5,
363 Sha512 = 6,
365 Intrinsic = 8,
367}
368
369impl HashAlgo {
370 fn decode(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
372 let (algo, bytes) = decode_u8_be(bytes)?;
373 Ok((algo.try_into()?, bytes))
374 }
375}
376
377impl TryFrom<u8> for HashAlgo {
378 type Error = Error;
379
380 fn try_from(value: u8) -> Result<Self, Self::Error> {
381 match value {
382 0 => Ok(HashAlgo::None),
383 1 => Ok(HashAlgo::Md5),
384 2 => Ok(HashAlgo::Sha1),
385 3 => Ok(HashAlgo::Sha224),
386 4 => Ok(HashAlgo::Sha256),
387 5 => Ok(HashAlgo::Sha384),
388 6 => Ok(HashAlgo::Sha512),
389 8 => Ok(HashAlgo::Intrinsic),
390 _ => Err(Error::DecodeHashAlgoError),
391 }
392 }
393}
394
395impl Display for HashAlgo {
396 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
397 match self {
398 HashAlgo::None => write!(f, "NONE"),
399 HashAlgo::Md5 => write!(f, "MD5"),
400 HashAlgo::Sha1 => write!(f, "SHA1"),
401 HashAlgo::Sha224 => write!(f, "SHA224"),
402 HashAlgo::Sha256 => write!(f, "SHA256"),
403 HashAlgo::Sha384 => write!(f, "SHA384"),
404 HashAlgo::Sha512 => write!(f, "SHA512"),
405 HashAlgo::Intrinsic => write!(f, "INTRINSIC"),
406 }
407 }
408}