blob: 8ccdb0afa7eebe859a88e176d15b3c34977e1dcb [file] [log] [blame]
David Browne2acfae2020-01-21 16:45:01 -07001// Copyright (c) 2017-2020 Linaro LTD
2// Copyright (c) 2017-2020 JUUL Labs
Salome Thirot6fdbf552021-05-14 16:46:14 +01003// Copyright (c) 2021 Arm Limited
David Browne2acfae2020-01-21 16:45:01 -07004//
5// SPDX-License-Identifier: Apache-2.0
6
David Brown187dd882017-07-11 11:15:23 -06007//! TLV Support
8//!
9//! mcuboot images are followed immediately by a list of TLV items that contain integrity
10//! information about the image. Their generation is made a little complicated because the size of
11//! the TLV block is in the image header, which is included in the hash. Since some signatures can
12//! vary in size, we just make them the largest size possible.
13//!
14//! Because of this header, we have to make two passes. The first pass will compute the size of
15//! the TLV, and the second pass will build the data for the TLV.
16
David Brown91d68632019-07-29 14:32:13 -060017use byteorder::{
18 LittleEndian, WriteBytesExt,
19};
David Brown7a81c4b2019-07-29 15:20:21 -060020use crate::image::ImageVersion;
Fabio Utzige84f0ef2019-11-22 12:29:32 -030021use log::info;
Fabio Utzig90f449e2019-10-24 07:43:53 -030022use ring::{digest, rand, agreement, hkdf, hmac};
Fabio Utzige84f0ef2019-11-22 12:29:32 -030023use ring::rand::SecureRandom;
Fabio Utzig05ab0142018-07-10 09:15:28 -030024use ring::signature::{
25 RsaKeyPair,
26 RSA_PSS_SHA256,
27 EcdsaKeyPair,
28 ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig97710282019-05-24 17:44:49 -030029 Ed25519KeyPair,
Fabio Utzig05ab0142018-07-10 09:15:28 -030030};
Fabio Utzig90f449e2019-10-24 07:43:53 -030031use aes_ctr::{
32 Aes128Ctr,
Salome Thirot6fdbf552021-05-14 16:46:14 +010033 Aes256Ctr,
Fabio Utzig90f449e2019-10-24 07:43:53 -030034 stream_cipher::{
35 generic_array::GenericArray,
David Brown8a99adf2020-07-09 16:52:38 -060036 NewStreamCipher,
37 SyncStreamCipher,
Fabio Utzig90f449e2019-10-24 07:43:53 -030038 },
39};
Fabio Utzig80fde2f2017-12-05 09:25:31 -020040use mcuboot_sys::c;
Salome Thirot6fdbf552021-05-14 16:46:14 +010041use typenum::{U16, U32};
David Brown187dd882017-07-11 11:15:23 -060042
David Brown69721182019-12-04 14:50:52 -070043#[repr(u16)]
David Brownc3898d62019-08-05 14:20:02 -060044#[derive(Copy, Clone, Debug, PartialEq, Eq)]
David Brown187dd882017-07-11 11:15:23 -060045#[allow(dead_code)] // TODO: For now
46pub enum TlvKinds {
David Brown43cda332017-09-01 09:53:23 -060047 KEYHASH = 0x01,
David Brown27648b82017-08-31 10:40:29 -060048 SHA256 = 0x10,
49 RSA2048 = 0x20,
50 ECDSA224 = 0x21,
51 ECDSA256 = 0x22,
Fabio Utzig39297432019-05-08 18:51:10 -030052 RSA3072 = 0x23,
Fabio Utzig97710282019-05-24 17:44:49 -030053 ED25519 = 0x24,
Fabio Utzig1e48b912018-09-18 09:04:18 -030054 ENCRSA2048 = 0x30,
Salome Thirot0f641972021-05-14 11:19:55 +010055 ENCKW = 0x31,
Fabio Utzig90f449e2019-10-24 07:43:53 -030056 ENCEC256 = 0x32,
Fabio Utzig3fa72ca2020-04-02 11:20:37 -030057 ENCX25519 = 0x33,
David Brown7a81c4b2019-07-29 15:20:21 -060058 DEPENDENCY = 0x40,
Fabio Utzig1e48b912018-09-18 09:04:18 -030059}
60
61#[allow(dead_code, non_camel_case_types)]
62pub enum TlvFlags {
63 PIC = 0x01,
64 NON_BOOTABLE = 0x02,
Salome Thirot6fdbf552021-05-14 16:46:14 +010065 ENCRYPTED_AES128 = 0x04,
Fabio Utzig1e48b912018-09-18 09:04:18 -030066 RAM_LOAD = 0x20,
Salome Thirot6fdbf552021-05-14 16:46:14 +010067 ENCRYPTED_AES256 = 0x08,
David Brown187dd882017-07-11 11:15:23 -060068}
69
David Brown43643dd2019-01-11 15:43:28 -070070/// A generator for manifests. The format of the manifest can be either a
71/// traditional "TLV" or a SUIT-style manifest.
72pub trait ManifestGen {
David Brownac46e262019-01-11 15:46:18 -070073 /// Retrieve the header magic value for this manifest type.
74 fn get_magic(&self) -> u32;
75
David Brown43643dd2019-01-11 15:43:28 -070076 /// Retrieve the flags value for this particular manifest type.
77 fn get_flags(&self) -> u32;
78
David Brown7a81c4b2019-07-29 15:20:21 -060079 /// Retrieve the number of bytes of this manifest that is "protected".
80 /// This field is stored in the outside image header instead of the
81 /// manifest header.
82 fn protect_size(&self) -> u16;
83
84 /// Add a dependency on another image.
85 fn add_dependency(&mut self, id: u8, version: &ImageVersion);
86
David Brown43643dd2019-01-11 15:43:28 -070087 /// Add a sequence of bytes to the payload that the manifest is
88 /// protecting.
89 fn add_bytes(&mut self, bytes: &[u8]);
90
David Browne90b13f2019-12-06 15:04:00 -070091 /// Set an internal flag indicating that the next `make_tlv` should
92 /// corrupt the signature.
93 fn corrupt_sig(&mut self);
94
David Brown43643dd2019-01-11 15:43:28 -070095 /// Construct the manifest for this payload.
96 fn make_tlv(self: Box<Self>) -> Vec<u8>;
Fabio Utzig90f449e2019-10-24 07:43:53 -030097
Fabio Utzige84f0ef2019-11-22 12:29:32 -030098 /// Generate a new encryption random key
99 fn generate_enc_key(&mut self);
Fabio Utzig90f449e2019-10-24 07:43:53 -0300100
101 /// Return the current encryption key
102 fn get_enc_key(&self) -> Vec<u8>;
David Brown43643dd2019-01-11 15:43:28 -0700103}
104
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300105#[derive(Debug, Default)]
David Brown187dd882017-07-11 11:15:23 -0600106pub struct TlvGen {
David Brown43cda332017-09-01 09:53:23 -0600107 flags: u32,
David Brown187dd882017-07-11 11:15:23 -0600108 kinds: Vec<TlvKinds>,
David Brown4243ab02017-07-11 12:24:23 -0600109 payload: Vec<u8>,
David Brown7a81c4b2019-07-29 15:20:21 -0600110 dependencies: Vec<Dependency>,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300111 enc_key: Vec<u8>,
David Browne90b13f2019-12-06 15:04:00 -0700112 /// Should this signature be corrupted.
113 gen_corrupted: bool,
David Brown7a81c4b2019-07-29 15:20:21 -0600114}
115
David Brownc3898d62019-08-05 14:20:02 -0600116#[derive(Debug)]
David Brown7a81c4b2019-07-29 15:20:21 -0600117struct Dependency {
118 id: u8,
119 version: ImageVersion,
David Brown187dd882017-07-11 11:15:23 -0600120}
121
122impl 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)]
Salome Thirot6fdbf552021-05-14 16:46:14 +0100165 pub fn new_enc_rsa(aes_key_size: u32) -> TlvGen {
166 let flag = if aes_key_size == 256 {
167 TlvFlags::ENCRYPTED_AES256 as u32
168 } else {
169 TlvFlags::ENCRYPTED_AES128 as u32
170 };
Fabio Utzig1e48b912018-09-18 09:04:18 -0300171 TlvGen {
Salome Thirot6fdbf552021-05-14 16:46:14 +0100172 flags: flag,
Fabio Utzig1e48b912018-09-18 09:04:18 -0300173 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300174 ..Default::default()
Fabio Utzig1e48b912018-09-18 09:04:18 -0300175 }
176 }
177
178 #[allow(dead_code)]
Salome Thirot6fdbf552021-05-14 16:46:14 +0100179 pub fn new_sig_enc_rsa(aes_key_size: u32) -> TlvGen {
180 let flag = if aes_key_size == 256 {
181 TlvFlags::ENCRYPTED_AES256 as u32
182 } else {
183 TlvFlags::ENCRYPTED_AES128 as u32
184 };
Fabio Utzig754438d2018-12-14 06:39:58 -0200185 TlvGen {
Salome Thirot6fdbf552021-05-14 16:46:14 +0100186 flags: flag,
Fabio Utzig754438d2018-12-14 06:39:58 -0200187 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCRSA2048],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300188 ..Default::default()
Fabio Utzig754438d2018-12-14 06:39:58 -0200189 }
190 }
191
192 #[allow(dead_code)]
Salome Thirot6fdbf552021-05-14 16:46:14 +0100193 pub fn new_enc_kw(aes_key_size: u32) -> TlvGen {
194 let flag = if aes_key_size == 256 {
195 TlvFlags::ENCRYPTED_AES256 as u32
196 } else {
197 TlvFlags::ENCRYPTED_AES128 as u32
198 };
Fabio Utzig1e48b912018-09-18 09:04:18 -0300199 TlvGen {
Salome Thirot6fdbf552021-05-14 16:46:14 +0100200 flags: flag,
Salome Thirot0f641972021-05-14 11:19:55 +0100201 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300202 ..Default::default()
Fabio Utzig1e48b912018-09-18 09:04:18 -0300203 }
204 }
205
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200206 #[allow(dead_code)]
Salome Thirot6fdbf552021-05-14 16:46:14 +0100207 pub fn new_rsa_kw(aes_key_size: u32) -> TlvGen {
208 let flag = if aes_key_size == 256 {
209 TlvFlags::ENCRYPTED_AES256 as u32
210 } else {
211 TlvFlags::ENCRYPTED_AES128 as u32
212 };
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200213 TlvGen {
Salome Thirot6fdbf552021-05-14 16:46:14 +0100214 flags: flag,
Salome Thirot0f641972021-05-14 11:19:55 +0100215 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCKW],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300216 ..Default::default()
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200217 }
218 }
219
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200220 #[allow(dead_code)]
Salome Thirot6fdbf552021-05-14 16:46:14 +0100221 pub fn new_ecdsa_kw(aes_key_size: u32) -> TlvGen {
222 let flag = if aes_key_size == 256 {
223 TlvFlags::ENCRYPTED_AES256 as u32
224 } else {
225 TlvFlags::ENCRYPTED_AES128 as u32
226 };
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200227 TlvGen {
Salome Thirot6fdbf552021-05-14 16:46:14 +0100228 flags: flag,
Salome Thirot0f641972021-05-14 11:19:55 +0100229 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCKW],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300230 ..Default::default()
Fabio Utzig90f449e2019-10-24 07:43:53 -0300231 }
232 }
233
234 #[allow(dead_code)]
Salome Thirot6fdbf552021-05-14 16:46:14 +0100235 pub fn new_ecies_p256(aes_key_size: u32) -> TlvGen {
236 let flag = if aes_key_size == 256 {
237 TlvFlags::ENCRYPTED_AES256 as u32
238 } else {
239 TlvFlags::ENCRYPTED_AES128 as u32
240 };
Fabio Utzig66b4caa2020-01-04 20:19:28 -0300241 TlvGen {
Salome Thirot6fdbf552021-05-14 16:46:14 +0100242 flags: flag,
Fabio Utzig66b4caa2020-01-04 20:19:28 -0300243 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCEC256],
Fabio Utzig66b4caa2020-01-04 20:19:28 -0300244 ..Default::default()
245 }
246 }
247
248 #[allow(dead_code)]
Salome Thirot6fdbf552021-05-14 16:46:14 +0100249 pub fn new_ecdsa_ecies_p256(aes_key_size: u32) -> TlvGen {
250 let flag = if aes_key_size == 256 {
251 TlvFlags::ENCRYPTED_AES256 as u32
252 } else {
253 TlvFlags::ENCRYPTED_AES128 as u32
254 };
Fabio Utzig90f449e2019-10-24 07:43:53 -0300255 TlvGen {
Salome Thirot6fdbf552021-05-14 16:46:14 +0100256 flags: flag,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300257 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCEC256],
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300258 ..Default::default()
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200259 }
260 }
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300261
262 #[allow(dead_code)]
Salome Thirot6fdbf552021-05-14 16:46:14 +0100263 pub fn new_ecies_x25519(aes_key_size: u32) -> TlvGen {
264 let flag = if aes_key_size == 256 {
265 TlvFlags::ENCRYPTED_AES256 as u32
266 } else {
267 TlvFlags::ENCRYPTED_AES128 as u32
268 };
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300269 TlvGen {
Salome Thirot6fdbf552021-05-14 16:46:14 +0100270 flags: flag,
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300271 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCX25519],
272 ..Default::default()
273 }
274 }
275
276 #[allow(dead_code)]
Salome Thirot6fdbf552021-05-14 16:46:14 +0100277 pub fn new_ed25519_ecies_x25519(aes_key_size: u32) -> TlvGen {
278 let flag = if aes_key_size == 256 {
279 TlvFlags::ENCRYPTED_AES256 as u32
280 } else {
281 TlvFlags::ENCRYPTED_AES128 as u32
282 };
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300283 TlvGen {
Salome Thirot6fdbf552021-05-14 16:46:14 +0100284 flags: flag,
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300285 kinds: vec![TlvKinds::SHA256, TlvKinds::ED25519, TlvKinds::ENCX25519],
286 ..Default::default()
287 }
288 }
David Brown43643dd2019-01-11 15:43:28 -0700289}
290
291impl ManifestGen for TlvGen {
David Brownac46e262019-01-11 15:46:18 -0700292 fn get_magic(&self) -> u32 {
293 0x96f3b83d
294 }
295
David Brown43643dd2019-01-11 15:43:28 -0700296 /// Retrieve the header flags for this configuration. This can be called at any time.
297 fn get_flags(&self) -> u32 {
298 self.flags
299 }
David Brown187dd882017-07-11 11:15:23 -0600300
301 /// Add bytes to the covered hash.
David Brown43643dd2019-01-11 15:43:28 -0700302 fn add_bytes(&mut self, bytes: &[u8]) {
David Brown4243ab02017-07-11 12:24:23 -0600303 self.payload.extend_from_slice(bytes);
David Brown187dd882017-07-11 11:15:23 -0600304 }
305
David Brown7a81c4b2019-07-29 15:20:21 -0600306 fn protect_size(&self) -> u16 {
David Brown2b73ed92020-01-08 17:01:22 -0700307 if self.dependencies.is_empty() {
David Brown7a81c4b2019-07-29 15:20:21 -0600308 0
309 } else {
David Brown2b73ed92020-01-08 17:01:22 -0700310 // Include the header and space for each dependency.
311 4 + (self.dependencies.len() as u16) * (4 + 4 + 8)
David Brown7a81c4b2019-07-29 15:20:21 -0600312 }
313 }
314
315 fn add_dependency(&mut self, id: u8, version: &ImageVersion) {
David Brown7a81c4b2019-07-29 15:20:21 -0600316 self.dependencies.push(Dependency {
David Brown4dfb33c2021-03-10 05:15:45 -0700317 id,
David Brown7a81c4b2019-07-29 15:20:21 -0600318 version: version.clone(),
319 });
320 }
321
David Browne90b13f2019-12-06 15:04:00 -0700322 fn corrupt_sig(&mut self) {
323 self.gen_corrupted = true;
324 }
325
David Brown187dd882017-07-11 11:15:23 -0600326 /// Compute the TLV given the specified block of data.
David Brown43643dd2019-01-11 15:43:28 -0700327 fn make_tlv(self: Box<Self>) -> Vec<u8> {
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300328 let mut protected_tlv: Vec<u8> = vec![];
David Brown187dd882017-07-11 11:15:23 -0600329
David Brown2b73ed92020-01-08 17:01:22 -0700330 if self.protect_size() > 0 {
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300331 protected_tlv.push(0x08);
332 protected_tlv.push(0x69);
David Brown2b73ed92020-01-08 17:01:22 -0700333 let size = self.protect_size();
334 protected_tlv.write_u16::<LittleEndian>(size).unwrap();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300335 for dep in &self.dependencies {
David Brown69721182019-12-04 14:50:52 -0700336 protected_tlv.write_u16::<LittleEndian>(TlvKinds::DEPENDENCY as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700337 protected_tlv.write_u16::<LittleEndian>(12).unwrap();
David Brownf5b33d82017-09-01 10:58:27 -0600338
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300339 // The dependency.
340 protected_tlv.push(dep.id);
David Brownf66b2052021-03-10 05:26:36 -0700341 protected_tlv.push(0);
342 protected_tlv.write_u16::<LittleEndian>(0).unwrap();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300343 protected_tlv.push(dep.version.major);
344 protected_tlv.push(dep.version.minor);
345 protected_tlv.write_u16::<LittleEndian>(dep.version.revision).unwrap();
346 protected_tlv.write_u32::<LittleEndian>(dep.version.build_num).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600347 }
David Brown2b73ed92020-01-08 17:01:22 -0700348
349 assert_eq!(size, protected_tlv.len() as u16, "protected TLV length incorrect");
David Brown7a81c4b2019-07-29 15:20:21 -0600350 }
351
352 // Ring does the signature itself, which means that it must be
353 // given a full, contiguous payload. Although this does help from
354 // a correct usage perspective, it is fairly stupid from an
355 // efficiency view. If this is shown to be a performance issue
356 // with the tests, the protected data could be appended to the
357 // payload, and then removed after the signature is done. For now,
358 // just make a signed payload.
359 let mut sig_payload = self.payload.clone();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300360 sig_payload.extend_from_slice(&protected_tlv);
361
362 let mut result: Vec<u8> = vec![];
363
364 // add back signed payload
365 result.extend_from_slice(&protected_tlv);
366
367 // add non-protected payload
David Brown3dc86c92020-01-08 17:22:55 -0700368 let npro_pos = result.len();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300369 result.push(0x07);
370 result.push(0x69);
David Brown3dc86c92020-01-08 17:22:55 -0700371 // Placeholder for the size.
372 result.write_u16::<LittleEndian>(0).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600373
David Brown187dd882017-07-11 11:15:23 -0600374 if self.kinds.contains(&TlvKinds::SHA256) {
David Browne90b13f2019-12-06 15:04:00 -0700375 // If a signature is not requested, corrupt the hash we are
376 // generating. But, if there is a signature, output the
377 // correct hash. We want the hash test to pass so that the
378 // signature verification can be validated.
379 let mut corrupt_hash = self.gen_corrupted;
380 for k in &[TlvKinds::RSA2048, TlvKinds::RSA3072,
381 TlvKinds::ECDSA224, TlvKinds::ECDSA256,
382 TlvKinds::ED25519]
383 {
384 if self.kinds.contains(k) {
385 corrupt_hash = false;
386 break;
387 }
388 }
389
390 if corrupt_hash {
391 sig_payload[0] ^= 1;
392 }
393
David Brown7a81c4b2019-07-29 15:20:21 -0600394 let hash = digest::digest(&digest::SHA256, &sig_payload);
David Brown8054ce22017-07-11 12:12:09 -0600395 let hash = hash.as_ref();
David Brown187dd882017-07-11 11:15:23 -0600396
David Brown8054ce22017-07-11 12:12:09 -0600397 assert!(hash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700398 result.write_u16::<LittleEndian>(TlvKinds::SHA256 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700399 result.write_u16::<LittleEndian>(32).unwrap();
David Brown8054ce22017-07-11 12:12:09 -0600400 result.extend_from_slice(hash);
David Browne90b13f2019-12-06 15:04:00 -0700401
402 // Undo the corruption.
403 if corrupt_hash {
404 sig_payload[0] ^= 1;
405 }
406
407 }
408
409 if self.gen_corrupted {
410 // Corrupt what is signed by modifying the input to the
411 // signature code.
412 sig_payload[0] ^= 1;
David Brown187dd882017-07-11 11:15:23 -0600413 }
414
Fabio Utzig39297432019-05-08 18:51:10 -0300415 if self.kinds.contains(&TlvKinds::RSA2048) ||
416 self.kinds.contains(&TlvKinds::RSA3072) {
417
418 let is_rsa2048 = self.kinds.contains(&TlvKinds::RSA2048);
419
David Brown43cda332017-09-01 09:53:23 -0600420 // Output the hash of the public key.
Fabio Utzig39297432019-05-08 18:51:10 -0300421 let hash = if is_rsa2048 {
422 digest::digest(&digest::SHA256, RSA_PUB_KEY)
423 } else {
424 digest::digest(&digest::SHA256, RSA3072_PUB_KEY)
425 };
David Brown43cda332017-09-01 09:53:23 -0600426 let hash = hash.as_ref();
427
428 assert!(hash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700429 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700430 result.write_u16::<LittleEndian>(32).unwrap();
David Brown43cda332017-09-01 09:53:23 -0600431 result.extend_from_slice(hash);
432
David Brown7e701d82017-07-11 13:24:25 -0600433 // For now assume PSS.
Fabio Utzig39297432019-05-08 18:51:10 -0300434 let key_bytes = if is_rsa2048 {
435 pem::parse(include_bytes!("../../root-rsa-2048.pem").as_ref()).unwrap()
436 } else {
437 pem::parse(include_bytes!("../../root-rsa-3072.pem").as_ref()).unwrap()
438 };
David Brown7e701d82017-07-11 13:24:25 -0600439 assert_eq!(key_bytes.tag, "RSA PRIVATE KEY");
Fabio Utzig90f449e2019-10-24 07:43:53 -0300440 let key_pair = RsaKeyPair::from_der(&key_bytes.contents).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600441 let rng = rand::SystemRandom::new();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300442 let mut signature = vec![0; key_pair.public_modulus_len()];
Fabio Utzig39297432019-05-08 18:51:10 -0300443 if is_rsa2048 {
444 assert_eq!(signature.len(), 256);
445 } else {
446 assert_eq!(signature.len(), 384);
447 }
David Brown7a81c4b2019-07-29 15:20:21 -0600448 key_pair.sign(&RSA_PSS_SHA256, &rng, &sig_payload, &mut signature).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600449
Fabio Utzig39297432019-05-08 18:51:10 -0300450 if is_rsa2048 {
David Brown69721182019-12-04 14:50:52 -0700451 result.write_u16::<LittleEndian>(TlvKinds::RSA2048 as u16).unwrap();
Fabio Utzig39297432019-05-08 18:51:10 -0300452 } else {
David Brown69721182019-12-04 14:50:52 -0700453 result.write_u16::<LittleEndian>(TlvKinds::RSA3072 as u16).unwrap();
Fabio Utzig39297432019-05-08 18:51:10 -0300454 }
David Brown91d68632019-07-29 14:32:13 -0600455 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600456 result.extend_from_slice(&signature);
457 }
458
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200459 if self.kinds.contains(&TlvKinds::ECDSA256) {
460 let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY);
461 let keyhash = keyhash.as_ref();
462
463 assert!(keyhash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700464 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700465 result.write_u16::<LittleEndian>(32).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200466 result.extend_from_slice(keyhash);
467
Fabio Utzig05ab0142018-07-10 09:15:28 -0300468 let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap();
469 assert_eq!(key_bytes.tag, "PRIVATE KEY");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200470
Fabio Utzig05ab0142018-07-10 09:15:28 -0300471 let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300472 &key_bytes.contents).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300473 let rng = rand::SystemRandom::new();
Fabio Utzig90f449e2019-10-24 07:43:53 -0300474 let signature = key_pair.sign(&rng, &sig_payload).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200475
David Brown69721182019-12-04 14:50:52 -0700476 result.write_u16::<LittleEndian>(TlvKinds::ECDSA256 as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300477
David Browna4c58642019-12-12 17:28:33 -0700478 let signature = signature.as_ref().to_vec();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300479
David Brown91d68632019-07-29 14:32:13 -0600480 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300481 result.extend_from_slice(signature.as_ref());
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200482 }
483
Fabio Utzig97710282019-05-24 17:44:49 -0300484 if self.kinds.contains(&TlvKinds::ED25519) {
485 let keyhash = digest::digest(&digest::SHA256, ED25519_PUB_KEY);
486 let keyhash = keyhash.as_ref();
487
488 assert!(keyhash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700489 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700490 result.write_u16::<LittleEndian>(32).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300491 result.extend_from_slice(keyhash);
492
David Brown7a81c4b2019-07-29 15:20:21 -0600493 let hash = digest::digest(&digest::SHA256, &sig_payload);
Fabio Utzig97710282019-05-24 17:44:49 -0300494 let hash = hash.as_ref();
495 assert!(hash.len() == 32);
496
497 let key_bytes = pem::parse(include_bytes!("../../root-ed25519.pem").as_ref()).unwrap();
498 assert_eq!(key_bytes.tag, "PRIVATE KEY");
499
Fabio Utzig90f449e2019-10-24 07:43:53 -0300500 let key_pair = Ed25519KeyPair::from_seed_and_public_key(
501 &key_bytes.contents[16..48], &ED25519_PUB_KEY[12..44]).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300502 let signature = key_pair.sign(&hash);
503
David Brown69721182019-12-04 14:50:52 -0700504 result.write_u16::<LittleEndian>(TlvKinds::ED25519 as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300505
506 let signature = signature.as_ref().to_vec();
David Brown91d68632019-07-29 14:32:13 -0600507 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300508 result.extend_from_slice(signature.as_ref());
509 }
510
Fabio Utzig1e48b912018-09-18 09:04:18 -0300511 if self.kinds.contains(&TlvKinds::ENCRSA2048) {
512 let key_bytes = pem::parse(include_bytes!("../../enc-rsa2048-pub.pem")
513 .as_ref()).unwrap();
514 assert_eq!(key_bytes.tag, "PUBLIC KEY");
515
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300516 let cipherkey = self.get_enc_key();
517 let cipherkey = cipherkey.as_slice();
518 let encbuf = match c::rsa_oaep_encrypt(&key_bytes.contents, cipherkey) {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300519 Ok(v) => v,
520 Err(_) => panic!("Failed to encrypt secret key"),
521 };
522
523 assert!(encbuf.len() == 256);
David Brown69721182019-12-04 14:50:52 -0700524 result.write_u16::<LittleEndian>(TlvKinds::ENCRSA2048 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700525 result.write_u16::<LittleEndian>(256).unwrap();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300526 result.extend_from_slice(&encbuf);
527 }
528
Salome Thirot0f641972021-05-14 11:19:55 +0100529 if self.kinds.contains(&TlvKinds::ENCKW) {
Salome Thirot6fdbf552021-05-14 16:46:14 +0100530 let flag = TlvFlags::ENCRYPTED_AES256 as u32;
531 let aes256 = (self.get_flags() & flag) == flag;
532 let key_bytes = if aes256 {
533 base64::decode(
534 include_str!("../../enc-aes256kw.b64").trim()).unwrap()
535 } else {
536 base64::decode(
537 include_str!("../../enc-aes128kw.b64").trim()).unwrap()
538 };
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300539 let cipherkey = self.get_enc_key();
540 let cipherkey = cipherkey.as_slice();
Salome Thirot6fdbf552021-05-14 16:46:14 +0100541 let keylen = if aes256 { 32 } else { 16 };
542 let encbuf = match c::kw_encrypt(&key_bytes, cipherkey, keylen) {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300543 Ok(v) => v,
544 Err(_) => panic!("Failed to encrypt secret key"),
545 };
546
Salome Thirot6fdbf552021-05-14 16:46:14 +0100547 let size = if aes256 { 40 } else { 24 };
548 assert!(encbuf.len() == size);
Salome Thirot0f641972021-05-14 11:19:55 +0100549 result.write_u16::<LittleEndian>(TlvKinds::ENCKW as u16).unwrap();
Salome Thirot6fdbf552021-05-14 16:46:14 +0100550 result.write_u16::<LittleEndian>(size as u16).unwrap();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300551 result.extend_from_slice(&encbuf);
552 }
553
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300554 if self.kinds.contains(&TlvKinds::ENCEC256) || self.kinds.contains(&TlvKinds::ENCX25519) {
555 let key_bytes = if self.kinds.contains(&TlvKinds::ENCEC256) {
556 pem::parse(include_bytes!("../../enc-ec256-pub.pem").as_ref()).unwrap()
557 } else {
558 pem::parse(include_bytes!("../../enc-x25519-pub.pem").as_ref()).unwrap()
559 };
Fabio Utzig90f449e2019-10-24 07:43:53 -0300560 assert_eq!(key_bytes.tag, "PUBLIC KEY");
Fabio Utzig90f449e2019-10-24 07:43:53 -0300561 let rng = rand::SystemRandom::new();
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300562 let alg = if self.kinds.contains(&TlvKinds::ENCEC256) {
563 &agreement::ECDH_P256
564 } else {
565 &agreement::X25519
566 };
567 let pk = match agreement::EphemeralPrivateKey::generate(alg, &rng) {
Fabio Utzig90f449e2019-10-24 07:43:53 -0300568 Ok(v) => v,
569 Err(_) => panic!("Failed to generate ephemeral keypair"),
570 };
571
572 let pubk = match pk.compute_public_key() {
573 Ok(pubk) => pubk,
574 Err(_) => panic!("Failed computing ephemeral public key"),
575 };
576
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300577 let peer_pubk = if self.kinds.contains(&TlvKinds::ENCEC256) {
578 agreement::UnparsedPublicKey::new(&agreement::ECDH_P256, &key_bytes.contents[26..])
579 } else {
580 agreement::UnparsedPublicKey::new(&agreement::X25519, &key_bytes.contents[12..])
581 };
Fabio Utzig90f449e2019-10-24 07:43:53 -0300582
583 #[derive(Debug, PartialEq)]
584 struct OkmLen<T: core::fmt::Debug + PartialEq>(T);
585
586 impl hkdf::KeyType for OkmLen<usize> {
587 fn len(&self) -> usize {
588 self.0
589 }
590 }
591
Salome Thirot6fdbf552021-05-14 16:46:14 +0100592 let flag = TlvFlags::ENCRYPTED_AES256 as u32;
593 let aes256 = (self.get_flags() & flag) == flag;
594
Fabio Utzig90f449e2019-10-24 07:43:53 -0300595 let derived_key = match agreement::agree_ephemeral(
596 pk, &peer_pubk, ring::error::Unspecified, |shared| {
597 let salt = hkdf::Salt::new(hkdf::HKDF_SHA256, &[]);
598 let prk = salt.extract(&shared);
Salome Thirot6fdbf552021-05-14 16:46:14 +0100599 let okm_len = if aes256 { 64 } else { 48 };
600 let okm = match prk.expand(&[b"MCUBoot_ECIES_v1"], OkmLen(okm_len)) {
Fabio Utzig90f449e2019-10-24 07:43:53 -0300601 Ok(okm) => okm,
602 Err(_) => panic!("Failed building HKDF OKM"),
603 };
Salome Thirot6fdbf552021-05-14 16:46:14 +0100604 let mut buf = if aes256 { vec![0u8; 64] } else { vec![0u8; 48] };
Fabio Utzig90f449e2019-10-24 07:43:53 -0300605 match okm.fill(&mut buf) {
606 Ok(_) => Ok(buf),
607 Err(_) => panic!("Failed generating HKDF output"),
608 }
609 },
610 ) {
611 Ok(v) => v,
612 Err(_) => panic!("Failed building HKDF"),
613 };
614
Fabio Utzig90f449e2019-10-24 07:43:53 -0300615 let nonce = GenericArray::from_slice(&[0; 16]);
Fabio Utzig90f449e2019-10-24 07:43:53 -0300616 let mut cipherkey = self.get_enc_key();
Salome Thirot6fdbf552021-05-14 16:46:14 +0100617 if aes256 {
618 let key: &GenericArray<u8, U32> = GenericArray::from_slice(&derived_key[..32]);
619 let mut cipher = Aes256Ctr::new(&key, &nonce);
620 cipher.apply_keystream(&mut cipherkey);
621 } else {
622 let key: &GenericArray<u8, U16> = GenericArray::from_slice(&derived_key[..16]);
623 let mut cipher = Aes128Ctr::new(&key, &nonce);
624 cipher.apply_keystream(&mut cipherkey);
625 }
Fabio Utzig90f449e2019-10-24 07:43:53 -0300626
Salome Thirot6fdbf552021-05-14 16:46:14 +0100627 let size = if aes256 { 32 } else { 16 };
628 let key = hmac::Key::new(hmac::HMAC_SHA256, &derived_key[size..]);
Fabio Utzig90f449e2019-10-24 07:43:53 -0300629 let tag = hmac::sign(&key, &cipherkey);
630
631 let mut buf = vec![];
632 buf.append(&mut pubk.as_ref().to_vec());
633 buf.append(&mut tag.as_ref().to_vec());
634 buf.append(&mut cipherkey);
635
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300636 if self.kinds.contains(&TlvKinds::ENCEC256) {
Salome Thirot6fdbf552021-05-14 16:46:14 +0100637 let size = if aes256 { 129 } else { 113 };
638 assert!(buf.len() == size);
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300639 result.write_u16::<LittleEndian>(TlvKinds::ENCEC256 as u16).unwrap();
Salome Thirot6fdbf552021-05-14 16:46:14 +0100640 result.write_u16::<LittleEndian>(size as u16).unwrap();
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300641 } else {
Salome Thirot6fdbf552021-05-14 16:46:14 +0100642 let size = if aes256 { 96 } else { 80 };
643 assert!(buf.len() == size);
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300644 result.write_u16::<LittleEndian>(TlvKinds::ENCX25519 as u16).unwrap();
Salome Thirot6fdbf552021-05-14 16:46:14 +0100645 result.write_u16::<LittleEndian>(size as u16).unwrap();
Fabio Utzig3fa72ca2020-04-02 11:20:37 -0300646 }
Fabio Utzig90f449e2019-10-24 07:43:53 -0300647 result.extend_from_slice(&buf);
648 }
649
David Brown3dc86c92020-01-08 17:22:55 -0700650 // Patch the size back into the TLV header.
651 let size = (result.len() - npro_pos) as u16;
652 let mut size_buf = &mut result[npro_pos + 2 .. npro_pos + 4];
653 size_buf.write_u16::<LittleEndian>(size).unwrap();
654
David Brown187dd882017-07-11 11:15:23 -0600655 result
656 }
Fabio Utzig90f449e2019-10-24 07:43:53 -0300657
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300658 fn generate_enc_key(&mut self) {
659 let rng = rand::SystemRandom::new();
Salome Thirot6fdbf552021-05-14 16:46:14 +0100660 let flag = TlvFlags::ENCRYPTED_AES256 as u32;
661 let aes256 = (self.get_flags() & flag) == flag;
662 let mut buf = if aes256 {
663 vec![0u8; 32]
664 } else {
665 vec![0u8; 16]
666 };
David Brown26edaf32021-03-10 05:27:38 -0700667 if rng.fill(&mut buf).is_err() {
668 panic!("Error generating encrypted key");
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300669 }
670 info!("New encryption key: {:02x?}", buf);
671 self.enc_key = buf;
Fabio Utzig90f449e2019-10-24 07:43:53 -0300672 }
673
674 fn get_enc_key(&self) -> Vec<u8> {
Salome Thirot6fdbf552021-05-14 16:46:14 +0100675 if self.enc_key.len() != 32 && self.enc_key.len() != 16 {
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300676 panic!("No random key was generated");
677 }
678 self.enc_key.clone()
Fabio Utzig90f449e2019-10-24 07:43:53 -0300679 }
David Brown187dd882017-07-11 11:15:23 -0600680}
David Brown43cda332017-09-01 09:53:23 -0600681
682include!("rsa_pub_key-rs.txt");
Fabio Utzig39297432019-05-08 18:51:10 -0300683include!("rsa3072_pub_key-rs.txt");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200684include!("ecdsa_pub_key-rs.txt");
Fabio Utzig97710282019-05-24 17:44:49 -0300685include!("ed25519_pub_key-rs.txt");