1use super::{Encoding, Receiver};
4use crate::{envelope::Envelope, update};
5
6#[derive(Debug)]
9pub struct PreparedUpdate {
10 plan: TransferPlan,
11}
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct TransferEncoding {
16 pub header: Encoding,
18 pub body: Encoding,
20}
21
22#[derive(Debug, Clone)]
25pub struct TransferPlan {
26 receiver: Receiver,
27 class: crate::DriveClass,
28 image: Vec<u8>,
29 transfer: Option<Vec<u8>>,
30 encoding: TransferEncoding,
31 prepare: crate::cdb::Prepare,
32 mode: update::flash::ExecutionMode,
33}
34
35#[derive(Debug)]
43#[non_exhaustive]
44pub enum ExecuteError<E> {
45 Receiver(super::Error<E>),
47 Flash(update::FlashError<E>),
49}
50
51impl<E: core::fmt::Debug> core::fmt::Display for ExecuteError<E> {
52 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
53 match self {
54 Self::Receiver(error) => {
55 write!(f, "receiver revalidation failed before writing: {error}")
56 }
57 Self::Flash(error) => write!(f, "{error}"),
58 }
59 }
60}
61impl<E: core::fmt::Debug + 'static> std::error::Error for ExecuteError<E> {
62 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
63 match self {
64 Self::Receiver(source) => Some(source),
65 Self::Flash(source) => Some(source),
66 }
67 }
68}
69
70impl Receiver {
71 pub fn bind_prepared(
74 &self,
75 update: &update::PreparedUpdate,
76 ) -> Result<PreparedUpdate, update::PrepareError> {
77 Ok(PreparedUpdate {
78 plan: TransferPlan::new(
79 self,
80 update.image(),
81 update.class(),
82 update::flash::ExecutionMode::Flash,
83 )?,
84 })
85 }
86
87 pub fn prepare_without_installed(
90 &self,
91 envelope: &Envelope,
92 live: &crate::Identity,
93 ) -> Result<PreparedUpdate, update::PrepareError> {
94 let update = update::PreparedUpdate::prepare_without_installed(envelope.image(), live)?;
95 self.bind_prepared(&update)
96 }
97
98 pub fn prepare(
102 &self,
103 envelope: &Envelope,
104 installed: &update::InstalledFirmware,
105 ) -> Result<PreparedUpdate, update::PrepareError> {
106 let update = update::PreparedUpdate::prepare(envelope.image(), installed)?;
110 self.bind_prepared(&update)
111 }
112}
113
114impl PreparedUpdate {
115 pub fn plan(&self) -> &TransferPlan {
117 &self.plan
118 }
119 pub fn flash<R, W, H>(
121 &self,
122 io: update::FlashTransport<'_, R, W>,
123 runtime: &mut H,
124 ) -> Result<update::Verified, ExecuteError<W::Error>>
125 where
126 W: crate::drive::Transport,
127 R: crate::drive::Transport<Error = W::Error>,
128 H: update::FlashRuntime<W::Error>,
129 {
130 self.flash_completed(io, runtime)?
131 .into_verified()
132 .map_err(ExecuteError::Flash)
133 }
134
135 pub fn flash_completed<R, W, H>(
138 &self,
139 io: update::FlashTransport<'_, R, W>,
140 runtime: &mut H,
141 ) -> Result<update::Completion, ExecuteError<W::Error>>
142 where
143 W: crate::drive::Transport,
144 R: crate::drive::Transport<Error = W::Error>,
145 H: update::FlashRuntime<W::Error>,
146 {
147 self.plan.execute_completed(io, runtime)
148 }
149}
150
151fn wire(
152 image: &[u8],
153 operations: &[super::layout::Operation],
154) -> Result<Vec<u8>, update::PrepareError> {
155 let layout =
156 super::layout::analyze(image.len(), operations).map_err(update::PrepareError::Layout)?;
157 layout.encode(image).map_err(update::PrepareError::Layout)
158}
159
160fn encode_transfer(
163 receiver: &Receiver,
164 image: &[u8],
165) -> Result<(Option<Vec<u8>>, TransferEncoding, bool), update::PrepareError> {
166 if let Some(analysis) = receiver.application_analysis() {
167 if analysis.conflicting_arguments() {
168 return Err(update::PrepareError::ReceiverContract);
169 }
170 if !analysis.scratch_decoders().is_empty() {
171 let contract = receiver
172 .profile
173 .as_ref()
174 .and_then(|p| p.mixed.as_ref())
175 .ok_or(update::PrepareError::ReceiverContract)?;
176 if image.get(contract.descriptor_byte()) != Some(&0xde) {
177 return Err(update::PrepareError::ReceiverContract);
178 }
179 use super::layout::Operation;
180 let mut operations = vec![Operation::CheckDecrypted(contract.header_range())];
181 for entry in crate::image::cmac::parse_table(image)
184 .map_err(|_| update::PrepareError::Integrity)?
185 .into_iter()
186 .filter(|entry| entry.is_active())
187 {
188 let range = entry.start as usize..entry.end as usize + 1;
189 if !contract.programmed_ranges().iter().any(|programmed| {
190 programmed.start <= range.start && programmed.end >= range.end
191 }) {
192 return Err(update::PrepareError::ReceiverContract);
195 }
196 operations.push(Operation::CheckPlaintext(range));
197 }
198 for range in contract.programmed_ranges() {
199 operations.push(Operation::Program(range.clone()));
200 }
201 let wire = wire(image, &operations)?;
202 return Ok((
203 Some(wire),
204 TransferEncoding {
205 header: Encoding::Encrypted,
206 body: Encoding::Plaintext,
207 },
208 true,
209 ));
210 }
211 if receiver.encoding() == Encoding::Encrypted {
212 let [bulk] = analysis.bulk_decoders() else {
213 return Err(update::PrepareError::ReceiverContract);
214 };
215 use super::decoding::Value;
216 let Value::Loaded { cell, offset: 0 } = bulk.from_zero.source else {
217 return Err(update::PrepareError::ReceiverContract);
218 };
219 if bulk.from_zero.destination != bulk.from_zero.source
220 || bulk.from_zero.length as usize != image.len()
221 || bulk.header.source
222 != (Value::Loaded {
223 cell,
224 offset: 0x3000,
225 })
226 || bulk.header.length != 16
227 || !matches!(bulk.header.destination, Value::Stack(_))
228 || bulk.header.target != bulk.from_zero.target
229 {
230 return Err(update::PrepareError::ReceiverContract);
231 }
232 let mut wire = image.to_vec();
233 crate::enc::encrypt(&mut wire).map_err(|_| update::PrepareError::ReceiverContract)?;
235 return Ok((
236 Some(wire),
237 TransferEncoding {
238 header: Encoding::Encrypted,
239 body: Encoding::Encrypted,
240 },
241 false,
242 ));
243 }
244 if !analysis.bulk_decoders().is_empty() {
245 return Err(update::PrepareError::ReceiverContract);
246 }
247 }
248 if receiver.encoding() == Encoding::Encrypted {
251 let mut wire = image.to_vec();
252 crate::enc::encrypt(&mut wire).map_err(|_| update::PrepareError::ReceiverContract)?;
253 Ok((
254 Some(wire),
255 TransferEncoding {
256 header: Encoding::Encrypted,
257 body: Encoding::Encrypted,
258 },
259 false,
260 ))
261 } else {
262 Ok((
263 None,
264 TransferEncoding {
265 header: Encoding::Plaintext,
266 body: Encoding::Plaintext,
267 },
268 false,
269 ))
270 }
271}
272
273impl TransferPlan {
274 pub(crate) fn new(
275 receiver: &Receiver,
276 image: &[u8],
277 class: crate::DriveClass,
278 mode: update::flash::ExecutionMode,
279 ) -> Result<Self, update::PrepareError> {
280 let profile = receiver
281 .profile
282 .as_ref()
283 .ok_or(update::PrepareError::ReceiverEntry)?;
284 let image_chip = crate::Chip::from_banner(
285 crate::layout::BANNER
286 .of(image)
287 .ok_or(update::PrepareError::UnknownChip)?,
288 )
289 .ok_or(update::PrepareError::UnknownChip)?;
290 if image_chip != profile.chip {
291 return Err(update::PrepareError::ChipMismatch {
292 image: image_chip,
293 drive: profile.chip,
294 });
295 }
296 if class.verification_ranges(image).is_empty() {
297 return Err(update::PrepareError::Integrity);
298 }
299 let mut prepare = profile.prepare;
300 let (transfer, encoding, preserve_boot) = encode_transfer(receiver, image)?;
301 if preserve_boot {
302 use crate::cdb::Prepare;
303 prepare = match prepare {
304 Prepare::ModeOne | Prepare::ModeOnePreserveBoot => Prepare::ModeOnePreserveBoot,
305 Prepare::ModeSix67 | Prepare::ModeSix67PreserveBoot => {
306 Prepare::ModeSix67PreserveBoot
307 }
308 };
309 }
310 Ok(Self {
311 receiver: receiver.clone(),
312 class,
313 image: image.to_vec(),
314 transfer,
315 encoding,
316 prepare,
317 mode,
318 })
319 }
320
321 pub(crate) fn execute_completed<R, W, H>(
322 &self,
323 io: update::FlashTransport<'_, R, W>,
324 runtime: &mut H,
325 ) -> Result<update::Completion, ExecuteError<W::Error>>
326 where
327 W: crate::drive::Transport,
328 R: crate::drive::Transport<Error = W::Error>,
329 H: update::FlashRuntime<W::Error>,
330 {
331 self.receiver
332 .revalidate(io.reads)
333 .map_err(ExecuteError::Receiver)?;
334 update::flash::Payload {
335 class: self.class,
336 image: self.image(),
337 transfer: self.transfer(),
338 }
339 .flash_completed(io, runtime, self.mode, self.prepare)
340 .map_err(ExecuteError::Flash)
341 }
342
343 pub fn encoding(&self) -> TransferEncoding {
345 self.encoding
346 }
347
348 pub fn programmed_ranges(&self) -> Option<&[core::ops::Range<usize>]> {
352 self.receiver
353 .profile
354 .as_ref()?
355 .mixed
356 .as_ref()
357 .map(|contract| contract.programmed_ranges())
358 }
359
360 pub fn preserved_ranges(&self) -> Option<Vec<core::ops::Range<usize>>> {
363 let programmed = self.programmed_ranges()?;
364 let mut preserved = Vec::new();
365 let mut end = 0;
366 for range in programmed {
367 if end < range.start {
368 preserved.push(end..range.start);
369 }
370 end = range.end;
371 }
372 if end < self.image.len() {
373 preserved.push(end..self.image.len());
374 }
375 Some(preserved)
376 }
377
378 pub fn prepare_command(&self) -> crate::cdb::Prepare {
380 self.prepare
381 }
382 pub fn class(&self) -> crate::DriveClass {
384 self.class
385 }
386 pub fn receiver(&self) -> &Receiver {
388 &self.receiver
389 }
390 pub fn image(&self) -> &[u8] {
392 &self.image
393 }
394 pub fn transfer(&self) -> &[u8] {
396 self.transfer.as_deref().unwrap_or(&self.image)
397 }
398 pub fn steps(&self) -> std::vec::Vec<update::Step> {
400 let mut steps = self.class.steps();
401 if self.mode == update::flash::ExecutionMode::Recovery {
402 steps.drain(..2);
405 }
406 for step in &mut steps {
407 if step.label == "PREPARE" {
408 step.cdb = self.prepare.command();
409 }
410 }
411 steps
412 }
413}
414
415#[cfg(test)]
416mod tests {
417 use super::*;
418
419 #[test]
420 fn contradictory_layout_keeps_its_cause() {
421 use super::super::layout::{Error, Operation};
422 let image = vec![0; layout::IMAGE_SIZE];
423 let operations = [
424 Operation::CheckDecrypted(0x3000..0x3010),
425 Operation::CheckPlaintext(0x3000..0x3010),
426 Operation::Program(0..layout::IMAGE_SIZE),
427 ];
428 assert!(matches!(
429 wire(&image, &operations),
430 Err(update::PrepareError::Layout(Error::Conflict { .. }))
431 ));
432 }
433 use crate::{
434 fixtures::{self, BU3},
435 layout, Identity, INQUIRY_LEN,
436 };
437
438 #[test]
439 fn an_image_with_no_verifiable_ranges_is_refused_before_any_write() {
440 let mut image = fixtures::image(&BU3, 7);
441 let at = crate::image::cmac::TABLE_OFFSET;
442 image[at + 4..at + 8].copy_from_slice(&0u32.to_le_bytes());
443 image[at + 8..at + 12].copy_from_slice(&0xFFFu32.to_le_bytes());
444 let image = crate::image::cmac::resign(&image).unwrap();
445 let class = crate::DriveClass::of(crate::Chip::Mt1959);
446 assert!(class.verification_ranges(&image).is_empty());
447 let receiver = Receiver {
448 identity: super::super::DetectedMode {
449 mode: super::super::Mode::Firmware,
450 inquiry: [0; INQUIRY_LEN],
451 },
452 encoding: Encoding::Plaintext,
453 site: super::super::Evidence::new(0x98000, &[1, 2]),
454 transform: None,
455 reference: None,
456 profile: Some(super::super::profile::Profile::testing()),
457 };
458 assert!(matches!(
459 TransferPlan::new(
460 &receiver,
461 &image,
462 class,
463 update::flash::ExecutionMode::Flash
464 ),
465 Err(update::PrepareError::Integrity)
466 ));
467 }
468
469 #[test]
470 fn input_envelope_never_selects_the_running_receivers_wire_encoding() {
471 let image = fixtures::image(&BU3, 7);
472 let identity = Identity::parse(
473 &[0; INQUIRY_LEN],
474 layout::BANNER.of(&image).unwrap(),
475 layout::DESCRIPTOR.of(&image).unwrap(),
476 )
477 .unwrap();
478 let installed =
479 update::InstalledFirmware::new(identity, &fixtures::drive_read(&image)).unwrap();
480 let mut ciphertext = image.clone();
481 crate::enc::encrypt(&mut ciphertext).unwrap();
482 for encoding in [Encoding::Plaintext, Encoding::Encrypted] {
483 let receiver = Receiver {
484 identity: super::super::DetectedMode {
485 mode: super::super::Mode::Firmware,
486 inquiry: [0; INQUIRY_LEN],
487 },
488 encoding,
489 site: super::super::Evidence::new(0x98000, &[1, 2]),
490 transform: None,
491 reference: None,
492 profile: Some(super::super::profile::Profile::testing()),
493 };
494 for input in [&image, &ciphertext] {
495 let prepared = receiver
496 .prepare(&Envelope::load(input).unwrap(), &installed)
497 .unwrap();
498 assert_eq!(prepared.plan().image(), image);
499 assert_eq!(
500 prepared.plan().transfer(),
501 if encoding == Encoding::Encrypted {
502 &ciphertext
503 } else {
504 &image
505 }
506 );
507 assert_eq!(prepared.plan().receiver(), &receiver);
508 let steps = prepared.plan().steps();
509 assert_eq!(
510 steps[..3].iter().map(|s| s.label).collect::<Vec<_>>(),
511 ["PROBE", "READY", "PREPARE"]
512 );
513 let recovery = TransferPlan::new(
514 &receiver,
515 &image,
516 prepared.plan().class(),
517 update::flash::ExecutionMode::Recovery,
518 )
519 .unwrap();
520 let recovery_steps = recovery.steps();
521 assert_eq!(recovery_steps[0].label, "PREPARE");
522 assert_eq!(recovery_steps.len() + 2, steps.len());
523 for (recovery, flash) in recovery_steps.iter().zip(&steps[2..]) {
524 assert_eq!(recovery.cdb, flash.cdb);
525 assert_eq!(recovery.direction, flash.direction);
526 assert_eq!(recovery.length, flash.length);
527 }
528 }
529 }
530 }
531}