blob: ac6ac5d5724fbc27620060b82147347d0103efb4 [file] [log] [blame]
David Brown187dd882017-07-11 11:15:23 -06001//! TLV Support
2//!
3//! mcuboot images are followed immediately by a list of TLV items that contain integrity
4//! information about the image. Their generation is made a little complicated because the size of
5//! the TLV block is in the image header, which is included in the hash. Since some signatures can
6//! vary in size, we just make them the largest size possible.
7//!
8//! Because of this header, we have to make two passes. The first pass will compute the size of
9//! the TLV, and the second pass will build the data for the TLV.
10
David Brown8054ce22017-07-11 12:12:09 -060011use ring::digest;
David Brown187dd882017-07-11 11:15:23 -060012
David Brown1e158592017-07-11 12:29:25 -060013bitflags! {
14 struct Flags: u32 {
15 const FLAG_PIC = 0x000001;
16 const FLAG_SHA256 = 0x000002;
17 const FLAG_PKCS15_RSA2048_SHA256 = 0x000004;
18 const FLAG_ECDSA224_SHA256 = 0x000008;
19 const FLAG_NON_BOOTABLE = 0x000010;
20 const FLAG_ECDSA256_SHA256 = 0x000020;
21 const FLAG_PKCS1_PSS_RSA2048_SHA256 = 0x000040;
22 }
David Brown187dd882017-07-11 11:15:23 -060023}
24
25#[repr(u8)]
26#[derive(Copy, Clone, PartialEq, Eq)]
27#[allow(dead_code)] // TODO: For now
28pub enum TlvKinds {
29 SHA256 = 1,
30 RSA2048 = 2,
31 ECDSA224 = 3,
32 ECDSA256 = 4,
33}
34
35pub struct TlvGen {
36 flags: Flags,
37 kinds: Vec<TlvKinds>,
38 size: u16,
David Brown4243ab02017-07-11 12:24:23 -060039 payload: Vec<u8>,
David Brown187dd882017-07-11 11:15:23 -060040}
41
42impl TlvGen {
43 /// Construct a new tlv generator that will only contain a hash of the data.
44 pub fn new_hash_only() -> TlvGen {
45 TlvGen {
David Brown1e158592017-07-11 12:29:25 -060046 flags: FLAG_SHA256,
David Brown187dd882017-07-11 11:15:23 -060047 kinds: vec![TlvKinds::SHA256],
48 size: 4 + 32,
David Brown4243ab02017-07-11 12:24:23 -060049 payload: vec![],
David Brown187dd882017-07-11 11:15:23 -060050 }
51 }
52
53 /// Retrieve the header flags for this configuration. This can be called at any time.
54 pub fn get_flags(&self) -> u32 {
David Brown1e158592017-07-11 12:29:25 -060055 self.flags.bits()
David Brown187dd882017-07-11 11:15:23 -060056 }
57
58 /// Retrieve the size that the TLV will occupy. This can be called at any time.
59 pub fn get_size(&self) -> u16 {
60 self.size
61 }
62
63 /// Add bytes to the covered hash.
64 pub fn add_bytes(&mut self, bytes: &[u8]) {
David Brown4243ab02017-07-11 12:24:23 -060065 self.payload.extend_from_slice(bytes);
David Brown187dd882017-07-11 11:15:23 -060066 }
67
68 /// Compute the TLV given the specified block of data.
David Brown8054ce22017-07-11 12:12:09 -060069 pub fn make_tlv(self) -> Vec<u8> {
David Brown187dd882017-07-11 11:15:23 -060070 let mut result: Vec<u8> = vec![];
71
72 if self.kinds.contains(&TlvKinds::SHA256) {
David Brown4243ab02017-07-11 12:24:23 -060073 let hash = digest::digest(&digest::SHA256, &self.payload);
David Brown8054ce22017-07-11 12:12:09 -060074 let hash = hash.as_ref();
David Brown187dd882017-07-11 11:15:23 -060075
David Brown8054ce22017-07-11 12:12:09 -060076 assert!(hash.len() == 32);
David Brown187dd882017-07-11 11:15:23 -060077 result.push(TlvKinds::SHA256 as u8);
78 result.push(0);
79 result.push(32);
80 result.push(0);
David Brown8054ce22017-07-11 12:12:09 -060081 result.extend_from_slice(hash);
David Brown187dd882017-07-11 11:15:23 -060082 }
83
84 result
85 }
86}