1#![forbid(unsafe_code,
12 unstable_features)]
13#![deny(trivial_casts,
14 trivial_numeric_casts,
15 missing_docs,
16 unused_import_braces,
17 unused_extern_crates,
18 unused_qualifications)]
19
20#![no_std]
21
22extern crate alloc;
23
24use alloc::vec::Vec;
25
26#[derive(Debug)]
32pub struct Log<'a> {
33 pub description: &'a str,
36
37 pub url: &'a str,
40
41 pub operated_by: &'a str,
44
45 pub key: &'a [u8],
50
51 pub id: [u8; 32],
54
55 pub max_merge_delay: usize
58}
59
60#[derive(Debug, PartialEq, Clone, Copy)]
62pub enum Error {
63 MalformedSCT,
65
66 InvalidSignature,
68
69 TimestampInFuture,
71
72 UnsupportedSCTVersion,
74
75 UnknownLog,
77}
78
79impl Error {
80 pub fn should_be_fatal(&self) -> bool {
90 match *self {
91 Error::UnknownLog
92 | Error::UnsupportedSCTVersion => false,
93 _ => true
94 }
95 }
96}
97
98fn lookup(logs: &[&Log], id: &[u8]) -> Result<usize, Error> {
99 for (i, l) in logs.iter().enumerate() {
100 if id == &l.id {
101 return Ok(i);
102 }
103 }
104
105 Err(Error::UnknownLog)
106}
107
108fn decode_u64(inp: untrusted::Input) -> u64 {
109 let b = inp.as_slice_less_safe();
110 assert_eq!(b.len(), 8);
111 (b[0] as u64) << 56 |
112 (b[1] as u64) << 48 |
113 (b[2] as u64) << 40 |
114 (b[3] as u64) << 32 |
115 (b[4] as u64) << 24 |
116 (b[5] as u64) << 16 |
117 (b[6] as u64) << 8 |
118 (b[7] as u64)
119}
120
121fn decode_u16(inp: untrusted::Input) -> u16 {
122 let b = inp.as_slice_less_safe();
123 assert_eq!(b.len(), 2);
124 (b[0] as u16) << 8 | (b[1] as u16)
125}
126
127fn write_u64(v: u64, out: &mut Vec<u8>) {
128 out.push((v >> 56) as u8);
129 out.push((v >> 48) as u8);
130 out.push((v >> 40) as u8);
131 out.push((v >> 32) as u8);
132 out.push((v >> 24) as u8);
133 out.push((v >> 16) as u8);
134 out.push((v >> 8) as u8);
135 out.push(v as u8);
136}
137
138fn write_u24(v: u32, out: &mut Vec<u8>) {
139 out.push((v >> 16) as u8);
140 out.push((v >> 8) as u8);
141 out.push(v as u8);
142}
143
144fn write_u16(v: u16, out: &mut Vec<u8>) {
145 out.push((v >> 8) as u8);
146 out.push(v as u8);
147}
148
149struct SCT<'a> {
150 log_id: &'a [u8],
151 timestamp: u64,
152 sig_alg: u16,
153 sig: &'a [u8],
154 exts: &'a [u8],
155}
156
157const ECDSA_SHA256: u16 = 0x0403;
158const ECDSA_SHA384: u16 = 0x0503;
159const RSA_PKCS1_SHA256: u16 = 0x0401;
160const RSA_PKCS1_SHA384: u16 = 0x0501;
161const SCT_V1: u8 = 0u8;
162const SCT_TIMESTAMP: u8 = 0u8;
163const SCT_X509_ENTRY: [u8; 2] = [0, 0];
164
165impl<'a> SCT<'a> {
166 fn verify(&self, key: &[u8], cert: &[u8]) -> Result<(), Error> {
167 let alg: &dyn ring::signature::VerificationAlgorithm = match self.sig_alg {
168 ECDSA_SHA256 => &ring::signature::ECDSA_P256_SHA256_ASN1,
169 ECDSA_SHA384 => &ring::signature::ECDSA_P384_SHA384_ASN1,
170 RSA_PKCS1_SHA256 => &ring::signature::RSA_PKCS1_2048_8192_SHA256,
171 RSA_PKCS1_SHA384 => &ring::signature::RSA_PKCS1_2048_8192_SHA384,
172 _ => return Err(Error::InvalidSignature)
173 };
174
175 let mut data = Vec::new();
176 data.push(SCT_V1);
177 data.push(SCT_TIMESTAMP);
178 write_u64(self.timestamp, &mut data);
179 data.extend_from_slice(&SCT_X509_ENTRY);
180 write_u24(cert.len() as u32, &mut data);
181 data.extend_from_slice(cert);
182 write_u16(self.exts.len() as u16, &mut data);
183 data.extend_from_slice(self.exts);
184
185 let key = ring::signature::UnparsedPublicKey::new(alg, key);
186
187 key.verify(&data, self.sig)
188 .map_err(|_| Error::InvalidSignature)
189 }
190
191 fn parse(enc: &'a [u8]) -> Result<SCT<'a>, Error> {
192 let inp = untrusted::Input::from(enc);
193
194 inp.read_all(
195 Error::MalformedSCT,
196 |rd| {
197 let version = rd.read_byte()
198 .map_err(|_| Error::MalformedSCT)?;
199 if version != 0 {
200 return Err(Error::UnsupportedSCTVersion);
201 }
202
203 let id = rd.read_bytes(32)
204 .map_err(|_| Error::MalformedSCT)?;
205 let timestamp = rd.read_bytes(8)
206 .map_err(|_| Error::MalformedSCT)
207 .map(decode_u64)?;
208
209 let ext_len = rd.read_bytes(2)
210 .map_err(|_| Error::MalformedSCT)
211 .map(decode_u16)?;
212 let exts = rd.read_bytes(ext_len as usize)
213 .map_err(|_| Error::MalformedSCT)?;
214
215 let sig_alg = rd.read_bytes(2)
216 .map_err(|_| Error::MalformedSCT)
217 .map(decode_u16)?;
218 let sig_len = rd.read_bytes(2)
219 .map_err(|_| Error::MalformedSCT)
220 .map(decode_u16)?;
221 let sig = rd.read_bytes(sig_len as usize)
222 .map_err(|_| Error::MalformedSCT)?;
223
224 let ret = SCT {
225 log_id: id.as_slice_less_safe(),
226 timestamp: timestamp,
227 sig_alg: sig_alg,
228 sig: sig.as_slice_less_safe(),
229 exts: exts.as_slice_less_safe(),
230 };
231
232 Ok(ret)
233 })
234 }
235}
236
237pub fn verify_sct(cert: &[u8],
245 sct: &[u8],
246 at_time: u64,
247 logs: &[&Log]) -> Result<usize, Error> {
248 let sct = SCT::parse(sct)?;
249 let i = lookup(logs, &sct.log_id)?;
250 let log = logs[i];
251 sct.verify(log.key, cert)?;
252
253 if sct.timestamp > at_time {
254 return Err(Error::TimestampInFuture);
255 }
256
257 Ok(i)
258}
259
260#[cfg(test)]
261mod tests_google;
262#[cfg(test)]
263mod tests_generated;
264#[cfg(test)]
265mod tests;