blob: 03390dbde9120b0f71a3a46959fc193198f0ac48 [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 Brown7e701d82017-07-11 13:24:25 -060011use pem;
Fabio Utzig1e48b912018-09-18 09:04:18 -030012use base64;
Fabio Utzig05ab0142018-07-10 09:15:28 -030013use ring::{digest, rand};
14use ring::signature::{
15 RsaKeyPair,
16 RSA_PSS_SHA256,
17 EcdsaKeyPair,
18 ECDSA_P256_SHA256_ASN1_SIGNING,
19};
David Brown7e701d82017-07-11 13:24:25 -060020use untrusted;
Fabio Utzig80fde2f2017-12-05 09:25:31 -020021use mcuboot_sys::c;
David Brown187dd882017-07-11 11:15:23 -060022
David Brown187dd882017-07-11 11:15:23 -060023#[repr(u8)]
24#[derive(Copy, Clone, PartialEq, Eq)]
25#[allow(dead_code)] // TODO: For now
26pub enum TlvKinds {
David Brown43cda332017-09-01 09:53:23 -060027 KEYHASH = 0x01,
David Brown27648b82017-08-31 10:40:29 -060028 SHA256 = 0x10,
29 RSA2048 = 0x20,
30 ECDSA224 = 0x21,
31 ECDSA256 = 0x22,
Fabio Utzig1e48b912018-09-18 09:04:18 -030032 ENCRSA2048 = 0x30,
33 ENCKW128 = 0x31,
34}
35
36#[allow(dead_code, non_camel_case_types)]
37pub enum TlvFlags {
38 PIC = 0x01,
39 NON_BOOTABLE = 0x02,
40 ENCRYPTED = 0x04,
41 RAM_LOAD = 0x20,
David Brown187dd882017-07-11 11:15:23 -060042}
43
44pub struct TlvGen {
David Brown43cda332017-09-01 09:53:23 -060045 flags: u32,
David Brown187dd882017-07-11 11:15:23 -060046 kinds: Vec<TlvKinds>,
47 size: u16,
David Brown4243ab02017-07-11 12:24:23 -060048 payload: Vec<u8>,
David Brown187dd882017-07-11 11:15:23 -060049}
50
Fabio Utzig1e48b912018-09-18 09:04:18 -030051pub const AES_SEC_KEY: &[u8; 16] = b"0123456789ABCDEF";
52
David Brown187dd882017-07-11 11:15:23 -060053impl TlvGen {
54 /// Construct a new tlv generator that will only contain a hash of the data.
David Brown7e701d82017-07-11 13:24:25 -060055 #[allow(dead_code)]
David Brown187dd882017-07-11 11:15:23 -060056 pub fn new_hash_only() -> TlvGen {
57 TlvGen {
David Brown43cda332017-09-01 09:53:23 -060058 flags: 0,
David Brown187dd882017-07-11 11:15:23 -060059 kinds: vec![TlvKinds::SHA256],
60 size: 4 + 32,
David Brown4243ab02017-07-11 12:24:23 -060061 payload: vec![],
David Brown187dd882017-07-11 11:15:23 -060062 }
63 }
64
David Brown7e701d82017-07-11 13:24:25 -060065 #[allow(dead_code)]
66 pub fn new_rsa_pss() -> TlvGen {
67 TlvGen {
David Brown43cda332017-09-01 09:53:23 -060068 flags: 0,
Fabio Utzig754438d2018-12-14 06:39:58 -020069 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048],
70 size: 4 + 32 + 4 + 32 + 4 + 256,
David Brown7e701d82017-07-11 13:24:25 -060071 payload: vec![],
72 }
73 }
74
Fabio Utzig80fde2f2017-12-05 09:25:31 -020075 #[allow(dead_code)]
76 pub fn new_ecdsa() -> TlvGen {
77 TlvGen {
78 flags: 0,
Fabio Utzig754438d2018-12-14 06:39:58 -020079 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256],
80 size: 4 + 32 + 4 + 32 + 4 + 72,
Fabio Utzig80fde2f2017-12-05 09:25:31 -020081 payload: vec![],
82 }
83 }
84
Fabio Utzig1e48b912018-09-18 09:04:18 -030085 #[allow(dead_code)]
86 pub fn new_enc_rsa() -> TlvGen {
87 TlvGen {
88 flags: TlvFlags::ENCRYPTED as u32,
89 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
90 size: 4 + 32 + 4 + 256,
91 payload: vec![],
92 }
93 }
94
95 #[allow(dead_code)]
Fabio Utzig754438d2018-12-14 06:39:58 -020096 pub fn new_sig_enc_rsa() -> TlvGen {
97 TlvGen {
98 flags: TlvFlags::ENCRYPTED as u32,
99 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCRSA2048],
100 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 256,
101 payload: vec![],
102 }
103 }
104
105 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300106 pub fn new_enc_kw() -> TlvGen {
107 TlvGen {
108 flags: TlvFlags::ENCRYPTED as u32,
109 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW128],
110 size: 4 + 32 + 4 + 24,
111 payload: vec![],
112 }
113 }
114
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200115 #[allow(dead_code)]
116 pub fn new_rsa_kw() -> TlvGen {
117 TlvGen {
118 flags: TlvFlags::ENCRYPTED as u32,
119 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCKW128],
120 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 24,
121 payload: vec![],
122 }
123 }
124
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200125 #[allow(dead_code)]
126 pub fn new_ecdsa_kw() -> TlvGen {
127 TlvGen {
128 flags: TlvFlags::ENCRYPTED as u32,
129 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCKW128],
130 size: 4 + 32 + 4 + 32 + 4 + 72 + 4 + 24,
131 payload: vec![],
132 }
133 }
134
David Brown187dd882017-07-11 11:15:23 -0600135 /// Retrieve the header flags for this configuration. This can be called at any time.
136 pub fn get_flags(&self) -> u32 {
David Brown43cda332017-09-01 09:53:23 -0600137 self.flags
David Brown187dd882017-07-11 11:15:23 -0600138 }
139
140 /// Retrieve the size that the TLV will occupy. This can be called at any time.
141 pub fn get_size(&self) -> u16 {
David Brownf5b33d82017-09-01 10:58:27 -0600142 4 + self.size
David Brown187dd882017-07-11 11:15:23 -0600143 }
144
145 /// Add bytes to the covered hash.
146 pub fn add_bytes(&mut self, bytes: &[u8]) {
David Brown4243ab02017-07-11 12:24:23 -0600147 self.payload.extend_from_slice(bytes);
David Brown187dd882017-07-11 11:15:23 -0600148 }
149
150 /// Compute the TLV given the specified block of data.
David Brown8054ce22017-07-11 12:12:09 -0600151 pub fn make_tlv(self) -> Vec<u8> {
David Brown187dd882017-07-11 11:15:23 -0600152 let mut result: Vec<u8> = vec![];
153
David Brownf5b33d82017-09-01 10:58:27 -0600154 let size = self.get_size();
155 result.push(0x07);
156 result.push(0x69);
157 result.push((size & 0xFF) as u8);
158 result.push(((size >> 8) & 0xFF) as u8);
159
David Brown187dd882017-07-11 11:15:23 -0600160 if self.kinds.contains(&TlvKinds::SHA256) {
David Brown4243ab02017-07-11 12:24:23 -0600161 let hash = digest::digest(&digest::SHA256, &self.payload);
David Brown8054ce22017-07-11 12:12:09 -0600162 let hash = hash.as_ref();
David Brown187dd882017-07-11 11:15:23 -0600163
David Brown8054ce22017-07-11 12:12:09 -0600164 assert!(hash.len() == 32);
David Brown187dd882017-07-11 11:15:23 -0600165 result.push(TlvKinds::SHA256 as u8);
166 result.push(0);
167 result.push(32);
168 result.push(0);
David Brown8054ce22017-07-11 12:12:09 -0600169 result.extend_from_slice(hash);
David Brown187dd882017-07-11 11:15:23 -0600170 }
171
David Brown7e701d82017-07-11 13:24:25 -0600172 if self.kinds.contains(&TlvKinds::RSA2048) {
David Brown43cda332017-09-01 09:53:23 -0600173 // Output the hash of the public key.
174 let hash = digest::digest(&digest::SHA256, RSA_PUB_KEY);
175 let hash = hash.as_ref();
176
177 assert!(hash.len() == 32);
178 result.push(TlvKinds::KEYHASH as u8);
179 result.push(0);
180 result.push(32);
181 result.push(0);
182 result.extend_from_slice(hash);
183
David Brown7e701d82017-07-11 13:24:25 -0600184 // For now assume PSS.
185 let key_bytes = pem::parse(include_bytes!("../../root-rsa-2048.pem").as_ref()).unwrap();
186 assert_eq!(key_bytes.tag, "RSA PRIVATE KEY");
187 let key_bytes = untrusted::Input::from(&key_bytes.contents);
Fabio Utzig05ab0142018-07-10 09:15:28 -0300188 let key_pair = RsaKeyPair::from_der(key_bytes).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600189 let rng = rand::SystemRandom::new();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300190 let mut signature = vec![0; key_pair.public_modulus_len()];
David Brown7e701d82017-07-11 13:24:25 -0600191 assert_eq!(signature.len(), 256);
Fabio Utzig05ab0142018-07-10 09:15:28 -0300192 key_pair.sign(&RSA_PSS_SHA256, &rng, &self.payload, &mut signature).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600193
194 result.push(TlvKinds::RSA2048 as u8);
195 result.push(0);
196 result.push((signature.len() & 0xFF) as u8);
197 result.push(((signature.len() >> 8) & 0xFF) as u8);
198 result.extend_from_slice(&signature);
199 }
200
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200201 if self.kinds.contains(&TlvKinds::ECDSA256) {
202 let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY);
203 let keyhash = keyhash.as_ref();
204
205 assert!(keyhash.len() == 32);
206 result.push(TlvKinds::KEYHASH as u8);
207 result.push(0);
208 result.push(32);
209 result.push(0);
210 result.extend_from_slice(keyhash);
211
Fabio Utzig05ab0142018-07-10 09:15:28 -0300212 let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap();
213 assert_eq!(key_bytes.tag, "PRIVATE KEY");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200214
Fabio Utzig05ab0142018-07-10 09:15:28 -0300215 let key_bytes = untrusted::Input::from(&key_bytes.contents);
216 let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING,
217 key_bytes).unwrap();
218 let rng = rand::SystemRandom::new();
219 let payload = untrusted::Input::from(&self.payload);
220 let signature = key_pair.sign(&rng, payload).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200221
222 result.push(TlvKinds::ECDSA256 as u8);
223 result.push(0);
Fabio Utzig05ab0142018-07-10 09:15:28 -0300224
225 // signature must be padded...
226 let mut signature = signature.as_ref().to_vec();
227 while signature.len() < 72 {
228 signature.push(0);
229 signature[1] += 1;
230 }
231
232 result.push((signature.len() & 0xFF) as u8);
233 result.push(((signature.len() >> 8) & 0xFF) as u8);
234 result.extend_from_slice(signature.as_ref());
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200235 }
236
Fabio Utzig1e48b912018-09-18 09:04:18 -0300237 if self.kinds.contains(&TlvKinds::ENCRSA2048) {
238 let key_bytes = pem::parse(include_bytes!("../../enc-rsa2048-pub.pem")
239 .as_ref()).unwrap();
240 assert_eq!(key_bytes.tag, "PUBLIC KEY");
241
242 let encbuf = match c::rsa_oaep_encrypt(&key_bytes.contents, AES_SEC_KEY) {
243 Ok(v) => v,
244 Err(_) => panic!("Failed to encrypt secret key"),
245 };
246
247 assert!(encbuf.len() == 256);
248 result.push(TlvKinds::ENCRSA2048 as u8);
249 result.push(0);
250 result.push(0);
251 result.push(1);
252 result.extend_from_slice(&encbuf);
253 }
254
255 if self.kinds.contains(&TlvKinds::ENCKW128) {
256 let key_bytes = base64::decode(
257 include_str!("../../enc-aes128kw.b64").trim()).unwrap();
258
259 let encbuf = match c::kw_encrypt(&key_bytes, AES_SEC_KEY) {
260 Ok(v) => v,
261 Err(_) => panic!("Failed to encrypt secret key"),
262 };
263
264 assert!(encbuf.len() == 24);
265 result.push(TlvKinds::ENCKW128 as u8);
266 result.push(0);
267 result.push(24);
268 result.push(0);
269 result.extend_from_slice(&encbuf);
270 }
271
David Brown187dd882017-07-11 11:15:23 -0600272 result
273 }
274}
David Brown43cda332017-09-01 09:53:23 -0600275
276include!("rsa_pub_key-rs.txt");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200277include!("ecdsa_pub_key-rs.txt");