blob: c8200e65fbede365f64e3857d3b96d379535e10f [file] [log] [blame]
David Browne2acfae2020-01-21 16:45:01 -07001// Copyright (c) 2017-2020 Linaro LTD
2// Copyright (c) 2017-2020 JUUL Labs
3//
4// SPDX-License-Identifier: Apache-2.0
5
David Brown187dd882017-07-11 11:15:23 -06006//! TLV Support
7//!
8//! mcuboot images are followed immediately by a list of TLV items that contain integrity
9//! information about the image. Their generation is made a little complicated because the size of
10//! the TLV block is in the image header, which is included in the hash. Since some signatures can
11//! vary in size, we just make them the largest size possible.
12//!
13//! Because of this header, we have to make two passes. The first pass will compute the size of
14//! the TLV, and the second pass will build the data for the TLV.
15
David Brown91d68632019-07-29 14:32:13 -060016use byteorder::{
17 LittleEndian, WriteBytesExt,
18};
David Brown7a81c4b2019-07-29 15:20:21 -060019use crate::image::ImageVersion;
David Brown7e701d82017-07-11 13:24:25 -060020use pem;
Fabio Utzig1e48b912018-09-18 09:04:18 -030021use base64;
Fabio Utzige84f0ef2019-11-22 12:29:32 -030022use log::info;
Fabio Utzig90f449e2019-10-24 07:43:53 -030023use ring::{digest, rand, agreement, hkdf, hmac};
Fabio Utzige84f0ef2019-11-22 12:29:32 -030024use ring::rand::SecureRandom;
Fabio Utzig05ab0142018-07-10 09:15:28 -030025use ring::signature::{
26 RsaKeyPair,
27 RSA_PSS_SHA256,
28 EcdsaKeyPair,
29 ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig97710282019-05-24 17:44:49 -030030 Ed25519KeyPair,
Fabio Utzig05ab0142018-07-10 09:15:28 -030031};
Fabio Utzig90f449e2019-10-24 07:43:53 -030032use aes_ctr::{
33 Aes128Ctr,
34 stream_cipher::{
35 generic_array::GenericArray,
36 NewFixStreamCipher,
37 StreamCipherCore,
38 },
39};
Fabio Utzig80fde2f2017-12-05 09:25:31 -020040use mcuboot_sys::c;
David Brown187dd882017-07-11 11:15:23 -060041
David Brown69721182019-12-04 14:50:52 -070042#[repr(u16)]
David Brownc3898d62019-08-05 14:20:02 -060043#[derive(Copy, Clone, Debug, PartialEq, Eq)]
David Brown187dd882017-07-11 11:15:23 -060044#[allow(dead_code)] // TODO: For now
45pub enum TlvKinds {
David Brown43cda332017-09-01 09:53:23 -060046 KEYHASH = 0x01,
David Brown27648b82017-08-31 10:40:29 -060047 SHA256 = 0x10,
48 RSA2048 = 0x20,
49 ECDSA224 = 0x21,
50 ECDSA256 = 0x22,
Fabio Utzig39297432019-05-08 18:51:10 -030051 RSA3072 = 0x23,
Fabio Utzig97710282019-05-24 17:44:49 -030052 ED25519 = 0x24,
Fabio Utzig1e48b912018-09-18 09:04:18 -030053 ENCRSA2048 = 0x30,
54 ENCKW128 = 0x31,
Fabio Utzig90f449e2019-10-24 07:43:53 -030055 ENCEC256 = 0x32,
David Brown7a81c4b2019-07-29 15:20:21 -060056 DEPENDENCY = 0x40,
Fabio Utzig1e48b912018-09-18 09:04:18 -030057}
58
59#[allow(dead_code, non_camel_case_types)]
60pub enum TlvFlags {
61 PIC = 0x01,
62 NON_BOOTABLE = 0x02,
63 ENCRYPTED = 0x04,
64 RAM_LOAD = 0x20,
David Brown187dd882017-07-11 11:15:23 -060065}
66
David Brown43643dd2019-01-11 15:43:28 -070067/// A generator for manifests. The format of the manifest can be either a
68/// traditional "TLV" or a SUIT-style manifest.
69pub trait ManifestGen {
David Brownac46e262019-01-11 15:46:18 -070070 /// Retrieve the header magic value for this manifest type.
71 fn get_magic(&self) -> u32;
72
David Brown43643dd2019-01-11 15:43:28 -070073 /// Retrieve the flags value for this particular manifest type.
74 fn get_flags(&self) -> u32;
75
David Brown7a81c4b2019-07-29 15:20:21 -060076 /// Retrieve the number of bytes of this manifest that is "protected".
77 /// This field is stored in the outside image header instead of the
78 /// manifest header.
79 fn protect_size(&self) -> u16;
80
81 /// Add a dependency on another image.
82 fn add_dependency(&mut self, id: u8, version: &ImageVersion);
83
David Brown43643dd2019-01-11 15:43:28 -070084 /// Add a sequence of bytes to the payload that the manifest is
85 /// protecting.
86 fn add_bytes(&mut self, bytes: &[u8]);
87
David Browne90b13f2019-12-06 15:04:00 -070088 /// Set an internal flag indicating that the next `make_tlv` should
89 /// corrupt the signature.
90 fn corrupt_sig(&mut self);
91
David Brown43643dd2019-01-11 15:43:28 -070092 /// Construct the manifest for this payload.
93 fn make_tlv(self: Box<Self>) -> Vec<u8>;
Fabio Utzig90f449e2019-10-24 07:43:53 -030094
Fabio Utzige84f0ef2019-11-22 12:29:32 -030095 /// Generate a new encryption random key
96 fn generate_enc_key(&mut self);
Fabio Utzig90f449e2019-10-24 07:43:53 -030097
98 /// Return the current encryption key
99 fn get_enc_key(&self) -> Vec<u8>;
David Brown43643dd2019-01-11 15:43:28 -0700100}
101
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300102#[derive(Debug, Default)]
David Brown187dd882017-07-11 11:15:23 -0600103pub struct TlvGen {
David Brown43cda332017-09-01 09:53:23 -0600104 flags: u32,
David Brown187dd882017-07-11 11:15:23 -0600105 kinds: Vec<TlvKinds>,
David Brown4243ab02017-07-11 12:24:23 -0600106 payload: Vec<u8>,
David Brown7a81c4b2019-07-29 15:20:21 -0600107 dependencies: Vec<Dependency>,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300108 enc_key: Vec<u8>,
David Browne90b13f2019-12-06 15:04:00 -0700109 /// Should this signature be corrupted.
110 gen_corrupted: bool,
David Brown7a81c4b2019-07-29 15:20:21 -0600111}
112
David Brownc3898d62019-08-05 14:20:02 -0600113#[derive(Debug)]
David Brown7a81c4b2019-07-29 15:20:21 -0600114struct Dependency {
115 id: u8,
116 version: ImageVersion,
David Brown187dd882017-07-11 11:15:23 -0600117}
118
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300119const AES_KEY_LEN: usize = 16;
Fabio Utzig1e48b912018-09-18 09:04:18 -0300120
David Brown187dd882017-07-11 11:15:23 -0600121impl TlvGen {
122 /// Construct a new tlv generator that will only contain a hash of the data.
David Brown7e701d82017-07-11 13:24:25 -0600123 #[allow(dead_code)]
David Brown187dd882017-07-11 11:15:23 -0600124 pub fn new_hash_only() -> TlvGen {
125 TlvGen {
David Brown187dd882017-07-11 11:15:23 -0600126 kinds: vec![TlvKinds::SHA256],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300127 ..Default::default()
David Brown187dd882017-07-11 11:15:23 -0600128 }
129 }
130
David Brown7e701d82017-07-11 13:24:25 -0600131 #[allow(dead_code)]
132 pub fn new_rsa_pss() -> TlvGen {
133 TlvGen {
Fabio Utzig754438d2018-12-14 06:39:58 -0200134 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300135 ..Default::default()
David Brown7e701d82017-07-11 13:24:25 -0600136 }
137 }
138
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200139 #[allow(dead_code)]
Fabio Utzig39297432019-05-08 18:51:10 -0300140 pub fn new_rsa3072_pss() -> TlvGen {
141 TlvGen {
Fabio Utzig39297432019-05-08 18:51:10 -0300142 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA3072],
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],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300151 ..Default::default()
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200152 }
153 }
154
Fabio Utzig1e48b912018-09-18 09:04:18 -0300155 #[allow(dead_code)]
Fabio Utzig97710282019-05-24 17:44:49 -0300156 pub fn new_ed25519() -> TlvGen {
157 TlvGen {
Fabio Utzig97710282019-05-24 17:44:49 -0300158 kinds: vec![TlvKinds::SHA256, TlvKinds::ED25519],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300159 ..Default::default()
Fabio Utzig97710282019-05-24 17:44:49 -0300160 }
161 }
162
163 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300164 pub fn new_enc_rsa() -> TlvGen {
165 TlvGen {
166 flags: TlvFlags::ENCRYPTED as u32,
167 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300168 ..Default::default()
Fabio Utzig1e48b912018-09-18 09:04:18 -0300169 }
170 }
171
172 #[allow(dead_code)]
Fabio Utzig754438d2018-12-14 06:39:58 -0200173 pub fn new_sig_enc_rsa() -> TlvGen {
174 TlvGen {
175 flags: TlvFlags::ENCRYPTED as u32,
176 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCRSA2048],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300177 ..Default::default()
Fabio Utzig754438d2018-12-14 06:39:58 -0200178 }
179 }
180
181 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300182 pub fn new_enc_kw() -> TlvGen {
183 TlvGen {
184 flags: TlvFlags::ENCRYPTED as u32,
185 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW128],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300186 ..Default::default()
Fabio Utzig1e48b912018-09-18 09:04:18 -0300187 }
188 }
189
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200190 #[allow(dead_code)]
191 pub fn new_rsa_kw() -> TlvGen {
192 TlvGen {
193 flags: TlvFlags::ENCRYPTED as u32,
194 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCKW128],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300195 ..Default::default()
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200196 }
197 }
198
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200199 #[allow(dead_code)]
200 pub fn new_ecdsa_kw() -> TlvGen {
201 TlvGen {
202 flags: TlvFlags::ENCRYPTED as u32,
203 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCKW128],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300204 ..Default::default()
Fabio Utzig90f449e2019-10-24 07:43:53 -0300205 }
206 }
207
208 #[allow(dead_code)]
Fabio Utzig66b4caa2020-01-04 20:19:28 -0300209 pub fn new_ecies_p256() -> TlvGen {
210 TlvGen {
211 flags: TlvFlags::ENCRYPTED as u32,
212 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCEC256],
Fabio Utzig66b4caa2020-01-04 20:19:28 -0300213 ..Default::default()
214 }
215 }
216
217 #[allow(dead_code)]
Fabio Utzig90f449e2019-10-24 07:43:53 -0300218 pub fn new_ecdsa_ecies_p256() -> TlvGen {
219 TlvGen {
220 flags: TlvFlags::ENCRYPTED as u32,
221 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCEC256],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300222 ..Default::default()
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200223 }
224 }
David Brown43643dd2019-01-11 15:43:28 -0700225}
226
227impl ManifestGen for TlvGen {
David Brownac46e262019-01-11 15:46:18 -0700228 fn get_magic(&self) -> u32 {
229 0x96f3b83d
230 }
231
David Brown43643dd2019-01-11 15:43:28 -0700232 /// Retrieve the header flags for this configuration. This can be called at any time.
233 fn get_flags(&self) -> u32 {
234 self.flags
235 }
David Brown187dd882017-07-11 11:15:23 -0600236
237 /// Add bytes to the covered hash.
David Brown43643dd2019-01-11 15:43:28 -0700238 fn add_bytes(&mut self, bytes: &[u8]) {
David Brown4243ab02017-07-11 12:24:23 -0600239 self.payload.extend_from_slice(bytes);
David Brown187dd882017-07-11 11:15:23 -0600240 }
241
David Brown7a81c4b2019-07-29 15:20:21 -0600242 fn protect_size(&self) -> u16 {
David Brown2b73ed92020-01-08 17:01:22 -0700243 if self.dependencies.is_empty() {
David Brown7a81c4b2019-07-29 15:20:21 -0600244 0
245 } else {
David Brown2b73ed92020-01-08 17:01:22 -0700246 // Include the header and space for each dependency.
247 4 + (self.dependencies.len() as u16) * (4 + 4 + 8)
David Brown7a81c4b2019-07-29 15:20:21 -0600248 }
249 }
250
251 fn add_dependency(&mut self, id: u8, version: &ImageVersion) {
David Brown7a81c4b2019-07-29 15:20:21 -0600252 self.dependencies.push(Dependency {
253 id: id,
254 version: version.clone(),
255 });
256 }
257
David Browne90b13f2019-12-06 15:04:00 -0700258 fn corrupt_sig(&mut self) {
259 self.gen_corrupted = true;
260 }
261
David Brown187dd882017-07-11 11:15:23 -0600262 /// Compute the TLV given the specified block of data.
David Brown43643dd2019-01-11 15:43:28 -0700263 fn make_tlv(self: Box<Self>) -> Vec<u8> {
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300264 let mut protected_tlv: Vec<u8> = vec![];
David Brown187dd882017-07-11 11:15:23 -0600265
David Brown2b73ed92020-01-08 17:01:22 -0700266 if self.protect_size() > 0 {
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300267 protected_tlv.push(0x08);
268 protected_tlv.push(0x69);
David Brown2b73ed92020-01-08 17:01:22 -0700269 let size = self.protect_size();
270 protected_tlv.write_u16::<LittleEndian>(size).unwrap();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300271 for dep in &self.dependencies {
David Brown69721182019-12-04 14:50:52 -0700272 protected_tlv.write_u16::<LittleEndian>(TlvKinds::DEPENDENCY as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700273 protected_tlv.write_u16::<LittleEndian>(12).unwrap();
David Brownf5b33d82017-09-01 10:58:27 -0600274
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300275 // The dependency.
276 protected_tlv.push(dep.id);
277 for _ in 0 .. 3 {
278 protected_tlv.push(0);
279 }
280 protected_tlv.push(dep.version.major);
281 protected_tlv.push(dep.version.minor);
282 protected_tlv.write_u16::<LittleEndian>(dep.version.revision).unwrap();
283 protected_tlv.write_u32::<LittleEndian>(dep.version.build_num).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600284 }
David Brown2b73ed92020-01-08 17:01:22 -0700285
286 assert_eq!(size, protected_tlv.len() as u16, "protected TLV length incorrect");
David Brown7a81c4b2019-07-29 15:20:21 -0600287 }
288
289 // Ring does the signature itself, which means that it must be
290 // given a full, contiguous payload. Although this does help from
291 // a correct usage perspective, it is fairly stupid from an
292 // efficiency view. If this is shown to be a performance issue
293 // with the tests, the protected data could be appended to the
294 // payload, and then removed after the signature is done. For now,
295 // just make a signed payload.
296 let mut sig_payload = self.payload.clone();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300297 sig_payload.extend_from_slice(&protected_tlv);
298
299 let mut result: Vec<u8> = vec![];
300
301 // add back signed payload
302 result.extend_from_slice(&protected_tlv);
303
304 // add non-protected payload
David Brown3dc86c92020-01-08 17:22:55 -0700305 let npro_pos = result.len();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300306 result.push(0x07);
307 result.push(0x69);
David Brown3dc86c92020-01-08 17:22:55 -0700308 // Placeholder for the size.
309 result.write_u16::<LittleEndian>(0).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600310
David Brown187dd882017-07-11 11:15:23 -0600311 if self.kinds.contains(&TlvKinds::SHA256) {
David Browne90b13f2019-12-06 15:04:00 -0700312 // If a signature is not requested, corrupt the hash we are
313 // generating. But, if there is a signature, output the
314 // correct hash. We want the hash test to pass so that the
315 // signature verification can be validated.
316 let mut corrupt_hash = self.gen_corrupted;
317 for k in &[TlvKinds::RSA2048, TlvKinds::RSA3072,
318 TlvKinds::ECDSA224, TlvKinds::ECDSA256,
319 TlvKinds::ED25519]
320 {
321 if self.kinds.contains(k) {
322 corrupt_hash = false;
323 break;
324 }
325 }
326
327 if corrupt_hash {
328 sig_payload[0] ^= 1;
329 }
330
David Brown7a81c4b2019-07-29 15:20:21 -0600331 let hash = digest::digest(&digest::SHA256, &sig_payload);
David Brown8054ce22017-07-11 12:12:09 -0600332 let hash = hash.as_ref();
David Brown187dd882017-07-11 11:15:23 -0600333
David Brown8054ce22017-07-11 12:12:09 -0600334 assert!(hash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700335 result.write_u16::<LittleEndian>(TlvKinds::SHA256 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700336 result.write_u16::<LittleEndian>(32).unwrap();
David Brown8054ce22017-07-11 12:12:09 -0600337 result.extend_from_slice(hash);
David Browne90b13f2019-12-06 15:04:00 -0700338
339 // Undo the corruption.
340 if corrupt_hash {
341 sig_payload[0] ^= 1;
342 }
343
344 }
345
346 if self.gen_corrupted {
347 // Corrupt what is signed by modifying the input to the
348 // signature code.
349 sig_payload[0] ^= 1;
David Brown187dd882017-07-11 11:15:23 -0600350 }
351
Fabio Utzig39297432019-05-08 18:51:10 -0300352 if self.kinds.contains(&TlvKinds::RSA2048) ||
353 self.kinds.contains(&TlvKinds::RSA3072) {
354
355 let is_rsa2048 = self.kinds.contains(&TlvKinds::RSA2048);
356
David Brown43cda332017-09-01 09:53:23 -0600357 // Output the hash of the public key.
Fabio Utzig39297432019-05-08 18:51:10 -0300358 let hash = if is_rsa2048 {
359 digest::digest(&digest::SHA256, RSA_PUB_KEY)
360 } else {
361 digest::digest(&digest::SHA256, RSA3072_PUB_KEY)
362 };
David Brown43cda332017-09-01 09:53:23 -0600363 let hash = hash.as_ref();
364
365 assert!(hash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700366 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700367 result.write_u16::<LittleEndian>(32).unwrap();
David Brown43cda332017-09-01 09:53:23 -0600368 result.extend_from_slice(hash);
369
David Brown7e701d82017-07-11 13:24:25 -0600370 // For now assume PSS.
Fabio Utzig39297432019-05-08 18:51:10 -0300371 let key_bytes = if is_rsa2048 {
372 pem::parse(include_bytes!("../../root-rsa-2048.pem").as_ref()).unwrap()
373 } else {
374 pem::parse(include_bytes!("../../root-rsa-3072.pem").as_ref()).unwrap()
375 };
David Brown7e701d82017-07-11 13:24:25 -0600376 assert_eq!(key_bytes.tag, "RSA PRIVATE KEY");
Fabio Utzig90f449e2019-10-24 07:43:53 -0300377 let key_pair = RsaKeyPair::from_der(&key_bytes.contents).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600378 let rng = rand::SystemRandom::new();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300379 let mut signature = vec![0; key_pair.public_modulus_len()];
Fabio Utzig39297432019-05-08 18:51:10 -0300380 if is_rsa2048 {
381 assert_eq!(signature.len(), 256);
382 } else {
383 assert_eq!(signature.len(), 384);
384 }
David Brown7a81c4b2019-07-29 15:20:21 -0600385 key_pair.sign(&RSA_PSS_SHA256, &rng, &sig_payload, &mut signature).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600386
Fabio Utzig39297432019-05-08 18:51:10 -0300387 if is_rsa2048 {
David Brown69721182019-12-04 14:50:52 -0700388 result.write_u16::<LittleEndian>(TlvKinds::RSA2048 as u16).unwrap();
Fabio Utzig39297432019-05-08 18:51:10 -0300389 } else {
David Brown69721182019-12-04 14:50:52 -0700390 result.write_u16::<LittleEndian>(TlvKinds::RSA3072 as u16).unwrap();
Fabio Utzig39297432019-05-08 18:51:10 -0300391 }
David Brown91d68632019-07-29 14:32:13 -0600392 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600393 result.extend_from_slice(&signature);
394 }
395
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200396 if self.kinds.contains(&TlvKinds::ECDSA256) {
397 let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY);
398 let keyhash = keyhash.as_ref();
399
400 assert!(keyhash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700401 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700402 result.write_u16::<LittleEndian>(32).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200403 result.extend_from_slice(keyhash);
404
Fabio Utzig05ab0142018-07-10 09:15:28 -0300405 let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap();
406 assert_eq!(key_bytes.tag, "PRIVATE KEY");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200407
Fabio Utzig05ab0142018-07-10 09:15:28 -0300408 let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300409 &key_bytes.contents).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300410 let rng = rand::SystemRandom::new();
Fabio Utzig90f449e2019-10-24 07:43:53 -0300411 let signature = key_pair.sign(&rng, &sig_payload).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200412
David Brown69721182019-12-04 14:50:52 -0700413 result.write_u16::<LittleEndian>(TlvKinds::ECDSA256 as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300414
David Browna4c58642019-12-12 17:28:33 -0700415 let signature = signature.as_ref().to_vec();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300416
David Brown91d68632019-07-29 14:32:13 -0600417 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300418 result.extend_from_slice(signature.as_ref());
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200419 }
420
Fabio Utzig97710282019-05-24 17:44:49 -0300421 if self.kinds.contains(&TlvKinds::ED25519) {
422 let keyhash = digest::digest(&digest::SHA256, ED25519_PUB_KEY);
423 let keyhash = keyhash.as_ref();
424
425 assert!(keyhash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700426 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700427 result.write_u16::<LittleEndian>(32).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300428 result.extend_from_slice(keyhash);
429
David Brown7a81c4b2019-07-29 15:20:21 -0600430 let hash = digest::digest(&digest::SHA256, &sig_payload);
Fabio Utzig97710282019-05-24 17:44:49 -0300431 let hash = hash.as_ref();
432 assert!(hash.len() == 32);
433
434 let key_bytes = pem::parse(include_bytes!("../../root-ed25519.pem").as_ref()).unwrap();
435 assert_eq!(key_bytes.tag, "PRIVATE KEY");
436
Fabio Utzig90f449e2019-10-24 07:43:53 -0300437 let key_pair = Ed25519KeyPair::from_seed_and_public_key(
438 &key_bytes.contents[16..48], &ED25519_PUB_KEY[12..44]).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300439 let signature = key_pair.sign(&hash);
440
David Brown69721182019-12-04 14:50:52 -0700441 result.write_u16::<LittleEndian>(TlvKinds::ED25519 as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300442
443 let signature = signature.as_ref().to_vec();
David Brown91d68632019-07-29 14:32:13 -0600444 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300445 result.extend_from_slice(signature.as_ref());
446 }
447
Fabio Utzig1e48b912018-09-18 09:04:18 -0300448 if self.kinds.contains(&TlvKinds::ENCRSA2048) {
449 let key_bytes = pem::parse(include_bytes!("../../enc-rsa2048-pub.pem")
450 .as_ref()).unwrap();
451 assert_eq!(key_bytes.tag, "PUBLIC KEY");
452
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300453 let cipherkey = self.get_enc_key();
454 let cipherkey = cipherkey.as_slice();
455 let encbuf = match c::rsa_oaep_encrypt(&key_bytes.contents, cipherkey) {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300456 Ok(v) => v,
457 Err(_) => panic!("Failed to encrypt secret key"),
458 };
459
460 assert!(encbuf.len() == 256);
David Brown69721182019-12-04 14:50:52 -0700461 result.write_u16::<LittleEndian>(TlvKinds::ENCRSA2048 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700462 result.write_u16::<LittleEndian>(256).unwrap();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300463 result.extend_from_slice(&encbuf);
464 }
465
466 if self.kinds.contains(&TlvKinds::ENCKW128) {
467 let key_bytes = base64::decode(
468 include_str!("../../enc-aes128kw.b64").trim()).unwrap();
469
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300470 let cipherkey = self.get_enc_key();
471 let cipherkey = cipherkey.as_slice();
472 let encbuf = match c::kw_encrypt(&key_bytes, cipherkey) {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300473 Ok(v) => v,
474 Err(_) => panic!("Failed to encrypt secret key"),
475 };
476
477 assert!(encbuf.len() == 24);
David Brown69721182019-12-04 14:50:52 -0700478 result.write_u16::<LittleEndian>(TlvKinds::ENCKW128 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700479 result.write_u16::<LittleEndian>(24).unwrap();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300480 result.extend_from_slice(&encbuf);
481 }
482
Fabio Utzig90f449e2019-10-24 07:43:53 -0300483 if self.kinds.contains(&TlvKinds::ENCEC256) {
484 let key_bytes = pem::parse(include_bytes!("../../enc-ec256-pub.pem").as_ref()).unwrap();
485 assert_eq!(key_bytes.tag, "PUBLIC KEY");
486
487 let rng = rand::SystemRandom::new();
488 let pk = match agreement::EphemeralPrivateKey::generate(&agreement::ECDH_P256, &rng) {
489 Ok(v) => v,
490 Err(_) => panic!("Failed to generate ephemeral keypair"),
491 };
492
493 let pubk = match pk.compute_public_key() {
494 Ok(pubk) => pubk,
495 Err(_) => panic!("Failed computing ephemeral public key"),
496 };
497
498 let peer_pubk = agreement::UnparsedPublicKey::new(&agreement::ECDH_P256, &key_bytes.contents[26..]);
499
500 #[derive(Debug, PartialEq)]
501 struct OkmLen<T: core::fmt::Debug + PartialEq>(T);
502
503 impl hkdf::KeyType for OkmLen<usize> {
504 fn len(&self) -> usize {
505 self.0
506 }
507 }
508
509 let derived_key = match agreement::agree_ephemeral(
510 pk, &peer_pubk, ring::error::Unspecified, |shared| {
511 let salt = hkdf::Salt::new(hkdf::HKDF_SHA256, &[]);
512 let prk = salt.extract(&shared);
513 let okm = match prk.expand(&[b"MCUBoot_ECIES_v1"], OkmLen(48)) {
514 Ok(okm) => okm,
515 Err(_) => panic!("Failed building HKDF OKM"),
516 };
517 let mut buf = [0u8; 48];
518 match okm.fill(&mut buf) {
519 Ok(_) => Ok(buf),
520 Err(_) => panic!("Failed generating HKDF output"),
521 }
522 },
523 ) {
524 Ok(v) => v,
525 Err(_) => panic!("Failed building HKDF"),
526 };
527
528 let key = GenericArray::from_slice(&derived_key[..16]);
529 let nonce = GenericArray::from_slice(&[0; 16]);
530 let mut cipher = Aes128Ctr::new(&key, &nonce);
531 let mut cipherkey = self.get_enc_key();
532 cipher.apply_keystream(&mut cipherkey);
533
534 let key = hmac::Key::new(hmac::HMAC_SHA256, &derived_key[16..]);
535 let tag = hmac::sign(&key, &cipherkey);
536
537 let mut buf = vec![];
538 buf.append(&mut pubk.as_ref().to_vec());
539 buf.append(&mut tag.as_ref().to_vec());
540 buf.append(&mut cipherkey);
541
542 assert!(buf.len() == 113);
David Brown69721182019-12-04 14:50:52 -0700543 result.write_u16::<LittleEndian>(TlvKinds::ENCEC256 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700544 result.write_u16::<LittleEndian>(113).unwrap();
Fabio Utzig90f449e2019-10-24 07:43:53 -0300545 result.extend_from_slice(&buf);
546 }
547
David Brown3dc86c92020-01-08 17:22:55 -0700548 // Patch the size back into the TLV header.
549 let size = (result.len() - npro_pos) as u16;
550 let mut size_buf = &mut result[npro_pos + 2 .. npro_pos + 4];
551 size_buf.write_u16::<LittleEndian>(size).unwrap();
552
David Brown187dd882017-07-11 11:15:23 -0600553 result
554 }
Fabio Utzig90f449e2019-10-24 07:43:53 -0300555
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300556 fn generate_enc_key(&mut self) {
557 let rng = rand::SystemRandom::new();
558 let mut buf = vec![0u8; AES_KEY_LEN];
559 match rng.fill(&mut buf) {
560 Err(_) => panic!("Error generating encrypted key"),
561 Ok(_) => (),
562 }
563 info!("New encryption key: {:02x?}", buf);
564 self.enc_key = buf;
Fabio Utzig90f449e2019-10-24 07:43:53 -0300565 }
566
567 fn get_enc_key(&self) -> Vec<u8> {
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300568 if self.enc_key.len() != AES_KEY_LEN {
569 panic!("No random key was generated");
570 }
571 self.enc_key.clone()
Fabio Utzig90f449e2019-10-24 07:43:53 -0300572 }
David Brown187dd882017-07-11 11:15:23 -0600573}
David Brown43cda332017-09-01 09:53:23 -0600574
575include!("rsa_pub_key-rs.txt");
Fabio Utzig39297432019-05-08 18:51:10 -0300576include!("rsa3072_pub_key-rs.txt");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200577include!("ecdsa_pub_key-rs.txt");
Fabio Utzig97710282019-05-24 17:44:49 -0300578include!("ed25519_pub_key-rs.txt");