blob: 1af8618b6deb48cfbd6a45df0432b76e00ca3e4f [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,
Fabio Utzig97710282019-05-24 17:44:49 -030019 Ed25519KeyPair,
Fabio Utzig05ab0142018-07-10 09:15:28 -030020};
David Brown7e701d82017-07-11 13:24:25 -060021use untrusted;
Fabio Utzig80fde2f2017-12-05 09:25:31 -020022use mcuboot_sys::c;
David Brown187dd882017-07-11 11:15:23 -060023
David Brown187dd882017-07-11 11:15:23 -060024#[repr(u8)]
25#[derive(Copy, Clone, PartialEq, Eq)]
26#[allow(dead_code)] // TODO: For now
27pub enum TlvKinds {
David Brown43cda332017-09-01 09:53:23 -060028 KEYHASH = 0x01,
David Brown27648b82017-08-31 10:40:29 -060029 SHA256 = 0x10,
30 RSA2048 = 0x20,
31 ECDSA224 = 0x21,
32 ECDSA256 = 0x22,
Fabio Utzig39297432019-05-08 18:51:10 -030033 RSA3072 = 0x23,
Fabio Utzig97710282019-05-24 17:44:49 -030034 ED25519 = 0x24,
Fabio Utzig1e48b912018-09-18 09:04:18 -030035 ENCRSA2048 = 0x30,
36 ENCKW128 = 0x31,
37}
38
39#[allow(dead_code, non_camel_case_types)]
40pub enum TlvFlags {
41 PIC = 0x01,
42 NON_BOOTABLE = 0x02,
43 ENCRYPTED = 0x04,
44 RAM_LOAD = 0x20,
David Brown187dd882017-07-11 11:15:23 -060045}
46
David Brown43643dd2019-01-11 15:43:28 -070047/// A generator for manifests. The format of the manifest can be either a
48/// traditional "TLV" or a SUIT-style manifest.
49pub trait ManifestGen {
David Brownac46e262019-01-11 15:46:18 -070050 /// Retrieve the header magic value for this manifest type.
51 fn get_magic(&self) -> u32;
52
David Brown43643dd2019-01-11 15:43:28 -070053 /// Retrieve the flags value for this particular manifest type.
54 fn get_flags(&self) -> u32;
55
56 /// Add a sequence of bytes to the payload that the manifest is
57 /// protecting.
58 fn add_bytes(&mut self, bytes: &[u8]);
59
60 /// Construct the manifest for this payload.
61 fn make_tlv(self: Box<Self>) -> Vec<u8>;
62}
63
David Brown187dd882017-07-11 11:15:23 -060064pub struct TlvGen {
David Brown43cda332017-09-01 09:53:23 -060065 flags: u32,
David Brown187dd882017-07-11 11:15:23 -060066 kinds: Vec<TlvKinds>,
67 size: u16,
David Brown4243ab02017-07-11 12:24:23 -060068 payload: Vec<u8>,
David Brown187dd882017-07-11 11:15:23 -060069}
70
Fabio Utzig1e48b912018-09-18 09:04:18 -030071pub const AES_SEC_KEY: &[u8; 16] = b"0123456789ABCDEF";
72
David Brown187dd882017-07-11 11:15:23 -060073impl TlvGen {
74 /// Construct a new tlv generator that will only contain a hash of the data.
David Brown7e701d82017-07-11 13:24:25 -060075 #[allow(dead_code)]
David Brown187dd882017-07-11 11:15:23 -060076 pub fn new_hash_only() -> TlvGen {
77 TlvGen {
David Brown43cda332017-09-01 09:53:23 -060078 flags: 0,
David Brown187dd882017-07-11 11:15:23 -060079 kinds: vec![TlvKinds::SHA256],
80 size: 4 + 32,
David Brown4243ab02017-07-11 12:24:23 -060081 payload: vec![],
David Brown187dd882017-07-11 11:15:23 -060082 }
83 }
84
David Brown7e701d82017-07-11 13:24:25 -060085 #[allow(dead_code)]
86 pub fn new_rsa_pss() -> TlvGen {
87 TlvGen {
David Brown43cda332017-09-01 09:53:23 -060088 flags: 0,
Fabio Utzig754438d2018-12-14 06:39:58 -020089 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048],
90 size: 4 + 32 + 4 + 32 + 4 + 256,
David Brown7e701d82017-07-11 13:24:25 -060091 payload: vec![],
92 }
93 }
94
Fabio Utzig80fde2f2017-12-05 09:25:31 -020095 #[allow(dead_code)]
Fabio Utzig39297432019-05-08 18:51:10 -030096 pub fn new_rsa3072_pss() -> TlvGen {
97 TlvGen {
98 flags: 0,
99 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA3072],
100 size: 4 + 32 + 4 + 32 + 4 + 384,
101 payload: vec![],
102 }
103 }
104
105 #[allow(dead_code)]
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200106 pub fn new_ecdsa() -> TlvGen {
107 TlvGen {
108 flags: 0,
Fabio Utzig754438d2018-12-14 06:39:58 -0200109 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256],
110 size: 4 + 32 + 4 + 32 + 4 + 72,
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200111 payload: vec![],
112 }
113 }
114
Fabio Utzig1e48b912018-09-18 09:04:18 -0300115 #[allow(dead_code)]
Fabio Utzig97710282019-05-24 17:44:49 -0300116 pub fn new_ed25519() -> TlvGen {
117 TlvGen {
118 flags: 0,
119 kinds: vec![TlvKinds::SHA256, TlvKinds::ED25519],
120 size: 4 + 32 + 4 + 32 + 4 + 64,
121 payload: vec![],
122 }
123 }
124
125 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300126 pub fn new_enc_rsa() -> TlvGen {
127 TlvGen {
128 flags: TlvFlags::ENCRYPTED as u32,
129 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
130 size: 4 + 32 + 4 + 256,
131 payload: vec![],
132 }
133 }
134
135 #[allow(dead_code)]
Fabio Utzig754438d2018-12-14 06:39:58 -0200136 pub fn new_sig_enc_rsa() -> TlvGen {
137 TlvGen {
138 flags: TlvFlags::ENCRYPTED as u32,
139 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCRSA2048],
140 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 256,
141 payload: vec![],
142 }
143 }
144
145 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300146 pub fn new_enc_kw() -> TlvGen {
147 TlvGen {
148 flags: TlvFlags::ENCRYPTED as u32,
149 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW128],
150 size: 4 + 32 + 4 + 24,
151 payload: vec![],
152 }
153 }
154
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200155 #[allow(dead_code)]
156 pub fn new_rsa_kw() -> TlvGen {
157 TlvGen {
158 flags: TlvFlags::ENCRYPTED as u32,
159 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCKW128],
160 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 24,
161 payload: vec![],
162 }
163 }
164
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200165 #[allow(dead_code)]
166 pub fn new_ecdsa_kw() -> TlvGen {
167 TlvGen {
168 flags: TlvFlags::ENCRYPTED as u32,
169 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCKW128],
170 size: 4 + 32 + 4 + 32 + 4 + 72 + 4 + 24,
171 payload: vec![],
172 }
173 }
174
David Brown187dd882017-07-11 11:15:23 -0600175 /// Retrieve the size that the TLV will occupy. This can be called at any time.
176 pub fn get_size(&self) -> u16 {
David Brownf5b33d82017-09-01 10:58:27 -0600177 4 + self.size
David Brown187dd882017-07-11 11:15:23 -0600178 }
David Brown43643dd2019-01-11 15:43:28 -0700179}
180
181impl ManifestGen for TlvGen {
David Brownac46e262019-01-11 15:46:18 -0700182 fn get_magic(&self) -> u32 {
183 0x96f3b83d
184 }
185
David Brown43643dd2019-01-11 15:43:28 -0700186 /// Retrieve the header flags for this configuration. This can be called at any time.
187 fn get_flags(&self) -> u32 {
188 self.flags
189 }
David Brown187dd882017-07-11 11:15:23 -0600190
191 /// Add bytes to the covered hash.
David Brown43643dd2019-01-11 15:43:28 -0700192 fn add_bytes(&mut self, bytes: &[u8]) {
David Brown4243ab02017-07-11 12:24:23 -0600193 self.payload.extend_from_slice(bytes);
David Brown187dd882017-07-11 11:15:23 -0600194 }
195
196 /// Compute the TLV given the specified block of data.
David Brown43643dd2019-01-11 15:43:28 -0700197 fn make_tlv(self: Box<Self>) -> Vec<u8> {
David Brown187dd882017-07-11 11:15:23 -0600198 let mut result: Vec<u8> = vec![];
199
David Brownf5b33d82017-09-01 10:58:27 -0600200 let size = self.get_size();
201 result.push(0x07);
202 result.push(0x69);
203 result.push((size & 0xFF) as u8);
204 result.push(((size >> 8) & 0xFF) as u8);
205
David Brown187dd882017-07-11 11:15:23 -0600206 if self.kinds.contains(&TlvKinds::SHA256) {
David Brown4243ab02017-07-11 12:24:23 -0600207 let hash = digest::digest(&digest::SHA256, &self.payload);
David Brown8054ce22017-07-11 12:12:09 -0600208 let hash = hash.as_ref();
David Brown187dd882017-07-11 11:15:23 -0600209
David Brown8054ce22017-07-11 12:12:09 -0600210 assert!(hash.len() == 32);
David Brown187dd882017-07-11 11:15:23 -0600211 result.push(TlvKinds::SHA256 as u8);
212 result.push(0);
213 result.push(32);
214 result.push(0);
David Brown8054ce22017-07-11 12:12:09 -0600215 result.extend_from_slice(hash);
David Brown187dd882017-07-11 11:15:23 -0600216 }
217
Fabio Utzig39297432019-05-08 18:51:10 -0300218 if self.kinds.contains(&TlvKinds::RSA2048) ||
219 self.kinds.contains(&TlvKinds::RSA3072) {
220
221 let is_rsa2048 = self.kinds.contains(&TlvKinds::RSA2048);
222
David Brown43cda332017-09-01 09:53:23 -0600223 // Output the hash of the public key.
Fabio Utzig39297432019-05-08 18:51:10 -0300224 let hash = if is_rsa2048 {
225 digest::digest(&digest::SHA256, RSA_PUB_KEY)
226 } else {
227 digest::digest(&digest::SHA256, RSA3072_PUB_KEY)
228 };
David Brown43cda332017-09-01 09:53:23 -0600229 let hash = hash.as_ref();
230
231 assert!(hash.len() == 32);
232 result.push(TlvKinds::KEYHASH as u8);
233 result.push(0);
234 result.push(32);
235 result.push(0);
236 result.extend_from_slice(hash);
237
David Brown7e701d82017-07-11 13:24:25 -0600238 // For now assume PSS.
Fabio Utzig39297432019-05-08 18:51:10 -0300239 let key_bytes = if is_rsa2048 {
240 pem::parse(include_bytes!("../../root-rsa-2048.pem").as_ref()).unwrap()
241 } else {
242 pem::parse(include_bytes!("../../root-rsa-3072.pem").as_ref()).unwrap()
243 };
David Brown7e701d82017-07-11 13:24:25 -0600244 assert_eq!(key_bytes.tag, "RSA PRIVATE KEY");
245 let key_bytes = untrusted::Input::from(&key_bytes.contents);
Fabio Utzig05ab0142018-07-10 09:15:28 -0300246 let key_pair = RsaKeyPair::from_der(key_bytes).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600247 let rng = rand::SystemRandom::new();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300248 let mut signature = vec![0; key_pair.public_modulus_len()];
Fabio Utzig39297432019-05-08 18:51:10 -0300249 if is_rsa2048 {
250 assert_eq!(signature.len(), 256);
251 } else {
252 assert_eq!(signature.len(), 384);
253 }
Fabio Utzig05ab0142018-07-10 09:15:28 -0300254 key_pair.sign(&RSA_PSS_SHA256, &rng, &self.payload, &mut signature).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600255
Fabio Utzig39297432019-05-08 18:51:10 -0300256 if is_rsa2048 {
257 result.push(TlvKinds::RSA2048 as u8);
258 } else {
259 result.push(TlvKinds::RSA3072 as u8);
260 }
David Brown7e701d82017-07-11 13:24:25 -0600261 result.push(0);
262 result.push((signature.len() & 0xFF) as u8);
263 result.push(((signature.len() >> 8) & 0xFF) as u8);
264 result.extend_from_slice(&signature);
265 }
266
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200267 if self.kinds.contains(&TlvKinds::ECDSA256) {
268 let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY);
269 let keyhash = keyhash.as_ref();
270
271 assert!(keyhash.len() == 32);
272 result.push(TlvKinds::KEYHASH as u8);
273 result.push(0);
274 result.push(32);
275 result.push(0);
276 result.extend_from_slice(keyhash);
277
Fabio Utzig05ab0142018-07-10 09:15:28 -0300278 let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap();
279 assert_eq!(key_bytes.tag, "PRIVATE KEY");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200280
Fabio Utzig05ab0142018-07-10 09:15:28 -0300281 let key_bytes = untrusted::Input::from(&key_bytes.contents);
282 let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING,
283 key_bytes).unwrap();
284 let rng = rand::SystemRandom::new();
285 let payload = untrusted::Input::from(&self.payload);
286 let signature = key_pair.sign(&rng, payload).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200287
288 result.push(TlvKinds::ECDSA256 as u8);
289 result.push(0);
Fabio Utzig05ab0142018-07-10 09:15:28 -0300290
291 // signature must be padded...
292 let mut signature = signature.as_ref().to_vec();
293 while signature.len() < 72 {
294 signature.push(0);
295 signature[1] += 1;
296 }
297
298 result.push((signature.len() & 0xFF) as u8);
299 result.push(((signature.len() >> 8) & 0xFF) as u8);
300 result.extend_from_slice(signature.as_ref());
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200301 }
302
Fabio Utzig97710282019-05-24 17:44:49 -0300303 if self.kinds.contains(&TlvKinds::ED25519) {
304 let keyhash = digest::digest(&digest::SHA256, ED25519_PUB_KEY);
305 let keyhash = keyhash.as_ref();
306
307 assert!(keyhash.len() == 32);
308 result.push(TlvKinds::KEYHASH as u8);
309 result.push(0);
310 result.push(32);
311 result.push(0);
312 result.extend_from_slice(keyhash);
313
314 let hash = digest::digest(&digest::SHA256, &self.payload);
315 let hash = hash.as_ref();
316 assert!(hash.len() == 32);
317
318 let key_bytes = pem::parse(include_bytes!("../../root-ed25519.pem").as_ref()).unwrap();
319 assert_eq!(key_bytes.tag, "PRIVATE KEY");
320
321 let seed = untrusted::Input::from(&key_bytes.contents[16..48]);
322 let public = untrusted::Input::from(&ED25519_PUB_KEY[12..44]);
323 let key_pair = Ed25519KeyPair::from_seed_and_public_key(seed, public).unwrap();
324 let signature = key_pair.sign(&hash);
325
326 result.push(TlvKinds::ED25519 as u8);
327 result.push(0);
328
329 let signature = signature.as_ref().to_vec();
330 result.push((signature.len() & 0xFF) as u8);
331 result.push(((signature.len() >> 8) & 0xFF) as u8);
332 result.extend_from_slice(signature.as_ref());
333 }
334
Fabio Utzig1e48b912018-09-18 09:04:18 -0300335 if self.kinds.contains(&TlvKinds::ENCRSA2048) {
336 let key_bytes = pem::parse(include_bytes!("../../enc-rsa2048-pub.pem")
337 .as_ref()).unwrap();
338 assert_eq!(key_bytes.tag, "PUBLIC KEY");
339
340 let encbuf = match c::rsa_oaep_encrypt(&key_bytes.contents, AES_SEC_KEY) {
341 Ok(v) => v,
342 Err(_) => panic!("Failed to encrypt secret key"),
343 };
344
345 assert!(encbuf.len() == 256);
346 result.push(TlvKinds::ENCRSA2048 as u8);
347 result.push(0);
348 result.push(0);
349 result.push(1);
350 result.extend_from_slice(&encbuf);
351 }
352
353 if self.kinds.contains(&TlvKinds::ENCKW128) {
354 let key_bytes = base64::decode(
355 include_str!("../../enc-aes128kw.b64").trim()).unwrap();
356
357 let encbuf = match c::kw_encrypt(&key_bytes, AES_SEC_KEY) {
358 Ok(v) => v,
359 Err(_) => panic!("Failed to encrypt secret key"),
360 };
361
362 assert!(encbuf.len() == 24);
363 result.push(TlvKinds::ENCKW128 as u8);
364 result.push(0);
365 result.push(24);
366 result.push(0);
367 result.extend_from_slice(&encbuf);
368 }
369
David Brown187dd882017-07-11 11:15:23 -0600370 result
371 }
372}
David Brown43cda332017-09-01 09:53:23 -0600373
374include!("rsa_pub_key-rs.txt");
Fabio Utzig39297432019-05-08 18:51:10 -0300375include!("rsa3072_pub_key-rs.txt");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200376include!("ecdsa_pub_key-rs.txt");
Fabio Utzig97710282019-05-24 17:44:49 -0300377include!("ed25519_pub_key-rs.txt");