diff --git a/libcitadel/src/keys.rs b/libcitadel/src/keys.rs index 5cef4c3..3914691 100644 --- a/libcitadel/src/keys.rs +++ b/libcitadel/src/keys.rs @@ -11,6 +11,7 @@ use rustc_serialize::hex::{FromHex,ToHex}; /// /// +#[derive(Clone)] pub struct PublicKey([u8; ED25519_PUBLIC_KEY_LEN]); pub struct KeyPair([u8; ED25519_PKCS8_V2_LEN]); pub struct Signature(signature::Signature); diff --git a/libcitadel/src/partition.rs b/libcitadel/src/partition.rs index 649174a..c7d5b61 100644 --- a/libcitadel/src/partition.rs +++ b/libcitadel/src/partition.rs @@ -1,6 +1,6 @@ use std::path::{Path,PathBuf}; use std::fs; -use {CommandLine,Result,ImageHeader,MetaInfo,Mount}; +use {Result,ImageHeader,MetaInfo,Mount,PublicKey,public_key_for_channel}; #[derive(Clone)] pub struct Partition { @@ -13,6 +13,8 @@ pub struct Partition { struct HeaderInfo { header: ImageHeader, metainfo: MetaInfo, + // None if no public key available for channel named in metainfo + pubkey: Option, } impl Partition { @@ -44,8 +46,17 @@ impl Partition { return Ok(None); }, }; + + let pubkey = match public_key_for_channel(metainfo.channel()) { + Ok(result) => result, + Err(err) => { + warn!("Error parsing pubkey for channel '{}': {}", metainfo.channel(), err); + None + } + }; + Ok(Some(HeaderInfo { - header, metainfo + header, metainfo, pubkey, })) } @@ -95,34 +106,63 @@ impl Partition { self.header().has_flag(ImageHeader::FLAG_PREFER_BOOT) } + pub fn is_sig_failed(&self) -> bool { + self.header().status() == ImageHeader::STATUS_BAD_SIG + } + + pub fn is_signature_valid(&self) -> bool { + if let Some(ref hinfo) = self.hinfo { + if let Some(ref pubkey) = hinfo.pubkey { + return pubkey.verify( + &self.header().metainfo_bytes(), + &self.header().signature()) + + } + } + false + } + + pub fn has_public_key(&self) -> bool { + if let Some(ref h) = self.hinfo { + h.pubkey.is_some() + } else { + false + } + } + pub fn write_status(&mut self, status: u8) -> Result<()> { self.header_mut().set_status(status); self.header().write_partition(&self.path) } + pub fn set_flag_and_write(&mut self, flag: u8) -> Result<()> { + self.header_mut().set_flag(flag); + self.header().write_partition(&self.path) + } + + pub fn clear_flag_and_write(&mut self, flag: u8) -> Result<()> { + self.header_mut().clear_flag(flag); + self.header().write_partition(&self.path) + } + /// Called at boot to perform various checks and possibly /// update the status field to an error state. /// /// Mark `STATUS_TRY_BOOT` partition as `STATUS_FAILED`. /// - /// If metainfo cannot be parsed, mark as `STATUS_BAD_META`. - /// - /// Verify metainfo signature and mark `STATUS_BAD_SIG` if - /// signature verification fails. + /// If a partition that had prior signature failure now + /// has a valid signature set to STATUS_NEW /// pub fn boot_scan(&mut self) -> Result<()> { if !self.is_initialized() { return Ok(()) } if self.header().status() == ImageHeader::STATUS_TRY_BOOT { + warn!("Partition {} has STATUS_TRY_BOOT, assuming it failed boot attempt and marking STATUS_FAILED", self.path().display()); self.write_status(ImageHeader::STATUS_FAILED)?; } - - if !CommandLine::nosignatures() { - if let Err(e) = self.header().verify_signature() { - warn!("Signature verification failed on partition: {}", e); - self.write_status(ImageHeader::STATUS_BAD_SIG)?; - } + if self.is_sig_failed() && self.is_signature_valid() { + self.write_status(ImageHeader::STATUS_NEW)?; } Ok(()) }