sim: Add dependency encoding to TLV generator
The dependencies are kind of a special case, since they have to be
protected by the hashes.
Signed-off-by: David Brown <david.brown@linaro.org>
diff --git a/sim/src/image.rs b/sim/src/image.rs
index ac238e7..b0d996d 100644
--- a/sim/src/image.rs
+++ b/sim/src/image.rs
@@ -1032,7 +1032,7 @@
magic: tlv.get_magic(),
load_addr: 0,
hdr_size: HDR_SIZE as u16,
- _pad1: 0,
+ protect_tlv_size: tlv.protect_size(),
img_size: len as u32,
flags: tlv.get_flags(),
ver: ImageVersion {
@@ -1299,7 +1299,7 @@
magic: u32,
load_addr: u32,
hdr_size: u16,
- _pad1: u16,
+ protect_tlv_size: u16,
img_size: u32,
flags: u32,
ver: ImageVersion,
@@ -1309,11 +1309,12 @@
impl AsRaw for ImageHeader {}
#[repr(C)]
+#[derive(Clone)]
pub struct ImageVersion {
- major: u8,
- minor: u8,
- revision: u16,
- build_num: u32,
+ pub major: u8,
+ pub minor: u8,
+ pub revision: u16,
+ pub build_num: u32,
}
#[derive(Clone)]
diff --git a/sim/src/tlv.rs b/sim/src/tlv.rs
index f78c507..43dd2e2 100644
--- a/sim/src/tlv.rs
+++ b/sim/src/tlv.rs
@@ -11,6 +11,7 @@
use byteorder::{
LittleEndian, WriteBytesExt,
};
+use crate::image::ImageVersion;
use pem;
use base64;
use ring::{digest, rand};
@@ -37,6 +38,7 @@
ED25519 = 0x24,
ENCRSA2048 = 0x30,
ENCKW128 = 0x31,
+ DEPENDENCY = 0x40,
}
#[allow(dead_code, non_camel_case_types)]
@@ -56,6 +58,14 @@
/// Retrieve the flags value for this particular manifest type.
fn get_flags(&self) -> u32;
+ /// Retrieve the number of bytes of this manifest that is "protected".
+ /// This field is stored in the outside image header instead of the
+ /// manifest header.
+ fn protect_size(&self) -> u16;
+
+ /// Add a dependency on another image.
+ fn add_dependency(&mut self, id: u8, version: &ImageVersion);
+
/// Add a sequence of bytes to the payload that the manifest is
/// protecting.
fn add_bytes(&mut self, bytes: &[u8]);
@@ -67,8 +77,17 @@
pub struct TlvGen {
flags: u32,
kinds: Vec<TlvKinds>,
+ /// The total size of the payload.
size: u16,
+ /// Extra bytes of the TLV that are protected.
+ protect_size: u16,
payload: Vec<u8>,
+ dependencies: Vec<Dependency>,
+}
+
+struct Dependency {
+ id: u8,
+ version: ImageVersion,
}
pub const AES_SEC_KEY: &[u8; 16] = b"0123456789ABCDEF";
@@ -81,7 +100,9 @@
flags: 0,
kinds: vec![TlvKinds::SHA256],
size: 4 + 32,
+ protect_size: 0,
payload: vec![],
+ dependencies: vec![],
}
}
@@ -91,7 +112,9 @@
flags: 0,
kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048],
size: 4 + 32 + 4 + 32 + 4 + 256,
+ protect_size: 0,
payload: vec![],
+ dependencies: vec![],
}
}
@@ -101,7 +124,9 @@
flags: 0,
kinds: vec![TlvKinds::SHA256, TlvKinds::RSA3072],
size: 4 + 32 + 4 + 32 + 4 + 384,
+ protect_size: 0,
payload: vec![],
+ dependencies: vec![],
}
}
@@ -111,7 +136,9 @@
flags: 0,
kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256],
size: 4 + 32 + 4 + 32 + 4 + 72,
+ protect_size: 0,
payload: vec![],
+ dependencies: vec![],
}
}
@@ -121,7 +148,9 @@
flags: 0,
kinds: vec![TlvKinds::SHA256, TlvKinds::ED25519],
size: 4 + 32 + 4 + 32 + 4 + 64,
+ protect_size: 0,
payload: vec![],
+ dependencies: vec![],
}
}
@@ -131,7 +160,9 @@
flags: TlvFlags::ENCRYPTED as u32,
kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
size: 4 + 32 + 4 + 256,
+ protect_size: 0,
payload: vec![],
+ dependencies: vec![],
}
}
@@ -141,7 +172,9 @@
flags: TlvFlags::ENCRYPTED as u32,
kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCRSA2048],
size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 256,
+ protect_size: 0,
payload: vec![],
+ dependencies: vec![],
}
}
@@ -151,7 +184,9 @@
flags: TlvFlags::ENCRYPTED as u32,
kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW128],
size: 4 + 32 + 4 + 24,
+ protect_size: 0,
payload: vec![],
+ dependencies: vec![],
}
}
@@ -161,7 +196,9 @@
flags: TlvFlags::ENCRYPTED as u32,
kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCKW128],
size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 24,
+ protect_size: 0,
payload: vec![],
+ dependencies: vec![],
}
}
@@ -171,7 +208,9 @@
flags: TlvFlags::ENCRYPTED as u32,
kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCKW128],
size: 4 + 32 + 4 + 32 + 4 + 72 + 4 + 24,
+ protect_size: 0,
payload: vec![],
+ dependencies: vec![],
}
}
@@ -196,6 +235,25 @@
self.payload.extend_from_slice(bytes);
}
+ fn protect_size(&self) -> u16 {
+ if self.protect_size == 0 {
+ 0
+ } else {
+ // Include the protected size, as well as the TLV header.
+ 4 + self.protect_size
+ }
+ }
+
+ fn add_dependency(&mut self, id: u8, version: &ImageVersion) {
+ let my_size = 4 + 4 + 8;
+ self.protect_size += my_size;
+ self.size += my_size;
+ self.dependencies.push(Dependency {
+ id: id,
+ version: version.clone(),
+ });
+ }
+
/// Compute the TLV given the specified block of data.
fn make_tlv(self: Box<Self>) -> Vec<u8> {
let mut result: Vec<u8> = vec![];
@@ -205,8 +263,39 @@
result.push(0x69);
result.write_u16::<LittleEndian>(size).unwrap();
+ for dep in &self.dependencies {
+ result.push(TlvKinds::DEPENDENCY as u8);
+ result.push(0);
+ result.push(12);
+ result.push(0);
+
+ // The dependency.
+ result.push(dep.id);
+ for _ in 0 .. 3 {
+ result.push(0);
+ }
+ result.push(dep.version.major);
+ result.push(dep.version.minor);
+ result.write_u16::<LittleEndian>(dep.version.revision).unwrap();
+ result.write_u32::<LittleEndian>(dep.version.build_num).unwrap();
+ }
+
+ // Ring does the signature itself, which means that it must be
+ // given a full, contiguous payload. Although this does help from
+ // a correct usage perspective, it is fairly stupid from an
+ // efficiency view. If this is shown to be a performance issue
+ // with the tests, the protected data could be appended to the
+ // payload, and then removed after the signature is done. For now,
+ // just make a signed payload.
+ let mut sig_payload = self.payload.clone();
+ if self.protect_size > 0 {
+ assert_eq!(self.protect_size as usize + 4, result.len());
+ sig_payload.extend_from_slice(&result);
+ }
+ let sig_payload = sig_payload;
+
if self.kinds.contains(&TlvKinds::SHA256) {
- let hash = digest::digest(&digest::SHA256, &self.payload);
+ let hash = digest::digest(&digest::SHA256, &sig_payload);
let hash = hash.as_ref();
assert!(hash.len() == 32);
@@ -253,7 +342,7 @@
} else {
assert_eq!(signature.len(), 384);
}
- key_pair.sign(&RSA_PSS_SHA256, &rng, &self.payload, &mut signature).unwrap();
+ key_pair.sign(&RSA_PSS_SHA256, &rng, &sig_payload, &mut signature).unwrap();
if is_rsa2048 {
result.push(TlvKinds::RSA2048 as u8);
@@ -283,7 +372,7 @@
let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING,
key_bytes).unwrap();
let rng = rand::SystemRandom::new();
- let payload = untrusted::Input::from(&self.payload);
+ let payload = untrusted::Input::from(&sig_payload);
let signature = key_pair.sign(&rng, payload).unwrap();
result.push(TlvKinds::ECDSA256 as u8);
@@ -311,7 +400,7 @@
result.push(0);
result.extend_from_slice(keyhash);
- let hash = digest::digest(&digest::SHA256, &self.payload);
+ let hash = digest::digest(&digest::SHA256, &sig_payload);
let hash = hash.as_ref();
assert!(hash.len() == 32);