1use crate::manifest::{OtaManifest, OtaManifestError, parse_ota_manifest};
8use ota_manifest_proto::fuchsia::update::manifest as proto;
9use prost::Message as _;
10use ring::signature::{KeyPair as _, UnparsedPublicKey};
11use zerocopy::byteorder::little_endian::U32;
12use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
13
14#[derive(Debug, PartialEq, Eq, FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]
16#[repr(C)]
17struct Header {
18 magic: [u8; 4],
19 version: U32,
20 manifest_size: U32,
21}
22
23pub const MAGIC: [u8; 4] = [0xfc, 0x1a, 0x07, 0xaf];
25
26pub const VERSION: u32 = 1;
28
29pub const MAX_MANIFEST_SIZE: usize = 10 * 1024 * 1024;
31
32pub const MAX_SIGNATURE_SIZE: usize = 1024 * 1024;
34
35trait U32Ext {
36 fn get_usize(&self) -> usize;
37}
38
39impl U32Ext for U32 {
40 fn get_usize(&self) -> usize {
41 const { assert!(usize::BITS >= u32::BITS) }
42 self.get() as usize
43 }
44}
45
46#[derive(Debug, thiserror::Error)]
48#[allow(missing_docs)]
49pub enum SignedManifestError {
50 #[error("file truncated: file size {file_size} is less than required size {expected_size}")]
51 Truncated { file_size: usize, expected_size: usize },
52
53 #[error("invalid magic: {0:?}")]
54 InvalidMagic([u8; 4]),
55
56 #[error("unknown version: {0}")]
57 UnknownVersion(u32),
58
59 #[error("manifest size too large: {0} > {MAX_MANIFEST_SIZE}")]
60 ManifestSizeTooLarge(usize),
61
62 #[error("signature size too large: {0} > {MAX_SIGNATURE_SIZE}")]
63 SignatureSizeTooLarge(usize),
64
65 #[error("failed to deserialize signatures")]
66 InvalidSignatures(#[source] prost::DecodeError),
67
68 #[error("root signature verification failed")]
69 RootSignatureVerificationFailed,
70
71 #[error("manifest signature verification failed")]
72 ManifestSignatureVerificationFailed,
73
74 #[error("invalid manifest")]
75 InvalidManifest(#[from] OtaManifestError),
76}
77
78pub struct RawManifest<'a> {
80 pub version: u32,
82 pub manifest_payload: &'a [u8],
84 pub signatures: proto::Signatures,
86 pub signed_bytes: &'a [u8],
88}
89
90impl<'a> RawManifest<'a> {
91 pub fn verify(
94 &self,
95 public_keys: &[UnparsedPublicKey<Vec<u8>>],
96 ) -> Result<(), SignedManifestError> {
97 if !public_keys.iter().any(|root_key| {
98 root_key
99 .verify(
100 &self.signatures.manifest_public_key,
101 &self.signatures.manifest_key_signature,
102 )
103 .is_ok()
104 }) {
105 return Err(SignedManifestError::RootSignatureVerificationFailed);
106 }
107
108 let manifest_public_key =
109 UnparsedPublicKey::new(&ring::signature::ED25519, &self.signatures.manifest_public_key);
110 match manifest_public_key.verify(self.signed_bytes, &self.signatures.manifest_signature) {
111 Ok(()) => Ok(()),
112 Err(ring::error::Unspecified) => {
113 Err(SignedManifestError::ManifestSignatureVerificationFailed)
114 }
115 }
116 }
117}
118
119pub fn parse_raw(bytes: &[u8]) -> Result<RawManifest<'_>, SignedManifestError> {
123 let (header, rest) =
124 Header::read_from_prefix(bytes).map_err(|_| SignedManifestError::Truncated {
125 file_size: bytes.len(),
126 expected_size: std::mem::size_of::<Header>(),
127 })?;
128
129 if header.magic != MAGIC {
130 return Err(SignedManifestError::InvalidMagic(header.magic));
131 }
132
133 let version = header.version.get();
134 if version != VERSION {
135 return Err(SignedManifestError::UnknownVersion(version));
136 }
137
138 let manifest_size = header.manifest_size.get_usize();
139 if manifest_size > MAX_MANIFEST_SIZE {
140 return Err(SignedManifestError::ManifestSizeTooLarge(manifest_size));
141 }
142
143 let (manifest_payload, after_manifest) =
144 rest.split_at_checked(manifest_size).ok_or_else(|| SignedManifestError::Truncated {
145 file_size: bytes.len(),
146 expected_size: std::mem::size_of::<Header>() + manifest_size,
147 })?;
148
149 let (signature_size_val, signature_bytes) =
150 U32::read_from_prefix(after_manifest).map_err(|_| SignedManifestError::Truncated {
151 file_size: bytes.len(),
152 expected_size: std::mem::size_of::<Header>()
153 + manifest_size
154 + std::mem::size_of::<U32>(),
155 })?;
156
157 let signature_size = signature_size_val.get_usize();
158 if signature_size > MAX_SIGNATURE_SIZE {
159 return Err(SignedManifestError::SignatureSizeTooLarge(signature_size));
160 }
161
162 let (signature_payload, _) =
163 signature_bytes.split_at_checked(signature_size).ok_or_else(|| {
164 SignedManifestError::Truncated {
165 file_size: bytes.len(),
166 expected_size: std::mem::size_of::<Header>()
167 + manifest_size
168 + std::mem::size_of::<U32>()
169 + signature_size,
170 }
171 })?;
172
173 let signatures_msg = proto::Signatures::decode(signature_payload)
174 .map_err(SignedManifestError::InvalidSignatures)?;
175
176 let signed_bytes = &bytes[..std::mem::size_of::<Header>() + manifest_size];
178
179 Ok(RawManifest { version, manifest_payload, signatures: signatures_msg, signed_bytes })
180}
181
182pub fn parse_and_verify(
186 bytes: &[u8],
187 public_keys: &[UnparsedPublicKey<Vec<u8>>],
188) -> Result<OtaManifest, SignedManifestError> {
189 let raw = parse_raw(bytes)?;
190 let () = raw.verify(public_keys)?;
191 Ok(parse_ota_manifest(raw.manifest_payload)?)
192}
193
194pub fn generate(
197 manifest: OtaManifest,
198 manifest_key: &ring::signature::Ed25519KeyPair,
199 key_signature: Option<&[u8]>,
200) -> Result<Vec<u8>, SignedManifestError> {
201 let manifest_bytes = manifest.serialize();
202 if manifest_bytes.len() > MAX_MANIFEST_SIZE {
203 return Err(SignedManifestError::ManifestSizeTooLarge(manifest_bytes.len()));
204 }
205 let manifest_size = manifest_bytes.len() as u32;
206
207 let header =
208 Header { magic: MAGIC, version: U32::new(VERSION), manifest_size: U32::new(manifest_size) };
209
210 let mut signed_bytes = Vec::with_capacity(std::mem::size_of::<Header>() + manifest_bytes.len());
211 signed_bytes.extend_from_slice(header.as_bytes());
212 signed_bytes.extend_from_slice(&manifest_bytes);
213
214 let manifest_signature = manifest_key.sign(&signed_bytes).as_ref().to_vec();
215 let manifest_public_key = manifest_key.public_key().as_ref().to_vec();
216 let manifest_key_signature = match key_signature {
217 Some(sig) => sig.to_vec(),
218 None => manifest_key.sign(&manifest_public_key).as_ref().to_vec(),
219 };
220
221 let signatures_msg =
222 proto::Signatures { manifest_signature, manifest_public_key, manifest_key_signature };
223 let signatures_bytes = signatures_msg.encode_to_vec();
224 if signatures_bytes.len() > MAX_SIGNATURE_SIZE {
225 return Err(SignedManifestError::SignatureSizeTooLarge(signatures_bytes.len()));
226 }
227 let signatures_size = signatures_bytes.len() as u32;
228
229 let mut out = signed_bytes;
230 out.extend_from_slice(U32::new(signatures_size).as_bytes());
231 out.extend_from_slice(&signatures_bytes);
232 Ok(out)
233}
234
235#[cfg(test)]
236mod tests {
237 use super::*;
238 use assert_matches::assert_matches;
239
240 fn make_ota_manifest() -> OtaManifest {
241 OtaManifest {
242 product_bundle_version: "1.2.3.4".parse().unwrap(),
243 board: "test-board".to_string(),
244 epoch: 1,
245 mode: crate::update_mode::UpdateMode::Normal,
246 blob_base_url: "http://example.com".to_string(),
247 images: vec![],
248 blobs: vec![],
249 }
250 }
251
252 fn make_keypair() -> ring::signature::Ed25519KeyPair {
253 let rng = ring::rand::SystemRandom::new();
254 let pkcs8 = ring::signature::Ed25519KeyPair::generate_pkcs8(&rng).unwrap();
255 ring::signature::Ed25519KeyPair::from_pkcs8(pkcs8.as_ref()).unwrap()
256 }
257
258 fn make_public_key(keypair: &ring::signature::Ed25519KeyPair) -> UnparsedPublicKey<Vec<u8>> {
259 UnparsedPublicKey::new(&ring::signature::ED25519, keypair.public_key().as_ref().to_vec())
260 }
261
262 #[test]
263 fn test_parse_and_verify_success() {
264 let manifest_key = make_keypair();
265 let manifest = make_ota_manifest();
266 let bytes = generate(manifest.clone(), &manifest_key, None).unwrap();
267
268 let trusted_keys = vec![make_public_key(&manifest_key)];
269 let parsed = parse_and_verify(&bytes, &trusted_keys).unwrap();
270 assert_eq!(parsed, manifest);
271 }
272
273 #[test]
274 fn test_parse_and_verify_wrong_magic() {
275 let manifest_key = make_keypair();
276 let manifest = make_ota_manifest();
277 let mut bytes = generate(manifest, &manifest_key, None).unwrap();
278
279 bytes[0] ^= 0xff;
280
281 let trusted_keys = vec![make_public_key(&manifest_key)];
282 let err = parse_and_verify(&bytes, &trusted_keys).unwrap_err();
283 assert_matches!(err, SignedManifestError::InvalidMagic(_));
284 }
285
286 #[test]
287 fn test_parse_and_verify_wrong_version() {
288 let manifest_key = make_keypair();
289 let manifest = make_ota_manifest();
290 let mut bytes = generate(manifest, &manifest_key, None).unwrap();
291
292 bytes[4] ^= 0x01;
294
295 let trusted_keys = vec![make_public_key(&manifest_key)];
296 let err = parse_and_verify(&bytes, &trusted_keys).unwrap_err();
297 assert_matches!(err, SignedManifestError::UnknownVersion(_));
298 }
299
300 #[test]
301 fn test_parse_and_verify_truncated_header() {
302 let trusted_keys = vec![];
303 let bytes = vec![0; std::mem::size_of::<Header>() - 1];
304 let err = parse_and_verify(&bytes, &trusted_keys).unwrap_err();
305 assert_matches!(err, SignedManifestError::Truncated { .. });
306 }
307
308 #[test]
309 fn test_parse_and_verify_truncated_signature() {
310 let manifest_key = make_keypair();
311 let manifest = make_ota_manifest();
312 let mut bytes = generate(manifest, &manifest_key, None).unwrap();
313
314 bytes.truncate(bytes.len() - 1);
316
317 let trusted_keys = vec![make_public_key(&manifest_key)];
318 let err = parse_and_verify(&bytes, &trusted_keys).unwrap_err();
319 assert_matches!(err, SignedManifestError::Truncated { .. });
320 }
321
322 #[test]
323 fn test_parse_and_verify_bad_root_signature() {
324 let manifest_key = make_keypair();
325 let root_key = make_keypair();
326 let manifest = make_ota_manifest();
327 let bad_sig = vec![0u8; 64];
328 let bytes = generate(manifest, &manifest_key, Some(&bad_sig)).unwrap();
329
330 let trusted_keys = vec![make_public_key(&root_key)];
331
332 let err = parse_and_verify(&bytes, &trusted_keys).unwrap_err();
333 assert_matches!(err, SignedManifestError::RootSignatureVerificationFailed);
334 }
335
336 #[test]
337 fn test_parse_and_verify_bad_manifest_signature() {
338 let manifest_key = make_keypair();
339 let manifest = make_ota_manifest();
340 let mut bytes = generate(manifest, &manifest_key, None).unwrap();
341
342 let payload_start = std::mem::size_of::<Header>();
344 bytes[payload_start] ^= 0xFF;
345
346 let trusted_keys = vec![make_public_key(&manifest_key)];
347
348 let err = parse_and_verify(&bytes, &trusted_keys).unwrap_err();
349 assert_matches!(err, SignedManifestError::ManifestSignatureVerificationFailed);
350 }
351
352 #[test]
353 fn test_generate_with_key_signature() {
354 let manifest_key = make_keypair();
355 let root_key = make_keypair();
356 let manifest = make_ota_manifest();
357
358 let manifest_public_key = manifest_key.public_key().as_ref();
359 let manifest_key_sig = root_key.sign(manifest_public_key).as_ref().to_vec();
360
361 let bytes = generate(manifest.clone(), &manifest_key, Some(&manifest_key_sig)).unwrap();
362
363 let trusted_keys = vec![make_public_key(&root_key)];
364 let parsed = parse_and_verify(&bytes, &trusted_keys).unwrap();
365 assert_eq!(parsed, manifest);
366 }
367}