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);