blob: f78c5073e0767dd2cb4d424d954410bc752ae59e [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 Brown91d68632019-07-29 14:32:13 -060011use byteorder::{
12 LittleEndian, WriteBytesExt,
13};
David Brown7e701d82017-07-11 13:24:25 -060014use pem;
Fabio Utzig1e48b912018-09-18 09:04:18 -030015use base64;
Fabio Utzig05ab0142018-07-10 09:15:28 -030016use ring::{digest, rand};
17use ring::signature::{
18 RsaKeyPair,
19 RSA_PSS_SHA256,
20 EcdsaKeyPair,
21 ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig97710282019-05-24 17:44:49 -030022 Ed25519KeyPair,
Fabio Utzig05ab0142018-07-10 09:15:28 -030023};
David Brown7e701d82017-07-11 13:24:25 -060024use untrusted;
Fabio Utzig80fde2f2017-12-05 09:25:31 -020025use mcuboot_sys::c;
David Brown187dd882017-07-11 11:15:23 -060026
David Brown187dd882017-07-11 11:15:23 -060027#[repr(u8)]
28#[derive(Copy, Clone, PartialEq, Eq)]
29#[allow(dead_code)] // TODO: For now
30pub enum TlvKinds {
David Brown43cda332017-09-01 09:53:23 -060031 KEYHASH = 0x01,
David Brown27648b82017-08-31 10:40:29 -060032 SHA256 = 0x10,
33 RSA2048 = 0x20,
34 ECDSA224 = 0x21,
35 ECDSA256 = 0x22,
Fabio Utzig39297432019-05-08 18:51:10 -030036 RSA3072 = 0x23,
Fabio Utzig97710282019-05-24 17:44:49 -030037 ED25519 = 0x24,
Fabio Utzig1e48b912018-09-18 09:04:18 -030038 ENCRSA2048 = 0x30,
39 ENCKW128 = 0x31,
40}
41
42#[allow(dead_code, non_camel_case_types)]
43pub enum TlvFlags {
44 PIC = 0x01,
45 NON_BOOTABLE = 0x02,
46 ENCRYPTED = 0x04,
47 RAM_LOAD = 0x20,
David Brown187dd882017-07-11 11:15:23 -060048}
49
David Brown43643dd2019-01-11 15:43:28 -070050/// A generator for manifests. The format of the manifest can be either a
51/// traditional "TLV" or a SUIT-style manifest.
52pub trait ManifestGen {
David Brownac46e262019-01-11 15:46:18 -070053 /// Retrieve the header magic value for this manifest type.
54 fn get_magic(&self) -> u32;
55
David Brown43643dd2019-01-11 15:43:28 -070056 /// Retrieve the flags value for this particular manifest type.
57 fn get_flags(&self) -> u32;
58
59 /// Add a sequence of bytes to the payload that the manifest is
60 /// protecting.
61 fn add_bytes(&mut self, bytes: &[u8]);
62
63 /// Construct the manifest for this payload.
64 fn make_tlv(self: Box<Self>) -> Vec<u8>;
65}
66
David Brown187dd882017-07-11 11:15:23 -060067pub struct TlvGen {
David Brown43cda332017-09-01 09:53:23 -060068 flags: u32,
David Brown187dd882017-07-11 11:15:23 -060069 kinds: Vec<TlvKinds>,
70 size: u16,
David Brown4243ab02017-07-11 12:24:23 -060071 payload: Vec<u8>,
David Brown187dd882017-07-11 11:15:23 -060072}
73
Fabio Utzig1e48b912018-09-18 09:04:18 -030074pub const AES_SEC_KEY: &[u8; 16] = b"0123456789ABCDEF";
75
David Brown187dd882017-07-11 11:15:23 -060076impl TlvGen {
77 /// Construct a new tlv generator that will only contain a hash of the data.
David Brown7e701d82017-07-11 13:24:25 -060078 #[allow(dead_code)]
David Brown187dd882017-07-11 11:15:23 -060079 pub fn new_hash_only() -> TlvGen {
80 TlvGen {
David Brown43cda332017-09-01 09:53:23 -060081 flags: 0,
David Brown187dd882017-07-11 11:15:23 -060082 kinds: vec![TlvKinds::SHA256],
83 size: 4 + 32,
David Brown4243ab02017-07-11 12:24:23 -060084 payload: vec![],
David Brown187dd882017-07-11 11:15:23 -060085 }
86 }
87
David Brown7e701d82017-07-11 13:24:25 -060088 #[allow(dead_code)]
89 pub fn new_rsa_pss() -> TlvGen {
90 TlvGen {
David Brown43cda332017-09-01 09:53:23 -060091 flags: 0,
Fabio Utzig754438d2018-12-14 06:39:58 -020092 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048],
93 size: 4 + 32 + 4 + 32 + 4 + 256,
David Brown7e701d82017-07-11 13:24:25 -060094 payload: vec![],
95 }
96 }
97
Fabio Utzig80fde2f2017-12-05 09:25:31 -020098 #[allow(dead_code)]
Fabio Utzig39297432019-05-08 18:51:10 -030099 pub fn new_rsa3072_pss() -> TlvGen {
100 TlvGen {
101 flags: 0,
102 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA3072],
103 size: 4 + 32 + 4 + 32 + 4 + 384,
104 payload: vec![],
105 }
106 }
107
108 #[allow(dead_code)]
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200109 pub fn new_ecdsa() -> TlvGen {
110 TlvGen {
111 flags: 0,
Fabio Utzig754438d2018-12-14 06:39:58 -0200112 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256],
113 size: 4 + 32 + 4 + 32 + 4 + 72,
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200114 payload: vec![],
115 }
116 }
117
Fabio Utzig1e48b912018-09-18 09:04:18 -0300118 #[allow(dead_code)]
Fabio Utzig97710282019-05-24 17:44:49 -0300119 pub fn new_ed25519() -> TlvGen {
120 TlvGen {
121 flags: 0,
122 kinds: vec![TlvKinds::SHA256, TlvKinds::ED25519],
123 size: 4 + 32 + 4 + 32 + 4 + 64,
124 payload: vec![],
125 }
126 }
127
128 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300129 pub fn new_enc_rsa() -> TlvGen {
130 TlvGen {
131 flags: TlvFlags::ENCRYPTED as u32,
132 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
133 size: 4 + 32 + 4 + 256,
134 payload: vec![],
135 }
136 }
137
138 #[allow(dead_code)]
Fabio Utzig754438d2018-12-14 06:39:58 -0200139 pub fn new_sig_enc_rsa() -> TlvGen {
140 TlvGen {
141 flags: TlvFlags::ENCRYPTED as u32,
142 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCRSA2048],
143 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 256,
144 payload: vec![],
145 }
146 }
147
148 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300149 pub fn new_enc_kw() -> TlvGen {
150 TlvGen {
151 flags: TlvFlags::ENCRYPTED as u32,
152 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW128],
153 size: 4 + 32 + 4 + 24,
154 payload: vec![],
155 }
156 }
157
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200158 #[allow(dead_code)]
159 pub fn new_rsa_kw() -> TlvGen {
160 TlvGen {
161 flags: TlvFlags::ENCRYPTED as u32,
162 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCKW128],
163 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 24,
164 payload: vec![],
165 }
166 }
167
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200168 #[allow(dead_code)]
169 pub fn new_ecdsa_kw() -> TlvGen {
170 TlvGen {
171 flags: TlvFlags::ENCRYPTED as u32,
172 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCKW128],
173 size: 4 + 32 + 4 + 32 + 4 + 72 + 4 + 24,
174 payload: vec![],
175 }
176 }
177
David Brown187dd882017-07-11 11:15:23 -0600178 /// Retrieve the size that the TLV will occupy. This can be called at any time.
179 pub fn get_size(&self) -> u16 {
David Brownf5b33d82017-09-01 10:58:27 -0600180 4 + self.size
David Brown187dd882017-07-11 11:15:23 -0600181 }
David Brown43643dd2019-01-11 15:43:28 -0700182}
183
184impl ManifestGen for TlvGen {
David Brownac46e262019-01-11 15:46:18 -0700185 fn get_magic(&self) -> u32 {
186 0x96f3b83d
187 }
188
David Brown43643dd2019-01-11 15:43:28 -0700189 /// Retrieve the header flags for this configuration. This can be called at any time.
190 fn get_flags(&self) -> u32 {
191 self.flags
192 }
David Brown187dd882017-07-11 11:15:23 -0600193
194 /// Add bytes to the covered hash.
David Brown43643dd2019-01-11 15:43:28 -0700195 fn add_bytes(&mut self, bytes: &[u8]) {
David Brown4243ab02017-07-11 12:24:23 -0600196 self.payload.extend_from_slice(bytes);
David Brown187dd882017-07-11 11:15:23 -0600197 }
198
199 /// Compute the TLV given the specified block of data.
David Brown43643dd2019-01-11 15:43:28 -0700200 fn make_tlv(self: Box<Self>) -> Vec<u8> {
David Brown187dd882017-07-11 11:15:23 -0600201 let mut result: Vec<u8> = vec![];
202
David Brownf5b33d82017-09-01 10:58:27 -0600203 let size = self.get_size();
204 result.push(0x07);
205 result.push(0x69);
David Brown91d68632019-07-29 14:32:13 -0600206 result.write_u16::<LittleEndian>(size).unwrap();
David Brownf5b33d82017-09-01 10:58:27 -0600207
David Brown187dd882017-07-11 11:15:23 -0600208 if self.kinds.contains(&TlvKinds::SHA256) {
David Brown4243ab02017-07-11 12:24:23 -0600209 let hash = digest::digest(&digest::SHA256, &self.payload);
David Brown8054ce22017-07-11 12:12:09 -0600210 let hash = hash.as_ref();
David Brown187dd882017-07-11 11:15:23 -0600211
David Brown8054ce22017-07-11 12:12:09 -0600212 assert!(hash.len() == 32);
David Brown187dd882017-07-11 11:15:23 -0600213 result.push(TlvKinds::SHA256 as u8);
214 result.push(0);
215 result.push(32);
216 result.push(0);
David Brown8054ce22017-07-11 12:12:09 -0600217 result.extend_from_slice(hash);
David Brown187dd882017-07-11 11:15:23 -0600218 }
219
Fabio Utzig39297432019-05-08 18:51:10 -0300220 if self.kinds.contains(&TlvKinds::RSA2048) ||
221 self.kinds.contains(&TlvKinds::RSA3072) {
222
223 let is_rsa2048 = self.kinds.contains(&TlvKinds::RSA2048);
224
David Brown43cda332017-09-01 09:53:23 -0600225 // Output the hash of the public key.
Fabio Utzig39297432019-05-08 18:51:10 -0300226 let hash = if is_rsa2048 {
227 digest::digest(&digest::SHA256, RSA_PUB_KEY)
228 } else {
229 digest::digest(&digest::SHA256, RSA3072_PUB_KEY)
230 };
David Brown43cda332017-09-01 09:53:23 -0600231 let hash = hash.as_ref();
232
233 assert!(hash.len() == 32);
234 result.push(TlvKinds::KEYHASH as u8);
235 result.push(0);
236 result.push(32);
237 result.push(0);
238 result.extend_from_slice(hash);
239
David Brown7e701d82017-07-11 13:24:25 -0600240 // For now assume PSS.
Fabio Utzig39297432019-05-08 18:51:10 -0300241 let key_bytes = if is_rsa2048 {
242 pem::parse(include_bytes!("../../root-rsa-2048.pem").as_ref()).unwrap()
243 } else {
244 pem::parse(include_bytes!("../../root-rsa-3072.pem").as_ref()).unwrap()
245 };
David Brown7e701d82017-07-11 13:24:25 -0600246 assert_eq!(key_bytes.tag, "RSA PRIVATE KEY");
247 let key_bytes = untrusted::Input::from(&key_bytes.contents);
Fabio Utzig05ab0142018-07-10 09:15:28 -0300248 let key_pair = RsaKeyPair::from_der(key_bytes).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600249 let rng = rand::SystemRandom::new();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300250 let mut signature = vec![0; key_pair.public_modulus_len()];
Fabio Utzig39297432019-05-08 18:51:10 -0300251 if is_rsa2048 {
252 assert_eq!(signature.len(), 256);
253 } else {
254 assert_eq!(signature.len(), 384);
255 }
Fabio Utzig05ab0142018-07-10 09:15:28 -0300256 key_pair.sign(&RSA_PSS_SHA256, &rng, &self.payload, &mut signature).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600257
Fabio Utzig39297432019-05-08 18:51:10 -0300258 if is_rsa2048 {
259 result.push(TlvKinds::RSA2048 as u8);
260 } else {
261 result.push(TlvKinds::RSA3072 as u8);
262 }
David Brown7e701d82017-07-11 13:24:25 -0600263 result.push(0);
David Brown91d68632019-07-29 14:32:13 -0600264 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600265 result.extend_from_slice(&signature);
266 }
267
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200268 if self.kinds.contains(&TlvKinds::ECDSA256) {
269 let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY);
270 let keyhash = keyhash.as_ref();
271
272 assert!(keyhash.len() == 32);
273 result.push(TlvKinds::KEYHASH as u8);
274 result.push(0);
275 result.push(32);
276 result.push(0);
277 result.extend_from_slice(keyhash);
278
Fabio Utzig05ab0142018-07-10 09:15:28 -0300279 let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap();
280 assert_eq!(key_bytes.tag, "PRIVATE KEY");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200281
Fabio Utzig05ab0142018-07-10 09:15:28 -0300282 let key_bytes = untrusted::Input::from(&key_bytes.contents);
283 let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING,
284 key_bytes).unwrap();
285 let rng = rand::SystemRandom::new();
286 let payload = untrusted::Input::from(&self.payload);
287 let signature = key_pair.sign(&rng, payload).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200288
289 result.push(TlvKinds::ECDSA256 as u8);
290 result.push(0);
Fabio Utzig05ab0142018-07-10 09:15:28 -0300291
292 // signature must be padded...
293 let mut signature = signature.as_ref().to_vec();
294 while signature.len() < 72 {
295 signature.push(0);
296 signature[1] += 1;
297 }
298
David Brown91d68632019-07-29 14:32:13 -0600299 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300300 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();
David Brown91d68632019-07-29 14:32:13 -0600330 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300331 result.extend_from_slice(signature.as_ref());
332 }
333
Fabio Utzig1e48b912018-09-18 09:04:18 -0300334 if self.kinds.contains(&TlvKinds::ENCRSA2048) {
335 let key_bytes = pem::parse(include_bytes!("../../enc-rsa2048-pub.pem")
336 .as_ref()).unwrap();
337 assert_eq!(key_bytes.tag, "PUBLIC KEY");
338
339 let encbuf = match c::rsa_oaep_encrypt(&key_bytes.contents, AES_SEC_KEY) {
340 Ok(v) => v,
341 Err(_) => panic!("Failed to encrypt secret key"),
342 };
343
344 assert!(encbuf.len() == 256);
345 result.push(TlvKinds::ENCRSA2048 as u8);
346 result.push(0);
347 result.push(0);
348 result.push(1);
349 result.extend_from_slice(&encbuf);
350 }
351
352 if self.kinds.contains(&TlvKinds::ENCKW128) {
353 let key_bytes = base64::decode(
354 include_str!("../../enc-aes128kw.b64").trim()).unwrap();
355
356 let encbuf = match c::kw_encrypt(&key_bytes, AES_SEC_KEY) {
357 Ok(v) => v,
358 Err(_) => panic!("Failed to encrypt secret key"),
359 };
360
361 assert!(encbuf.len() == 24);
362 result.push(TlvKinds::ENCKW128 as u8);
363 result.push(0);
364 result.push(24);
365 result.push(0);
366 result.extend_from_slice(&encbuf);
367 }
368
David Brown187dd882017-07-11 11:15:23 -0600369 result
370 }
371}
David Brown43cda332017-09-01 09:53:23 -0600372
373include!("rsa_pub_key-rs.txt");
Fabio Utzig39297432019-05-08 18:51:10 -0300374include!("rsa3072_pub_key-rs.txt");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200375include!("ecdsa_pub_key-rs.txt");
Fabio Utzig97710282019-05-24 17:44:49 -0300376include!("ed25519_pub_key-rs.txt");