[opentitanlib] Add serialization for num_de types
A few wrapper types exist for deserialization of some string wrapped
numeric types in HJSON config files. This adds the ability to serialize
those types in serde.
Signed-off-by: Jon Flatley <jflat@google.com>
diff --git a/sw/host/opentitanlib/src/image/image.rs b/sw/host/opentitanlib/src/image/image.rs
index 79e9f35..443728a 100644
--- a/sw/host/opentitanlib/src/image/image.rs
+++ b/sw/host/opentitanlib/src/image/image.rs
@@ -16,7 +16,6 @@
use crate::image::manifest::Manifest;
use crate::image::manifest_def::ManifestDef;
-use crate::util::bigint;
use crate::util::parse_int::ParseInt;
#[derive(Debug, Error)]
@@ -92,16 +91,29 @@
/// Overwrites all fields in the image's manifest that are defined in `other`.
pub fn overwrite_manifest(&mut self, other: ManifestDef) -> Result<()> {
- let manifest_slice = &mut self.data.bytes[0..size_of::<Manifest>()];
- let manifest_layout: LayoutVerified<&mut [u8], Manifest> =
- LayoutVerified::new(&mut *manifest_slice).ok_or(ImageError::Parse)?;
- let manifest: &mut Manifest = manifest_layout.into_mut();
+ let manifest = self.borrow_manifest_mut()?;
let mut manifest_def: ManifestDef = (&*manifest).try_into()?;
manifest_def.overwrite_fields(other);
*manifest = manifest_def.try_into()?;
Ok(())
}
+ pub fn borrow_manifest(&self) -> Result<&Manifest> {
+ let manifest_slice = &self.data.bytes[0..size_of::<Manifest>()];
+ let manifest_layout: LayoutVerified<&[u8], Manifest> =
+ LayoutVerified::new(manifest_slice).ok_or(ImageError::Parse)?;
+ let manifest: &Manifest = manifest_layout.into_ref();
+ Ok(manifest)
+ }
+
+ pub fn borrow_manifest_mut(&mut self) -> Result<&mut Manifest> {
+ let manifest_slice = &mut self.data.bytes[0..size_of::<Manifest>()];
+ let manifest_layout: LayoutVerified<&mut [u8], Manifest> =
+ LayoutVerified::new(&mut *manifest_slice).ok_or(ImageError::Parse)?;
+ let manifest: &mut Manifest = manifest_layout.into_mut();
+ Ok(manifest)
+ }
+
/// Compute the SHA256 digest for the signed portion of the `Image`.
pub fn compute_digest(&self) -> Vec<u8> {
let mut hasher = Sha256::new();
diff --git a/sw/host/opentitanlib/src/image/manifest_def.rs b/sw/host/opentitanlib/src/image/manifest_def.rs
index 42af264..e369226 100644
--- a/sw/host/opentitanlib/src/image/manifest_def.rs
+++ b/sw/host/opentitanlib/src/image/manifest_def.rs
@@ -8,8 +8,9 @@
use crate::util::parse_int::ParseInt;
use anyhow::{bail, Result};
-use serde::Deserialize;
+use serde::{Deserialize, Serialize};
use std::convert::{TryFrom, TryInto};
+use std::fmt;
use std::iter::IntoIterator;
use std::path::Path;
use thiserror::Error;
@@ -24,11 +25,17 @@
fixed_size_bigint!(ManifestRsa, at_most 3072);
-#[derive(Clone, Default, Debug, Deserialize)]
+#[derive(Clone, Default, Debug, Deserialize, Serialize)]
struct ManifestBigInt(Option<HexEncoded<ManifestRsa>>);
-#[derive(Clone, Default, Debug, Deserialize)]
-struct ManifestSmallInt<T: ParseInt>(Option<HexEncoded<T>>);
+#[derive(Clone, Default, Debug, Deserialize, Serialize)]
+struct ManifestSmallInt<T: ParseInt + fmt::UpperHex>(Option<HexEncoded<T>>);
+
+impl fmt::UpperHex for ManifestRsa {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ fmt::UpperHex::fmt(&self.as_biguint(), f)
+ }
+}
/// A macro for wrapping manifest struct definitions that parse from HJSON.
///
@@ -42,7 +49,7 @@
$field_name:ident: $field_type:ty,
)*
}, $out_type:ident) => {
- #[derive(Clone, Default, Deserialize, Debug)]
+ #[derive(Clone, Default, Deserialize, Serialize, Debug)]
$access struct $name {
$(
$(#[$doc])?
@@ -123,7 +130,7 @@
}
}
-impl<T: ParseInt> ManifestPacked<T> for ManifestSmallInt<T> {
+impl<T: ParseInt + fmt::UpperHex> ManifestPacked<T> for ManifestSmallInt<T> {
fn unpack(self, name: &'static str) -> Result<T> {
match self.0 {
Some(v) => Ok(v.0),
@@ -138,7 +145,9 @@
}
}
-impl<T: ParseInt, const N: usize> ManifestPacked<[T; N]> for [ManifestSmallInt<T>; N] {
+impl<T: ParseInt + fmt::UpperHex, const N: usize> ManifestPacked<[T; N]>
+ for [ManifestSmallInt<T>; N]
+{
fn unpack(self, name: &'static str) -> Result<[T; N]> {
let results = self.map(|e| e.unpack(name));
if let Some(err_idx) = results.iter().position(Result::is_err) {
@@ -254,7 +263,7 @@
impl<T> From<&T> for ManifestSmallInt<T>
where
- T: ParseInt + Copy,
+ T: ParseInt + fmt::UpperHex + Copy,
{
fn from(o: &T) -> ManifestSmallInt<T> {
ManifestSmallInt(Some(HexEncoded(*o)))
diff --git a/sw/host/opentitanlib/src/otp/otp_mmap.rs b/sw/host/opentitanlib/src/otp/otp_mmap.rs
index 516fdf8..f676ab0 100644
--- a/sw/host/opentitanlib/src/otp/otp_mmap.rs
+++ b/sw/host/opentitanlib/src/otp/otp_mmap.rs
@@ -18,9 +18,9 @@
#[derive(Deserialize, Debug)]
struct OtpMapConfig {
- #[serde(with = "num_de")]
+ #[serde(deserialize_with = "num_de::deserialize")]
width: usize,
- #[serde(with = "num_de")]
+ #[serde(deserialize_with = "num_de::deserialize")]
depth: usize,
}
@@ -39,11 +39,11 @@
#[derive(Deserialize, Debug)]
struct OtpMapScrambling {
- #[serde(with = "num_de")]
+ #[serde(deserialize_with = "num_de::deserialize")]
key_size: usize,
- #[serde(with = "num_de")]
+ #[serde(deserialize_with = "num_de::deserialize")]
iv_size: usize,
- #[serde(with = "num_de")]
+ #[serde(deserialize_with = "num_de::deserialize")]
cnst_size: usize,
keys: Vec<OtpMapKey>,
digests: Vec<OtpMapDigest>,
@@ -52,7 +52,7 @@
#[derive(Deserialize, Debug)]
struct OtpMapItem {
name: String,
- #[serde(with = "num_de")]
+ #[serde(deserialize_with = "num_de::deserialize")]
size: usize,
#[serde(default)]
#[allow(dead_code)]
@@ -66,7 +66,7 @@
name: String,
#[allow(dead_code)]
secret: bool,
- #[serde(default, with = "num_de")]
+ #[serde(default, deserialize_with = "num_de::deserialize")]
size: usize,
sw_digest: bool,
hw_digest: bool,
diff --git a/sw/host/opentitanlib/src/util/num_de.rs b/sw/host/opentitanlib/src/util/num_de.rs
index a3122d3..8dc6983 100644
--- a/sw/host/opentitanlib/src/util/num_de.rs
+++ b/sw/host/opentitanlib/src/util/num_de.rs
@@ -27,14 +27,6 @@
use crate::util::parse_int::{ParseInt, ParseIntError};
-pub fn _serialize<S, T>(_r: T, _ser: S) -> Result<S::Ok, S::Error>
-where
- S: Serializer,
- T: Serialize + Copy,
-{
- unimplemented!();
-}
-
/// Deserialize numeric types from HJSON config files.
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
@@ -105,7 +97,7 @@
}
#[derive(Debug, Clone, Deserialize)]
-pub struct DeferredValue(#[serde(with = "self")] DeferredInit);
+pub struct DeferredValue(#[serde(deserialize_with = "deserialize")] DeferredInit);
impl DeferredValue {
pub fn resolve(&self, size: usize, rng: &mut dyn RngCore) -> Vec<u8> {
@@ -158,19 +150,25 @@
/// Wrapper type to force deserialization assuming octal encoding.
#[derive(Clone, Deserialize, Debug)]
-pub struct OctEncoded<T: ParseInt>(#[serde(with = "self")] pub T);
+pub struct OctEncoded<T>(#[serde(deserialize_with = "deserialize")] pub T)
+where
+ T: ParseInt + fmt::Octal;
/// Wrapper type to force deserialization assuming decimal encoding.
#[derive(Clone, Deserialize, Debug)]
-pub struct DecEncoded<T: ParseInt>(#[serde(with = "self")] pub T);
+pub struct DecEncoded<T>(#[serde(deserialize_with = "deserialize")] pub T)
+where
+ T: ParseInt + fmt::Display;
/// Wrapper type to force deserialization assuming hexadecimal encoding.
#[derive(Clone, Deserialize, Debug)]
-pub struct HexEncoded<T: ParseInt>(#[serde(with = "self")] pub T);
+pub struct HexEncoded<T>(#[serde(deserialize_with = "deserialize")] pub T)
+where
+ T: ParseInt + fmt::UpperHex;
macro_rules! impl_parse_int_enc {
- ($ty:ident, $radix:expr) => {
- impl<T: ParseInt> std::ops::Deref for $ty<T> {
+ ($ty:ident, $radix:expr, $fmt:path) => {
+ impl<T: ParseInt + $fmt> std::ops::Deref for $ty<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
@@ -178,7 +176,7 @@
}
}
- impl<T: ParseInt> ParseInt for $ty<T> {
+ impl<T: ParseInt + $fmt> ParseInt for $ty<T> {
type FromStrRadixErr = T::FromStrRadixErr;
fn from_str_radix(src: &str, radix: u32) -> Result<Self, T::FromStrRadixErr> {
@@ -189,12 +187,27 @@
Self::from_str_radix(src, $radix).map_err(|e| e.into())
}
}
+
+ impl<T: ParseInt + $fmt> fmt::Display for $ty<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ <_ as $fmt>::fmt(&self.0, f)
+ }
+ }
+
+ impl<T: ParseInt + $fmt> Serialize for $ty<T> {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.serialize_str(&self.to_string())
+ }
+ }
};
}
-impl_parse_int_enc!(OctEncoded, 8);
-impl_parse_int_enc!(DecEncoded, 10);
-impl_parse_int_enc!(HexEncoded, 16);
+impl_parse_int_enc!(OctEncoded, 8, fmt::Octal);
+impl_parse_int_enc!(DecEncoded, 10, fmt::Display);
+impl_parse_int_enc!(HexEncoded, 16, fmt::UpperHex);
#[cfg(test)]
mod test {
@@ -205,11 +218,11 @@
fn de_u8() -> Result<()> {
#[derive(Debug, Deserialize)]
struct TestData {
- #[serde(with = "super")]
+ #[serde(deserialize_with = "deserialize")]
oct: OctEncoded<u8>,
- #[serde(with = "super")]
+ #[serde(deserialize_with = "deserialize")]
dec: DecEncoded<u8>,
- #[serde(with = "super")]
+ #[serde(deserialize_with = "deserialize")]
hex: HexEncoded<u8>,
}
diff --git a/sw/host/opentitantool/src/command/image.rs b/sw/host/opentitantool/src/command/image.rs
index 26b6333..a38d9cb 100644
--- a/sw/host/opentitantool/src/command/image.rs
+++ b/sw/host/opentitantool/src/command/image.rs
@@ -5,6 +5,7 @@
use anyhow::{ensure, Result};
use erased_serde::Serialize;
use std::any::Any;
+use std::convert::TryInto;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
@@ -78,7 +79,9 @@
_context: &dyn Any,
_transport: &TransportWrapper,
) -> Result<Option<Box<dyn Serialize>>> {
- Ok(None)
+ let image = image::Image::read_from_file(&self.image)?;
+ let manifest_def: ManifestDef = image.borrow_manifest()?.try_into()?;
+ Ok(Some(Box::new(manifest_def)))
}
}