ota.rs (6004B)
1 use nb::block; 2 3 use embassy_time::{Timer}; 4 5 use ed25519_dalek::{VerifyingKey, Verifier, Signature}; 6 7 use esp_hal_ota::Ota; 8 use esp_storage::FlashStorage; 9 use embedded_io_async::{Read,ReadExactError}; 10 11 use esp_hal::sha; 12 use core::convert::Infallible; 13 14 use log::{warn, info}; 15 16 use alloc::string::String; 17 18 19 const ERASE_BLOCK_BYTES : usize = 4096; 20 const ED25519_SIGNATURE_BYTES : usize = 64; 21 const SHA256_BYTES : usize = 32; 22 23 pub struct Flasher<'a> { 24 peripheral: esp_hal::peripherals::FLASH<'a>, 25 sha_engine : sha::Sha<'a> 26 } 27 28 #[derive(Debug)] 29 pub enum FlashError { 30 UnexpectedEof, 31 OtaFailed, 32 InvalidSignature, 33 Infallible 34 } 35 36 impl<E> From<ReadExactError<E>> for FlashError { 37 fn from(_e : ReadExactError<E>) -> Self { 38 Self::UnexpectedEof 39 } 40 } 41 42 impl From<esp_hal_ota::OtaError> for FlashError { 43 fn from(_e : esp_hal_ota::OtaError) -> Self { 44 Self::OtaFailed 45 } 46 } 47 48 impl From<Infallible> for FlashError { 49 fn from(_e : Infallible) -> Self { 50 Self::Infallible 51 } 52 } 53 54 55 impl Flasher<'_> { 56 pub fn new(flash_peripheral: esp_hal::peripherals::FLASH<'static>, 57 sha_peripheral: esp_hal::peripherals::SHA<'static>) -> Self { 58 let sha_engine = sha::Sha::new(sha_peripheral); 59 60 Self { peripheral: flash_peripheral, sha_engine } 61 } 62 63 pub async fn write(&mut self, sock: &mut embassy_net::tcp::TcpSocket<'_>) -> Result<(), FlashError> { 64 let storage = FlashStorage::new(self.peripheral.reborrow()); 65 let mut ota = Ota::new(storage).unwrap(); 66 write_ota(&mut ota, &mut self.sha_engine, sock).await 67 } 68 69 pub fn var(&mut self, name: &str) -> Option<String> { 70 let storage = FlashStorage::new(self.peripheral.reborrow()); 71 let mut nvs = 72 esp_nvs::Nvs::new(0x9000, 0x4000, storage).expect("failed to create nvs"); 73 let ns = const { esp_nvs::Key::from_str("eculocate") }; 74 match nvs.get(&ns, &esp_nvs::Key::from_str(name)) { 75 Ok(s) => Some(s), 76 Err(e) => None 77 } 78 } 79 80 pub fn set_var(&mut self, name: &str, value: Option<&str>) -> Result<(), esp_nvs::error::Error> { 81 let storage = FlashStorage::new(self.peripheral.reborrow()); 82 let mut nvs = 83 esp_nvs::Nvs::new(0x9000, 0x4000, storage).expect("failed to create nvs"); 84 let ns = const { esp_nvs::Key::from_str("eculocate") }; 85 match value { 86 Some(v) => { 87 nvs.set(&ns, &esp_nvs::Key::from_str(name), v) 88 } 89 None => { 90 nvs.delete(&ns, &esp_nvs::Key::from_str(name)) 91 } 92 } 93 } 94 } 95 96 97 async fn write_ota(ota : &mut Ota<FlashStorage<'_>>, 98 sha_engine : &mut sha::Sha<'_>, 99 sock: &mut embassy_net::tcp::TcpSocket<'_>) -> Result<(), FlashError> { 100 let mut buf = [0u8; SHA256_BYTES + ERASE_BLOCK_BYTES]; 101 let mut buf_offset = 0; 102 let mut signed; 103 let mut signature = [0u8; ED25519_SIGNATURE_BYTES ]; 104 let mut next_block_hash = [0u8; SHA256_BYTES]; 105 106 // ed25519 signature of first block 107 // first block is sha256 of second block, plus length as u32 108 // second+ block is sha256 of successor block, plus data 109 110 let mut block0 = [0u8; SHA256_BYTES + 4]; 111 112 sock.read_exact(&mut signature).await?; 113 sock.read_exact(&mut block0[..SHA256_BYTES + 4]).await?; 114 115 let verifying_key_bytes = include_bytes!("../../pubkey.bin"); 116 let verifying_key: VerifyingKey = VerifyingKey::from_bytes(verifying_key_bytes).expect("verify"); 117 signed = verifying_key.verify(&mut block0, 118 &Signature::try_from(&signature).expect("sig")).is_ok(); 119 120 info!("initial sig checks out? {:?}", signed); 121 122 let (sha, len_bytes) = block0.split_at(SHA256_BYTES); 123 let len = u32::from_be_bytes(len_bytes.try_into().expect("4 bytes")); 124 next_block_hash.clone_from_slice(sha); 125 126 info!("ota length {}", len); 127 128 ota.ota_begin(len, 0)?; 129 130 // total payload to expect is image size plus per-block hashes 131 let mut remaining = len + (len/(ERASE_BLOCK_BYTES as u32)+ 1) * (SHA256_BYTES as u32); 132 133 while remaining > 0 { 134 // info!("remaining {}, offset {}", remaining, buf_offset); 135 match sock.read(&mut buf[buf_offset..]).await { 136 Ok(0) => { 137 info!("unexpected eof on read"); 138 break; 139 } 140 Ok(chunksize) => { 141 buf_offset += chunksize; 142 remaining -= chunksize as u32; 143 } 144 Err(x) => { 145 warn!("error reading ota image: {:?}", x); 146 break; 147 } 148 } 149 150 if remaining <= 0 || buf_offset == SHA256_BYTES + ERASE_BLOCK_BYTES { 151 let mut actual_hash = [0u8; SHA256_BYTES]; 152 let mut hasher = sha_engine.start::<sha::Sha256>(); 153 let mut p = &buf[..buf_offset]; 154 while !p.is_empty() { 155 match block!(hasher.update(p)) { 156 Ok(remaining) => { p = remaining; } 157 _ => () 158 } 159 } 160 block!(hasher.finish(&mut actual_hash))?; 161 162 signed = signed && next_block_hash == actual_hash; 163 164 if signed { 165 if let Err(e) = ota.ota_write_chunk(&buf[SHA256_BYTES..buf_offset]) { 166 warn!("error writing chunk {:?}", e); 167 break; 168 } 169 } else { 170 // accept the rest of the update, just don't flash it. 171 warn!("signature invalid with {remaining} left"); 172 } 173 174 buf_offset = 0; 175 next_block_hash.copy_from_slice(&buf[0..SHA256_BYTES]); 176 } 177 } 178 if remaining == 0 { 179 info!("wrote all bytes"); 180 info!("write {:?}", sock.write(b"BYE\n").await); 181 let _ = sock.flush().await; 182 sock.close(); 183 if signed { 184 ota.ota_flush(false, false)?; 185 Timer::after_millis(1000).await; 186 esp_hal::system::software_reset(); 187 } else { 188 return Err(FlashError::InvalidSignature) 189 } 190 } else { 191 warn!("stream ended early or flash failed with {} bytes left", remaining); 192 Err(FlashError::UnexpectedEof) 193 } 194 }