blob: aa0d7f0b9de3acc9e63a452f7892025078d6c77e [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
David Brown43643dd2019-01-11 15:43:28 -070044/// A generator for manifests. The format of the manifest can be either a
45/// traditional "TLV" or a SUIT-style manifest.
46pub trait ManifestGen {
David Brownac46e262019-01-11 15:46:18 -070047 /// Retrieve the header magic value for this manifest type.
48 fn get_magic(&self) -> u32;
49
David Brown43643dd2019-01-11 15:43:28 -070050 /// Retrieve the flags value for this particular manifest type.
51 fn get_flags(&self) -> u32;
52
53 /// Add a sequence of bytes to the payload that the manifest is
54 /// protecting.
55 fn add_bytes(&mut self, bytes: &[u8]);
56
57 /// Construct the manifest for this payload.
58 fn make_tlv(self: Box<Self>) -> Vec<u8>;
59}
60
David Brown187dd882017-07-11 11:15:23 -060061pub struct TlvGen {
David Brown43cda332017-09-01 09:53:23 -060062 flags: u32,
David Brown187dd882017-07-11 11:15:23 -060063 kinds: Vec<TlvKinds>,
64 size: u16,
David Brown4243ab02017-07-11 12:24:23 -060065 payload: Vec<u8>,
David Brown187dd882017-07-11 11:15:23 -060066}
67
Fabio Utzig1e48b912018-09-18 09:04:18 -030068pub const AES_SEC_KEY: &[u8; 16] = b"0123456789ABCDEF";
69
David Brown187dd882017-07-11 11:15:23 -060070impl TlvGen {
71 /// Construct a new tlv generator that will only contain a hash of the data.
David Brown7e701d82017-07-11 13:24:25 -060072 #[allow(dead_code)]
David Brown187dd882017-07-11 11:15:23 -060073 pub fn new_hash_only() -> TlvGen {
74 TlvGen {
David Brown43cda332017-09-01 09:53:23 -060075 flags: 0,
David Brown187dd882017-07-11 11:15:23 -060076 kinds: vec![TlvKinds::SHA256],
77 size: 4 + 32,
David Brown4243ab02017-07-11 12:24:23 -060078 payload: vec![],
David Brown187dd882017-07-11 11:15:23 -060079 }
80 }
81
David Brown7e701d82017-07-11 13:24:25 -060082 #[allow(dead_code)]
83 pub fn new_rsa_pss() -> TlvGen {
84 TlvGen {
David Brown43cda332017-09-01 09:53:23 -060085 flags: 0,
Fabio Utzig754438d2018-12-14 06:39:58 -020086 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048],
87 size: 4 + 32 + 4 + 32 + 4 + 256,
David Brown7e701d82017-07-11 13:24:25 -060088 payload: vec![],
89 }
90 }
91
Fabio Utzig80fde2f2017-12-05 09:25:31 -020092 #[allow(dead_code)]
93 pub fn new_ecdsa() -> TlvGen {
94 TlvGen {
95 flags: 0,
Fabio Utzig754438d2018-12-14 06:39:58 -020096 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256],
97 size: 4 + 32 + 4 + 32 + 4 + 72,
Fabio Utzig80fde2f2017-12-05 09:25:31 -020098 payload: vec![],
99 }
100 }
101
Fabio Utzig1e48b912018-09-18 09:04:18 -0300102 #[allow(dead_code)]
103 pub fn new_enc_rsa() -> TlvGen {
104 TlvGen {
105 flags: TlvFlags::ENCRYPTED as u32,
106 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
107 size: 4 + 32 + 4 + 256,
108 payload: vec![],
109 }
110 }
111
112 #[allow(dead_code)]
Fabio Utzig754438d2018-12-14 06:39:58 -0200113 pub fn new_sig_enc_rsa() -> TlvGen {
114 TlvGen {
115 flags: TlvFlags::ENCRYPTED as u32,
116 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCRSA2048],
117 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 256,
118 payload: vec![],
119 }
120 }
121
122 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300123 pub fn new_enc_kw() -> TlvGen {
124 TlvGen {
125 flags: TlvFlags::ENCRYPTED as u32,
126 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW128],
127 size: 4 + 32 + 4 + 24,
128 payload: vec![],
129 }
130 }
131
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200132 #[allow(dead_code)]
133 pub fn new_rsa_kw() -> TlvGen {
134 TlvGen {
135 flags: TlvFlags::ENCRYPTED as u32,
136 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCKW128],
137 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 24,
138 payload: vec![],
139 }
140 }
141
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200142 #[allow(dead_code)]
143 pub fn new_ecdsa_kw() -> TlvGen {
144 TlvGen {
145 flags: TlvFlags::ENCRYPTED as u32,
146 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCKW128],
147 size: 4 + 32 + 4 + 32 + 4 + 72 + 4 + 24,
148 payload: vec![],
149 }
150 }
151
David Brown187dd882017-07-11 11:15:23 -0600152 /// Retrieve the size that the TLV will occupy. This can be called at any time.
153 pub fn get_size(&self) -> u16 {
David Brownf5b33d82017-09-01 10:58:27 -0600154 4 + self.size
David Brown187dd882017-07-11 11:15:23 -0600155 }
David Brown43643dd2019-01-11 15:43:28 -0700156}
157
158impl ManifestGen for TlvGen {
David Brownac46e262019-01-11 15:46:18 -0700159 fn get_magic(&self) -> u32 {
160 0x96f3b83d
161 }
162
David Brown43643dd2019-01-11 15:43:28 -0700163 /// Retrieve the header flags for this configuration. This can be called at any time.
164 fn get_flags(&self) -> u32 {
165 self.flags
166 }
David Brown187dd882017-07-11 11:15:23 -0600167
168 /// Add bytes to the covered hash.
David Brown43643dd2019-01-11 15:43:28 -0700169 fn add_bytes(&mut self, bytes: &[u8]) {
David Brown4243ab02017-07-11 12:24:23 -0600170 self.payload.extend_from_slice(bytes);
David Brown187dd882017-07-11 11:15:23 -0600171 }
172
173 /// Compute the TLV given the specified block of data.
David Brown43643dd2019-01-11 15:43:28 -0700174 fn make_tlv(self: Box<Self>) -> Vec<u8> {
David Brown187dd882017-07-11 11:15:23 -0600175 let mut result: Vec<u8> = vec![];
176
David Brownf5b33d82017-09-01 10:58:27 -0600177 let size = self.get_size();
178 result.push(0x07);
179 result.push(0x69);
180 result.push((size & 0xFF) as u8);
181 result.push(((size >> 8) & 0xFF) as u8);
182
David Brown187dd882017-07-11 11:15:23 -0600183 if self.kinds.contains(&TlvKinds::SHA256) {
David Brown4243ab02017-07-11 12:24:23 -0600184 let hash = digest::digest(&digest::SHA256, &self.payload);
David Brown8054ce22017-07-11 12:12:09 -0600185 let hash = hash.as_ref();
David Brown187dd882017-07-11 11:15:23 -0600186
David Brown8054ce22017-07-11 12:12:09 -0600187 assert!(hash.len() == 32);
David Brown187dd882017-07-11 11:15:23 -0600188 result.push(TlvKinds::SHA256 as u8);
189 result.push(0);
190 result.push(32);
191 result.push(0);
David Brown8054ce22017-07-11 12:12:09 -0600192 result.extend_from_slice(hash);
David Brown187dd882017-07-11 11:15:23 -0600193 }
194
David Brown7e701d82017-07-11 13:24:25 -0600195 if self.kinds.contains(&TlvKinds::RSA2048) {
David Brown43cda332017-09-01 09:53:23 -0600196 // Output the hash of the public key.
197 let hash = digest::digest(&digest::SHA256, RSA_PUB_KEY);
198 let hash = hash.as_ref();
199
200 assert!(hash.len() == 32);
201 result.push(TlvKinds::KEYHASH as u8);
202 result.push(0);
203 result.push(32);
204 result.push(0);
205 result.extend_from_slice(hash);
206
David Brown7e701d82017-07-11 13:24:25 -0600207 // For now assume PSS.
208 let key_bytes = pem::parse(include_bytes!("../../root-rsa-2048.pem").as_ref()).unwrap();
209 assert_eq!(key_bytes.tag, "RSA PRIVATE KEY");
210 let key_bytes = untrusted::Input::from(&key_bytes.contents);
Fabio Utzig05ab0142018-07-10 09:15:28 -0300211 let key_pair = RsaKeyPair::from_der(key_bytes).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600212 let rng = rand::SystemRandom::new();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300213 let mut signature = vec![0; key_pair.public_modulus_len()];
David Brown7e701d82017-07-11 13:24:25 -0600214 assert_eq!(signature.len(), 256);
Fabio Utzig05ab0142018-07-10 09:15:28 -0300215 key_pair.sign(&RSA_PSS_SHA256, &rng, &self.payload, &mut signature).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600216
217 result.push(TlvKinds::RSA2048 as u8);
218 result.push(0);
219 result.push((signature.len() & 0xFF) as u8);
220 result.push(((signature.len() >> 8) & 0xFF) as u8);
221 result.extend_from_slice(&signature);
222 }
223
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200224 if self.kinds.contains(&TlvKinds::ECDSA256) {
225 let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY);
226 let keyhash = keyhash.as_ref();
227
228 assert!(keyhash.len() == 32);
229 result.push(TlvKinds::KEYHASH as u8);
230 result.push(0);
231 result.push(32);
232 result.push(0);
233 result.extend_from_slice(keyhash);
234
Fabio Utzig05ab0142018-07-10 09:15:28 -0300235 let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap();
236 assert_eq!(key_bytes.tag, "PRIVATE KEY");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200237
Fabio Utzig05ab0142018-07-10 09:15:28 -0300238 let key_bytes = untrusted::Input::from(&key_bytes.contents);
239 let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING,
240 key_bytes).unwrap();
241 let rng = rand::SystemRandom::new();
242 let payload = untrusted::Input::from(&self.payload);
243 let signature = key_pair.sign(&rng, payload).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200244
245 result.push(TlvKinds::ECDSA256 as u8);
246 result.push(0);
Fabio Utzig05ab0142018-07-10 09:15:28 -0300247
248 // signature must be padded...
249 let mut signature = signature.as_ref().to_vec();
250 while signature.len() < 72 {
251 signature.push(0);
252 signature[1] += 1;
253 }
254
255 result.push((signature.len() & 0xFF) as u8);
256 result.push(((signature.len() >> 8) & 0xFF) as u8);
257 result.extend_from_slice(signature.as_ref());
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200258 }
259
Fabio Utzig1e48b912018-09-18 09:04:18 -0300260 if self.kinds.contains(&TlvKinds::ENCRSA2048) {
261 let key_bytes = pem::parse(include_bytes!("../../enc-rsa2048-pub.pem")
262 .as_ref()).unwrap();
263 assert_eq!(key_bytes.tag, "PUBLIC KEY");
264
265 let encbuf = match c::rsa_oaep_encrypt(&key_bytes.contents, AES_SEC_KEY) {
266 Ok(v) => v,
267 Err(_) => panic!("Failed to encrypt secret key"),
268 };
269
270 assert!(encbuf.len() == 256);
271 result.push(TlvKinds::ENCRSA2048 as u8);
272 result.push(0);
273 result.push(0);
274 result.push(1);
275 result.extend_from_slice(&encbuf);
276 }
277
278 if self.kinds.contains(&TlvKinds::ENCKW128) {
279 let key_bytes = base64::decode(
280 include_str!("../../enc-aes128kw.b64").trim()).unwrap();
281
282 let encbuf = match c::kw_encrypt(&key_bytes, AES_SEC_KEY) {
283 Ok(v) => v,
284 Err(_) => panic!("Failed to encrypt secret key"),
285 };
286
287 assert!(encbuf.len() == 24);
288 result.push(TlvKinds::ENCKW128 as u8);
289 result.push(0);
290 result.push(24);
291 result.push(0);
292 result.extend_from_slice(&encbuf);
293 }
294
David Brown187dd882017-07-11 11:15:23 -0600295 result
296 }
297}
David Brown43cda332017-09-01 09:53:23 -0600298
299include!("rsa_pub_key-rs.txt");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200300include!("ecdsa_pub_key-rs.txt");