blob: b6c3c969d0d0c95b9d1c68c38ded9ca7579259fc [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;
Fabio Utzige84f0ef2019-11-22 12:29:32 -030020use log::info;
Fabio Utzig90f449e2019-10-24 07:43:53 -030021use ring::{digest, rand, agreement, hkdf, hmac};
Fabio Utzige84f0ef2019-11-22 12:29:32 -030022use ring::rand::SecureRandom;
Fabio Utzig05ab0142018-07-10 09:15:28 -030023use ring::signature::{
24 RsaKeyPair,
25 RSA_PSS_SHA256,
26 EcdsaKeyPair,
27 ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig97710282019-05-24 17:44:49 -030028 Ed25519KeyPair,
Fabio Utzig05ab0142018-07-10 09:15:28 -030029};
Fabio Utzig90f449e2019-10-24 07:43:53 -030030use aes_ctr::{
31 Aes128Ctr,
32 stream_cipher::{
33 generic_array::GenericArray,
David Brown8a99adf2020-07-09 16:52:38 -060034 NewStreamCipher,
35 SyncStreamCipher,
Fabio Utzig90f449e2019-10-24 07:43:53 -030036 },
37};
Fabio Utzig80fde2f2017-12-05 09:25:31 -020038use mcuboot_sys::c;
David Brown187dd882017-07-11 11:15:23 -060039
David Brown69721182019-12-04 14:50:52 -070040#[repr(u16)]
David Brownc3898d62019-08-05 14:20:02 -060041#[derive(Copy, Clone, Debug, PartialEq, Eq)]
David Brown187dd882017-07-11 11:15:23 -060042#[allow(dead_code)] // TODO: For now
43pub enum TlvKinds {
David Brown43cda332017-09-01 09:53:23 -060044 KEYHASH = 0x01,
David Brown27648b82017-08-31 10:40:29 -060045 SHA256 = 0x10,
46 RSA2048 = 0x20,
47 ECDSA224 = 0x21,
48 ECDSA256 = 0x22,
Fabio Utzig39297432019-05-08 18:51:10 -030049 RSA3072 = 0x23,
Fabio Utzig97710282019-05-24 17:44:49 -030050 ED25519 = 0x24,
Fabio Utzig1e48b912018-09-18 09:04:18 -030051 ENCRSA2048 = 0x30,
52 ENCKW128 = 0x31,
Fabio Utzig90f449e2019-10-24 07:43:53 -030053 ENCEC256 = 0x32,
Fabio Utzig3fa72ca2020-04-02 11:20:37 -030054 ENCX25519 = 0x33,
David Brown7a81c4b2019-07-29 15:20:21 -060055 DEPENDENCY = 0x40,
Fabio Utzig1e48b912018-09-18 09:04:18 -030056}
57
58#[allow(dead_code, non_camel_case_types)]
59pub enum TlvFlags {
60 PIC = 0x01,
61 NON_BOOTABLE = 0x02,
62 ENCRYPTED = 0x04,
63 RAM_LOAD = 0x20,
David Brown187dd882017-07-11 11:15:23 -060064}
65
David Brown43643dd2019-01-11 15:43:28 -070066/// A generator for manifests. The format of the manifest can be either a
67/// traditional "TLV" or a SUIT-style manifest.
68pub trait ManifestGen {
David Brownac46e262019-01-11 15:46:18 -070069 /// Retrieve the header magic value for this manifest type.
70 fn get_magic(&self) -> u32;
71
David Brown43643dd2019-01-11 15:43:28 -070072 /// Retrieve the flags value for this particular manifest type.
73 fn get_flags(&self) -> u32;
74
David Brown7a81c4b2019-07-29 15:20:21 -060075 /// Retrieve the number of bytes of this manifest that is "protected".
76 /// This field is stored in the outside image header instead of the
77 /// manifest header.
78 fn protect_size(&self) -> u16;
79
80 /// Add a dependency on another image.
81 fn add_dependency(&mut self, id: u8, version: &ImageVersion);
82
David Brown43643dd2019-01-11 15:43:28 -070083 /// Add a sequence of bytes to the payload that the manifest is
84 /// protecting.
85 fn add_bytes(&mut self, bytes: &[u8]);
86
David Browne90b13f2019-12-06 15:04:00 -070087 /// Set an internal flag indicating that the next `make_tlv` should
88 /// corrupt the signature.
89 fn corrupt_sig(&mut self);
90
David Brown43643dd2019-01-11 15:43:28 -070091 /// Construct the manifest for this payload.
92 fn make_tlv(self: Box<Self>) -> Vec<u8>;
Fabio Utzig90f449e2019-10-24 07:43:53 -030093
Fabio Utzige84f0ef2019-11-22 12:29:32 -030094 /// Generate a new encryption random key
95 fn generate_enc_key(&mut self);
Fabio Utzig90f449e2019-10-24 07:43:53 -030096
97 /// Return the current encryption key
98 fn get_enc_key(&self) -> Vec<u8>;
David Brown43643dd2019-01-11 15:43:28 -070099}
100
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300101#[derive(Debug, Default)]
David Brown187dd882017-07-11 11:15:23 -0600102pub struct TlvGen {
David Brown43cda332017-09-01 09:53:23 -0600103 flags: u32,
David Brown187dd882017-07-11 11:15:23 -0600104 kinds: Vec<TlvKinds>,
David Brown4243ab02017-07-11 12:24:23 -0600105 payload: Vec<u8>,
David Brown7a81c4b2019-07-29 15:20:21 -0600106 dependencies: Vec<Dependency>,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300107 enc_key: Vec<u8>,
David Browne90b13f2019-12-06 15:04:00 -0700108 /// Should this signature be corrupted.
109 gen_corrupted: bool,
David Brown7a81c4b2019-07-29 15:20:21 -0600110}
111
David Brownc3898d62019-08-05 14:20:02 -0600112#[derive(Debug)]
David Brown7a81c4b2019-07-29 15:20:21 -0600113struct Dependency {
114 id: u8,
115 version: ImageVersion,
David Brown187dd882017-07-11 11:15:23 -0600116}
117
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300118const AES_KEY_LEN: usize = 16;
Fabio Utzig1e48b912018-09-18 09:04:18 -0300119
David Brown187dd882017-07-11 11:15:23 -0600120impl TlvGen {
121 /// Construct a new tlv generator that will only contain a hash of the data.
David Brown7e701d82017-07-11 13:24:25 -0600122 #[allow(dead_code)]
David Brown187dd882017-07-11 11:15:23 -0600123 pub fn new_hash_only() -> TlvGen {
124 TlvGen {
David Brown187dd882017-07-11 11:15:23 -0600125 kinds: vec![TlvKinds::SHA256],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300126 ..Default::default()
David Brown187dd882017-07-11 11:15:23 -0600127 }
128 }
129
David Brown7e701d82017-07-11 13:24:25 -0600130 #[allow(dead_code)]
131 pub fn new_rsa_pss() -> TlvGen {
132 TlvGen {
Fabio Utzig754438d2018-12-14 06:39:58 -0200133 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048],
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],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300142 ..Default::default()
Fabio Utzig39297432019-05-08 18:51:10 -0300143 }
144 }
145
146 #[allow(dead_code)]
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200147 pub fn new_ecdsa() -> TlvGen {
148 TlvGen {
Fabio Utzig754438d2018-12-14 06:39:58 -0200149 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300150 ..Default::default()
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200151 }
152 }
153
Fabio Utzig1e48b912018-09-18 09:04:18 -0300154 #[allow(dead_code)]
Fabio Utzig97710282019-05-24 17:44:49 -0300155 pub fn new_ed25519() -> TlvGen {
156 TlvGen {
Fabio Utzig97710282019-05-24 17:44:49 -0300157 kinds: vec![TlvKinds::SHA256, TlvKinds::ED25519],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300158 ..Default::default()
Fabio Utzig97710282019-05-24 17:44:49 -0300159 }
160 }
161
162 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300163 pub fn new_enc_rsa() -> TlvGen {
164 TlvGen {
165 flags: TlvFlags::ENCRYPTED as u32,
166 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300167 ..Default::default()
Fabio Utzig1e48b912018-09-18 09:04:18 -0300168 }
169 }
170
171 #[allow(dead_code)]
Fabio Utzig754438d2018-12-14 06:39:58 -0200172 pub fn new_sig_enc_rsa() -> TlvGen {
173 TlvGen {
174 flags: TlvFlags::ENCRYPTED as u32,
175 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCRSA2048],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300176 ..Default::default()
Fabio Utzig754438d2018-12-14 06:39:58 -0200177 }
178 }
179
180 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300181 pub fn new_enc_kw() -> TlvGen {
182 TlvGen {
183 flags: TlvFlags::ENCRYPTED as u32,
184 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW128],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300185 ..Default::default()
Fabio Utzig1e48b912018-09-18 09:04:18 -0300186 }
187 }
188
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200189 #[allow(dead_code)]
190 pub fn new_rsa_kw() -> TlvGen {
191 TlvGen {
192 flags: TlvFlags::ENCRYPTED as u32,
193 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCKW128],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300194 ..Default::default()
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200195 }
196 }
197
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200198 #[allow(dead_code)]
199 pub fn new_ecdsa_kw() -> TlvGen {
200 TlvGen {
201 flags: TlvFlags::ENCRYPTED as u32,
202 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCKW128],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300203 ..Default::default()
Fabio Utzig90f449e2019-10-24 07:43:53 -0300204 }
205 }
206
207 #[allow(dead_code)]
Fabio Utzig66b4caa2020-01-04 20:19:28 -0300208 pub fn new_ecies_p256() -> TlvGen {
209 TlvGen {
210 flags: TlvFlags::ENCRYPTED as u32,
211 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCEC256],
Fabio Utzig66b4caa2020-01-04 20:19:28 -0300212 ..Default::default()
213 }
214 }
215
216 #[allow(dead_code)]
Fabio Utzig90f449e2019-10-24 07:43:53 -0300217 pub fn new_ecdsa_ecies_p256() -> TlvGen {
218 TlvGen {
219 flags: TlvFlags::ENCRYPTED as u32,
220 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCEC256],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300221 ..Default::default()
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200222 }
223 }
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300224
225 #[allow(dead_code)]
226 pub fn new_ecies_x25519() -> TlvGen {
227 TlvGen {
228 flags: TlvFlags::ENCRYPTED as u32,
229 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCX25519],
230 ..Default::default()
231 }
232 }
233
234 #[allow(dead_code)]
235 pub fn new_ed25519_ecies_x25519() -> TlvGen {
236 TlvGen {
237 flags: TlvFlags::ENCRYPTED as u32,
238 kinds: vec![TlvKinds::SHA256, TlvKinds::ED25519, TlvKinds::ENCX25519],
239 ..Default::default()
240 }
241 }
David Brown43643dd2019-01-11 15:43:28 -0700242}
243
244impl ManifestGen for TlvGen {
David Brownac46e262019-01-11 15:46:18 -0700245 fn get_magic(&self) -> u32 {
246 0x96f3b83d
247 }
248
David Brown43643dd2019-01-11 15:43:28 -0700249 /// Retrieve the header flags for this configuration. This can be called at any time.
250 fn get_flags(&self) -> u32 {
251 self.flags
252 }
David Brown187dd882017-07-11 11:15:23 -0600253
254 /// Add bytes to the covered hash.
David Brown43643dd2019-01-11 15:43:28 -0700255 fn add_bytes(&mut self, bytes: &[u8]) {
David Brown4243ab02017-07-11 12:24:23 -0600256 self.payload.extend_from_slice(bytes);
David Brown187dd882017-07-11 11:15:23 -0600257 }
258
David Brown7a81c4b2019-07-29 15:20:21 -0600259 fn protect_size(&self) -> u16 {
David Brown2b73ed92020-01-08 17:01:22 -0700260 if self.dependencies.is_empty() {
David Brown7a81c4b2019-07-29 15:20:21 -0600261 0
262 } else {
David Brown2b73ed92020-01-08 17:01:22 -0700263 // Include the header and space for each dependency.
264 4 + (self.dependencies.len() as u16) * (4 + 4 + 8)
David Brown7a81c4b2019-07-29 15:20:21 -0600265 }
266 }
267
268 fn add_dependency(&mut self, id: u8, version: &ImageVersion) {
David Brown7a81c4b2019-07-29 15:20:21 -0600269 self.dependencies.push(Dependency {
David Brown4dfb33c2021-03-10 05:15:45 -0700270 id,
David Brown7a81c4b2019-07-29 15:20:21 -0600271 version: version.clone(),
272 });
273 }
274
David Browne90b13f2019-12-06 15:04:00 -0700275 fn corrupt_sig(&mut self) {
276 self.gen_corrupted = true;
277 }
278
David Brown187dd882017-07-11 11:15:23 -0600279 /// Compute the TLV given the specified block of data.
David Brown43643dd2019-01-11 15:43:28 -0700280 fn make_tlv(self: Box<Self>) -> Vec<u8> {
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300281 let mut protected_tlv: Vec<u8> = vec![];
David Brown187dd882017-07-11 11:15:23 -0600282
David Brown2b73ed92020-01-08 17:01:22 -0700283 if self.protect_size() > 0 {
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300284 protected_tlv.push(0x08);
285 protected_tlv.push(0x69);
David Brown2b73ed92020-01-08 17:01:22 -0700286 let size = self.protect_size();
287 protected_tlv.write_u16::<LittleEndian>(size).unwrap();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300288 for dep in &self.dependencies {
David Brown69721182019-12-04 14:50:52 -0700289 protected_tlv.write_u16::<LittleEndian>(TlvKinds::DEPENDENCY as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700290 protected_tlv.write_u16::<LittleEndian>(12).unwrap();
David Brownf5b33d82017-09-01 10:58:27 -0600291
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300292 // The dependency.
293 protected_tlv.push(dep.id);
David Brownf66b2052021-03-10 05:26:36 -0700294 protected_tlv.push(0);
295 protected_tlv.write_u16::<LittleEndian>(0).unwrap();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300296 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
David Brown3dc86c92020-01-08 17:22:55 -0700321 let npro_pos = result.len();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300322 result.push(0x07);
323 result.push(0x69);
David Brown3dc86c92020-01-08 17:22:55 -0700324 // Placeholder for the size.
325 result.write_u16::<LittleEndian>(0).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600326
David Brown187dd882017-07-11 11:15:23 -0600327 if self.kinds.contains(&TlvKinds::SHA256) {
David Browne90b13f2019-12-06 15:04:00 -0700328 // If a signature is not requested, corrupt the hash we are
329 // generating. But, if there is a signature, output the
330 // correct hash. We want the hash test to pass so that the
331 // signature verification can be validated.
332 let mut corrupt_hash = self.gen_corrupted;
333 for k in &[TlvKinds::RSA2048, TlvKinds::RSA3072,
334 TlvKinds::ECDSA224, TlvKinds::ECDSA256,
335 TlvKinds::ED25519]
336 {
337 if self.kinds.contains(k) {
338 corrupt_hash = false;
339 break;
340 }
341 }
342
343 if corrupt_hash {
344 sig_payload[0] ^= 1;
345 }
346
David Brown7a81c4b2019-07-29 15:20:21 -0600347 let hash = digest::digest(&digest::SHA256, &sig_payload);
David Brown8054ce22017-07-11 12:12:09 -0600348 let hash = hash.as_ref();
David Brown187dd882017-07-11 11:15:23 -0600349
David Brown8054ce22017-07-11 12:12:09 -0600350 assert!(hash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700351 result.write_u16::<LittleEndian>(TlvKinds::SHA256 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700352 result.write_u16::<LittleEndian>(32).unwrap();
David Brown8054ce22017-07-11 12:12:09 -0600353 result.extend_from_slice(hash);
David Browne90b13f2019-12-06 15:04:00 -0700354
355 // Undo the corruption.
356 if corrupt_hash {
357 sig_payload[0] ^= 1;
358 }
359
360 }
361
362 if self.gen_corrupted {
363 // Corrupt what is signed by modifying the input to the
364 // signature code.
365 sig_payload[0] ^= 1;
David Brown187dd882017-07-11 11:15:23 -0600366 }
367
Fabio Utzig39297432019-05-08 18:51:10 -0300368 if self.kinds.contains(&TlvKinds::RSA2048) ||
369 self.kinds.contains(&TlvKinds::RSA3072) {
370
371 let is_rsa2048 = self.kinds.contains(&TlvKinds::RSA2048);
372
David Brown43cda332017-09-01 09:53:23 -0600373 // Output the hash of the public key.
Fabio Utzig39297432019-05-08 18:51:10 -0300374 let hash = if is_rsa2048 {
375 digest::digest(&digest::SHA256, RSA_PUB_KEY)
376 } else {
377 digest::digest(&digest::SHA256, RSA3072_PUB_KEY)
378 };
David Brown43cda332017-09-01 09:53:23 -0600379 let hash = hash.as_ref();
380
381 assert!(hash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700382 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700383 result.write_u16::<LittleEndian>(32).unwrap();
David Brown43cda332017-09-01 09:53:23 -0600384 result.extend_from_slice(hash);
385
David Brown7e701d82017-07-11 13:24:25 -0600386 // For now assume PSS.
Fabio Utzig39297432019-05-08 18:51:10 -0300387 let key_bytes = if is_rsa2048 {
388 pem::parse(include_bytes!("../../root-rsa-2048.pem").as_ref()).unwrap()
389 } else {
390 pem::parse(include_bytes!("../../root-rsa-3072.pem").as_ref()).unwrap()
391 };
David Brown7e701d82017-07-11 13:24:25 -0600392 assert_eq!(key_bytes.tag, "RSA PRIVATE KEY");
Fabio Utzig90f449e2019-10-24 07:43:53 -0300393 let key_pair = RsaKeyPair::from_der(&key_bytes.contents).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600394 let rng = rand::SystemRandom::new();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300395 let mut signature = vec![0; key_pair.public_modulus_len()];
Fabio Utzig39297432019-05-08 18:51:10 -0300396 if is_rsa2048 {
397 assert_eq!(signature.len(), 256);
398 } else {
399 assert_eq!(signature.len(), 384);
400 }
David Brown7a81c4b2019-07-29 15:20:21 -0600401 key_pair.sign(&RSA_PSS_SHA256, &rng, &sig_payload, &mut signature).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600402
Fabio Utzig39297432019-05-08 18:51:10 -0300403 if is_rsa2048 {
David Brown69721182019-12-04 14:50:52 -0700404 result.write_u16::<LittleEndian>(TlvKinds::RSA2048 as u16).unwrap();
Fabio Utzig39297432019-05-08 18:51:10 -0300405 } else {
David Brown69721182019-12-04 14:50:52 -0700406 result.write_u16::<LittleEndian>(TlvKinds::RSA3072 as u16).unwrap();
Fabio Utzig39297432019-05-08 18:51:10 -0300407 }
David Brown91d68632019-07-29 14:32:13 -0600408 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600409 result.extend_from_slice(&signature);
410 }
411
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200412 if self.kinds.contains(&TlvKinds::ECDSA256) {
413 let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY);
414 let keyhash = keyhash.as_ref();
415
416 assert!(keyhash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700417 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700418 result.write_u16::<LittleEndian>(32).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200419 result.extend_from_slice(keyhash);
420
Fabio Utzig05ab0142018-07-10 09:15:28 -0300421 let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap();
422 assert_eq!(key_bytes.tag, "PRIVATE KEY");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200423
Fabio Utzig05ab0142018-07-10 09:15:28 -0300424 let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300425 &key_bytes.contents).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300426 let rng = rand::SystemRandom::new();
Fabio Utzig90f449e2019-10-24 07:43:53 -0300427 let signature = key_pair.sign(&rng, &sig_payload).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200428
David Brown69721182019-12-04 14:50:52 -0700429 result.write_u16::<LittleEndian>(TlvKinds::ECDSA256 as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300430
David Browna4c58642019-12-12 17:28:33 -0700431 let signature = signature.as_ref().to_vec();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300432
David Brown91d68632019-07-29 14:32:13 -0600433 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300434 result.extend_from_slice(signature.as_ref());
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200435 }
436
Fabio Utzig97710282019-05-24 17:44:49 -0300437 if self.kinds.contains(&TlvKinds::ED25519) {
438 let keyhash = digest::digest(&digest::SHA256, ED25519_PUB_KEY);
439 let keyhash = keyhash.as_ref();
440
441 assert!(keyhash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700442 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700443 result.write_u16::<LittleEndian>(32).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300444 result.extend_from_slice(keyhash);
445
David Brown7a81c4b2019-07-29 15:20:21 -0600446 let hash = digest::digest(&digest::SHA256, &sig_payload);
Fabio Utzig97710282019-05-24 17:44:49 -0300447 let hash = hash.as_ref();
448 assert!(hash.len() == 32);
449
450 let key_bytes = pem::parse(include_bytes!("../../root-ed25519.pem").as_ref()).unwrap();
451 assert_eq!(key_bytes.tag, "PRIVATE KEY");
452
Fabio Utzig90f449e2019-10-24 07:43:53 -0300453 let key_pair = Ed25519KeyPair::from_seed_and_public_key(
454 &key_bytes.contents[16..48], &ED25519_PUB_KEY[12..44]).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300455 let signature = key_pair.sign(&hash);
456
David Brown69721182019-12-04 14:50:52 -0700457 result.write_u16::<LittleEndian>(TlvKinds::ED25519 as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300458
459 let signature = signature.as_ref().to_vec();
David Brown91d68632019-07-29 14:32:13 -0600460 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300461 result.extend_from_slice(signature.as_ref());
462 }
463
Fabio Utzig1e48b912018-09-18 09:04:18 -0300464 if self.kinds.contains(&TlvKinds::ENCRSA2048) {
465 let key_bytes = pem::parse(include_bytes!("../../enc-rsa2048-pub.pem")
466 .as_ref()).unwrap();
467 assert_eq!(key_bytes.tag, "PUBLIC KEY");
468
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300469 let cipherkey = self.get_enc_key();
470 let cipherkey = cipherkey.as_slice();
471 let encbuf = match c::rsa_oaep_encrypt(&key_bytes.contents, cipherkey) {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300472 Ok(v) => v,
473 Err(_) => panic!("Failed to encrypt secret key"),
474 };
475
476 assert!(encbuf.len() == 256);
David Brown69721182019-12-04 14:50:52 -0700477 result.write_u16::<LittleEndian>(TlvKinds::ENCRSA2048 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700478 result.write_u16::<LittleEndian>(256).unwrap();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300479 result.extend_from_slice(&encbuf);
480 }
481
482 if self.kinds.contains(&TlvKinds::ENCKW128) {
483 let key_bytes = base64::decode(
484 include_str!("../../enc-aes128kw.b64").trim()).unwrap();
485
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300486 let cipherkey = self.get_enc_key();
487 let cipherkey = cipherkey.as_slice();
488 let encbuf = match c::kw_encrypt(&key_bytes, cipherkey) {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300489 Ok(v) => v,
490 Err(_) => panic!("Failed to encrypt secret key"),
491 };
492
493 assert!(encbuf.len() == 24);
David Brown69721182019-12-04 14:50:52 -0700494 result.write_u16::<LittleEndian>(TlvKinds::ENCKW128 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700495 result.write_u16::<LittleEndian>(24).unwrap();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300496 result.extend_from_slice(&encbuf);
497 }
498
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300499 if self.kinds.contains(&TlvKinds::ENCEC256) || self.kinds.contains(&TlvKinds::ENCX25519) {
500 let key_bytes = if self.kinds.contains(&TlvKinds::ENCEC256) {
501 pem::parse(include_bytes!("../../enc-ec256-pub.pem").as_ref()).unwrap()
502 } else {
503 pem::parse(include_bytes!("../../enc-x25519-pub.pem").as_ref()).unwrap()
504 };
Fabio Utzig90f449e2019-10-24 07:43:53 -0300505 assert_eq!(key_bytes.tag, "PUBLIC KEY");
506
507 let rng = rand::SystemRandom::new();
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300508 let alg = if self.kinds.contains(&TlvKinds::ENCEC256) {
509 &agreement::ECDH_P256
510 } else {
511 &agreement::X25519
512 };
513 let pk = match agreement::EphemeralPrivateKey::generate(alg, &rng) {
Fabio Utzig90f449e2019-10-24 07:43:53 -0300514 Ok(v) => v,
515 Err(_) => panic!("Failed to generate ephemeral keypair"),
516 };
517
518 let pubk = match pk.compute_public_key() {
519 Ok(pubk) => pubk,
520 Err(_) => panic!("Failed computing ephemeral public key"),
521 };
522
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300523 let peer_pubk = if self.kinds.contains(&TlvKinds::ENCEC256) {
524 agreement::UnparsedPublicKey::new(&agreement::ECDH_P256, &key_bytes.contents[26..])
525 } else {
526 agreement::UnparsedPublicKey::new(&agreement::X25519, &key_bytes.contents[12..])
527 };
Fabio Utzig90f449e2019-10-24 07:43:53 -0300528
529 #[derive(Debug, PartialEq)]
530 struct OkmLen<T: core::fmt::Debug + PartialEq>(T);
531
532 impl hkdf::KeyType for OkmLen<usize> {
533 fn len(&self) -> usize {
534 self.0
535 }
536 }
537
538 let derived_key = match agreement::agree_ephemeral(
539 pk, &peer_pubk, ring::error::Unspecified, |shared| {
540 let salt = hkdf::Salt::new(hkdf::HKDF_SHA256, &[]);
541 let prk = salt.extract(&shared);
542 let okm = match prk.expand(&[b"MCUBoot_ECIES_v1"], OkmLen(48)) {
543 Ok(okm) => okm,
544 Err(_) => panic!("Failed building HKDF OKM"),
545 };
546 let mut buf = [0u8; 48];
547 match okm.fill(&mut buf) {
548 Ok(_) => Ok(buf),
549 Err(_) => panic!("Failed generating HKDF output"),
550 }
551 },
552 ) {
553 Ok(v) => v,
554 Err(_) => panic!("Failed building HKDF"),
555 };
556
557 let key = GenericArray::from_slice(&derived_key[..16]);
558 let nonce = GenericArray::from_slice(&[0; 16]);
559 let mut cipher = Aes128Ctr::new(&key, &nonce);
560 let mut cipherkey = self.get_enc_key();
561 cipher.apply_keystream(&mut cipherkey);
562
563 let key = hmac::Key::new(hmac::HMAC_SHA256, &derived_key[16..]);
564 let tag = hmac::sign(&key, &cipherkey);
565
566 let mut buf = vec![];
567 buf.append(&mut pubk.as_ref().to_vec());
568 buf.append(&mut tag.as_ref().to_vec());
569 buf.append(&mut cipherkey);
570
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300571 if self.kinds.contains(&TlvKinds::ENCEC256) {
572 assert!(buf.len() == 113);
573 result.write_u16::<LittleEndian>(TlvKinds::ENCEC256 as u16).unwrap();
574 result.write_u16::<LittleEndian>(113).unwrap();
575 } else {
576 assert!(buf.len() == 80);
577 result.write_u16::<LittleEndian>(TlvKinds::ENCX25519 as u16).unwrap();
578 result.write_u16::<LittleEndian>(80).unwrap();
579 }
Fabio Utzig90f449e2019-10-24 07:43:53 -0300580 result.extend_from_slice(&buf);
581 }
582
David Brown3dc86c92020-01-08 17:22:55 -0700583 // Patch the size back into the TLV header.
584 let size = (result.len() - npro_pos) as u16;
585 let mut size_buf = &mut result[npro_pos + 2 .. npro_pos + 4];
586 size_buf.write_u16::<LittleEndian>(size).unwrap();
587
David Brown187dd882017-07-11 11:15:23 -0600588 result
589 }
Fabio Utzig90f449e2019-10-24 07:43:53 -0300590
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300591 fn generate_enc_key(&mut self) {
592 let rng = rand::SystemRandom::new();
593 let mut buf = vec![0u8; AES_KEY_LEN];
David Brown26edaf32021-03-10 05:27:38 -0700594 if rng.fill(&mut buf).is_err() {
595 panic!("Error generating encrypted key");
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300596 }
597 info!("New encryption key: {:02x?}", buf);
598 self.enc_key = buf;
Fabio Utzig90f449e2019-10-24 07:43:53 -0300599 }
600
601 fn get_enc_key(&self) -> Vec<u8> {
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300602 if self.enc_key.len() != AES_KEY_LEN {
603 panic!("No random key was generated");
604 }
605 self.enc_key.clone()
Fabio Utzig90f449e2019-10-24 07:43:53 -0300606 }
David Brown187dd882017-07-11 11:15:23 -0600607}
David Brown43cda332017-09-01 09:53:23 -0600608
609include!("rsa_pub_key-rs.txt");
Fabio Utzig39297432019-05-08 18:51:10 -0300610include!("rsa3072_pub_key-rs.txt");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200611include!("ecdsa_pub_key-rs.txt");
Fabio Utzig97710282019-05-24 17:44:49 -0300612include!("ed25519_pub_key-rs.txt");