blob: c4bd54ea565b4e41f125748f50cf9eebf7cc032b [file] [log] [blame]
David Brown187dd882017-07-11 11:15:23 -06001//! TLV Support
2//!
3//! mcuboot images are followed immediately by a list of TLV items that contain integrity
4//! information about the image. Their generation is made a little complicated because the size of
5//! the TLV block is in the image header, which is included in the hash. Since some signatures can
6//! vary in size, we just make them the largest size possible.
7//!
8//! Because of this header, we have to make two passes. The first pass will compute the size of
9//! the TLV, and the second pass will build the data for the TLV.
10
David Brown91d68632019-07-29 14:32:13 -060011use byteorder::{
12 LittleEndian, WriteBytesExt,
13};
David Brown7a81c4b2019-07-29 15:20:21 -060014use crate::image::ImageVersion;
David Brown7e701d82017-07-11 13:24:25 -060015use pem;
Fabio Utzig1e48b912018-09-18 09:04:18 -030016use base64;
Fabio Utzige84f0ef2019-11-22 12:29:32 -030017use log::info;
Fabio Utzig90f449e2019-10-24 07:43:53 -030018use ring::{digest, rand, agreement, hkdf, hmac};
Fabio Utzige84f0ef2019-11-22 12:29:32 -030019use ring::rand::SecureRandom;
Fabio Utzig05ab0142018-07-10 09:15:28 -030020use ring::signature::{
21 RsaKeyPair,
22 RSA_PSS_SHA256,
23 EcdsaKeyPair,
24 ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig97710282019-05-24 17:44:49 -030025 Ed25519KeyPair,
Fabio Utzig05ab0142018-07-10 09:15:28 -030026};
Fabio Utzig90f449e2019-10-24 07:43:53 -030027use aes_ctr::{
28 Aes128Ctr,
29 stream_cipher::{
30 generic_array::GenericArray,
31 NewFixStreamCipher,
32 StreamCipherCore,
33 },
34};
Fabio Utzig80fde2f2017-12-05 09:25:31 -020035use mcuboot_sys::c;
David Brown187dd882017-07-11 11:15:23 -060036
David Brown69721182019-12-04 14:50:52 -070037#[repr(u16)]
David Brownc3898d62019-08-05 14:20:02 -060038#[derive(Copy, Clone, Debug, PartialEq, Eq)]
David Brown187dd882017-07-11 11:15:23 -060039#[allow(dead_code)] // TODO: For now
40pub enum TlvKinds {
David Brown43cda332017-09-01 09:53:23 -060041 KEYHASH = 0x01,
David Brown27648b82017-08-31 10:40:29 -060042 SHA256 = 0x10,
43 RSA2048 = 0x20,
44 ECDSA224 = 0x21,
45 ECDSA256 = 0x22,
Fabio Utzig39297432019-05-08 18:51:10 -030046 RSA3072 = 0x23,
Fabio Utzig97710282019-05-24 17:44:49 -030047 ED25519 = 0x24,
Fabio Utzig1e48b912018-09-18 09:04:18 -030048 ENCRSA2048 = 0x30,
49 ENCKW128 = 0x31,
Fabio Utzig90f449e2019-10-24 07:43:53 -030050 ENCEC256 = 0x32,
David Brown7a81c4b2019-07-29 15:20:21 -060051 DEPENDENCY = 0x40,
Fabio Utzig1e48b912018-09-18 09:04:18 -030052}
53
54#[allow(dead_code, non_camel_case_types)]
55pub enum TlvFlags {
56 PIC = 0x01,
57 NON_BOOTABLE = 0x02,
58 ENCRYPTED = 0x04,
59 RAM_LOAD = 0x20,
David Brown187dd882017-07-11 11:15:23 -060060}
61
David Brown43643dd2019-01-11 15:43:28 -070062/// A generator for manifests. The format of the manifest can be either a
63/// traditional "TLV" or a SUIT-style manifest.
64pub trait ManifestGen {
David Brownac46e262019-01-11 15:46:18 -070065 /// Retrieve the header magic value for this manifest type.
66 fn get_magic(&self) -> u32;
67
David Brown43643dd2019-01-11 15:43:28 -070068 /// Retrieve the flags value for this particular manifest type.
69 fn get_flags(&self) -> u32;
70
David Brown7a81c4b2019-07-29 15:20:21 -060071 /// Retrieve the number of bytes of this manifest that is "protected".
72 /// This field is stored in the outside image header instead of the
73 /// manifest header.
74 fn protect_size(&self) -> u16;
75
76 /// Add a dependency on another image.
77 fn add_dependency(&mut self, id: u8, version: &ImageVersion);
78
David Brown43643dd2019-01-11 15:43:28 -070079 /// Add a sequence of bytes to the payload that the manifest is
80 /// protecting.
81 fn add_bytes(&mut self, bytes: &[u8]);
82
David Browne90b13f2019-12-06 15:04:00 -070083 /// Set an internal flag indicating that the next `make_tlv` should
84 /// corrupt the signature.
85 fn corrupt_sig(&mut self);
86
David Brown43643dd2019-01-11 15:43:28 -070087 /// Construct the manifest for this payload.
88 fn make_tlv(self: Box<Self>) -> Vec<u8>;
Fabio Utzig90f449e2019-10-24 07:43:53 -030089
Fabio Utzige84f0ef2019-11-22 12:29:32 -030090 /// Generate a new encryption random key
91 fn generate_enc_key(&mut self);
Fabio Utzig90f449e2019-10-24 07:43:53 -030092
93 /// Return the current encryption key
94 fn get_enc_key(&self) -> Vec<u8>;
David Brown43643dd2019-01-11 15:43:28 -070095}
96
Fabio Utzig9a2b5de2019-11-22 12:50:02 -030097#[derive(Debug, Default)]
David Brown187dd882017-07-11 11:15:23 -060098pub struct TlvGen {
David Brown43cda332017-09-01 09:53:23 -060099 flags: u32,
David Brown187dd882017-07-11 11:15:23 -0600100 kinds: Vec<TlvKinds>,
David Brown7a81c4b2019-07-29 15:20:21 -0600101 /// The total size of the payload.
David Brown187dd882017-07-11 11:15:23 -0600102 size: u16,
David Brown7a81c4b2019-07-29 15:20:21 -0600103 /// Extra bytes of the TLV that are protected.
104 protect_size: u16,
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],
126 size: 4 + 32,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300127 ..Default::default()
David Brown187dd882017-07-11 11:15:23 -0600128 }
129 }
130
David Brown7e701d82017-07-11 13:24:25 -0600131 #[allow(dead_code)]
132 pub fn new_rsa_pss() -> TlvGen {
133 TlvGen {
Fabio Utzig754438d2018-12-14 06:39:58 -0200134 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048],
135 size: 4 + 32 + 4 + 32 + 4 + 256,
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],
144 size: 4 + 32 + 4 + 32 + 4 + 384,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300145 ..Default::default()
Fabio Utzig39297432019-05-08 18:51:10 -0300146 }
147 }
148
149 #[allow(dead_code)]
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200150 pub fn new_ecdsa() -> TlvGen {
151 TlvGen {
Fabio Utzig754438d2018-12-14 06:39:58 -0200152 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256],
153 size: 4 + 32 + 4 + 32 + 4 + 72,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300154 ..Default::default()
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200155 }
156 }
157
Fabio Utzig1e48b912018-09-18 09:04:18 -0300158 #[allow(dead_code)]
Fabio Utzig97710282019-05-24 17:44:49 -0300159 pub fn new_ed25519() -> TlvGen {
160 TlvGen {
Fabio Utzig97710282019-05-24 17:44:49 -0300161 kinds: vec![TlvKinds::SHA256, TlvKinds::ED25519],
162 size: 4 + 32 + 4 + 32 + 4 + 64,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300163 ..Default::default()
Fabio Utzig97710282019-05-24 17:44:49 -0300164 }
165 }
166
167 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300168 pub fn new_enc_rsa() -> TlvGen {
169 TlvGen {
170 flags: TlvFlags::ENCRYPTED as u32,
171 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
172 size: 4 + 32 + 4 + 256,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300173 ..Default::default()
Fabio Utzig1e48b912018-09-18 09:04:18 -0300174 }
175 }
176
177 #[allow(dead_code)]
Fabio Utzig754438d2018-12-14 06:39:58 -0200178 pub fn new_sig_enc_rsa() -> TlvGen {
179 TlvGen {
180 flags: TlvFlags::ENCRYPTED as u32,
181 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCRSA2048],
182 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 256,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300183 ..Default::default()
Fabio Utzig754438d2018-12-14 06:39:58 -0200184 }
185 }
186
187 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300188 pub fn new_enc_kw() -> TlvGen {
189 TlvGen {
190 flags: TlvFlags::ENCRYPTED as u32,
191 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW128],
192 size: 4 + 32 + 4 + 24,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300193 ..Default::default()
Fabio Utzig1e48b912018-09-18 09:04:18 -0300194 }
195 }
196
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200197 #[allow(dead_code)]
198 pub fn new_rsa_kw() -> TlvGen {
199 TlvGen {
200 flags: TlvFlags::ENCRYPTED as u32,
201 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCKW128],
202 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 24,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300203 ..Default::default()
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200204 }
205 }
206
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200207 #[allow(dead_code)]
208 pub fn new_ecdsa_kw() -> TlvGen {
209 TlvGen {
210 flags: TlvFlags::ENCRYPTED as u32,
211 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCKW128],
212 size: 4 + 32 + 4 + 32 + 4 + 72 + 4 + 24,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300213 ..Default::default()
Fabio Utzig90f449e2019-10-24 07:43:53 -0300214 }
215 }
216
217 #[allow(dead_code)]
218 pub fn new_ecdsa_ecies_p256() -> TlvGen {
219 TlvGen {
220 flags: TlvFlags::ENCRYPTED as u32,
221 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCEC256],
222 size: 4 + 32 + 4 + 32 + 4 + 72 + 4 + 113,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300223 ..Default::default()
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200224 }
225 }
226
David Brown187dd882017-07-11 11:15:23 -0600227 /// Retrieve the size that the TLV will occupy. This can be called at any time.
228 pub fn get_size(&self) -> u16 {
David Brownf5b33d82017-09-01 10:58:27 -0600229 4 + self.size
David Brown187dd882017-07-11 11:15:23 -0600230 }
David Brown43643dd2019-01-11 15:43:28 -0700231}
232
233impl ManifestGen for TlvGen {
David Brownac46e262019-01-11 15:46:18 -0700234 fn get_magic(&self) -> u32 {
235 0x96f3b83d
236 }
237
David Brown43643dd2019-01-11 15:43:28 -0700238 /// Retrieve the header flags for this configuration. This can be called at any time.
239 fn get_flags(&self) -> u32 {
240 self.flags
241 }
David Brown187dd882017-07-11 11:15:23 -0600242
243 /// Add bytes to the covered hash.
David Brown43643dd2019-01-11 15:43:28 -0700244 fn add_bytes(&mut self, bytes: &[u8]) {
David Brown4243ab02017-07-11 12:24:23 -0600245 self.payload.extend_from_slice(bytes);
David Brown187dd882017-07-11 11:15:23 -0600246 }
247
David Brown7a81c4b2019-07-29 15:20:21 -0600248 fn protect_size(&self) -> u16 {
249 if self.protect_size == 0 {
250 0
251 } else {
252 // Include the protected size, as well as the TLV header.
253 4 + self.protect_size
254 }
255 }
256
257 fn add_dependency(&mut self, id: u8, version: &ImageVersion) {
258 let my_size = 4 + 4 + 8;
259 self.protect_size += my_size;
260 self.size += my_size;
261 self.dependencies.push(Dependency {
262 id: id,
263 version: version.clone(),
264 });
265 }
266
David Browne90b13f2019-12-06 15:04:00 -0700267 fn corrupt_sig(&mut self) {
268 self.gen_corrupted = true;
269 }
270
David Brown187dd882017-07-11 11:15:23 -0600271 /// Compute the TLV given the specified block of data.
David Brown43643dd2019-01-11 15:43:28 -0700272 fn make_tlv(self: Box<Self>) -> Vec<u8> {
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300273 let mut protected_tlv: Vec<u8> = vec![];
David Brown187dd882017-07-11 11:15:23 -0600274
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300275 if self.protect_size > 0 {
276 protected_tlv.push(0x08);
277 protected_tlv.push(0x69);
278 protected_tlv.write_u16::<LittleEndian>(self.protect_size()).unwrap();
279 for dep in &self.dependencies {
David Brown69721182019-12-04 14:50:52 -0700280 protected_tlv.write_u16::<LittleEndian>(TlvKinds::DEPENDENCY as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700281 protected_tlv.write_u16::<LittleEndian>(12).unwrap();
David Brownf5b33d82017-09-01 10:58:27 -0600282
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300283 // The dependency.
284 protected_tlv.push(dep.id);
285 for _ in 0 .. 3 {
286 protected_tlv.push(0);
287 }
288 protected_tlv.push(dep.version.major);
289 protected_tlv.push(dep.version.minor);
290 protected_tlv.write_u16::<LittleEndian>(dep.version.revision).unwrap();
291 protected_tlv.write_u32::<LittleEndian>(dep.version.build_num).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600292 }
David Brown7a81c4b2019-07-29 15:20:21 -0600293 }
294
295 // Ring does the signature itself, which means that it must be
296 // given a full, contiguous payload. Although this does help from
297 // a correct usage perspective, it is fairly stupid from an
298 // efficiency view. If this is shown to be a performance issue
299 // with the tests, the protected data could be appended to the
300 // payload, and then removed after the signature is done. For now,
301 // just make a signed payload.
302 let mut sig_payload = self.payload.clone();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300303 sig_payload.extend_from_slice(&protected_tlv);
304
305 let mut result: Vec<u8> = vec![];
306
307 // add back signed payload
308 result.extend_from_slice(&protected_tlv);
309
310 // add non-protected payload
311 result.push(0x07);
312 result.push(0x69);
313 result.write_u16::<LittleEndian>(self.get_size()).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600314
David Brown187dd882017-07-11 11:15:23 -0600315 if self.kinds.contains(&TlvKinds::SHA256) {
David Browne90b13f2019-12-06 15:04:00 -0700316 // If a signature is not requested, corrupt the hash we are
317 // generating. But, if there is a signature, output the
318 // correct hash. We want the hash test to pass so that the
319 // signature verification can be validated.
320 let mut corrupt_hash = self.gen_corrupted;
321 for k in &[TlvKinds::RSA2048, TlvKinds::RSA3072,
322 TlvKinds::ECDSA224, TlvKinds::ECDSA256,
323 TlvKinds::ED25519]
324 {
325 if self.kinds.contains(k) {
326 corrupt_hash = false;
327 break;
328 }
329 }
330
331 if corrupt_hash {
332 sig_payload[0] ^= 1;
333 }
334
David Brown7a81c4b2019-07-29 15:20:21 -0600335 let hash = digest::digest(&digest::SHA256, &sig_payload);
David Brown8054ce22017-07-11 12:12:09 -0600336 let hash = hash.as_ref();
David Brown187dd882017-07-11 11:15:23 -0600337
David Brown8054ce22017-07-11 12:12:09 -0600338 assert!(hash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700339 result.write_u16::<LittleEndian>(TlvKinds::SHA256 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700340 result.write_u16::<LittleEndian>(32).unwrap();
David Brown8054ce22017-07-11 12:12:09 -0600341 result.extend_from_slice(hash);
David Browne90b13f2019-12-06 15:04:00 -0700342
343 // Undo the corruption.
344 if corrupt_hash {
345 sig_payload[0] ^= 1;
346 }
347
348 }
349
350 if self.gen_corrupted {
351 // Corrupt what is signed by modifying the input to the
352 // signature code.
353 sig_payload[0] ^= 1;
David Brown187dd882017-07-11 11:15:23 -0600354 }
355
Fabio Utzig39297432019-05-08 18:51:10 -0300356 if self.kinds.contains(&TlvKinds::RSA2048) ||
357 self.kinds.contains(&TlvKinds::RSA3072) {
358
359 let is_rsa2048 = self.kinds.contains(&TlvKinds::RSA2048);
360
David Brown43cda332017-09-01 09:53:23 -0600361 // Output the hash of the public key.
Fabio Utzig39297432019-05-08 18:51:10 -0300362 let hash = if is_rsa2048 {
363 digest::digest(&digest::SHA256, RSA_PUB_KEY)
364 } else {
365 digest::digest(&digest::SHA256, RSA3072_PUB_KEY)
366 };
David Brown43cda332017-09-01 09:53:23 -0600367 let hash = hash.as_ref();
368
369 assert!(hash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700370 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700371 result.write_u16::<LittleEndian>(32).unwrap();
David Brown43cda332017-09-01 09:53:23 -0600372 result.extend_from_slice(hash);
373
David Brown7e701d82017-07-11 13:24:25 -0600374 // For now assume PSS.
Fabio Utzig39297432019-05-08 18:51:10 -0300375 let key_bytes = if is_rsa2048 {
376 pem::parse(include_bytes!("../../root-rsa-2048.pem").as_ref()).unwrap()
377 } else {
378 pem::parse(include_bytes!("../../root-rsa-3072.pem").as_ref()).unwrap()
379 };
David Brown7e701d82017-07-11 13:24:25 -0600380 assert_eq!(key_bytes.tag, "RSA PRIVATE KEY");
Fabio Utzig90f449e2019-10-24 07:43:53 -0300381 let key_pair = RsaKeyPair::from_der(&key_bytes.contents).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600382 let rng = rand::SystemRandom::new();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300383 let mut signature = vec![0; key_pair.public_modulus_len()];
Fabio Utzig39297432019-05-08 18:51:10 -0300384 if is_rsa2048 {
385 assert_eq!(signature.len(), 256);
386 } else {
387 assert_eq!(signature.len(), 384);
388 }
David Brown7a81c4b2019-07-29 15:20:21 -0600389 key_pair.sign(&RSA_PSS_SHA256, &rng, &sig_payload, &mut signature).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600390
Fabio Utzig39297432019-05-08 18:51:10 -0300391 if is_rsa2048 {
David Brown69721182019-12-04 14:50:52 -0700392 result.write_u16::<LittleEndian>(TlvKinds::RSA2048 as u16).unwrap();
Fabio Utzig39297432019-05-08 18:51:10 -0300393 } else {
David Brown69721182019-12-04 14:50:52 -0700394 result.write_u16::<LittleEndian>(TlvKinds::RSA3072 as u16).unwrap();
Fabio Utzig39297432019-05-08 18:51:10 -0300395 }
David Brown91d68632019-07-29 14:32:13 -0600396 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600397 result.extend_from_slice(&signature);
398 }
399
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200400 if self.kinds.contains(&TlvKinds::ECDSA256) {
401 let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY);
402 let keyhash = keyhash.as_ref();
403
404 assert!(keyhash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700405 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700406 result.write_u16::<LittleEndian>(32).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200407 result.extend_from_slice(keyhash);
408
Fabio Utzig05ab0142018-07-10 09:15:28 -0300409 let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap();
410 assert_eq!(key_bytes.tag, "PRIVATE KEY");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200411
Fabio Utzig05ab0142018-07-10 09:15:28 -0300412 let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300413 &key_bytes.contents).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300414 let rng = rand::SystemRandom::new();
Fabio Utzig90f449e2019-10-24 07:43:53 -0300415 let signature = key_pair.sign(&rng, &sig_payload).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200416
David Brown69721182019-12-04 14:50:52 -0700417 result.write_u16::<LittleEndian>(TlvKinds::ECDSA256 as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300418
David Browne90b13f2019-12-06 15:04:00 -0700419
Fabio Utzig05ab0142018-07-10 09:15:28 -0300420 // signature must be padded...
421 let mut signature = signature.as_ref().to_vec();
422 while signature.len() < 72 {
423 signature.push(0);
Fabio Utzig05ab0142018-07-10 09:15:28 -0300424 }
425
David Brown91d68632019-07-29 14:32:13 -0600426 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300427 result.extend_from_slice(signature.as_ref());
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200428 }
429
Fabio Utzig97710282019-05-24 17:44:49 -0300430 if self.kinds.contains(&TlvKinds::ED25519) {
431 let keyhash = digest::digest(&digest::SHA256, ED25519_PUB_KEY);
432 let keyhash = keyhash.as_ref();
433
434 assert!(keyhash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700435 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700436 result.write_u16::<LittleEndian>(32).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300437 result.extend_from_slice(keyhash);
438
David Brown7a81c4b2019-07-29 15:20:21 -0600439 let hash = digest::digest(&digest::SHA256, &sig_payload);
Fabio Utzig97710282019-05-24 17:44:49 -0300440 let hash = hash.as_ref();
441 assert!(hash.len() == 32);
442
443 let key_bytes = pem::parse(include_bytes!("../../root-ed25519.pem").as_ref()).unwrap();
444 assert_eq!(key_bytes.tag, "PRIVATE KEY");
445
Fabio Utzig90f449e2019-10-24 07:43:53 -0300446 let key_pair = Ed25519KeyPair::from_seed_and_public_key(
447 &key_bytes.contents[16..48], &ED25519_PUB_KEY[12..44]).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300448 let signature = key_pair.sign(&hash);
449
David Brown69721182019-12-04 14:50:52 -0700450 result.write_u16::<LittleEndian>(TlvKinds::ED25519 as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300451
452 let signature = signature.as_ref().to_vec();
David Brown91d68632019-07-29 14:32:13 -0600453 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300454 result.extend_from_slice(signature.as_ref());
455 }
456
Fabio Utzig1e48b912018-09-18 09:04:18 -0300457 if self.kinds.contains(&TlvKinds::ENCRSA2048) {
458 let key_bytes = pem::parse(include_bytes!("../../enc-rsa2048-pub.pem")
459 .as_ref()).unwrap();
460 assert_eq!(key_bytes.tag, "PUBLIC KEY");
461
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300462 let cipherkey = self.get_enc_key();
463 let cipherkey = cipherkey.as_slice();
464 let encbuf = match c::rsa_oaep_encrypt(&key_bytes.contents, cipherkey) {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300465 Ok(v) => v,
466 Err(_) => panic!("Failed to encrypt secret key"),
467 };
468
469 assert!(encbuf.len() == 256);
David Brown69721182019-12-04 14:50:52 -0700470 result.write_u16::<LittleEndian>(TlvKinds::ENCRSA2048 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700471 result.write_u16::<LittleEndian>(256).unwrap();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300472 result.extend_from_slice(&encbuf);
473 }
474
475 if self.kinds.contains(&TlvKinds::ENCKW128) {
476 let key_bytes = base64::decode(
477 include_str!("../../enc-aes128kw.b64").trim()).unwrap();
478
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300479 let cipherkey = self.get_enc_key();
480 let cipherkey = cipherkey.as_slice();
481 let encbuf = match c::kw_encrypt(&key_bytes, cipherkey) {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300482 Ok(v) => v,
483 Err(_) => panic!("Failed to encrypt secret key"),
484 };
485
486 assert!(encbuf.len() == 24);
David Brown69721182019-12-04 14:50:52 -0700487 result.write_u16::<LittleEndian>(TlvKinds::ENCKW128 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700488 result.write_u16::<LittleEndian>(24).unwrap();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300489 result.extend_from_slice(&encbuf);
490 }
491
Fabio Utzig90f449e2019-10-24 07:43:53 -0300492 if self.kinds.contains(&TlvKinds::ENCEC256) {
493 let key_bytes = pem::parse(include_bytes!("../../enc-ec256-pub.pem").as_ref()).unwrap();
494 assert_eq!(key_bytes.tag, "PUBLIC KEY");
495
496 let rng = rand::SystemRandom::new();
497 let pk = match agreement::EphemeralPrivateKey::generate(&agreement::ECDH_P256, &rng) {
498 Ok(v) => v,
499 Err(_) => panic!("Failed to generate ephemeral keypair"),
500 };
501
502 let pubk = match pk.compute_public_key() {
503 Ok(pubk) => pubk,
504 Err(_) => panic!("Failed computing ephemeral public key"),
505 };
506
507 let peer_pubk = agreement::UnparsedPublicKey::new(&agreement::ECDH_P256, &key_bytes.contents[26..]);
508
509 #[derive(Debug, PartialEq)]
510 struct OkmLen<T: core::fmt::Debug + PartialEq>(T);
511
512 impl hkdf::KeyType for OkmLen<usize> {
513 fn len(&self) -> usize {
514 self.0
515 }
516 }
517
518 let derived_key = match agreement::agree_ephemeral(
519 pk, &peer_pubk, ring::error::Unspecified, |shared| {
520 let salt = hkdf::Salt::new(hkdf::HKDF_SHA256, &[]);
521 let prk = salt.extract(&shared);
522 let okm = match prk.expand(&[b"MCUBoot_ECIES_v1"], OkmLen(48)) {
523 Ok(okm) => okm,
524 Err(_) => panic!("Failed building HKDF OKM"),
525 };
526 let mut buf = [0u8; 48];
527 match okm.fill(&mut buf) {
528 Ok(_) => Ok(buf),
529 Err(_) => panic!("Failed generating HKDF output"),
530 }
531 },
532 ) {
533 Ok(v) => v,
534 Err(_) => panic!("Failed building HKDF"),
535 };
536
537 let key = GenericArray::from_slice(&derived_key[..16]);
538 let nonce = GenericArray::from_slice(&[0; 16]);
539 let mut cipher = Aes128Ctr::new(&key, &nonce);
540 let mut cipherkey = self.get_enc_key();
541 cipher.apply_keystream(&mut cipherkey);
542
543 let key = hmac::Key::new(hmac::HMAC_SHA256, &derived_key[16..]);
544 let tag = hmac::sign(&key, &cipherkey);
545
546 let mut buf = vec![];
547 buf.append(&mut pubk.as_ref().to_vec());
548 buf.append(&mut tag.as_ref().to_vec());
549 buf.append(&mut cipherkey);
550
551 assert!(buf.len() == 113);
David Brown69721182019-12-04 14:50:52 -0700552 result.write_u16::<LittleEndian>(TlvKinds::ENCEC256 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700553 result.write_u16::<LittleEndian>(113).unwrap();
Fabio Utzig90f449e2019-10-24 07:43:53 -0300554 result.extend_from_slice(&buf);
555 }
556
David Brown187dd882017-07-11 11:15:23 -0600557 result
558 }
Fabio Utzig90f449e2019-10-24 07:43:53 -0300559
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300560 fn generate_enc_key(&mut self) {
561 let rng = rand::SystemRandom::new();
562 let mut buf = vec![0u8; AES_KEY_LEN];
563 match rng.fill(&mut buf) {
564 Err(_) => panic!("Error generating encrypted key"),
565 Ok(_) => (),
566 }
567 info!("New encryption key: {:02x?}", buf);
568 self.enc_key = buf;
Fabio Utzig90f449e2019-10-24 07:43:53 -0300569 }
570
571 fn get_enc_key(&self) -> Vec<u8> {
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300572 if self.enc_key.len() != AES_KEY_LEN {
573 panic!("No random key was generated");
574 }
575 self.enc_key.clone()
Fabio Utzig90f449e2019-10-24 07:43:53 -0300576 }
David Brown187dd882017-07-11 11:15:23 -0600577}
David Brown43cda332017-09-01 09:53:23 -0600578
579include!("rsa_pub_key-rs.txt");
Fabio Utzig39297432019-05-08 18:51:10 -0300580include!("rsa3072_pub_key-rs.txt");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200581include!("ecdsa_pub_key-rs.txt");
Fabio Utzig97710282019-05-24 17:44:49 -0300582include!("ed25519_pub_key-rs.txt");