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)]
37pub enum ExecuteError<E> {
38 Receiver(super::Error<E>),
40 Flash(update::FlashError<E>),
42}
43
44impl<E: core::fmt::Debug> core::fmt::Display for ExecuteError<E> {
45 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
46 match self {
47 Self::Receiver(error) => {
48 write!(f, "receiver revalidation failed before writing: {error}")
49 }
50 Self::Flash(error) => write!(f, "{error}"),
51 }
52 }
53}
54impl<E: core::fmt::Debug + 'static> std::error::Error for ExecuteError<E> {
55 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
56 match self {
57 Self::Receiver(source) => Some(source),
58 Self::Flash(source) => Some(source),
59 }
60 }
61}
62
63impl Receiver {
64 pub fn bind_prepared(
67 &self,
68 update: &update::PreparedUpdate,
69 ) -> Result<PreparedUpdate, update::PrepareError> {
70 Ok(PreparedUpdate {
71 plan: TransferPlan::new(
72 self,
73 update.image(),
74 update.class(),
75 update::flash::ExecutionMode::Flash,
76 )?,
77 })
78 }
79
80 pub fn prepare_without_installed(
83 &self,
84 envelope: &Envelope,
85 live: &crate::Identity,
86 ) -> Result<PreparedUpdate, update::PrepareError> {
87 let update = update::PreparedUpdate::prepare_without_installed(envelope.image(), live)?;
88 self.bind_prepared(&update)
89 }
90
91 pub fn prepare(
95 &self,
96 envelope: &Envelope,
97 installed: &update::InstalledFirmware,
98 ) -> Result<PreparedUpdate, update::PrepareError> {
99 let update = update::PreparedUpdate::prepare(envelope.image(), installed)?;
103 self.bind_prepared(&update)
104 }
105}
106
107impl PreparedUpdate {
108 pub fn plan(&self) -> &TransferPlan {
110 &self.plan
111 }
112 pub fn flash<R, W, H>(
114 &self,
115 io: update::FlashTransport<'_, R, W>,
116 runtime: &mut H,
117 ) -> Result<update::Verified, ExecuteError<W::Error>>
118 where
119 W: crate::drive::Transport,
120 R: crate::drive::Transport<Error = W::Error>,
121 H: update::FlashRuntime<W::Error>,
122 {
123 self.flash_completed(io, runtime)?
124 .into_verified()
125 .map_err(ExecuteError::Flash)
126 }
127
128 pub fn flash_completed<R, W, H>(
131 &self,
132 io: update::FlashTransport<'_, R, W>,
133 runtime: &mut H,
134 ) -> Result<update::Completion, ExecuteError<W::Error>>
135 where
136 W: crate::drive::Transport,
137 R: crate::drive::Transport<Error = W::Error>,
138 H: update::FlashRuntime<W::Error>,
139 {
140 self.plan.execute_completed(io, runtime)
141 }
142}
143
144fn encode_transfer(
147 receiver: &Receiver,
148 image: &[u8],
149) -> Result<(Option<Vec<u8>>, TransferEncoding, bool), update::PrepareError> {
150 if let Some(analysis) = receiver.application_analysis() {
151 if analysis.conflicting_arguments() {
152 return Err(update::PrepareError::ReceiverContract);
153 }
154 if !analysis.scratch_decoders().is_empty() {
155 let contract = receiver
156 .profile
157 .as_ref()
158 .and_then(|p| p.mixed.as_ref())
159 .ok_or(update::PrepareError::ReceiverContract)?;
160 if image.get(contract.descriptor_byte()) != Some(&0xde) {
161 return Err(update::PrepareError::ReceiverContract);
162 }
163 use super::layout::Operation;
164 let mut operations = vec![Operation::CheckDecrypted(contract.header_range())];
165 for entry in crate::image::cmac::parse_table(image)
168 .map_err(|_| update::PrepareError::Integrity)?
169 .into_iter()
170 .filter(|entry| entry.is_active())
171 {
172 let range = entry.start as usize..entry.end as usize + 1;
173 if !contract.programmed_ranges().iter().any(|programmed| {
174 programmed.start <= range.start && programmed.end >= range.end
175 }) {
176 return Err(update::PrepareError::ReceiverContract);
179 }
180 operations.push(Operation::CheckPlaintext(range));
181 }
182 for range in contract.programmed_ranges() {
183 operations.push(Operation::Program(range.clone()));
184 }
185 let layout = super::layout::analyze(image.len(), &operations)
186 .map_err(|_| update::PrepareError::ReceiverContract)?;
187 let wire = layout
188 .encode(image)
189 .map_err(|_| update::PrepareError::ReceiverContract)?;
190 return Ok((
191 Some(wire),
192 TransferEncoding {
193 header: Encoding::Encrypted,
194 body: Encoding::Plaintext,
195 },
196 true,
197 ));
198 }
199 if receiver.encoding() == Encoding::Encrypted {
200 let [bulk] = analysis.bulk_decoders() else {
201 return Err(update::PrepareError::ReceiverContract);
202 };
203 use super::decoding::Value;
204 let Value::Loaded { cell, offset: 0 } = bulk.from_zero.source else {
205 return Err(update::PrepareError::ReceiverContract);
206 };
207 if bulk.from_zero.destination != bulk.from_zero.source
208 || bulk.from_zero.length as usize != image.len()
209 || bulk.header.source
210 != (Value::Loaded {
211 cell,
212 offset: 0x3000,
213 })
214 || bulk.header.length != 16
215 || !matches!(bulk.header.destination, Value::Stack(_))
216 || bulk.header.target != bulk.from_zero.target
217 {
218 return Err(update::PrepareError::ReceiverContract);
219 }
220 let mut wire = image.to_vec();
221 crate::enc::encrypt(&mut wire).map_err(|_| update::PrepareError::ReceiverContract)?;
223 return Ok((
224 Some(wire),
225 TransferEncoding {
226 header: Encoding::Encrypted,
227 body: Encoding::Encrypted,
228 },
229 false,
230 ));
231 }
232 if !analysis.bulk_decoders().is_empty() {
233 return Err(update::PrepareError::ReceiverContract);
234 }
235 }
236 if receiver.encoding() == Encoding::Encrypted {
239 let mut wire = image.to_vec();
240 crate::enc::encrypt(&mut wire).map_err(|_| update::PrepareError::ReceiverContract)?;
241 Ok((
242 Some(wire),
243 TransferEncoding {
244 header: Encoding::Encrypted,
245 body: Encoding::Encrypted,
246 },
247 false,
248 ))
249 } else {
250 Ok((
251 None,
252 TransferEncoding {
253 header: Encoding::Plaintext,
254 body: Encoding::Plaintext,
255 },
256 false,
257 ))
258 }
259}
260
261impl TransferPlan {
262 pub(crate) fn new(
263 receiver: &Receiver,
264 image: &[u8],
265 class: crate::DriveClass,
266 mode: update::flash::ExecutionMode,
267 ) -> Result<Self, update::PrepareError> {
268 let profile = receiver
269 .profile
270 .as_ref()
271 .ok_or(update::PrepareError::ReceiverEntry)?;
272 let image_chip = crate::Chip::from_banner(
273 crate::layout::BANNER
274 .of(image)
275 .ok_or(update::PrepareError::UnknownChip)?,
276 )
277 .ok_or(update::PrepareError::UnknownChip)?;
278 if image_chip != profile.chip {
279 return Err(update::PrepareError::ChipMismatch {
280 image: image_chip,
281 drive: profile.chip,
282 });
283 }
284 let mut prepare = profile.prepare;
285 let (transfer, encoding, preserve_boot) = encode_transfer(receiver, image)?;
286 if preserve_boot {
287 use crate::cdb::Prepare;
288 prepare = match prepare {
289 Prepare::ModeOne | Prepare::ModeOnePreserveBoot => Prepare::ModeOnePreserveBoot,
290 Prepare::ModeSix67 | Prepare::ModeSix67PreserveBoot => {
291 Prepare::ModeSix67PreserveBoot
292 }
293 };
294 }
295 Ok(Self {
296 receiver: receiver.clone(),
297 class,
298 image: image.to_vec(),
299 transfer,
300 encoding,
301 prepare,
302 mode,
303 })
304 }
305
306 pub(crate) fn execute_completed<R, W, H>(
307 &self,
308 io: update::FlashTransport<'_, R, W>,
309 runtime: &mut H,
310 ) -> Result<update::Completion, ExecuteError<W::Error>>
311 where
312 W: crate::drive::Transport,
313 R: crate::drive::Transport<Error = W::Error>,
314 H: update::FlashRuntime<W::Error>,
315 {
316 self.receiver
317 .revalidate(io.reads)
318 .map_err(ExecuteError::Receiver)?;
319 update::flash::Payload {
320 class: self.class,
321 image: self.image(),
322 transfer: self.transfer(),
323 }
324 .flash_completed(io, runtime, self.mode, self.prepare)
325 .map_err(ExecuteError::Flash)
326 }
327
328 pub fn encoding(&self) -> TransferEncoding {
330 self.encoding
331 }
332
333 pub fn programmed_ranges(&self) -> Option<&[core::ops::Range<usize>]> {
337 self.receiver
338 .profile
339 .as_ref()?
340 .mixed
341 .as_ref()
342 .map(|contract| contract.programmed_ranges())
343 }
344
345 pub fn preserved_ranges(&self) -> Option<Vec<core::ops::Range<usize>>> {
348 let programmed = self.programmed_ranges()?;
349 let mut preserved = Vec::new();
350 let mut end = 0;
351 for range in programmed {
352 if end < range.start {
353 preserved.push(end..range.start);
354 }
355 end = range.end;
356 }
357 if end < self.image.len() {
358 preserved.push(end..self.image.len());
359 }
360 Some(preserved)
361 }
362
363 pub fn prepare_command(&self) -> crate::cdb::Prepare {
365 self.prepare
366 }
367 pub fn class(&self) -> crate::DriveClass {
369 self.class
370 }
371 pub fn receiver(&self) -> &Receiver {
373 &self.receiver
374 }
375 pub fn image(&self) -> &[u8] {
377 &self.image
378 }
379 pub fn transfer(&self) -> &[u8] {
381 self.transfer.as_deref().unwrap_or(&self.image)
382 }
383 pub fn steps(&self) -> std::vec::Vec<update::Step> {
385 let mut steps = self.class.steps();
386 if self.mode == update::flash::ExecutionMode::Recovery {
387 steps.drain(..2);
390 }
391 for step in &mut steps {
392 if step.label == "PREPARE" {
393 step.cdb = self.prepare.command();
394 }
395 }
396 steps
397 }
398}
399
400#[cfg(test)]
401mod tests {
402 use super::*;
403 use crate::{
404 fixtures::{self, BU3},
405 layout, Identity, INQUIRY_LEN,
406 };
407
408 #[test]
409 fn input_envelope_never_selects_the_running_receivers_wire_encoding() {
410 let image = fixtures::image(&BU3, 7);
411 let identity = Identity::parse(
412 &[0; INQUIRY_LEN],
413 layout::BANNER.of(&image).unwrap(),
414 layout::DESCRIPTOR.of(&image).unwrap(),
415 )
416 .unwrap();
417 let installed =
418 update::InstalledFirmware::new(identity, &fixtures::drive_read(&image)).unwrap();
419 let mut ciphertext = image.clone();
420 crate::enc::encrypt(&mut ciphertext).unwrap();
421 for encoding in [Encoding::Plaintext, Encoding::Encrypted] {
422 let receiver = Receiver {
423 identity: super::super::DetectedMode {
424 mode: super::super::Mode::Firmware,
425 inquiry: [0; INQUIRY_LEN],
426 },
427 encoding,
428 site: super::super::Evidence::new(0x98000, &[1, 2]),
429 transform: None,
430 reference: None,
431 profile: Some(super::super::profile::Profile::testing()),
432 };
433 for input in [&image, &ciphertext] {
434 let prepared = receiver
435 .prepare(&Envelope::load(input).unwrap(), &installed)
436 .unwrap();
437 assert_eq!(prepared.plan().image(), image);
438 assert_eq!(
439 prepared.plan().transfer(),
440 if encoding == Encoding::Encrypted {
441 &ciphertext
442 } else {
443 &image
444 }
445 );
446 assert_eq!(prepared.plan().receiver(), &receiver);
447 let steps = prepared.plan().steps();
448 assert_eq!(
449 steps[..3].iter().map(|s| s.label).collect::<Vec<_>>(),
450 ["PROBE", "READY", "PREPARE"]
451 );
452 let recovery = TransferPlan::new(
453 &receiver,
454 &image,
455 prepared.plan().class(),
456 update::flash::ExecutionMode::Recovery,
457 )
458 .unwrap();
459 let recovery_steps = recovery.steps();
460 assert_eq!(recovery_steps[0].label, "PREPARE");
461 assert_eq!(recovery_steps.len() + 2, steps.len());
462 for (recovery, flash) in recovery_steps.iter().zip(&steps[2..]) {
463 assert_eq!(recovery.cdb, flash.cdb);
464 assert_eq!(recovery.direction, flash.direction);
465 assert_eq!(recovery.length, flash.length);
466 }
467 }
468 }
469 }
470}