blob: 23f8bb8c7c90e6fde5e9390807c0c78da5360541 [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,
Fabio Utzig3fa72ca2020-04-02 11:20:37 -030056 ENCX25519 = 0x33,
David Brown7a81c4b2019-07-29 15:20:21 -060057 DEPENDENCY = 0x40,
Fabio Utzig1e48b912018-09-18 09:04:18 -030058}
59
60#[allow(dead_code, non_camel_case_types)]
61pub enum TlvFlags {
62 PIC = 0x01,
63 NON_BOOTABLE = 0x02,
64 ENCRYPTED = 0x04,
65 RAM_LOAD = 0x20,
David Brown187dd882017-07-11 11:15:23 -060066}
67
David Brown43643dd2019-01-11 15:43:28 -070068/// A generator for manifests. The format of the manifest can be either a
69/// traditional "TLV" or a SUIT-style manifest.
70pub trait ManifestGen {
David Brownac46e262019-01-11 15:46:18 -070071 /// Retrieve the header magic value for this manifest type.
72 fn get_magic(&self) -> u32;
73
David Brown43643dd2019-01-11 15:43:28 -070074 /// Retrieve the flags value for this particular manifest type.
75 fn get_flags(&self) -> u32;
76
David Brown7a81c4b2019-07-29 15:20:21 -060077 /// Retrieve the number of bytes of this manifest that is "protected".
78 /// This field is stored in the outside image header instead of the
79 /// manifest header.
80 fn protect_size(&self) -> u16;
81
82 /// Add a dependency on another image.
83 fn add_dependency(&mut self, id: u8, version: &ImageVersion);
84
David Brown43643dd2019-01-11 15:43:28 -070085 /// Add a sequence of bytes to the payload that the manifest is
86 /// protecting.
87 fn add_bytes(&mut self, bytes: &[u8]);
88
David Browne90b13f2019-12-06 15:04:00 -070089 /// Set an internal flag indicating that the next `make_tlv` should
90 /// corrupt the signature.
91 fn corrupt_sig(&mut self);
92
David Brown43643dd2019-01-11 15:43:28 -070093 /// Construct the manifest for this payload.
94 fn make_tlv(self: Box<Self>) -> Vec<u8>;
Fabio Utzig90f449e2019-10-24 07:43:53 -030095
Fabio Utzige84f0ef2019-11-22 12:29:32 -030096 /// Generate a new encryption random key
97 fn generate_enc_key(&mut self);
Fabio Utzig90f449e2019-10-24 07:43:53 -030098
99 /// Return the current encryption key
100 fn get_enc_key(&self) -> Vec<u8>;
David Brown43643dd2019-01-11 15:43:28 -0700101}
102
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300103#[derive(Debug, Default)]
David Brown187dd882017-07-11 11:15:23 -0600104pub struct TlvGen {
David Brown43cda332017-09-01 09:53:23 -0600105 flags: u32,
David Brown187dd882017-07-11 11:15:23 -0600106 kinds: Vec<TlvKinds>,
David Brown4243ab02017-07-11 12:24:23 -0600107 payload: Vec<u8>,
David Brown7a81c4b2019-07-29 15:20:21 -0600108 dependencies: Vec<Dependency>,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300109 enc_key: Vec<u8>,
David Browne90b13f2019-12-06 15:04:00 -0700110 /// Should this signature be corrupted.
111 gen_corrupted: bool,
David Brown7a81c4b2019-07-29 15:20:21 -0600112}
113
David Brownc3898d62019-08-05 14:20:02 -0600114#[derive(Debug)]
David Brown7a81c4b2019-07-29 15:20:21 -0600115struct Dependency {
116 id: u8,
117 version: ImageVersion,
David Brown187dd882017-07-11 11:15:23 -0600118}
119
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300120const AES_KEY_LEN: usize = 16;
Fabio Utzig1e48b912018-09-18 09:04:18 -0300121
David Brown187dd882017-07-11 11:15:23 -0600122impl TlvGen {
123 /// Construct a new tlv generator that will only contain a hash of the data.
David Brown7e701d82017-07-11 13:24:25 -0600124 #[allow(dead_code)]
David Brown187dd882017-07-11 11:15:23 -0600125 pub fn new_hash_only() -> TlvGen {
126 TlvGen {
David Brown187dd882017-07-11 11:15:23 -0600127 kinds: vec![TlvKinds::SHA256],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300128 ..Default::default()
David Brown187dd882017-07-11 11:15:23 -0600129 }
130 }
131
David Brown7e701d82017-07-11 13:24:25 -0600132 #[allow(dead_code)]
133 pub fn new_rsa_pss() -> TlvGen {
134 TlvGen {
Fabio Utzig754438d2018-12-14 06:39:58 -0200135 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300136 ..Default::default()
David Brown7e701d82017-07-11 13:24:25 -0600137 }
138 }
139
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200140 #[allow(dead_code)]
Fabio Utzig39297432019-05-08 18:51:10 -0300141 pub fn new_rsa3072_pss() -> TlvGen {
142 TlvGen {
Fabio Utzig39297432019-05-08 18:51:10 -0300143 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA3072],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300144 ..Default::default()
Fabio Utzig39297432019-05-08 18:51:10 -0300145 }
146 }
147
148 #[allow(dead_code)]
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200149 pub fn new_ecdsa() -> TlvGen {
150 TlvGen {
Fabio Utzig754438d2018-12-14 06:39:58 -0200151 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256],
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],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300160 ..Default::default()
Fabio Utzig97710282019-05-24 17:44:49 -0300161 }
162 }
163
164 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300165 pub fn new_enc_rsa() -> TlvGen {
166 TlvGen {
167 flags: TlvFlags::ENCRYPTED as u32,
168 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300169 ..Default::default()
Fabio Utzig1e48b912018-09-18 09:04:18 -0300170 }
171 }
172
173 #[allow(dead_code)]
Fabio Utzig754438d2018-12-14 06:39:58 -0200174 pub fn new_sig_enc_rsa() -> TlvGen {
175 TlvGen {
176 flags: TlvFlags::ENCRYPTED as u32,
177 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCRSA2048],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300178 ..Default::default()
Fabio Utzig754438d2018-12-14 06:39:58 -0200179 }
180 }
181
182 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300183 pub fn new_enc_kw() -> TlvGen {
184 TlvGen {
185 flags: TlvFlags::ENCRYPTED as u32,
186 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW128],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300187 ..Default::default()
Fabio Utzig1e48b912018-09-18 09:04:18 -0300188 }
189 }
190
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200191 #[allow(dead_code)]
192 pub fn new_rsa_kw() -> TlvGen {
193 TlvGen {
194 flags: TlvFlags::ENCRYPTED as u32,
195 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCKW128],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300196 ..Default::default()
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200197 }
198 }
199
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200200 #[allow(dead_code)]
201 pub fn new_ecdsa_kw() -> TlvGen {
202 TlvGen {
203 flags: TlvFlags::ENCRYPTED as u32,
204 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCKW128],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300205 ..Default::default()
Fabio Utzig90f449e2019-10-24 07:43:53 -0300206 }
207 }
208
209 #[allow(dead_code)]
Fabio Utzig66b4caa2020-01-04 20:19:28 -0300210 pub fn new_ecies_p256() -> TlvGen {
211 TlvGen {
212 flags: TlvFlags::ENCRYPTED as u32,
213 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCEC256],
Fabio Utzig66b4caa2020-01-04 20:19:28 -0300214 ..Default::default()
215 }
216 }
217
218 #[allow(dead_code)]
Fabio Utzig90f449e2019-10-24 07:43:53 -0300219 pub fn new_ecdsa_ecies_p256() -> TlvGen {
220 TlvGen {
221 flags: TlvFlags::ENCRYPTED as u32,
222 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCEC256],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300223 ..Default::default()
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200224 }
225 }
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300226
227 #[allow(dead_code)]
228 pub fn new_ecies_x25519() -> TlvGen {
229 TlvGen {
230 flags: TlvFlags::ENCRYPTED as u32,
231 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCX25519],
232 ..Default::default()
233 }
234 }
235
236 #[allow(dead_code)]
237 pub fn new_ed25519_ecies_x25519() -> TlvGen {
238 TlvGen {
239 flags: TlvFlags::ENCRYPTED as u32,
240 kinds: vec![TlvKinds::SHA256, TlvKinds::ED25519, TlvKinds::ENCX25519],
241 ..Default::default()
242 }
243 }
David Brown43643dd2019-01-11 15:43:28 -0700244}
245
246impl ManifestGen for TlvGen {
David Brownac46e262019-01-11 15:46:18 -0700247 fn get_magic(&self) -> u32 {
248 0x96f3b83d
249 }
250
David Brown43643dd2019-01-11 15:43:28 -0700251 /// Retrieve the header flags for this configuration. This can be called at any time.
252 fn get_flags(&self) -> u32 {
253 self.flags
254 }
David Brown187dd882017-07-11 11:15:23 -0600255
256 /// Add bytes to the covered hash.
David Brown43643dd2019-01-11 15:43:28 -0700257 fn add_bytes(&mut self, bytes: &[u8]) {
David Brown4243ab02017-07-11 12:24:23 -0600258 self.payload.extend_from_slice(bytes);
David Brown187dd882017-07-11 11:15:23 -0600259 }
260
David Brown7a81c4b2019-07-29 15:20:21 -0600261 fn protect_size(&self) -> u16 {
David Brown2b73ed92020-01-08 17:01:22 -0700262 if self.dependencies.is_empty() {
David Brown7a81c4b2019-07-29 15:20:21 -0600263 0
264 } else {
David Brown2b73ed92020-01-08 17:01:22 -0700265 // Include the header and space for each dependency.
266 4 + (self.dependencies.len() as u16) * (4 + 4 + 8)
David Brown7a81c4b2019-07-29 15:20:21 -0600267 }
268 }
269
270 fn add_dependency(&mut self, id: u8, version: &ImageVersion) {
David Brown7a81c4b2019-07-29 15:20:21 -0600271 self.dependencies.push(Dependency {
272 id: id,
273 version: version.clone(),
274 });
275 }
276
David Browne90b13f2019-12-06 15:04:00 -0700277 fn corrupt_sig(&mut self) {
278 self.gen_corrupted = true;
279 }
280
David Brown187dd882017-07-11 11:15:23 -0600281 /// Compute the TLV given the specified block of data.
David Brown43643dd2019-01-11 15:43:28 -0700282 fn make_tlv(self: Box<Self>) -> Vec<u8> {
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300283 let mut protected_tlv: Vec<u8> = vec![];
David Brown187dd882017-07-11 11:15:23 -0600284
David Brown2b73ed92020-01-08 17:01:22 -0700285 if self.protect_size() > 0 {
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300286 protected_tlv.push(0x08);
287 protected_tlv.push(0x69);
David Brown2b73ed92020-01-08 17:01:22 -0700288 let size = self.protect_size();
289 protected_tlv.write_u16::<LittleEndian>(size).unwrap();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300290 for dep in &self.dependencies {
David Brown69721182019-12-04 14:50:52 -0700291 protected_tlv.write_u16::<LittleEndian>(TlvKinds::DEPENDENCY as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700292 protected_tlv.write_u16::<LittleEndian>(12).unwrap();
David Brownf5b33d82017-09-01 10:58:27 -0600293
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300294 // The dependency.
295 protected_tlv.push(dep.id);
296 for _ in 0 .. 3 {
297 protected_tlv.push(0);
298 }
299 protected_tlv.push(dep.version.major);
300 protected_tlv.push(dep.version.minor);
301 protected_tlv.write_u16::<LittleEndian>(dep.version.revision).unwrap();
302 protected_tlv.write_u32::<LittleEndian>(dep.version.build_num).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600303 }
David Brown2b73ed92020-01-08 17:01:22 -0700304
305 assert_eq!(size, protected_tlv.len() as u16, "protected TLV length incorrect");
David Brown7a81c4b2019-07-29 15:20:21 -0600306 }
307
308 // Ring does the signature itself, which means that it must be
309 // given a full, contiguous payload. Although this does help from
310 // a correct usage perspective, it is fairly stupid from an
311 // efficiency view. If this is shown to be a performance issue
312 // with the tests, the protected data could be appended to the
313 // payload, and then removed after the signature is done. For now,
314 // just make a signed payload.
315 let mut sig_payload = self.payload.clone();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300316 sig_payload.extend_from_slice(&protected_tlv);
317
318 let mut result: Vec<u8> = vec![];
319
320 // add back signed payload
321 result.extend_from_slice(&protected_tlv);
322
323 // add non-protected payload
David Brown3dc86c92020-01-08 17:22:55 -0700324 let npro_pos = result.len();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300325 result.push(0x07);
326 result.push(0x69);
David Brown3dc86c92020-01-08 17:22:55 -0700327 // Placeholder for the size.
328 result.write_u16::<LittleEndian>(0).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600329
David Brown187dd882017-07-11 11:15:23 -0600330 if self.kinds.contains(&TlvKinds::SHA256) {
David Browne90b13f2019-12-06 15:04:00 -0700331 // If a signature is not requested, corrupt the hash we are
332 // generating. But, if there is a signature, output the
333 // correct hash. We want the hash test to pass so that the
334 // signature verification can be validated.
335 let mut corrupt_hash = self.gen_corrupted;
336 for k in &[TlvKinds::RSA2048, TlvKinds::RSA3072,
337 TlvKinds::ECDSA224, TlvKinds::ECDSA256,
338 TlvKinds::ED25519]
339 {
340 if self.kinds.contains(k) {
341 corrupt_hash = false;
342 break;
343 }
344 }
345
346 if corrupt_hash {
347 sig_payload[0] ^= 1;
348 }
349
David Brown7a81c4b2019-07-29 15:20:21 -0600350 let hash = digest::digest(&digest::SHA256, &sig_payload);
David Brown8054ce22017-07-11 12:12:09 -0600351 let hash = hash.as_ref();
David Brown187dd882017-07-11 11:15:23 -0600352
David Brown8054ce22017-07-11 12:12:09 -0600353 assert!(hash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700354 result.write_u16::<LittleEndian>(TlvKinds::SHA256 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700355 result.write_u16::<LittleEndian>(32).unwrap();
David Brown8054ce22017-07-11 12:12:09 -0600356 result.extend_from_slice(hash);
David Browne90b13f2019-12-06 15:04:00 -0700357
358 // Undo the corruption.
359 if corrupt_hash {
360 sig_payload[0] ^= 1;
361 }
362
363 }
364
365 if self.gen_corrupted {
366 // Corrupt what is signed by modifying the input to the
367 // signature code.
368 sig_payload[0] ^= 1;
David Brown187dd882017-07-11 11:15:23 -0600369 }
370
Fabio Utzig39297432019-05-08 18:51:10 -0300371 if self.kinds.contains(&TlvKinds::RSA2048) ||
372 self.kinds.contains(&TlvKinds::RSA3072) {
373
374 let is_rsa2048 = self.kinds.contains(&TlvKinds::RSA2048);
375
David Brown43cda332017-09-01 09:53:23 -0600376 // Output the hash of the public key.
Fabio Utzig39297432019-05-08 18:51:10 -0300377 let hash = if is_rsa2048 {
378 digest::digest(&digest::SHA256, RSA_PUB_KEY)
379 } else {
380 digest::digest(&digest::SHA256, RSA3072_PUB_KEY)
381 };
David Brown43cda332017-09-01 09:53:23 -0600382 let hash = hash.as_ref();
383
384 assert!(hash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700385 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700386 result.write_u16::<LittleEndian>(32).unwrap();
David Brown43cda332017-09-01 09:53:23 -0600387 result.extend_from_slice(hash);
388
David Brown7e701d82017-07-11 13:24:25 -0600389 // For now assume PSS.
Fabio Utzig39297432019-05-08 18:51:10 -0300390 let key_bytes = if is_rsa2048 {
391 pem::parse(include_bytes!("../../root-rsa-2048.pem").as_ref()).unwrap()
392 } else {
393 pem::parse(include_bytes!("../../root-rsa-3072.pem").as_ref()).unwrap()
394 };
David Brown7e701d82017-07-11 13:24:25 -0600395 assert_eq!(key_bytes.tag, "RSA PRIVATE KEY");
Fabio Utzig90f449e2019-10-24 07:43:53 -0300396 let key_pair = RsaKeyPair::from_der(&key_bytes.contents).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600397 let rng = rand::SystemRandom::new();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300398 let mut signature = vec![0; key_pair.public_modulus_len()];
Fabio Utzig39297432019-05-08 18:51:10 -0300399 if is_rsa2048 {
400 assert_eq!(signature.len(), 256);
401 } else {
402 assert_eq!(signature.len(), 384);
403 }
David Brown7a81c4b2019-07-29 15:20:21 -0600404 key_pair.sign(&RSA_PSS_SHA256, &rng, &sig_payload, &mut signature).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600405
Fabio Utzig39297432019-05-08 18:51:10 -0300406 if is_rsa2048 {
David Brown69721182019-12-04 14:50:52 -0700407 result.write_u16::<LittleEndian>(TlvKinds::RSA2048 as u16).unwrap();
Fabio Utzig39297432019-05-08 18:51:10 -0300408 } else {
David Brown69721182019-12-04 14:50:52 -0700409 result.write_u16::<LittleEndian>(TlvKinds::RSA3072 as u16).unwrap();
Fabio Utzig39297432019-05-08 18:51:10 -0300410 }
David Brown91d68632019-07-29 14:32:13 -0600411 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600412 result.extend_from_slice(&signature);
413 }
414
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200415 if self.kinds.contains(&TlvKinds::ECDSA256) {
416 let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY);
417 let keyhash = keyhash.as_ref();
418
419 assert!(keyhash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700420 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700421 result.write_u16::<LittleEndian>(32).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200422 result.extend_from_slice(keyhash);
423
Fabio Utzig05ab0142018-07-10 09:15:28 -0300424 let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap();
425 assert_eq!(key_bytes.tag, "PRIVATE KEY");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200426
Fabio Utzig05ab0142018-07-10 09:15:28 -0300427 let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300428 &key_bytes.contents).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300429 let rng = rand::SystemRandom::new();
Fabio Utzig90f449e2019-10-24 07:43:53 -0300430 let signature = key_pair.sign(&rng, &sig_payload).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200431
David Brown69721182019-12-04 14:50:52 -0700432 result.write_u16::<LittleEndian>(TlvKinds::ECDSA256 as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300433
David Browna4c58642019-12-12 17:28:33 -0700434 let signature = signature.as_ref().to_vec();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300435
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 Utzig3fa72ca2020-04-02 11:20:37 -0300502 if self.kinds.contains(&TlvKinds::ENCEC256) || self.kinds.contains(&TlvKinds::ENCX25519) {
503 let key_bytes = if self.kinds.contains(&TlvKinds::ENCEC256) {
504 pem::parse(include_bytes!("../../enc-ec256-pub.pem").as_ref()).unwrap()
505 } else {
506 pem::parse(include_bytes!("../../enc-x25519-pub.pem").as_ref()).unwrap()
507 };
Fabio Utzig90f449e2019-10-24 07:43:53 -0300508 assert_eq!(key_bytes.tag, "PUBLIC KEY");
509
510 let rng = rand::SystemRandom::new();
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300511 let alg = if self.kinds.contains(&TlvKinds::ENCEC256) {
512 &agreement::ECDH_P256
513 } else {
514 &agreement::X25519
515 };
516 let pk = match agreement::EphemeralPrivateKey::generate(alg, &rng) {
Fabio Utzig90f449e2019-10-24 07:43:53 -0300517 Ok(v) => v,
518 Err(_) => panic!("Failed to generate ephemeral keypair"),
519 };
520
521 let pubk = match pk.compute_public_key() {
522 Ok(pubk) => pubk,
523 Err(_) => panic!("Failed computing ephemeral public key"),
524 };
525
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300526 let peer_pubk = if self.kinds.contains(&TlvKinds::ENCEC256) {
527 agreement::UnparsedPublicKey::new(&agreement::ECDH_P256, &key_bytes.contents[26..])
528 } else {
529 agreement::UnparsedPublicKey::new(&agreement::X25519, &key_bytes.contents[12..])
530 };
Fabio Utzig90f449e2019-10-24 07:43:53 -0300531
532 #[derive(Debug, PartialEq)]
533 struct OkmLen<T: core::fmt::Debug + PartialEq>(T);
534
535 impl hkdf::KeyType for OkmLen<usize> {
536 fn len(&self) -> usize {
537 self.0
538 }
539 }
540
541 let derived_key = match agreement::agree_ephemeral(
542 pk, &peer_pubk, ring::error::Unspecified, |shared| {
543 let salt = hkdf::Salt::new(hkdf::HKDF_SHA256, &[]);
544 let prk = salt.extract(&shared);
545 let okm = match prk.expand(&[b"MCUBoot_ECIES_v1"], OkmLen(48)) {
546 Ok(okm) => okm,
547 Err(_) => panic!("Failed building HKDF OKM"),
548 };
549 let mut buf = [0u8; 48];
550 match okm.fill(&mut buf) {
551 Ok(_) => Ok(buf),
552 Err(_) => panic!("Failed generating HKDF output"),
553 }
554 },
555 ) {
556 Ok(v) => v,
557 Err(_) => panic!("Failed building HKDF"),
558 };
559
560 let key = GenericArray::from_slice(&derived_key[..16]);
561 let nonce = GenericArray::from_slice(&[0; 16]);
562 let mut cipher = Aes128Ctr::new(&key, &nonce);
563 let mut cipherkey = self.get_enc_key();
564 cipher.apply_keystream(&mut cipherkey);
565
566 let key = hmac::Key::new(hmac::HMAC_SHA256, &derived_key[16..]);
567 let tag = hmac::sign(&key, &cipherkey);
568
569 let mut buf = vec![];
570 buf.append(&mut pubk.as_ref().to_vec());
571 buf.append(&mut tag.as_ref().to_vec());
572 buf.append(&mut cipherkey);
573
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300574 if self.kinds.contains(&TlvKinds::ENCEC256) {
575 assert!(buf.len() == 113);
576 result.write_u16::<LittleEndian>(TlvKinds::ENCEC256 as u16).unwrap();
577 result.write_u16::<LittleEndian>(113).unwrap();
578 } else {
579 assert!(buf.len() == 80);
580 result.write_u16::<LittleEndian>(TlvKinds::ENCX25519 as u16).unwrap();
581 result.write_u16::<LittleEndian>(80).unwrap();
582 }
Fabio Utzig90f449e2019-10-24 07:43:53 -0300583 result.extend_from_slice(&buf);
584 }
585
David Brown3dc86c92020-01-08 17:22:55 -0700586 // Patch the size back into the TLV header.
587 let size = (result.len() - npro_pos) as u16;
588 let mut size_buf = &mut result[npro_pos + 2 .. npro_pos + 4];
589 size_buf.write_u16::<LittleEndian>(size).unwrap();
590
David Brown187dd882017-07-11 11:15:23 -0600591 result
592 }
Fabio Utzig90f449e2019-10-24 07:43:53 -0300593
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300594 fn generate_enc_key(&mut self) {
595 let rng = rand::SystemRandom::new();
596 let mut buf = vec![0u8; AES_KEY_LEN];
597 match rng.fill(&mut buf) {
598 Err(_) => panic!("Error generating encrypted key"),
599 Ok(_) => (),
600 }
601 info!("New encryption key: {:02x?}", buf);
602 self.enc_key = buf;
Fabio Utzig90f449e2019-10-24 07:43:53 -0300603 }
604
605 fn get_enc_key(&self) -> Vec<u8> {
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300606 if self.enc_key.len() != AES_KEY_LEN {
607 panic!("No random key was generated");
608 }
609 self.enc_key.clone()
Fabio Utzig90f449e2019-10-24 07:43:53 -0300610 }
David Brown187dd882017-07-11 11:15:23 -0600611}
David Brown43cda332017-09-01 09:53:23 -0600612
613include!("rsa_pub_key-rs.txt");
Fabio Utzig39297432019-05-08 18:51:10 -0300614include!("rsa3072_pub_key-rs.txt");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200615include!("ecdsa_pub_key-rs.txt");
Fabio Utzig97710282019-05-24 17:44:49 -0300616include!("ed25519_pub_key-rs.txt");