Skip to main content

luct_core/v1/
sct.rs

1use crate::{
2    CertificateChain, CtLog, Version,
3    signature::{Signature, SignatureValidationError},
4    store::Hashable,
5    tree::HashOutput,
6    utils::codec::{CodecError, Decode, Encode},
7    v1::{
8        LogEntry, LogId, SignatureType,
9        extension::{CtExtensions, LeafIndex},
10    },
11};
12use serde::{Deserialize, Serialize};
13use sha2::{Digest, Sha256};
14use std::io::{Cursor, ErrorKind, IoSlice, Read, Write};
15
16impl CtLog {
17    pub fn validate_sct_v1(
18        &self,
19        cert: &CertificateChain,
20        sct: &SignedCertificateTimestamp,
21        as_precert: bool,
22    ) -> Result<(), SignatureValidationError> {
23        let timestamp = CertificateTimeStamp {
24            sct_version: Version::V1,
25            timestamp: sct.timestamp,
26            entry: cert
27                .as_log_entry_v1(as_precert)
28                .map_err(SignatureValidationError::CodecError)?,
29            extensions: sct.extensions.clone(),
30        };
31
32        sct.signature.validate(&timestamp, &self.config.key)
33    }
34}
35
36/// See RFC 6962 3.2
37#[derive(Debug, Clone, PartialEq, Eq)]
38pub(crate) struct SctList(Vec<SignedCertificateTimestamp>);
39
40impl SctList {
41    #[allow(dead_code)]
42    pub fn new(scts: Vec<SignedCertificateTimestamp>) -> Self {
43        Self(scts)
44    }
45
46    pub fn into_inner(self) -> Vec<SignedCertificateTimestamp> {
47        self.0
48    }
49}
50
51impl Encode for SctList {
52    fn encode(&self, mut writer: impl Write) -> Result<(), CodecError> {
53        let mut bytes = 0;
54        let mut encoded_scts = vec![];
55        for sct in &self.0 {
56            let mut buf = Cursor::new(vec![0, 0]);
57            buf.set_position(2);
58
59            sct.encode(&mut buf)?;
60            let mut buf = buf.into_inner();
61
62            // Encode the length of the field
63            let len = ((buf.len() - 2) as u16).to_be_bytes();
64            buf[0] = len[0];
65            buf[1] = len[1];
66
67            // Add to byte counter for field size
68            bytes += buf.len();
69            encoded_scts.push(buf);
70        }
71        let mut slices = encoded_scts
72            .iter()
73            .map(|buf| IoSlice::new(buf))
74            .collect::<Vec<_>>();
75
76        let bytes: u16 = bytes.try_into().map_err(|_| CodecError::UnexpectedSize {
77            read: bytes,
78            expected: u16::MAX as usize,
79        })?;
80
81        bytes.encode(&mut writer)?;
82
83        let mut slices: &mut [IoSlice] = &mut slices;
84        while !slices.is_empty() {
85            match writer.write_vectored(slices) {
86                Ok(0) => {
87                    return Err(CodecError::IoError(std::io::ErrorKind::WriteZero));
88                }
89                Ok(n) => IoSlice::advance_slices(&mut slices, n),
90                Err(e) if e.kind() == ErrorKind::Interrupted => {}
91                Err(e) => return Err(e.into()),
92            }
93        }
94
95        Ok(())
96    }
97}
98
99impl Decode for SctList {
100    fn decode(mut reader: impl Read) -> Result<Self, CodecError> {
101        let length = u16::decode(&mut reader)?.into();
102        let mut scts = vec![];
103
104        let mut reader = reader.take(length);
105        loop {
106            match u16::decode(&mut reader) {
107                Ok(_) => (),
108                Err(CodecError::IoError(ErrorKind::UnexpectedEof)) => break,
109                Err(err) => return Err(err),
110            }
111
112            let sct = SignedCertificateTimestamp::decode(&mut reader)?;
113            scts.push(sct)
114        }
115
116        Ok(Self(scts))
117    }
118}
119
120/// A signed certificate timestamp of version 1.
121///
122/// See RFC 6962 3.2
123#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
124pub struct SignedCertificateTimestamp {
125    pub(crate) sct_version: Version,
126    pub(crate) id: LogId,
127    pub(crate) timestamp: u64,
128    pub(crate) extensions: CtExtensions,
129    pub(crate) signature: Signature<CertificateTimeStamp>,
130}
131
132impl SignedCertificateTimestamp {
133    pub fn log_id(&self) -> crate::LogId {
134        crate::LogId::V1(self.id.clone())
135    }
136
137    pub fn timestamp(&self) -> u64 {
138        self.timestamp
139    }
140
141    pub fn leaf_index(&self) -> Option<LeafIndex> {
142        self.extensions.leaf_index()
143    }
144}
145
146impl Encode for SignedCertificateTimestamp {
147    fn encode(&self, mut writer: impl Write) -> Result<(), CodecError> {
148        self.sct_version.encode(&mut writer)?;
149        self.id.encode(&mut writer)?;
150        self.timestamp.encode(&mut writer)?;
151        self.extensions.encode(&mut writer)?;
152        self.signature.encode(&mut writer)?;
153        Ok(())
154    }
155}
156
157impl Decode for SignedCertificateTimestamp {
158    fn decode(mut reader: impl Read) -> Result<Self, CodecError> {
159        Ok(Self {
160            sct_version: Version::decode(&mut reader)?,
161            id: LogId::decode(&mut reader)?,
162            timestamp: u64::decode(&mut reader)?,
163            extensions: CtExtensions::decode(&mut reader)?,
164            signature: Signature::decode(&mut reader)?,
165        })
166    }
167}
168
169impl Hashable for SignedCertificateTimestamp {
170    fn hash(&self) -> HashOutput {
171        let mut bytes = Cursor::new(vec![]);
172        self.encode(&mut bytes).unwrap();
173        Sha256::digest(bytes.into_inner()).into()
174    }
175}
176
177/// See RFC 6962 3.2
178#[derive(Debug, Clone, PartialEq, Eq)]
179pub(crate) struct CertificateTimeStamp {
180    sct_version: Version,
181    // SignatureType signature_type = certificate_timestamp;
182    timestamp: u64,
183    entry: LogEntry,
184    extensions: CtExtensions,
185}
186
187impl Encode for CertificateTimeStamp {
188    fn encode(&self, mut writer: impl Write) -> Result<(), CodecError> {
189        self.sct_version.encode(&mut writer)?;
190        SignatureType::CertificateTimeStamp.encode(&mut writer)?;
191        self.timestamp.encode(&mut writer)?;
192        self.entry.encode(&mut writer)?;
193        self.extensions.encode(&mut writer)?;
194        Ok(())
195    }
196}
197
198impl Decode for CertificateTimeStamp {
199    fn decode(mut reader: impl Read) -> Result<Self, CodecError> {
200        let sct_version = Version::decode(&mut reader)?;
201        let signature_type = SignatureType::decode(&mut reader)?;
202        match signature_type {
203            SignatureType::TreeHash => return Err(CodecError::UnexpectedVariant),
204            SignatureType::CertificateTimeStamp => (),
205        }
206        let timestamp = u64::decode(&mut reader)?;
207        let entry = LogEntry::decode(&mut reader)?;
208        let extensions = CtExtensions::decode(&mut reader)?;
209
210        Ok(Self {
211            sct_version,
212            timestamp,
213            entry,
214            extensions,
215        })
216    }
217}