blob: 39bb1b6692d4b9d335138388d73a05b97a637c75 [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);
294 for _ in 0 .. 3 {
295 protected_tlv.push(0);
296 }
297 protected_tlv.push(dep.version.major);
298 protected_tlv.push(dep.version.minor);
299 protected_tlv.write_u16::<LittleEndian>(dep.version.revision).unwrap();
300 protected_tlv.write_u32::<LittleEndian>(dep.version.build_num).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600301 }
David Brown2b73ed92020-01-08 17:01:22 -0700302
303 assert_eq!(size, protected_tlv.len() as u16, "protected TLV length incorrect");
David Brown7a81c4b2019-07-29 15:20:21 -0600304 }
305
306 // Ring does the signature itself, which means that it must be
307 // given a full, contiguous payload. Although this does help from
308 // a correct usage perspective, it is fairly stupid from an
309 // efficiency view. If this is shown to be a performance issue
310 // with the tests, the protected data could be appended to the
311 // payload, and then removed after the signature is done. For now,
312 // just make a signed payload.
313 let mut sig_payload = self.payload.clone();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300314 sig_payload.extend_from_slice(&protected_tlv);
315
316 let mut result: Vec<u8> = vec![];
317
318 // add back signed payload
319 result.extend_from_slice(&protected_tlv);
320
321 // add non-protected payload
David Brown3dc86c92020-01-08 17:22:55 -0700322 let npro_pos = result.len();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300323 result.push(0x07);
324 result.push(0x69);
David Brown3dc86c92020-01-08 17:22:55 -0700325 // Placeholder for the size.
326 result.write_u16::<LittleEndian>(0).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600327
David Brown187dd882017-07-11 11:15:23 -0600328 if self.kinds.contains(&TlvKinds::SHA256) {
David Browne90b13f2019-12-06 15:04:00 -0700329 // If a signature is not requested, corrupt the hash we are
330 // generating. But, if there is a signature, output the
331 // correct hash. We want the hash test to pass so that the
332 // signature verification can be validated.
333 let mut corrupt_hash = self.gen_corrupted;
334 for k in &[TlvKinds::RSA2048, TlvKinds::RSA3072,
335 TlvKinds::ECDSA224, TlvKinds::ECDSA256,
336 TlvKinds::ED25519]
337 {
338 if self.kinds.contains(k) {
339 corrupt_hash = false;
340 break;
341 }
342 }
343
344 if corrupt_hash {
345 sig_payload[0] ^= 1;
346 }
347
David Brown7a81c4b2019-07-29 15:20:21 -0600348 let hash = digest::digest(&digest::SHA256, &sig_payload);
David Brown8054ce22017-07-11 12:12:09 -0600349 let hash = hash.as_ref();
David Brown187dd882017-07-11 11:15:23 -0600350
David Brown8054ce22017-07-11 12:12:09 -0600351 assert!(hash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700352 result.write_u16::<LittleEndian>(TlvKinds::SHA256 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700353 result.write_u16::<LittleEndian>(32).unwrap();
David Brown8054ce22017-07-11 12:12:09 -0600354 result.extend_from_slice(hash);
David Browne90b13f2019-12-06 15:04:00 -0700355
356 // Undo the corruption.
357 if corrupt_hash {
358 sig_payload[0] ^= 1;
359 }
360
361 }
362
363 if self.gen_corrupted {
364 // Corrupt what is signed by modifying the input to the
365 // signature code.
366 sig_payload[0] ^= 1;
David Brown187dd882017-07-11 11:15:23 -0600367 }
368
Fabio Utzig39297432019-05-08 18:51:10 -0300369 if self.kinds.contains(&TlvKinds::RSA2048) ||
370 self.kinds.contains(&TlvKinds::RSA3072) {
371
372 let is_rsa2048 = self.kinds.contains(&TlvKinds::RSA2048);
373
David Brown43cda332017-09-01 09:53:23 -0600374 // Output the hash of the public key.
Fabio Utzig39297432019-05-08 18:51:10 -0300375 let hash = if is_rsa2048 {
376 digest::digest(&digest::SHA256, RSA_PUB_KEY)
377 } else {
378 digest::digest(&digest::SHA256, RSA3072_PUB_KEY)
379 };
David Brown43cda332017-09-01 09:53:23 -0600380 let hash = hash.as_ref();
381
382 assert!(hash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700383 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700384 result.write_u16::<LittleEndian>(32).unwrap();
David Brown43cda332017-09-01 09:53:23 -0600385 result.extend_from_slice(hash);
386
David Brown7e701d82017-07-11 13:24:25 -0600387 // For now assume PSS.
Fabio Utzig39297432019-05-08 18:51:10 -0300388 let key_bytes = if is_rsa2048 {
389 pem::parse(include_bytes!("../../root-rsa-2048.pem").as_ref()).unwrap()
390 } else {
391 pem::parse(include_bytes!("../../root-rsa-3072.pem").as_ref()).unwrap()
392 };
David Brown7e701d82017-07-11 13:24:25 -0600393 assert_eq!(key_bytes.tag, "RSA PRIVATE KEY");
Fabio Utzig90f449e2019-10-24 07:43:53 -0300394 let key_pair = RsaKeyPair::from_der(&key_bytes.contents).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600395 let rng = rand::SystemRandom::new();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300396 let mut signature = vec![0; key_pair.public_modulus_len()];
Fabio Utzig39297432019-05-08 18:51:10 -0300397 if is_rsa2048 {
398 assert_eq!(signature.len(), 256);
399 } else {
400 assert_eq!(signature.len(), 384);
401 }
David Brown7a81c4b2019-07-29 15:20:21 -0600402 key_pair.sign(&RSA_PSS_SHA256, &rng, &sig_payload, &mut signature).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600403
Fabio Utzig39297432019-05-08 18:51:10 -0300404 if is_rsa2048 {
David Brown69721182019-12-04 14:50:52 -0700405 result.write_u16::<LittleEndian>(TlvKinds::RSA2048 as u16).unwrap();
Fabio Utzig39297432019-05-08 18:51:10 -0300406 } else {
David Brown69721182019-12-04 14:50:52 -0700407 result.write_u16::<LittleEndian>(TlvKinds::RSA3072 as u16).unwrap();
Fabio Utzig39297432019-05-08 18:51:10 -0300408 }
David Brown91d68632019-07-29 14:32:13 -0600409 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600410 result.extend_from_slice(&signature);
411 }
412
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200413 if self.kinds.contains(&TlvKinds::ECDSA256) {
414 let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY);
415 let keyhash = keyhash.as_ref();
416
417 assert!(keyhash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700418 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700419 result.write_u16::<LittleEndian>(32).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200420 result.extend_from_slice(keyhash);
421
Fabio Utzig05ab0142018-07-10 09:15:28 -0300422 let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap();
423 assert_eq!(key_bytes.tag, "PRIVATE KEY");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200424
Fabio Utzig05ab0142018-07-10 09:15:28 -0300425 let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300426 &key_bytes.contents).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300427 let rng = rand::SystemRandom::new();
Fabio Utzig90f449e2019-10-24 07:43:53 -0300428 let signature = key_pair.sign(&rng, &sig_payload).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200429
David Brown69721182019-12-04 14:50:52 -0700430 result.write_u16::<LittleEndian>(TlvKinds::ECDSA256 as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300431
David Browna4c58642019-12-12 17:28:33 -0700432 let signature = signature.as_ref().to_vec();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300433
David Brown91d68632019-07-29 14:32:13 -0600434 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300435 result.extend_from_slice(signature.as_ref());
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200436 }
437
Fabio Utzig97710282019-05-24 17:44:49 -0300438 if self.kinds.contains(&TlvKinds::ED25519) {
439 let keyhash = digest::digest(&digest::SHA256, ED25519_PUB_KEY);
440 let keyhash = keyhash.as_ref();
441
442 assert!(keyhash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700443 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700444 result.write_u16::<LittleEndian>(32).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300445 result.extend_from_slice(keyhash);
446
David Brown7a81c4b2019-07-29 15:20:21 -0600447 let hash = digest::digest(&digest::SHA256, &sig_payload);
Fabio Utzig97710282019-05-24 17:44:49 -0300448 let hash = hash.as_ref();
449 assert!(hash.len() == 32);
450
451 let key_bytes = pem::parse(include_bytes!("../../root-ed25519.pem").as_ref()).unwrap();
452 assert_eq!(key_bytes.tag, "PRIVATE KEY");
453
Fabio Utzig90f449e2019-10-24 07:43:53 -0300454 let key_pair = Ed25519KeyPair::from_seed_and_public_key(
455 &key_bytes.contents[16..48], &ED25519_PUB_KEY[12..44]).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300456 let signature = key_pair.sign(&hash);
457
David Brown69721182019-12-04 14:50:52 -0700458 result.write_u16::<LittleEndian>(TlvKinds::ED25519 as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300459
460 let signature = signature.as_ref().to_vec();
David Brown91d68632019-07-29 14:32:13 -0600461 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300462 result.extend_from_slice(signature.as_ref());
463 }
464
Fabio Utzig1e48b912018-09-18 09:04:18 -0300465 if self.kinds.contains(&TlvKinds::ENCRSA2048) {
466 let key_bytes = pem::parse(include_bytes!("../../enc-rsa2048-pub.pem")
467 .as_ref()).unwrap();
468 assert_eq!(key_bytes.tag, "PUBLIC KEY");
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::rsa_oaep_encrypt(&key_bytes.contents, 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() == 256);
David Brown69721182019-12-04 14:50:52 -0700478 result.write_u16::<LittleEndian>(TlvKinds::ENCRSA2048 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700479 result.write_u16::<LittleEndian>(256).unwrap();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300480 result.extend_from_slice(&encbuf);
481 }
482
483 if self.kinds.contains(&TlvKinds::ENCKW128) {
484 let key_bytes = base64::decode(
485 include_str!("../../enc-aes128kw.b64").trim()).unwrap();
486
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300487 let cipherkey = self.get_enc_key();
488 let cipherkey = cipherkey.as_slice();
489 let encbuf = match c::kw_encrypt(&key_bytes, cipherkey) {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300490 Ok(v) => v,
491 Err(_) => panic!("Failed to encrypt secret key"),
492 };
493
494 assert!(encbuf.len() == 24);
David Brown69721182019-12-04 14:50:52 -0700495 result.write_u16::<LittleEndian>(TlvKinds::ENCKW128 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700496 result.write_u16::<LittleEndian>(24).unwrap();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300497 result.extend_from_slice(&encbuf);
498 }
499
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300500 if self.kinds.contains(&TlvKinds::ENCEC256) || self.kinds.contains(&TlvKinds::ENCX25519) {
501 let key_bytes = if self.kinds.contains(&TlvKinds::ENCEC256) {
502 pem::parse(include_bytes!("../../enc-ec256-pub.pem").as_ref()).unwrap()
503 } else {
504 pem::parse(include_bytes!("../../enc-x25519-pub.pem").as_ref()).unwrap()
505 };
Fabio Utzig90f449e2019-10-24 07:43:53 -0300506 assert_eq!(key_bytes.tag, "PUBLIC KEY");
507
508 let rng = rand::SystemRandom::new();
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300509 let alg = if self.kinds.contains(&TlvKinds::ENCEC256) {
510 &agreement::ECDH_P256
511 } else {
512 &agreement::X25519
513 };
514 let pk = match agreement::EphemeralPrivateKey::generate(alg, &rng) {
Fabio Utzig90f449e2019-10-24 07:43:53 -0300515 Ok(v) => v,
516 Err(_) => panic!("Failed to generate ephemeral keypair"),
517 };
518
519 let pubk = match pk.compute_public_key() {
520 Ok(pubk) => pubk,
521 Err(_) => panic!("Failed computing ephemeral public key"),
522 };
523
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300524 let peer_pubk = if self.kinds.contains(&TlvKinds::ENCEC256) {
525 agreement::UnparsedPublicKey::new(&agreement::ECDH_P256, &key_bytes.contents[26..])
526 } else {
527 agreement::UnparsedPublicKey::new(&agreement::X25519, &key_bytes.contents[12..])
528 };
Fabio Utzig90f449e2019-10-24 07:43:53 -0300529
530 #[derive(Debug, PartialEq)]
531 struct OkmLen<T: core::fmt::Debug + PartialEq>(T);
532
533 impl hkdf::KeyType for OkmLen<usize> {
534 fn len(&self) -> usize {
535 self.0
536 }
537 }
538
539 let derived_key = match agreement::agree_ephemeral(
540 pk, &peer_pubk, ring::error::Unspecified, |shared| {
541 let salt = hkdf::Salt::new(hkdf::HKDF_SHA256, &[]);
542 let prk = salt.extract(&shared);
543 let okm = match prk.expand(&[b"MCUBoot_ECIES_v1"], OkmLen(48)) {
544 Ok(okm) => okm,
545 Err(_) => panic!("Failed building HKDF OKM"),
546 };
547 let mut buf = [0u8; 48];
548 match okm.fill(&mut buf) {
549 Ok(_) => Ok(buf),
550 Err(_) => panic!("Failed generating HKDF output"),
551 }
552 },
553 ) {
554 Ok(v) => v,
555 Err(_) => panic!("Failed building HKDF"),
556 };
557
558 let key = GenericArray::from_slice(&derived_key[..16]);
559 let nonce = GenericArray::from_slice(&[0; 16]);
560 let mut cipher = Aes128Ctr::new(&key, &nonce);
561 let mut cipherkey = self.get_enc_key();
562 cipher.apply_keystream(&mut cipherkey);
563
564 let key = hmac::Key::new(hmac::HMAC_SHA256, &derived_key[16..]);
565 let tag = hmac::sign(&key, &cipherkey);
566
567 let mut buf = vec![];
568 buf.append(&mut pubk.as_ref().to_vec());
569 buf.append(&mut tag.as_ref().to_vec());
570 buf.append(&mut cipherkey);
571
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300572 if self.kinds.contains(&TlvKinds::ENCEC256) {
573 assert!(buf.len() == 113);
574 result.write_u16::<LittleEndian>(TlvKinds::ENCEC256 as u16).unwrap();
575 result.write_u16::<LittleEndian>(113).unwrap();
576 } else {
577 assert!(buf.len() == 80);
578 result.write_u16::<LittleEndian>(TlvKinds::ENCX25519 as u16).unwrap();
579 result.write_u16::<LittleEndian>(80).unwrap();
580 }
Fabio Utzig90f449e2019-10-24 07:43:53 -0300581 result.extend_from_slice(&buf);
582 }
583
David Brown3dc86c92020-01-08 17:22:55 -0700584 // Patch the size back into the TLV header.
585 let size = (result.len() - npro_pos) as u16;
586 let mut size_buf = &mut result[npro_pos + 2 .. npro_pos + 4];
587 size_buf.write_u16::<LittleEndian>(size).unwrap();
588
David Brown187dd882017-07-11 11:15:23 -0600589 result
590 }
Fabio Utzig90f449e2019-10-24 07:43:53 -0300591
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300592 fn generate_enc_key(&mut self) {
593 let rng = rand::SystemRandom::new();
594 let mut buf = vec![0u8; AES_KEY_LEN];
595 match rng.fill(&mut buf) {
596 Err(_) => panic!("Error generating encrypted key"),
597 Ok(_) => (),
598 }
599 info!("New encryption key: {:02x?}", buf);
600 self.enc_key = buf;
Fabio Utzig90f449e2019-10-24 07:43:53 -0300601 }
602
603 fn get_enc_key(&self) -> Vec<u8> {
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300604 if self.enc_key.len() != AES_KEY_LEN {
605 panic!("No random key was generated");
606 }
607 self.enc_key.clone()
Fabio Utzig90f449e2019-10-24 07:43:53 -0300608 }
David Brown187dd882017-07-11 11:15:23 -0600609}
David Brown43cda332017-09-01 09:53:23 -0600610
611include!("rsa_pub_key-rs.txt");
Fabio Utzig39297432019-05-08 18:51:10 -0300612include!("rsa3072_pub_key-rs.txt");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200613include!("ecdsa_pub_key-rs.txt");
Fabio Utzig97710282019-05-24 17:44:49 -0300614include!("ed25519_pub_key-rs.txt");