blob: afc34aac60cb6e65828f3fc048cb1b1266e943f1 [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 std::sync::Arc;
12use pem;
Fabio Utzig1e48b912018-09-18 09:04:18 -030013use base64;
David Brown7e701d82017-07-11 13:24:25 -060014use ring::{digest, rand, signature};
15use untrusted;
Fabio Utzig80fde2f2017-12-05 09:25:31 -020016use mcuboot_sys::c;
David Brown187dd882017-07-11 11:15:23 -060017
David Brown187dd882017-07-11 11:15:23 -060018#[repr(u8)]
19#[derive(Copy, Clone, PartialEq, Eq)]
20#[allow(dead_code)] // TODO: For now
21pub enum TlvKinds {
David Brown43cda332017-09-01 09:53:23 -060022 KEYHASH = 0x01,
David Brown27648b82017-08-31 10:40:29 -060023 SHA256 = 0x10,
24 RSA2048 = 0x20,
25 ECDSA224 = 0x21,
26 ECDSA256 = 0x22,
Fabio Utzig1e48b912018-09-18 09:04:18 -030027 ENCRSA2048 = 0x30,
28 ENCKW128 = 0x31,
29}
30
31#[allow(dead_code, non_camel_case_types)]
32pub enum TlvFlags {
33 PIC = 0x01,
34 NON_BOOTABLE = 0x02,
35 ENCRYPTED = 0x04,
36 RAM_LOAD = 0x20,
David Brown187dd882017-07-11 11:15:23 -060037}
38
39pub struct TlvGen {
David Brown43cda332017-09-01 09:53:23 -060040 flags: u32,
David Brown187dd882017-07-11 11:15:23 -060041 kinds: Vec<TlvKinds>,
42 size: u16,
David Brown4243ab02017-07-11 12:24:23 -060043 payload: Vec<u8>,
David Brown187dd882017-07-11 11:15:23 -060044}
45
Fabio Utzig1e48b912018-09-18 09:04:18 -030046pub const AES_SEC_KEY: &[u8; 16] = b"0123456789ABCDEF";
47
David Brown187dd882017-07-11 11:15:23 -060048impl TlvGen {
49 /// Construct a new tlv generator that will only contain a hash of the data.
David Brown7e701d82017-07-11 13:24:25 -060050 #[allow(dead_code)]
David Brown187dd882017-07-11 11:15:23 -060051 pub fn new_hash_only() -> TlvGen {
52 TlvGen {
David Brown43cda332017-09-01 09:53:23 -060053 flags: 0,
David Brown187dd882017-07-11 11:15:23 -060054 kinds: vec![TlvKinds::SHA256],
55 size: 4 + 32,
David Brown4243ab02017-07-11 12:24:23 -060056 payload: vec![],
David Brown187dd882017-07-11 11:15:23 -060057 }
58 }
59
David Brown7e701d82017-07-11 13:24:25 -060060 #[allow(dead_code)]
61 pub fn new_rsa_pss() -> TlvGen {
62 TlvGen {
David Brown43cda332017-09-01 09:53:23 -060063 flags: 0,
Fabio Utzig754438d2018-12-14 06:39:58 -020064 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048],
65 size: 4 + 32 + 4 + 32 + 4 + 256,
David Brown7e701d82017-07-11 13:24:25 -060066 payload: vec![],
67 }
68 }
69
Fabio Utzig80fde2f2017-12-05 09:25:31 -020070 #[allow(dead_code)]
71 pub fn new_ecdsa() -> TlvGen {
72 TlvGen {
73 flags: 0,
Fabio Utzig754438d2018-12-14 06:39:58 -020074 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256],
75 size: 4 + 32 + 4 + 32 + 4 + 72,
Fabio Utzig80fde2f2017-12-05 09:25:31 -020076 payload: vec![],
77 }
78 }
79
Fabio Utzig1e48b912018-09-18 09:04:18 -030080 #[allow(dead_code)]
81 pub fn new_enc_rsa() -> TlvGen {
82 TlvGen {
83 flags: TlvFlags::ENCRYPTED as u32,
84 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
85 size: 4 + 32 + 4 + 256,
86 payload: vec![],
87 }
88 }
89
90 #[allow(dead_code)]
Fabio Utzig754438d2018-12-14 06:39:58 -020091 pub fn new_sig_enc_rsa() -> TlvGen {
92 TlvGen {
93 flags: TlvFlags::ENCRYPTED as u32,
94 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCRSA2048],
95 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 256,
96 payload: vec![],
97 }
98 }
99
100 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300101 pub fn new_enc_kw() -> TlvGen {
102 TlvGen {
103 flags: TlvFlags::ENCRYPTED as u32,
104 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW128],
105 size: 4 + 32 + 4 + 24,
106 payload: vec![],
107 }
108 }
109
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200110 #[allow(dead_code)]
111 pub fn new_rsa_kw() -> TlvGen {
112 TlvGen {
113 flags: TlvFlags::ENCRYPTED as u32,
114 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCKW128],
115 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 24,
116 payload: vec![],
117 }
118 }
119
David Brown187dd882017-07-11 11:15:23 -0600120 /// Retrieve the header flags for this configuration. This can be called at any time.
121 pub fn get_flags(&self) -> u32 {
David Brown43cda332017-09-01 09:53:23 -0600122 self.flags
David Brown187dd882017-07-11 11:15:23 -0600123 }
124
125 /// Retrieve the size that the TLV will occupy. This can be called at any time.
126 pub fn get_size(&self) -> u16 {
David Brownf5b33d82017-09-01 10:58:27 -0600127 4 + self.size
David Brown187dd882017-07-11 11:15:23 -0600128 }
129
130 /// Add bytes to the covered hash.
131 pub fn add_bytes(&mut self, bytes: &[u8]) {
David Brown4243ab02017-07-11 12:24:23 -0600132 self.payload.extend_from_slice(bytes);
David Brown187dd882017-07-11 11:15:23 -0600133 }
134
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200135 /// Create a DER representation of one ec curve point
136 fn _make_der_int(&self, x: &[u8]) -> Vec<u8> {
137 assert!(x.len() == 32);
138
139 let mut i: Vec<u8> = vec![0x02];
140 if x[0] >= 0x7f {
141 i.push(33);
142 i.push(0);
143 } else {
144 i.push(32);
145 }
146 i.extend(x);
147 i
148 }
149
150 /// Create an ecdsa256 TLV
151 fn _make_der_sequence(&self, r: Vec<u8>, s: Vec<u8>) -> Vec<u8> {
152 let mut der: Vec<u8> = vec![0x30];
153 der.push(r.len() as u8 + s.len() as u8);
154 der.extend(r);
155 der.extend(s);
156 let mut size = der.len();
157 // must pad up to 72 bytes...
158 while size <= 72 {
159 der.push(0);
160 der[1] += 1;
161 size += 1;
162 }
163 der
164 }
165
David Brown187dd882017-07-11 11:15:23 -0600166 /// Compute the TLV given the specified block of data.
David Brown8054ce22017-07-11 12:12:09 -0600167 pub fn make_tlv(self) -> Vec<u8> {
David Brown187dd882017-07-11 11:15:23 -0600168 let mut result: Vec<u8> = vec![];
169
David Brownf5b33d82017-09-01 10:58:27 -0600170 let size = self.get_size();
171 result.push(0x07);
172 result.push(0x69);
173 result.push((size & 0xFF) as u8);
174 result.push(((size >> 8) & 0xFF) as u8);
175
David Brown187dd882017-07-11 11:15:23 -0600176 if self.kinds.contains(&TlvKinds::SHA256) {
David Brown4243ab02017-07-11 12:24:23 -0600177 let hash = digest::digest(&digest::SHA256, &self.payload);
David Brown8054ce22017-07-11 12:12:09 -0600178 let hash = hash.as_ref();
David Brown187dd882017-07-11 11:15:23 -0600179
David Brown8054ce22017-07-11 12:12:09 -0600180 assert!(hash.len() == 32);
David Brown187dd882017-07-11 11:15:23 -0600181 result.push(TlvKinds::SHA256 as u8);
182 result.push(0);
183 result.push(32);
184 result.push(0);
David Brown8054ce22017-07-11 12:12:09 -0600185 result.extend_from_slice(hash);
David Brown187dd882017-07-11 11:15:23 -0600186 }
187
David Brown7e701d82017-07-11 13:24:25 -0600188 if self.kinds.contains(&TlvKinds::RSA2048) {
David Brown43cda332017-09-01 09:53:23 -0600189 // Output the hash of the public key.
190 let hash = digest::digest(&digest::SHA256, RSA_PUB_KEY);
191 let hash = hash.as_ref();
192
193 assert!(hash.len() == 32);
194 result.push(TlvKinds::KEYHASH as u8);
195 result.push(0);
196 result.push(32);
197 result.push(0);
198 result.extend_from_slice(hash);
199
David Brown7e701d82017-07-11 13:24:25 -0600200 // For now assume PSS.
201 let key_bytes = pem::parse(include_bytes!("../../root-rsa-2048.pem").as_ref()).unwrap();
202 assert_eq!(key_bytes.tag, "RSA PRIVATE KEY");
203 let key_bytes = untrusted::Input::from(&key_bytes.contents);
204 let key = signature::RSAKeyPair::from_der(key_bytes).unwrap();
205 let mut signer = signature::RSASigningState::new(Arc::new(key)).unwrap();
206 let rng = rand::SystemRandom::new();
207 let mut signature = vec![0; signer.key_pair().public_modulus_len()];
208 assert_eq!(signature.len(), 256);
209 signer.sign(&signature::RSA_PSS_SHA256, &rng, &self.payload, &mut signature).unwrap();
210
211 result.push(TlvKinds::RSA2048 as u8);
212 result.push(0);
213 result.push((signature.len() & 0xFF) as u8);
214 result.push(((signature.len() >> 8) & 0xFF) as u8);
215 result.extend_from_slice(&signature);
216 }
217
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200218 if self.kinds.contains(&TlvKinds::ECDSA256) {
219 let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY);
220 let keyhash = keyhash.as_ref();
221
222 assert!(keyhash.len() == 32);
223 result.push(TlvKinds::KEYHASH as u8);
224 result.push(0);
225 result.push(32);
226 result.push(0);
227 result.extend_from_slice(keyhash);
228
229 let key_bytes = pem::parse(include_bytes!("../../root-ec-p256.pem").as_ref()).unwrap();
230 assert_eq!(key_bytes.tag, "EC PRIVATE KEY");
231
232 let hash = digest::digest(&digest::SHA256, &self.payload);
233 let hash = hash.as_ref();
234 assert!(hash.len() == 32);
235
236 /* FIXME
237 *
238 * Although `ring` has an ASN1 parser, it hides access
239 * to its low-level data, which was designed to be used
240 * by its internal signing/verifying functions. Since it does
241 * not yet support ecdsa signing, for the time being I am
242 * manually loading the key from its index in the PEM and
243 * building the TLV DER manually.
244 *
245 * Once ring gets ecdsa signing (hopefully soon!) this code
246 * should be updated to leverage its functionality...
247 */
248
249 /* Load key directly from PEM */
250 let key = &key_bytes.contents[7..39];
251
252 let signature = match c::ecdsa256_sign(&key, &hash) {
253 Ok(sign) => sign,
254 Err(_) => panic!("Failed signature generation"),
255 };
256
257 let r = self._make_der_int(&signature.to_vec()[..32]);
258 let s = self._make_der_int(&signature.to_vec()[32..64]);
259 let der = self._make_der_sequence(r, s);
260
261 result.push(TlvKinds::ECDSA256 as u8);
262 result.push(0);
263 result.push(der.len() as u8);
264 result.push(0);
265 result.extend(der);
266 }
267
Fabio Utzig1e48b912018-09-18 09:04:18 -0300268 if self.kinds.contains(&TlvKinds::ENCRSA2048) {
269 let key_bytes = pem::parse(include_bytes!("../../enc-rsa2048-pub.pem")
270 .as_ref()).unwrap();
271 assert_eq!(key_bytes.tag, "PUBLIC KEY");
272
273 let encbuf = match c::rsa_oaep_encrypt(&key_bytes.contents, AES_SEC_KEY) {
274 Ok(v) => v,
275 Err(_) => panic!("Failed to encrypt secret key"),
276 };
277
278 assert!(encbuf.len() == 256);
279 result.push(TlvKinds::ENCRSA2048 as u8);
280 result.push(0);
281 result.push(0);
282 result.push(1);
283 result.extend_from_slice(&encbuf);
284 }
285
286 if self.kinds.contains(&TlvKinds::ENCKW128) {
287 let key_bytes = base64::decode(
288 include_str!("../../enc-aes128kw.b64").trim()).unwrap();
289
290 let encbuf = match c::kw_encrypt(&key_bytes, AES_SEC_KEY) {
291 Ok(v) => v,
292 Err(_) => panic!("Failed to encrypt secret key"),
293 };
294
295 assert!(encbuf.len() == 24);
296 result.push(TlvKinds::ENCKW128 as u8);
297 result.push(0);
298 result.push(24);
299 result.push(0);
300 result.extend_from_slice(&encbuf);
301 }
302
David Brown187dd882017-07-11 11:15:23 -0600303 result
304 }
305}
David Brown43cda332017-09-01 09:53:23 -0600306
307include!("rsa_pub_key-rs.txt");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200308include!("ecdsa_pub_key-rs.txt");