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