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(
196 manifest: OtaManifest,
197 manifest_key: &ring::signature::Ed25519KeyPair,
198 root_key: &ring::signature::Ed25519KeyPair,
199) -> Result<Vec<u8>, SignedManifestError> {
200 let manifest_bytes = manifest.serialize();
201 if manifest_bytes.len() > MAX_MANIFEST_SIZE {
202 return Err(SignedManifestError::ManifestSizeTooLarge(manifest_bytes.len()));
203 }
204 let manifest_size = manifest_bytes.len() as u32;
205
206 let header =
207 Header { magic: MAGIC, version: U32::new(VERSION), manifest_size: U32::new(manifest_size) };
208
209 let mut signed_bytes = Vec::with_capacity(std::mem::size_of::<Header>() + manifest_bytes.len());
210 signed_bytes.extend_from_slice(header.as_bytes());
211 signed_bytes.extend_from_slice(&manifest_bytes);
212
213 let manifest_signature = manifest_key.sign(&signed_bytes).as_ref().to_vec();
214 let manifest_public_key = manifest_key.public_key().as_ref().to_vec();
215 let manifest_key_signature = root_key.sign(&manifest_public_key).as_ref().to_vec();
216
217 let signatures_msg =
218 proto::Signatures { manifest_signature, manifest_public_key, manifest_key_signature };
219 let signatures_bytes = signatures_msg.encode_to_vec();
220 if signatures_bytes.len() > MAX_SIGNATURE_SIZE {
221 return Err(SignedManifestError::SignatureSizeTooLarge(signatures_bytes.len()));
222 }
223 let signatures_size = signatures_bytes.len() as u32;
224
225 let mut out = signed_bytes;
226 out.extend_from_slice(U32::new(signatures_size).as_bytes());
227 out.extend_from_slice(&signatures_bytes);
228 Ok(out)
229}
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234 use assert_matches::assert_matches;
235
236 fn make_ota_manifest() -> OtaManifest {
237 OtaManifest {
238 build_info_version: "1.2.3.4".parse().unwrap(),
239 board: "test-board".to_string(),
240 epoch: 1,
241 mode: crate::update_mode::UpdateMode::Normal,
242 blob_base_url: "http://example.com".to_string(),
243 images: vec![],
244 blobs: vec![],
245 }
246 }
247
248 fn make_keypair() -> ring::signature::Ed25519KeyPair {
249 let rng = ring::rand::SystemRandom::new();
250 let pkcs8 = ring::signature::Ed25519KeyPair::generate_pkcs8(&rng).unwrap();
251 ring::signature::Ed25519KeyPair::from_pkcs8(pkcs8.as_ref()).unwrap()
252 }
253
254 fn make_public_key(keypair: &ring::signature::Ed25519KeyPair) -> UnparsedPublicKey<Vec<u8>> {
255 UnparsedPublicKey::new(&ring::signature::ED25519, keypair.public_key().as_ref().to_vec())
256 }
257
258 #[test]
259 fn test_parse_and_verify_success() {
260 let manifest_key = make_keypair();
261 let root_key = make_keypair();
262 let manifest = make_ota_manifest();
263 let bytes = generate(manifest.clone(), &manifest_key, &root_key).unwrap();
264
265 let trusted_keys = vec![make_public_key(&root_key)];
266 let parsed = parse_and_verify(&bytes, &trusted_keys).unwrap();
267 assert_eq!(parsed, manifest);
268 }
269
270 #[test]
271 fn test_parse_and_verify_wrong_magic() {
272 let manifest_key = make_keypair();
273 let root_key = make_keypair();
274 let manifest = make_ota_manifest();
275 let mut bytes = generate(manifest, &manifest_key, &root_key).unwrap();
276
277 bytes[0] ^= 0xff;
278
279 let trusted_keys = vec![make_public_key(&root_key)];
280 let err = parse_and_verify(&bytes, &trusted_keys).unwrap_err();
281 assert_matches!(err, SignedManifestError::InvalidMagic(_));
282 }
283
284 #[test]
285 fn test_parse_and_verify_wrong_version() {
286 let manifest_key = make_keypair();
287 let root_key = make_keypair();
288 let manifest = make_ota_manifest();
289 let mut bytes = generate(manifest, &manifest_key, &root_key).unwrap();
290
291 bytes[4] ^= 0x01;
293
294 let trusted_keys = vec![make_public_key(&root_key)];
295 let err = parse_and_verify(&bytes, &trusted_keys).unwrap_err();
296 assert_matches!(err, SignedManifestError::UnknownVersion(_));
297 }
298
299 #[test]
300 fn test_parse_and_verify_truncated_header() {
301 let trusted_keys = vec![];
302 let bytes = vec![0; std::mem::size_of::<Header>() - 1];
303 let err = parse_and_verify(&bytes, &trusted_keys).unwrap_err();
304 assert_matches!(err, SignedManifestError::Truncated { .. });
305 }
306
307 #[test]
308 fn test_parse_and_verify_truncated_signature() {
309 let manifest_key = make_keypair();
310 let root_key = make_keypair();
311 let manifest = make_ota_manifest();
312 let mut bytes = generate(manifest, &manifest_key, &root_key).unwrap();
313
314 bytes.truncate(bytes.len() - 1);
316
317 let trusted_keys = vec![make_public_key(&root_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 bytes = generate(manifest, &manifest_key, &root_key).unwrap();
328
329 let wrong_root_key = make_keypair();
330 let trusted_keys = vec![make_public_key(&wrong_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 root_key = make_keypair();
340 let manifest = make_ota_manifest();
341 let mut bytes = generate(manifest, &manifest_key, &root_key).unwrap();
342
343 let payload_start = std::mem::size_of::<Header>();
345 bytes[payload_start] ^= 0xFF;
346
347 let trusted_keys = vec![make_public_key(&root_key)];
348
349 let err = parse_and_verify(&bytes, &trusted_keys).unwrap_err();
350 assert_matches!(err, SignedManifestError::ManifestSignatureVerificationFailed);
351 }
352}