x509_cert/ext/pkix/
sct.rs

1//! Signed Certificate Timestamp list extension as defined in the
2//! [Certificate Transparency RFC 6962].
3//!
4//! [Certificate Transparency RFC 6962]: https://datatracker.ietf.org/doc/html/rfc6962
5
6#![cfg(feature = "sct")]
7
8use alloc::{format, vec::Vec};
9use const_oid::{AssociatedOid, ObjectIdentifier};
10use der::asn1::OctetString;
11use tls_codec::{
12    DeserializeBytes, SerializeBytes, TlsByteVecU16, TlsDeserializeBytes, TlsSerializeBytes,
13    TlsSize,
14};
15
16/// A signed certificate timestamp list (SCT list) as defined in [RFC 6962 Section 3.3].
17///
18/// ```text
19/// SignedCertificateTimestampList ::= OCTET STRING
20/// ```
21///
22/// [RFC 6962 Section 3.3]: https://datatracker.ietf.org/doc/html/rfc6962#section-3.3
23#[derive(Debug, PartialEq)]
24pub struct SignedCertificateTimestampList(OctetString);
25
26//TODO: Remove this and use const-oid's rfc6962::CT_PRECERT_SCTS once a const-oid version
27// containing it is published
28const CT_PRECERT_SCTS: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11129.2.4.2");
29
30impl AssociatedOid for SignedCertificateTimestampList {
31    const OID: ObjectIdentifier = CT_PRECERT_SCTS;
32}
33
34impl_newtype!(SignedCertificateTimestampList, OctetString);
35impl_extension!(SignedCertificateTimestampList, critical = false);
36
37/// Errors that are thrown by this module.
38#[derive(PartialEq, Debug)]
39pub enum Error {
40    /// [Errors][der::Error] from the `der` crate.
41    Der(der::Error),
42    /// [Errors][tls_codec::Error] from the `tls_codec` crate.
43    Tls(tls_codec::Error),
44}
45
46impl From<der::Error> for Error {
47    fn from(value: der::Error) -> Self {
48        Error::Der(value)
49    }
50}
51
52impl From<tls_codec::Error> for Error {
53    fn from(value: tls_codec::Error) -> Self {
54        Error::Tls(value)
55    }
56}
57
58impl SignedCertificateTimestampList {
59    /// Creates a new [`SignedCertificateTimestampList`] from a slice of [`SerializedSct`]s.
60    pub fn new(serialized_scts: &[SerializedSct]) -> Result<Self, Error> {
61        let mut result: Vec<u8> = Vec::new();
62        for timestamp in serialized_scts {
63            let buffer = timestamp.tls_serialize()?;
64            result.extend(buffer);
65        }
66        let tls_vec = TlsByteVecU16::new(result);
67        let buffer = tls_vec.tls_serialize()?;
68        Ok(SignedCertificateTimestampList(OctetString::new(buffer)?))
69    }
70
71    /// Parses the encoded [SerializedSct]s and returns a [Vec] containing them.
72    ///
73    /// Returns an [error][Error] if a [SerializedSct] can't be
74    /// deserialized or if there are trailing bytes after all [SerializedSct]s
75    /// are deserialized.
76    pub fn parse_timestamps(&self) -> Result<Vec<SerializedSct>, Error> {
77        let (tls_vec, rest) = TlsByteVecU16::tls_deserialize_bytes(self.0.as_bytes())?;
78        if !rest.is_empty() {
79            return Err(tls_codec::Error::TrailingData)?;
80        }
81        let mut bytes = tls_vec.as_slice();
82        let mut result = Vec::new();
83        while !bytes.is_empty() {
84            let (serialized_sct, rest) = SerializedSct::tls_deserialize_bytes(bytes)?;
85            result.push(serialized_sct);
86            bytes = rest;
87        }
88        Ok(result)
89    }
90}
91
92/// A byte string that contains a serialized [SignedCertificateTimestamp] as
93/// defined in [RFC 6962 section 3.3].
94///
95/// [RFC 6962 section 3.3]: https://datatracker.ietf.org/doc/html/rfc6962#section-3.3
96#[derive(PartialEq, Debug, TlsDeserializeBytes, TlsSerializeBytes, TlsSize)]
97pub struct SerializedSct {
98    data: TlsByteVecU16,
99}
100
101impl SerializedSct {
102    /// Creates a new [SerializedSct] from a [SignedCertificateTimestamp].
103    ///
104    /// Returns [tls_codec Error][tls_codec::Error] if the given [SignedCertificateTimestamp]
105    /// can't be serialized.
106    pub fn new(timestamp: SignedCertificateTimestamp) -> Result<Self, tls_codec::Error> {
107        let buffer = timestamp.tls_serialize()?;
108        Ok(SerializedSct {
109            data: TlsByteVecU16::from_slice(&buffer),
110        })
111    }
112
113    /// Parses a [SignedCertificateTimestamp] from a this [SerializedSct].
114    ///
115    /// Returns an [error][Error] if a [SignedCertificateTimestamp] can't be
116    /// deserialized or if there are trailing bytes after a
117    /// [SignedCertificateTimestamp] has been deserialized.
118    pub fn parse_timestamp(&self) -> Result<SignedCertificateTimestamp, Error> {
119        let (sct, rest) = SignedCertificateTimestamp::tls_deserialize_bytes(self.data.as_slice())?;
120        if !rest.is_empty() {
121            return Err(tls_codec::Error::TrailingData)?;
122        }
123        Ok(sct)
124    }
125}
126
127/// A signed certificate timestamp (SCT) as defined in [RFC 6962 section 3.2].
128///
129/// [RFC 6962 section 3.2]: https://datatracker.ietf.org/doc/html/rfc6962#section-3.2
130#[derive(PartialEq, Debug, TlsDeserializeBytes, TlsSerializeBytes, TlsSize)]
131pub struct SignedCertificateTimestamp {
132    /// The version of the protocol to which the SCT conforms.
133    /// Currently, it is always v1.
134    pub version: Version,
135    /// The SHA-256 hash of the log's public key, calculated over
136    /// the DER encoding of the key represented as [SubjectPublicKeyInfo][spki::SubjectPublicKeyInfo].
137    pub log_id: LogId,
138    /// the current NTP Time measured since the `UNIX_EPOCH`
139    /// (January 1, 1970, 00:00), ignoring leap seconds, in milliseconds.
140    pub timestamp: u64,
141    /// The future extensions to protocol version v1.
142    /// Currently, no extensions are specified.
143    pub extensions: TlsByteVecU16,
144    /// A digital signature over many fields including
145    /// version, timestamp, extensions and others. See [RFC 6962 section 3.2]
146    /// for a complete list.
147    ///
148    /// [RFC 6962 section 3.2]:https://datatracker.ietf.org/doc/html/rfc6962#section-3.2
149    pub signature: DigitallySigned,
150}
151
152impl SignedCertificateTimestamp {
153    /// Creates a [DateTime][der::DateTime] from the timestamp field since the `UNIX_EPOCH`.
154    ///
155    /// Returns an error if timestamp is outside the supported date range.
156    pub fn timestamp(&self) -> Result<der::DateTime, der::Error> {
157        der::DateTime::from_unix_duration(core::time::Duration::from_millis(self.timestamp))
158    }
159}
160
161/// The version of the protocol to which the SCT conforms
162/// as defined in [RFC 6962 section 3.2]. Currently, it is always v1.
163///
164/// [RFC 6962 section 3.2]: https://datatracker.ietf.org/doc/html/rfc6962#section-3.2
165#[derive(PartialEq, Debug, TlsDeserializeBytes, TlsSerializeBytes, TlsSize)]
166#[repr(u8)]
167pub enum Version {
168    /// Version 1.
169    V1 = 0,
170}
171
172/// The SHA-256 hash of the log's public key, calculated over
173/// the DER encoding of the key represented as [SubjectPublicKeyInfo][spki::SubjectPublicKeyInfo]
174/// as defined in [RFC 6962 section 3.2].
175///
176/// [RFC 6962 section 3.2]: https://datatracker.ietf.org/doc/html/rfc6962#section-3.2
177#[derive(PartialEq, Debug, TlsDeserializeBytes, TlsSerializeBytes, TlsSize)]
178pub struct LogId {
179    /// Hash of the log's public key.
180    pub key_id: [u8; 32],
181}
182
183/// Digital signature as defined in [RFC 5246 section 4.7].
184///
185/// [RFC 5246 section 4.7]: https://datatracker.ietf.org/doc/html/rfc5246#section-4.7
186#[derive(PartialEq, Debug, TlsDeserializeBytes, TlsSerializeBytes, TlsSize)]
187pub struct DigitallySigned {
188    /// [SignatureAndHashAlgorithm] as defined in [RFC 5246 section 7.4.1.4.1].
189    ///
190    /// [RFC 5246 section 7.4.1.4.1]: https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.1.4.1
191    pub algorithm: SignatureAndHashAlgorithm,
192    /// Digital signature over some contents using the [SignatureAndHashAlgorithm].
193    pub signature: TlsByteVecU16,
194}
195
196/// A combination of signature and hashing algorithms as defined in [RFC 5246 section 7.4.1.4.1].
197///
198/// [RFC 5246 section 7.4.1.4.1]: https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.1.4.1
199#[derive(PartialEq, Debug, TlsDeserializeBytes, TlsSerializeBytes, TlsSize)]
200pub struct SignatureAndHashAlgorithm {
201    /// The hashing algorithm.
202    pub hash: HashAlgorithm,
203    /// The signature algorithm.
204    pub signature: SignatureAlgorithm,
205}
206
207/// Signature algorithm as defined in [RFC 5246 section 7.4.1.4.1].
208///
209/// [RFC 5246 section 7.4.1.4.1]: https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.1.4.1
210#[derive(PartialEq, Debug, TlsDeserializeBytes, TlsSerializeBytes, TlsSize)]
211#[repr(u8)]
212pub enum SignatureAlgorithm {
213    /// Anonymous signature algorithm.
214    Anonymous = 0,
215    /// RSA signature algorithm.
216    Rsa = 1,
217    /// DSA signature algorithm.
218    Dsa = 2,
219    /// ECDSA signature algorithm.
220    Ecdsa = 3,
221    /// ED25519 signature algorithm.
222    Ed25519 = 7,
223    /// ED448 signature algorithm.
224    Ed448 = 8,
225}
226
227/// Hashing algorithm as defined in [RFC 5246 section 7.4.1.4.1].
228///
229/// [RFC 5246 section 7.4.1.4.1]: https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.1.4.1
230#[derive(PartialEq, Debug, TlsDeserializeBytes, TlsSerializeBytes, TlsSize)]
231#[repr(u8)]
232pub enum HashAlgorithm {
233    /// No algorithm.
234    None = 0,
235    /// MD5 algorithm.
236    Md5 = 1,
237    /// SHA1 algorithm.
238    Sha1 = 2,
239    /// SHA224 algorithm.
240    Sha224 = 3,
241    /// SHA256 algorithm.
242    Sha256 = 4,
243    /// SHA384 algorithm.
244    Sha384 = 5,
245    /// SHA512 algorithm.
246    Sha512 = 6,
247    /// Intrinsic algorithm.
248    Intrinsic = 8,
249}
250
251#[cfg(test)]
252mod tests {
253    use der::{asn1::OctetString, Decode, Encode};
254    use tls_codec::{DeserializeBytes, SerializeBytes, TlsByteVecU16};
255
256    use crate::ext::pkix::sct::LogId;
257
258    use super::{
259        DigitallySigned, HashAlgorithm, SerializedSct, SignatureAlgorithm,
260        SignatureAndHashAlgorithm, SignedCertificateTimestamp, SignedCertificateTimestampList,
261        Version,
262    };
263
264    fn run_deserialization_test<'a, T: DeserializeBytes + PartialEq + core::fmt::Debug>(
265        bytes: &'a [u8],
266        expected_result: Result<(T, &[u8]), tls_codec::Error>,
267    ) -> Result<(T, &'a [u8]), tls_codec::Error> {
268        let actual_result = T::tls_deserialize_bytes(bytes);
269        assert_eq!(actual_result, expected_result);
270        actual_result
271    }
272
273    fn run_serialization_test<T: SerializeBytes>(value: T, expected_bytes: &[u8]) {
274        let result = value.tls_serialize().expect("failed to serialize value");
275        assert_eq!(expected_bytes, &result);
276    }
277
278    #[test]
279    fn test_hash_algorithm_deserialization() {
280        let bytes = [0, 1, 2, 3, 4, 5, 6, 8];
281
282        let result = run_deserialization_test(
283            &bytes,
284            Ok((HashAlgorithm::None, [1, 2, 3, 4, 5, 6, 8].as_slice())),
285        );
286        let result = run_deserialization_test(
287            result.expect("run_deserialization_test failed").1,
288            Ok((HashAlgorithm::Md5, [2, 3, 4, 5, 6, 8].as_slice())),
289        );
290        let result = run_deserialization_test(
291            result.expect("run_deserialization_test failed").1,
292            Ok((HashAlgorithm::Sha1, [3, 4, 5, 6, 8].as_slice())),
293        );
294        let result = run_deserialization_test(
295            result.expect("run_deserialization_test failed").1,
296            Ok((HashAlgorithm::Sha224, [4, 5, 6, 8].as_slice())),
297        );
298        let result = run_deserialization_test(
299            result.expect("run_deserialization_test failed").1,
300            Ok((HashAlgorithm::Sha256, [5, 6, 8].as_slice())),
301        );
302        let result = run_deserialization_test(
303            result.expect("run_deserialization_test failed").1,
304            Ok((HashAlgorithm::Sha384, [6, 8].as_slice())),
305        );
306        let result = run_deserialization_test(
307            result.expect("run_deserialization_test failed").1,
308            Ok((HashAlgorithm::Sha512, [8].as_slice())),
309        );
310        let result = run_deserialization_test(
311            result.expect("run_deserialization_test failed").1,
312            Ok((HashAlgorithm::Intrinsic, [].as_slice())),
313        );
314        let _ = run_deserialization_test::<HashAlgorithm>(
315            result.expect("run_deserialization_test failed").1,
316            Err(tls_codec::Error::EndOfStream),
317        );
318        let _ =
319            run_deserialization_test::<HashAlgorithm>(&[7], Err(tls_codec::Error::UnknownValue(7)));
320        let _ =
321            run_deserialization_test::<HashAlgorithm>(&[9], Err(tls_codec::Error::UnknownValue(9)));
322    }
323
324    #[test]
325    fn test_hash_algorithm_serialization() {
326        run_serialization_test(HashAlgorithm::None, &[0]);
327        run_serialization_test(HashAlgorithm::Md5, &[1]);
328        run_serialization_test(HashAlgorithm::Sha1, &[2]);
329        run_serialization_test(HashAlgorithm::Sha224, &[3]);
330        run_serialization_test(HashAlgorithm::Sha256, &[4]);
331        run_serialization_test(HashAlgorithm::Sha384, &[5]);
332        run_serialization_test(HashAlgorithm::Sha512, &[6]);
333        run_serialization_test(HashAlgorithm::Intrinsic, &[8]);
334    }
335
336    #[test]
337    fn test_signature_algorithm_deserialization() {
338        let bytes = [0, 1, 2, 3, 7, 8];
339
340        let result = run_deserialization_test(
341            &bytes,
342            Ok((SignatureAlgorithm::Anonymous, [1, 2, 3, 7, 8].as_slice())),
343        );
344        let result = run_deserialization_test(
345            result.expect("run_deserialization_test failed").1,
346            Ok((SignatureAlgorithm::Rsa, [2, 3, 7, 8].as_slice())),
347        );
348        let result = run_deserialization_test(
349            result.expect("run_deserialization_test failed").1,
350            Ok((SignatureAlgorithm::Dsa, [3, 7, 8].as_slice())),
351        );
352        let result = run_deserialization_test(
353            result.expect("run_deserialization_test failed").1,
354            Ok((SignatureAlgorithm::Ecdsa, [7, 8].as_slice())),
355        );
356        let result = run_deserialization_test(
357            result.expect("run_deserialization_test failed").1,
358            Ok((SignatureAlgorithm::Ed25519, [8].as_slice())),
359        );
360        let result = run_deserialization_test(
361            result.expect("run_deserialization_test failed").1,
362            Ok((SignatureAlgorithm::Ed448, [].as_slice())),
363        );
364        let _ = run_deserialization_test::<SignatureAlgorithm>(
365            result.expect("run_deserialization_test failed").1,
366            Err(tls_codec::Error::EndOfStream),
367        );
368        let _ = run_deserialization_test::<SignatureAlgorithm>(
369            &[4],
370            Err(tls_codec::Error::UnknownValue(4)),
371        );
372        let _ = run_deserialization_test::<SignatureAlgorithm>(
373            &[5],
374            Err(tls_codec::Error::UnknownValue(5)),
375        );
376        let _ = run_deserialization_test::<SignatureAlgorithm>(
377            &[6],
378            Err(tls_codec::Error::UnknownValue(6)),
379        );
380        let _ = run_deserialization_test::<SignatureAlgorithm>(
381            &[9],
382            Err(tls_codec::Error::UnknownValue(9)),
383        );
384    }
385
386    #[test]
387    fn test_signature_algorithm_serialization() {
388        run_serialization_test(SignatureAlgorithm::Anonymous, &[0]);
389        run_serialization_test(SignatureAlgorithm::Rsa, &[1]);
390        run_serialization_test(SignatureAlgorithm::Dsa, &[2]);
391        run_serialization_test(SignatureAlgorithm::Ecdsa, &[3]);
392        run_serialization_test(SignatureAlgorithm::Ed25519, &[7]);
393        run_serialization_test(SignatureAlgorithm::Ed448, &[8]);
394    }
395
396    #[test]
397    fn test_signature_and_hash_algorithm_deserialization() {
398        let bytes = [4, 3, 2, 1];
399
400        let result = run_deserialization_test(
401            &bytes,
402            Ok((
403                SignatureAndHashAlgorithm {
404                    hash: HashAlgorithm::Sha256,
405                    signature: SignatureAlgorithm::Ecdsa,
406                },
407                [2, 1].as_slice(),
408            )),
409        );
410
411        let _ = run_deserialization_test(
412            result.expect("run_deserialization_test failed").1,
413            Ok((
414                SignatureAndHashAlgorithm {
415                    hash: HashAlgorithm::Sha1,
416                    signature: SignatureAlgorithm::Rsa,
417                },
418                [].as_slice(),
419            )),
420        );
421    }
422
423    #[test]
424    fn test_signature_and_hash_algorithm_serialization() {
425        run_serialization_test(
426            SignatureAndHashAlgorithm {
427                hash: HashAlgorithm::Sha1,
428                signature: SignatureAlgorithm::Rsa,
429            },
430            &[2, 1],
431        );
432        run_serialization_test(
433            SignatureAndHashAlgorithm {
434                hash: HashAlgorithm::Sha256,
435                signature: SignatureAlgorithm::Ecdsa,
436            },
437            &[4, 3],
438        );
439    }
440
441    #[test]
442    fn test_digitally_signed_deserialization() {
443        let bytes = [4, 3, 0, 3, 2, 1, 0, 2, 1, 0, 1, 9];
444
445        let result = run_deserialization_test(
446            &bytes,
447            Ok((
448                DigitallySigned {
449                    algorithm: SignatureAndHashAlgorithm {
450                        hash: HashAlgorithm::Sha256,
451                        signature: SignatureAlgorithm::Ecdsa,
452                    },
453                    signature: TlsByteVecU16::from_slice(&[2, 1, 0]),
454                },
455                [2, 1, 0, 1, 9].as_slice(),
456            )),
457        );
458
459        let _ = run_deserialization_test(
460            result.expect("run_deserialization_test failed").1,
461            Ok((
462                DigitallySigned {
463                    algorithm: SignatureAndHashAlgorithm {
464                        hash: HashAlgorithm::Sha1,
465                        signature: SignatureAlgorithm::Rsa,
466                    },
467                    signature: TlsByteVecU16::from_slice(&[9]),
468                },
469                [].as_slice(),
470            )),
471        );
472    }
473
474    #[test]
475    fn test_digitally_signed_serialization() {
476        run_serialization_test(
477            DigitallySigned {
478                algorithm: SignatureAndHashAlgorithm {
479                    hash: HashAlgorithm::Sha256,
480                    signature: SignatureAlgorithm::Ecdsa,
481                },
482                signature: TlsByteVecU16::from_slice(&[0, 1, 2]),
483            },
484            &[4, 3, 0, 3, 0, 1, 2],
485        );
486        run_serialization_test(
487            DigitallySigned {
488                algorithm: SignatureAndHashAlgorithm {
489                    hash: HashAlgorithm::Sha1,
490                    signature: SignatureAlgorithm::Rsa,
491                },
492                signature: TlsByteVecU16::from_slice(&[0, 1, 2]),
493            },
494            &[2, 1, 0, 3, 0, 1, 2],
495        );
496    }
497
498    #[test]
499    fn test_version_deserialization() {
500        let bytes = [0, 0];
501
502        let result = run_deserialization_test(&bytes, Ok((Version::V1, [0].as_slice())));
503
504        let _ = run_deserialization_test(
505            result.expect("run_deserialization_test failed").1,
506            Ok((Version::V1, [].as_slice())),
507        );
508        let _ = run_deserialization_test::<Version>(&[1], Err(tls_codec::Error::UnknownValue(1)));
509    }
510
511    #[test]
512    fn test_version_serialization() {
513        run_serialization_test(Version::V1, &[0]);
514    }
515
516    #[test]
517    fn test_log_id_deserialization() {
518        let bytes = [42; 36];
519
520        let _ =
521            run_deserialization_test(&bytes, Ok((LogId { key_id: [42; 32] }, [42; 4].as_slice())));
522    }
523
524    #[test]
525    fn test_log_id_serialization() {
526        run_serialization_test(LogId { key_id: [3; 32] }, &[3; 32]);
527    }
528
529    const TLS_SCT_EXAMPLE: [u8; 119] = [
530        0, 122, 50, 140, 84, 216, 183, 45, 182, 32, 234, 56, 224, 82, 30, 233, 132, 22, 112, 50,
531        19, 133, 77, 59, 210, 43, 193, 58, 87, 163, 82, 235, 82, 0, 0, 1, 135, 224, 74, 186, 106,
532        0, 0, 4, 3, 0, 72, 48, 70, 2, 33, 0, 170, 82, 81, 162, 157, 234, 14, 189, 167, 13, 247,
533        211, 97, 112, 248, 172, 149, 125, 58, 18, 238, 60, 150, 157, 124, 245, 188, 138, 102, 212,
534        244, 187, 2, 33, 0, 209, 79, 31, 63, 208, 79, 240, 233, 193, 187, 28, 33, 190, 95, 130, 66,
535        183, 222, 187, 42, 22, 83, 0, 119, 226, 246, 19, 197, 47, 237, 198, 149,
536    ];
537
538    #[test]
539    fn test_sct_deserialization() {
540        let _ = run_deserialization_test(
541            &TLS_SCT_EXAMPLE,
542            Ok((
543                SignedCertificateTimestamp {
544                    version: Version::V1,
545                    log_id: LogId {
546                        key_id: TLS_SCT_EXAMPLE[1..33]
547                            .try_into()
548                            .expect("failed to convert to u8 array"),
549                    },
550                    timestamp: u64::from_be_bytes(
551                        TLS_SCT_EXAMPLE[33..41]
552                            .try_into()
553                            .expect("failed to convert to u8 array"),
554                    ),
555                    extensions: TlsByteVecU16::from_slice(&[]),
556                    signature: DigitallySigned {
557                        algorithm: SignatureAndHashAlgorithm {
558                            hash: HashAlgorithm::Sha256,
559                            signature: SignatureAlgorithm::Ecdsa,
560                        },
561                        signature: TlsByteVecU16::from_slice(&TLS_SCT_EXAMPLE[47..]),
562                    },
563                },
564                &[],
565            )),
566        );
567    }
568
569    #[test]
570    fn test_sct_serialization() {
571        run_serialization_test(
572            SignedCertificateTimestamp {
573                version: Version::V1,
574                log_id: LogId {
575                    key_id: TLS_SCT_EXAMPLE[1..33]
576                        .try_into()
577                        .expect("failed to convert to u8 array"),
578                },
579                timestamp: u64::from_be_bytes(
580                    TLS_SCT_EXAMPLE[33..41]
581                        .try_into()
582                        .expect("failed to convert to u8 array"),
583                ),
584                extensions: TlsByteVecU16::from_slice(&[]),
585                signature: DigitallySigned {
586                    algorithm: SignatureAndHashAlgorithm {
587                        hash: HashAlgorithm::Sha256,
588                        signature: SignatureAlgorithm::Ecdsa,
589                    },
590                    signature: TlsByteVecU16::from_slice(&TLS_SCT_EXAMPLE[47..]),
591                },
592            },
593            &TLS_SCT_EXAMPLE,
594        );
595    }
596
597    const SCT_EXAMPLE: [u8; 245] = [
598        4, 129, 242, 0, 240, 0, 119, 0, 122, 50, 140, 84, 216, 183, 45, 182, 32, 234, 56, 224, 82,
599        30, 233, 132, 22, 112, 50, 19, 133, 77, 59, 210, 43, 193, 58, 87, 163, 82, 235, 82, 0, 0,
600        1, 135, 224, 74, 186, 106, 0, 0, 4, 3, 0, 72, 48, 70, 2, 33, 0, 170, 82, 81, 162, 157, 234,
601        14, 189, 167, 13, 247, 211, 97, 112, 248, 172, 149, 125, 58, 18, 238, 60, 150, 157, 124,
602        245, 188, 138, 102, 212, 244, 187, 2, 33, 0, 209, 79, 31, 63, 208, 79, 240, 233, 193, 187,
603        28, 33, 190, 95, 130, 66, 183, 222, 187, 42, 22, 83, 0, 119, 226, 246, 19, 197, 47, 237,
604        198, 149, 0, 117, 0, 173, 247, 190, 250, 124, 255, 16, 200, 139, 157, 61, 156, 30, 62, 24,
605        106, 180, 103, 41, 93, 207, 177, 12, 36, 202, 133, 134, 52, 235, 220, 130, 138, 0, 0, 1,
606        135, 224, 74, 186, 164, 0, 0, 4, 3, 0, 70, 48, 68, 2, 32, 29, 110, 144, 37, 157, 227, 170,
607        70, 67, 16, 68, 195, 212, 168, 246, 37, 94, 69, 210, 136, 42, 113, 217, 230, 34, 152, 253,
608        116, 13, 174, 232, 191, 2, 32, 16, 25, 200, 223, 59, 176, 40, 145, 76, 85, 242, 133, 130,
609        212, 61, 216, 83, 238, 115, 130, 82, 240, 196, 162, 249, 54, 199, 120, 175, 72, 223, 14,
610    ];
611
612    #[test]
613    fn test_sct_list_deserialization() {
614        fn run_test(
615            bytes: &[u8],
616            expected_result: Result<SignedCertificateTimestampList, der::Error>,
617        ) -> Result<SignedCertificateTimestampList, der::Error> {
618            let actual_result = SignedCertificateTimestampList::from_der(bytes);
619            assert_eq!(actual_result, expected_result);
620            actual_result
621        }
622
623        let result = run_test(
624            &SCT_EXAMPLE,
625            Ok(SignedCertificateTimestampList(
626                OctetString::new(&SCT_EXAMPLE[3..]).expect("failed to convert to u8 array"),
627            )),
628        );
629        let scts = result
630            .expect("run_test failed")
631            .parse_timestamps()
632            .expect("parse_timestamps failed");
633        assert_eq!(
634            scts[0].parse_timestamp(),
635            Ok(SignedCertificateTimestamp {
636                version: Version::V1,
637                log_id: LogId {
638                    key_id: SCT_EXAMPLE[8..40]
639                        .try_into()
640                        .expect("failed to convert to u8 array"),
641                },
642                timestamp: u64::from_be_bytes(
643                    SCT_EXAMPLE[40..48]
644                        .try_into()
645                        .expect("failed to convert to u8 array")
646                ),
647                extensions: TlsByteVecU16::from_slice(&[]),
648                signature: DigitallySigned {
649                    algorithm: SignatureAndHashAlgorithm {
650                        hash: HashAlgorithm::Sha256,
651                        signature: SignatureAlgorithm::Ecdsa,
652                    },
653                    signature: TlsByteVecU16::from_slice(&SCT_EXAMPLE[54..126]),
654                },
655            })
656        );
657        assert_eq!(
658            scts[1].parse_timestamp(),
659            Ok(SignedCertificateTimestamp {
660                version: Version::V1,
661                log_id: LogId {
662                    key_id: SCT_EXAMPLE[129..161]
663                        .try_into()
664                        .expect("failed to convert to u8 array"),
665                },
666                timestamp: u64::from_be_bytes(
667                    SCT_EXAMPLE[161..169]
668                        .try_into()
669                        .expect("failed to convert to u8 array")
670                ),
671                extensions: TlsByteVecU16::from_slice(&[]),
672                signature: DigitallySigned {
673                    algorithm: SignatureAndHashAlgorithm {
674                        hash: HashAlgorithm::Sha256,
675                        signature: SignatureAlgorithm::Ecdsa,
676                    },
677                    signature: TlsByteVecU16::from_slice(&SCT_EXAMPLE[175..]),
678                },
679            })
680        );
681    }
682
683    #[test]
684    fn test_sct_list_serialization() {
685        let serialized_sct1 = SerializedSct::new(SignedCertificateTimestamp {
686            version: Version::V1,
687            log_id: LogId {
688                key_id: SCT_EXAMPLE[8..40]
689                    .try_into()
690                    .expect("failed to convert to u8 array"),
691            },
692            timestamp: u64::from_be_bytes(
693                SCT_EXAMPLE[40..48]
694                    .try_into()
695                    .expect("failed to convert to u8 array"),
696            ),
697            extensions: TlsByteVecU16::from_slice(&[]),
698            signature: DigitallySigned {
699                algorithm: SignatureAndHashAlgorithm {
700                    hash: HashAlgorithm::Sha256,
701                    signature: SignatureAlgorithm::Ecdsa,
702                },
703                signature: TlsByteVecU16::from_slice(&SCT_EXAMPLE[54..126]),
704            },
705        })
706        .expect("failed to create SerializedSct");
707        let serialized_sct2 = SerializedSct::new(SignedCertificateTimestamp {
708            version: Version::V1,
709            log_id: LogId {
710                key_id: SCT_EXAMPLE[129..161]
711                    .try_into()
712                    .expect("failed to convert to u8 array"),
713            },
714            timestamp: u64::from_be_bytes(
715                SCT_EXAMPLE[161..169]
716                    .try_into()
717                    .expect("failed to convert to u8 array"),
718            ),
719            extensions: TlsByteVecU16::from_slice(&[]),
720            signature: DigitallySigned {
721                algorithm: SignatureAndHashAlgorithm {
722                    hash: HashAlgorithm::Sha256,
723                    signature: SignatureAlgorithm::Ecdsa,
724                },
725                signature: TlsByteVecU16::from_slice(&SCT_EXAMPLE[175..]),
726            },
727        })
728        .expect("failed to create SerializedSct");
729        let list = SignedCertificateTimestampList::new(&[serialized_sct1, serialized_sct2])
730            .expect("failed to create SignedCertificateTimestampList");
731        let der = list.to_der().expect("failed to convert to der");
732        assert_eq!(der.as_slice(), SCT_EXAMPLE.as_slice());
733    }
734}