blob: ad53c2724b5f775d75eff427f5f1ba71cbf1afb4 [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 Brown7a81c4b2019-07-29 15:20:21 -060014use crate::image::ImageVersion;
David Brown7e701d82017-07-11 13:24:25 -060015use pem;
Fabio Utzig1e48b912018-09-18 09:04:18 -030016use base64;
Fabio Utzige84f0ef2019-11-22 12:29:32 -030017use log::info;
Fabio Utzig90f449e2019-10-24 07:43:53 -030018use ring::{digest, rand, agreement, hkdf, hmac};
Fabio Utzige84f0ef2019-11-22 12:29:32 -030019use ring::rand::SecureRandom;
Fabio Utzig05ab0142018-07-10 09:15:28 -030020use ring::signature::{
21 RsaKeyPair,
22 RSA_PSS_SHA256,
23 EcdsaKeyPair,
24 ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig97710282019-05-24 17:44:49 -030025 Ed25519KeyPair,
Fabio Utzig05ab0142018-07-10 09:15:28 -030026};
Fabio Utzig90f449e2019-10-24 07:43:53 -030027use aes_ctr::{
28 Aes128Ctr,
29 stream_cipher::{
30 generic_array::GenericArray,
31 NewFixStreamCipher,
32 StreamCipherCore,
33 },
34};
Fabio Utzig80fde2f2017-12-05 09:25:31 -020035use mcuboot_sys::c;
David Brown187dd882017-07-11 11:15:23 -060036
David Brown69721182019-12-04 14:50:52 -070037#[repr(u16)]
David Brownc3898d62019-08-05 14:20:02 -060038#[derive(Copy, Clone, Debug, PartialEq, Eq)]
David Brown187dd882017-07-11 11:15:23 -060039#[allow(dead_code)] // TODO: For now
40pub enum TlvKinds {
David Brown43cda332017-09-01 09:53:23 -060041 KEYHASH = 0x01,
David Brown27648b82017-08-31 10:40:29 -060042 SHA256 = 0x10,
43 RSA2048 = 0x20,
44 ECDSA224 = 0x21,
45 ECDSA256 = 0x22,
Fabio Utzig39297432019-05-08 18:51:10 -030046 RSA3072 = 0x23,
Fabio Utzig97710282019-05-24 17:44:49 -030047 ED25519 = 0x24,
Fabio Utzig1e48b912018-09-18 09:04:18 -030048 ENCRSA2048 = 0x30,
49 ENCKW128 = 0x31,
Fabio Utzig90f449e2019-10-24 07:43:53 -030050 ENCEC256 = 0x32,
David Brown7a81c4b2019-07-29 15:20:21 -060051 DEPENDENCY = 0x40,
Fabio Utzig1e48b912018-09-18 09:04:18 -030052}
53
54#[allow(dead_code, non_camel_case_types)]
55pub enum TlvFlags {
56 PIC = 0x01,
57 NON_BOOTABLE = 0x02,
58 ENCRYPTED = 0x04,
59 RAM_LOAD = 0x20,
David Brown187dd882017-07-11 11:15:23 -060060}
61
David Brown43643dd2019-01-11 15:43:28 -070062/// A generator for manifests. The format of the manifest can be either a
63/// traditional "TLV" or a SUIT-style manifest.
64pub trait ManifestGen {
David Brownac46e262019-01-11 15:46:18 -070065 /// Retrieve the header magic value for this manifest type.
66 fn get_magic(&self) -> u32;
67
David Brown43643dd2019-01-11 15:43:28 -070068 /// Retrieve the flags value for this particular manifest type.
69 fn get_flags(&self) -> u32;
70
David Brown7a81c4b2019-07-29 15:20:21 -060071 /// Retrieve the number of bytes of this manifest that is "protected".
72 /// This field is stored in the outside image header instead of the
73 /// manifest header.
74 fn protect_size(&self) -> u16;
75
76 /// Add a dependency on another image.
77 fn add_dependency(&mut self, id: u8, version: &ImageVersion);
78
David Brown43643dd2019-01-11 15:43:28 -070079 /// Add a sequence of bytes to the payload that the manifest is
80 /// protecting.
81 fn add_bytes(&mut self, bytes: &[u8]);
82
David Browne90b13f2019-12-06 15:04:00 -070083 /// Set an internal flag indicating that the next `make_tlv` should
84 /// corrupt the signature.
85 fn corrupt_sig(&mut self);
86
David Brown43643dd2019-01-11 15:43:28 -070087 /// Construct the manifest for this payload.
88 fn make_tlv(self: Box<Self>) -> Vec<u8>;
Fabio Utzig90f449e2019-10-24 07:43:53 -030089
Fabio Utzige84f0ef2019-11-22 12:29:32 -030090 /// Generate a new encryption random key
91 fn generate_enc_key(&mut self);
Fabio Utzig90f449e2019-10-24 07:43:53 -030092
93 /// Return the current encryption key
94 fn get_enc_key(&self) -> Vec<u8>;
David Brown43643dd2019-01-11 15:43:28 -070095}
96
Fabio Utzig9a2b5de2019-11-22 12:50:02 -030097#[derive(Debug, Default)]
David Brown187dd882017-07-11 11:15:23 -060098pub struct TlvGen {
David Brown43cda332017-09-01 09:53:23 -060099 flags: u32,
David Brown187dd882017-07-11 11:15:23 -0600100 kinds: Vec<TlvKinds>,
David Brown7a81c4b2019-07-29 15:20:21 -0600101 /// The total size of the payload.
David Brown187dd882017-07-11 11:15:23 -0600102 size: u16,
David Brown4243ab02017-07-11 12:24:23 -0600103 payload: Vec<u8>,
David Brown7a81c4b2019-07-29 15:20:21 -0600104 dependencies: Vec<Dependency>,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300105 enc_key: Vec<u8>,
David Browne90b13f2019-12-06 15:04:00 -0700106 /// Should this signature be corrupted.
107 gen_corrupted: bool,
David Brown7a81c4b2019-07-29 15:20:21 -0600108}
109
David Brownc3898d62019-08-05 14:20:02 -0600110#[derive(Debug)]
David Brown7a81c4b2019-07-29 15:20:21 -0600111struct Dependency {
112 id: u8,
113 version: ImageVersion,
David Brown187dd882017-07-11 11:15:23 -0600114}
115
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300116const AES_KEY_LEN: usize = 16;
Fabio Utzig1e48b912018-09-18 09:04:18 -0300117
David Brown187dd882017-07-11 11:15:23 -0600118impl TlvGen {
119 /// Construct a new tlv generator that will only contain a hash of the data.
David Brown7e701d82017-07-11 13:24:25 -0600120 #[allow(dead_code)]
David Brown187dd882017-07-11 11:15:23 -0600121 pub fn new_hash_only() -> TlvGen {
122 TlvGen {
David Brown187dd882017-07-11 11:15:23 -0600123 kinds: vec![TlvKinds::SHA256],
124 size: 4 + 32,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300125 ..Default::default()
David Brown187dd882017-07-11 11:15:23 -0600126 }
127 }
128
David Brown7e701d82017-07-11 13:24:25 -0600129 #[allow(dead_code)]
130 pub fn new_rsa_pss() -> TlvGen {
131 TlvGen {
Fabio Utzig754438d2018-12-14 06:39:58 -0200132 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048],
133 size: 4 + 32 + 4 + 32 + 4 + 256,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300134 ..Default::default()
David Brown7e701d82017-07-11 13:24:25 -0600135 }
136 }
137
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200138 #[allow(dead_code)]
Fabio Utzig39297432019-05-08 18:51:10 -0300139 pub fn new_rsa3072_pss() -> TlvGen {
140 TlvGen {
Fabio Utzig39297432019-05-08 18:51:10 -0300141 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA3072],
142 size: 4 + 32 + 4 + 32 + 4 + 384,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300143 ..Default::default()
Fabio Utzig39297432019-05-08 18:51:10 -0300144 }
145 }
146
147 #[allow(dead_code)]
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200148 pub fn new_ecdsa() -> TlvGen {
149 TlvGen {
Fabio Utzig754438d2018-12-14 06:39:58 -0200150 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256],
151 size: 4 + 32 + 4 + 32 + 4 + 72,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300152 ..Default::default()
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200153 }
154 }
155
Fabio Utzig1e48b912018-09-18 09:04:18 -0300156 #[allow(dead_code)]
Fabio Utzig97710282019-05-24 17:44:49 -0300157 pub fn new_ed25519() -> TlvGen {
158 TlvGen {
Fabio Utzig97710282019-05-24 17:44:49 -0300159 kinds: vec![TlvKinds::SHA256, TlvKinds::ED25519],
160 size: 4 + 32 + 4 + 32 + 4 + 64,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300161 ..Default::default()
Fabio Utzig97710282019-05-24 17:44:49 -0300162 }
163 }
164
165 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300166 pub fn new_enc_rsa() -> TlvGen {
167 TlvGen {
168 flags: TlvFlags::ENCRYPTED as u32,
169 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
170 size: 4 + 32 + 4 + 256,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300171 ..Default::default()
Fabio Utzig1e48b912018-09-18 09:04:18 -0300172 }
173 }
174
175 #[allow(dead_code)]
Fabio Utzig754438d2018-12-14 06:39:58 -0200176 pub fn new_sig_enc_rsa() -> TlvGen {
177 TlvGen {
178 flags: TlvFlags::ENCRYPTED as u32,
179 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCRSA2048],
180 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 256,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300181 ..Default::default()
Fabio Utzig754438d2018-12-14 06:39:58 -0200182 }
183 }
184
185 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300186 pub fn new_enc_kw() -> TlvGen {
187 TlvGen {
188 flags: TlvFlags::ENCRYPTED as u32,
189 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW128],
190 size: 4 + 32 + 4 + 24,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300191 ..Default::default()
Fabio Utzig1e48b912018-09-18 09:04:18 -0300192 }
193 }
194
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200195 #[allow(dead_code)]
196 pub fn new_rsa_kw() -> TlvGen {
197 TlvGen {
198 flags: TlvFlags::ENCRYPTED as u32,
199 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCKW128],
200 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 24,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300201 ..Default::default()
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200202 }
203 }
204
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200205 #[allow(dead_code)]
206 pub fn new_ecdsa_kw() -> TlvGen {
207 TlvGen {
208 flags: TlvFlags::ENCRYPTED as u32,
209 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCKW128],
210 size: 4 + 32 + 4 + 32 + 4 + 72 + 4 + 24,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300211 ..Default::default()
Fabio Utzig90f449e2019-10-24 07:43:53 -0300212 }
213 }
214
215 #[allow(dead_code)]
Fabio Utzig66b4caa2020-01-04 20:19:28 -0300216 pub fn new_ecies_p256() -> TlvGen {
217 TlvGen {
218 flags: TlvFlags::ENCRYPTED as u32,
219 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCEC256],
220 size: 4 + 32 + 4 + 32 + 4 + 113,
221 ..Default::default()
222 }
223 }
224
225 #[allow(dead_code)]
Fabio Utzig90f449e2019-10-24 07:43:53 -0300226 pub fn new_ecdsa_ecies_p256() -> TlvGen {
227 TlvGen {
228 flags: TlvFlags::ENCRYPTED as u32,
229 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCEC256],
230 size: 4 + 32 + 4 + 32 + 4 + 72 + 4 + 113,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300231 ..Default::default()
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200232 }
233 }
234
David Brown187dd882017-07-11 11:15:23 -0600235 /// Retrieve the size that the TLV will occupy. This can be called at any time.
236 pub fn get_size(&self) -> u16 {
David Brownf5b33d82017-09-01 10:58:27 -0600237 4 + self.size
David Brown187dd882017-07-11 11:15:23 -0600238 }
David Brown43643dd2019-01-11 15:43:28 -0700239}
240
241impl ManifestGen for TlvGen {
David Brownac46e262019-01-11 15:46:18 -0700242 fn get_magic(&self) -> u32 {
243 0x96f3b83d
244 }
245
David Brown43643dd2019-01-11 15:43:28 -0700246 /// Retrieve the header flags for this configuration. This can be called at any time.
247 fn get_flags(&self) -> u32 {
248 self.flags
249 }
David Brown187dd882017-07-11 11:15:23 -0600250
251 /// Add bytes to the covered hash.
David Brown43643dd2019-01-11 15:43:28 -0700252 fn add_bytes(&mut self, bytes: &[u8]) {
David Brown4243ab02017-07-11 12:24:23 -0600253 self.payload.extend_from_slice(bytes);
David Brown187dd882017-07-11 11:15:23 -0600254 }
255
David Brown7a81c4b2019-07-29 15:20:21 -0600256 fn protect_size(&self) -> u16 {
David Brown2b73ed92020-01-08 17:01:22 -0700257 if self.dependencies.is_empty() {
David Brown7a81c4b2019-07-29 15:20:21 -0600258 0
259 } else {
David Brown2b73ed92020-01-08 17:01:22 -0700260 // Include the header and space for each dependency.
261 4 + (self.dependencies.len() as u16) * (4 + 4 + 8)
David Brown7a81c4b2019-07-29 15:20:21 -0600262 }
263 }
264
265 fn add_dependency(&mut self, id: u8, version: &ImageVersion) {
266 let my_size = 4 + 4 + 8;
David Brown7a81c4b2019-07-29 15:20:21 -0600267 self.size += my_size;
268 self.dependencies.push(Dependency {
269 id: id,
270 version: version.clone(),
271 });
272 }
273
David Browne90b13f2019-12-06 15:04:00 -0700274 fn corrupt_sig(&mut self) {
275 self.gen_corrupted = true;
276 }
277
David Brown187dd882017-07-11 11:15:23 -0600278 /// Compute the TLV given the specified block of data.
David Brown43643dd2019-01-11 15:43:28 -0700279 fn make_tlv(self: Box<Self>) -> Vec<u8> {
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300280 let mut protected_tlv: Vec<u8> = vec![];
David Brown187dd882017-07-11 11:15:23 -0600281
David Brown2b73ed92020-01-08 17:01:22 -0700282 if self.protect_size() > 0 {
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300283 protected_tlv.push(0x08);
284 protected_tlv.push(0x69);
David Brown2b73ed92020-01-08 17:01:22 -0700285 let size = self.protect_size();
286 protected_tlv.write_u16::<LittleEndian>(size).unwrap();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300287 for dep in &self.dependencies {
David Brown69721182019-12-04 14:50:52 -0700288 protected_tlv.write_u16::<LittleEndian>(TlvKinds::DEPENDENCY as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700289 protected_tlv.write_u16::<LittleEndian>(12).unwrap();
David Brownf5b33d82017-09-01 10:58:27 -0600290
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300291 // The dependency.
292 protected_tlv.push(dep.id);
293 for _ in 0 .. 3 {
294 protected_tlv.push(0);
295 }
296 protected_tlv.push(dep.version.major);
297 protected_tlv.push(dep.version.minor);
298 protected_tlv.write_u16::<LittleEndian>(dep.version.revision).unwrap();
299 protected_tlv.write_u32::<LittleEndian>(dep.version.build_num).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600300 }
David Brown2b73ed92020-01-08 17:01:22 -0700301
302 assert_eq!(size, protected_tlv.len() as u16, "protected TLV length incorrect");
David Brown7a81c4b2019-07-29 15:20:21 -0600303 }
304
305 // Ring does the signature itself, which means that it must be
306 // given a full, contiguous payload. Although this does help from
307 // a correct usage perspective, it is fairly stupid from an
308 // efficiency view. If this is shown to be a performance issue
309 // with the tests, the protected data could be appended to the
310 // payload, and then removed after the signature is done. For now,
311 // just make a signed payload.
312 let mut sig_payload = self.payload.clone();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300313 sig_payload.extend_from_slice(&protected_tlv);
314
315 let mut result: Vec<u8> = vec![];
316
317 // add back signed payload
318 result.extend_from_slice(&protected_tlv);
319
320 // add non-protected payload
321 result.push(0x07);
322 result.push(0x69);
323 result.write_u16::<LittleEndian>(self.get_size()).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600324
David Brown187dd882017-07-11 11:15:23 -0600325 if self.kinds.contains(&TlvKinds::SHA256) {
David Browne90b13f2019-12-06 15:04:00 -0700326 // If a signature is not requested, corrupt the hash we are
327 // generating. But, if there is a signature, output the
328 // correct hash. We want the hash test to pass so that the
329 // signature verification can be validated.
330 let mut corrupt_hash = self.gen_corrupted;
331 for k in &[TlvKinds::RSA2048, TlvKinds::RSA3072,
332 TlvKinds::ECDSA224, TlvKinds::ECDSA256,
333 TlvKinds::ED25519]
334 {
335 if self.kinds.contains(k) {
336 corrupt_hash = false;
337 break;
338 }
339 }
340
341 if corrupt_hash {
342 sig_payload[0] ^= 1;
343 }
344
David Brown7a81c4b2019-07-29 15:20:21 -0600345 let hash = digest::digest(&digest::SHA256, &sig_payload);
David Brown8054ce22017-07-11 12:12:09 -0600346 let hash = hash.as_ref();
David Brown187dd882017-07-11 11:15:23 -0600347
David Brown8054ce22017-07-11 12:12:09 -0600348 assert!(hash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700349 result.write_u16::<LittleEndian>(TlvKinds::SHA256 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700350 result.write_u16::<LittleEndian>(32).unwrap();
David Brown8054ce22017-07-11 12:12:09 -0600351 result.extend_from_slice(hash);
David Browne90b13f2019-12-06 15:04:00 -0700352
353 // Undo the corruption.
354 if corrupt_hash {
355 sig_payload[0] ^= 1;
356 }
357
358 }
359
360 if self.gen_corrupted {
361 // Corrupt what is signed by modifying the input to the
362 // signature code.
363 sig_payload[0] ^= 1;
David Brown187dd882017-07-11 11:15:23 -0600364 }
365
Fabio Utzig39297432019-05-08 18:51:10 -0300366 if self.kinds.contains(&TlvKinds::RSA2048) ||
367 self.kinds.contains(&TlvKinds::RSA3072) {
368
369 let is_rsa2048 = self.kinds.contains(&TlvKinds::RSA2048);
370
David Brown43cda332017-09-01 09:53:23 -0600371 // Output the hash of the public key.
Fabio Utzig39297432019-05-08 18:51:10 -0300372 let hash = if is_rsa2048 {
373 digest::digest(&digest::SHA256, RSA_PUB_KEY)
374 } else {
375 digest::digest(&digest::SHA256, RSA3072_PUB_KEY)
376 };
David Brown43cda332017-09-01 09:53:23 -0600377 let hash = hash.as_ref();
378
379 assert!(hash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700380 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700381 result.write_u16::<LittleEndian>(32).unwrap();
David Brown43cda332017-09-01 09:53:23 -0600382 result.extend_from_slice(hash);
383
David Brown7e701d82017-07-11 13:24:25 -0600384 // For now assume PSS.
Fabio Utzig39297432019-05-08 18:51:10 -0300385 let key_bytes = if is_rsa2048 {
386 pem::parse(include_bytes!("../../root-rsa-2048.pem").as_ref()).unwrap()
387 } else {
388 pem::parse(include_bytes!("../../root-rsa-3072.pem").as_ref()).unwrap()
389 };
David Brown7e701d82017-07-11 13:24:25 -0600390 assert_eq!(key_bytes.tag, "RSA PRIVATE KEY");
Fabio Utzig90f449e2019-10-24 07:43:53 -0300391 let key_pair = RsaKeyPair::from_der(&key_bytes.contents).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600392 let rng = rand::SystemRandom::new();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300393 let mut signature = vec![0; key_pair.public_modulus_len()];
Fabio Utzig39297432019-05-08 18:51:10 -0300394 if is_rsa2048 {
395 assert_eq!(signature.len(), 256);
396 } else {
397 assert_eq!(signature.len(), 384);
398 }
David Brown7a81c4b2019-07-29 15:20:21 -0600399 key_pair.sign(&RSA_PSS_SHA256, &rng, &sig_payload, &mut signature).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600400
Fabio Utzig39297432019-05-08 18:51:10 -0300401 if is_rsa2048 {
David Brown69721182019-12-04 14:50:52 -0700402 result.write_u16::<LittleEndian>(TlvKinds::RSA2048 as u16).unwrap();
Fabio Utzig39297432019-05-08 18:51:10 -0300403 } else {
David Brown69721182019-12-04 14:50:52 -0700404 result.write_u16::<LittleEndian>(TlvKinds::RSA3072 as u16).unwrap();
Fabio Utzig39297432019-05-08 18:51:10 -0300405 }
David Brown91d68632019-07-29 14:32:13 -0600406 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600407 result.extend_from_slice(&signature);
408 }
409
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200410 if self.kinds.contains(&TlvKinds::ECDSA256) {
411 let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY);
412 let keyhash = keyhash.as_ref();
413
414 assert!(keyhash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700415 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700416 result.write_u16::<LittleEndian>(32).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200417 result.extend_from_slice(keyhash);
418
Fabio Utzig05ab0142018-07-10 09:15:28 -0300419 let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap();
420 assert_eq!(key_bytes.tag, "PRIVATE KEY");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200421
Fabio Utzig05ab0142018-07-10 09:15:28 -0300422 let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300423 &key_bytes.contents).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300424 let rng = rand::SystemRandom::new();
Fabio Utzig90f449e2019-10-24 07:43:53 -0300425 let signature = key_pair.sign(&rng, &sig_payload).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200426
David Brown69721182019-12-04 14:50:52 -0700427 result.write_u16::<LittleEndian>(TlvKinds::ECDSA256 as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300428
David Browne90b13f2019-12-06 15:04:00 -0700429
Fabio Utzig05ab0142018-07-10 09:15:28 -0300430 // signature must be padded...
431 let mut signature = signature.as_ref().to_vec();
432 while signature.len() < 72 {
433 signature.push(0);
Fabio Utzig05ab0142018-07-10 09:15:28 -0300434 }
435
David Brown91d68632019-07-29 14:32:13 -0600436 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300437 result.extend_from_slice(signature.as_ref());
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200438 }
439
Fabio Utzig97710282019-05-24 17:44:49 -0300440 if self.kinds.contains(&TlvKinds::ED25519) {
441 let keyhash = digest::digest(&digest::SHA256, ED25519_PUB_KEY);
442 let keyhash = keyhash.as_ref();
443
444 assert!(keyhash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700445 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700446 result.write_u16::<LittleEndian>(32).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300447 result.extend_from_slice(keyhash);
448
David Brown7a81c4b2019-07-29 15:20:21 -0600449 let hash = digest::digest(&digest::SHA256, &sig_payload);
Fabio Utzig97710282019-05-24 17:44:49 -0300450 let hash = hash.as_ref();
451 assert!(hash.len() == 32);
452
453 let key_bytes = pem::parse(include_bytes!("../../root-ed25519.pem").as_ref()).unwrap();
454 assert_eq!(key_bytes.tag, "PRIVATE KEY");
455
Fabio Utzig90f449e2019-10-24 07:43:53 -0300456 let key_pair = Ed25519KeyPair::from_seed_and_public_key(
457 &key_bytes.contents[16..48], &ED25519_PUB_KEY[12..44]).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300458 let signature = key_pair.sign(&hash);
459
David Brown69721182019-12-04 14:50:52 -0700460 result.write_u16::<LittleEndian>(TlvKinds::ED25519 as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300461
462 let signature = signature.as_ref().to_vec();
David Brown91d68632019-07-29 14:32:13 -0600463 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300464 result.extend_from_slice(signature.as_ref());
465 }
466
Fabio Utzig1e48b912018-09-18 09:04:18 -0300467 if self.kinds.contains(&TlvKinds::ENCRSA2048) {
468 let key_bytes = pem::parse(include_bytes!("../../enc-rsa2048-pub.pem")
469 .as_ref()).unwrap();
470 assert_eq!(key_bytes.tag, "PUBLIC KEY");
471
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300472 let cipherkey = self.get_enc_key();
473 let cipherkey = cipherkey.as_slice();
474 let encbuf = match c::rsa_oaep_encrypt(&key_bytes.contents, cipherkey) {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300475 Ok(v) => v,
476 Err(_) => panic!("Failed to encrypt secret key"),
477 };
478
479 assert!(encbuf.len() == 256);
David Brown69721182019-12-04 14:50:52 -0700480 result.write_u16::<LittleEndian>(TlvKinds::ENCRSA2048 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700481 result.write_u16::<LittleEndian>(256).unwrap();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300482 result.extend_from_slice(&encbuf);
483 }
484
485 if self.kinds.contains(&TlvKinds::ENCKW128) {
486 let key_bytes = base64::decode(
487 include_str!("../../enc-aes128kw.b64").trim()).unwrap();
488
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300489 let cipherkey = self.get_enc_key();
490 let cipherkey = cipherkey.as_slice();
491 let encbuf = match c::kw_encrypt(&key_bytes, cipherkey) {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300492 Ok(v) => v,
493 Err(_) => panic!("Failed to encrypt secret key"),
494 };
495
496 assert!(encbuf.len() == 24);
David Brown69721182019-12-04 14:50:52 -0700497 result.write_u16::<LittleEndian>(TlvKinds::ENCKW128 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700498 result.write_u16::<LittleEndian>(24).unwrap();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300499 result.extend_from_slice(&encbuf);
500 }
501
Fabio Utzig90f449e2019-10-24 07:43:53 -0300502 if self.kinds.contains(&TlvKinds::ENCEC256) {
503 let key_bytes = pem::parse(include_bytes!("../../enc-ec256-pub.pem").as_ref()).unwrap();
504 assert_eq!(key_bytes.tag, "PUBLIC KEY");
505
506 let rng = rand::SystemRandom::new();
507 let pk = match agreement::EphemeralPrivateKey::generate(&agreement::ECDH_P256, &rng) {
508 Ok(v) => v,
509 Err(_) => panic!("Failed to generate ephemeral keypair"),
510 };
511
512 let pubk = match pk.compute_public_key() {
513 Ok(pubk) => pubk,
514 Err(_) => panic!("Failed computing ephemeral public key"),
515 };
516
517 let peer_pubk = agreement::UnparsedPublicKey::new(&agreement::ECDH_P256, &key_bytes.contents[26..]);
518
519 #[derive(Debug, PartialEq)]
520 struct OkmLen<T: core::fmt::Debug + PartialEq>(T);
521
522 impl hkdf::KeyType for OkmLen<usize> {
523 fn len(&self) -> usize {
524 self.0
525 }
526 }
527
528 let derived_key = match agreement::agree_ephemeral(
529 pk, &peer_pubk, ring::error::Unspecified, |shared| {
530 let salt = hkdf::Salt::new(hkdf::HKDF_SHA256, &[]);
531 let prk = salt.extract(&shared);
532 let okm = match prk.expand(&[b"MCUBoot_ECIES_v1"], OkmLen(48)) {
533 Ok(okm) => okm,
534 Err(_) => panic!("Failed building HKDF OKM"),
535 };
536 let mut buf = [0u8; 48];
537 match okm.fill(&mut buf) {
538 Ok(_) => Ok(buf),
539 Err(_) => panic!("Failed generating HKDF output"),
540 }
541 },
542 ) {
543 Ok(v) => v,
544 Err(_) => panic!("Failed building HKDF"),
545 };
546
547 let key = GenericArray::from_slice(&derived_key[..16]);
548 let nonce = GenericArray::from_slice(&[0; 16]);
549 let mut cipher = Aes128Ctr::new(&key, &nonce);
550 let mut cipherkey = self.get_enc_key();
551 cipher.apply_keystream(&mut cipherkey);
552
553 let key = hmac::Key::new(hmac::HMAC_SHA256, &derived_key[16..]);
554 let tag = hmac::sign(&key, &cipherkey);
555
556 let mut buf = vec![];
557 buf.append(&mut pubk.as_ref().to_vec());
558 buf.append(&mut tag.as_ref().to_vec());
559 buf.append(&mut cipherkey);
560
561 assert!(buf.len() == 113);
David Brown69721182019-12-04 14:50:52 -0700562 result.write_u16::<LittleEndian>(TlvKinds::ENCEC256 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700563 result.write_u16::<LittleEndian>(113).unwrap();
Fabio Utzig90f449e2019-10-24 07:43:53 -0300564 result.extend_from_slice(&buf);
565 }
566
David Brown187dd882017-07-11 11:15:23 -0600567 result
568 }
Fabio Utzig90f449e2019-10-24 07:43:53 -0300569
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300570 fn generate_enc_key(&mut self) {
571 let rng = rand::SystemRandom::new();
572 let mut buf = vec![0u8; AES_KEY_LEN];
573 match rng.fill(&mut buf) {
574 Err(_) => panic!("Error generating encrypted key"),
575 Ok(_) => (),
576 }
577 info!("New encryption key: {:02x?}", buf);
578 self.enc_key = buf;
Fabio Utzig90f449e2019-10-24 07:43:53 -0300579 }
580
581 fn get_enc_key(&self) -> Vec<u8> {
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300582 if self.enc_key.len() != AES_KEY_LEN {
583 panic!("No random key was generated");
584 }
585 self.enc_key.clone()
Fabio Utzig90f449e2019-10-24 07:43:53 -0300586 }
David Brown187dd882017-07-11 11:15:23 -0600587}
David Brown43cda332017-09-01 09:53:23 -0600588
589include!("rsa_pub_key-rs.txt");
Fabio Utzig39297432019-05-08 18:51:10 -0300590include!("rsa3072_pub_key-rs.txt");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200591include!("ecdsa_pub_key-rs.txt");
Fabio Utzig97710282019-05-24 17:44:49 -0300592include!("ed25519_pub_key-rs.txt");