blob: 187baec8000c6d597a938f4bc8a514d24ffa336c [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
83 /// Construct the manifest for this payload.
84 fn make_tlv(self: Box<Self>) -> Vec<u8>;
Fabio Utzig90f449e2019-10-24 07:43:53 -030085
Fabio Utzige84f0ef2019-11-22 12:29:32 -030086 /// Generate a new encryption random key
87 fn generate_enc_key(&mut self);
Fabio Utzig90f449e2019-10-24 07:43:53 -030088
89 /// Return the current encryption key
90 fn get_enc_key(&self) -> Vec<u8>;
David Brown43643dd2019-01-11 15:43:28 -070091}
92
Fabio Utzig9a2b5de2019-11-22 12:50:02 -030093#[derive(Debug, Default)]
David Brown187dd882017-07-11 11:15:23 -060094pub struct TlvGen {
David Brown43cda332017-09-01 09:53:23 -060095 flags: u32,
David Brown187dd882017-07-11 11:15:23 -060096 kinds: Vec<TlvKinds>,
David Brown7a81c4b2019-07-29 15:20:21 -060097 /// The total size of the payload.
David Brown187dd882017-07-11 11:15:23 -060098 size: u16,
David Brown7a81c4b2019-07-29 15:20:21 -060099 /// Extra bytes of the TLV that are protected.
100 protect_size: u16,
David Brown4243ab02017-07-11 12:24:23 -0600101 payload: Vec<u8>,
David Brown7a81c4b2019-07-29 15:20:21 -0600102 dependencies: Vec<Dependency>,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300103 enc_key: Vec<u8>,
David Brown7a81c4b2019-07-29 15:20:21 -0600104}
105
David Brownc3898d62019-08-05 14:20:02 -0600106#[derive(Debug)]
David Brown7a81c4b2019-07-29 15:20:21 -0600107struct Dependency {
108 id: u8,
109 version: ImageVersion,
David Brown187dd882017-07-11 11:15:23 -0600110}
111
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300112const AES_KEY_LEN: usize = 16;
Fabio Utzig1e48b912018-09-18 09:04:18 -0300113
David Brown187dd882017-07-11 11:15:23 -0600114impl TlvGen {
115 /// Construct a new tlv generator that will only contain a hash of the data.
David Brown7e701d82017-07-11 13:24:25 -0600116 #[allow(dead_code)]
David Brown187dd882017-07-11 11:15:23 -0600117 pub fn new_hash_only() -> TlvGen {
118 TlvGen {
David Brown187dd882017-07-11 11:15:23 -0600119 kinds: vec![TlvKinds::SHA256],
120 size: 4 + 32,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300121 ..Default::default()
David Brown187dd882017-07-11 11:15:23 -0600122 }
123 }
124
David Brown7e701d82017-07-11 13:24:25 -0600125 #[allow(dead_code)]
126 pub fn new_rsa_pss() -> TlvGen {
127 TlvGen {
Fabio Utzig754438d2018-12-14 06:39:58 -0200128 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048],
129 size: 4 + 32 + 4 + 32 + 4 + 256,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300130 ..Default::default()
David Brown7e701d82017-07-11 13:24:25 -0600131 }
132 }
133
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200134 #[allow(dead_code)]
Fabio Utzig39297432019-05-08 18:51:10 -0300135 pub fn new_rsa3072_pss() -> TlvGen {
136 TlvGen {
Fabio Utzig39297432019-05-08 18:51:10 -0300137 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA3072],
138 size: 4 + 32 + 4 + 32 + 4 + 384,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300139 ..Default::default()
Fabio Utzig39297432019-05-08 18:51:10 -0300140 }
141 }
142
143 #[allow(dead_code)]
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200144 pub fn new_ecdsa() -> TlvGen {
145 TlvGen {
Fabio Utzig754438d2018-12-14 06:39:58 -0200146 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256],
147 size: 4 + 32 + 4 + 32 + 4 + 72,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300148 ..Default::default()
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200149 }
150 }
151
Fabio Utzig1e48b912018-09-18 09:04:18 -0300152 #[allow(dead_code)]
Fabio Utzig97710282019-05-24 17:44:49 -0300153 pub fn new_ed25519() -> TlvGen {
154 TlvGen {
Fabio Utzig97710282019-05-24 17:44:49 -0300155 kinds: vec![TlvKinds::SHA256, TlvKinds::ED25519],
156 size: 4 + 32 + 4 + 32 + 4 + 64,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300157 ..Default::default()
Fabio Utzig97710282019-05-24 17:44:49 -0300158 }
159 }
160
161 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300162 pub fn new_enc_rsa() -> TlvGen {
163 TlvGen {
164 flags: TlvFlags::ENCRYPTED as u32,
165 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
166 size: 4 + 32 + 4 + 256,
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],
176 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 256,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300177 ..Default::default()
Fabio Utzig754438d2018-12-14 06:39:58 -0200178 }
179 }
180
181 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300182 pub fn new_enc_kw() -> TlvGen {
183 TlvGen {
184 flags: TlvFlags::ENCRYPTED as u32,
185 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW128],
186 size: 4 + 32 + 4 + 24,
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],
196 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 24,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300197 ..Default::default()
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200198 }
199 }
200
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200201 #[allow(dead_code)]
202 pub fn new_ecdsa_kw() -> TlvGen {
203 TlvGen {
204 flags: TlvFlags::ENCRYPTED as u32,
205 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCKW128],
206 size: 4 + 32 + 4 + 32 + 4 + 72 + 4 + 24,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300207 ..Default::default()
Fabio Utzig90f449e2019-10-24 07:43:53 -0300208 }
209 }
210
211 #[allow(dead_code)]
212 pub fn new_ecdsa_ecies_p256() -> TlvGen {
213 TlvGen {
214 flags: TlvFlags::ENCRYPTED as u32,
215 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCEC256],
216 size: 4 + 32 + 4 + 32 + 4 + 72 + 4 + 113,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300217 ..Default::default()
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200218 }
219 }
220
David Brown187dd882017-07-11 11:15:23 -0600221 /// Retrieve the size that the TLV will occupy. This can be called at any time.
222 pub fn get_size(&self) -> u16 {
David Brownf5b33d82017-09-01 10:58:27 -0600223 4 + self.size
David Brown187dd882017-07-11 11:15:23 -0600224 }
David Brown43643dd2019-01-11 15:43:28 -0700225}
226
227impl ManifestGen for TlvGen {
David Brownac46e262019-01-11 15:46:18 -0700228 fn get_magic(&self) -> u32 {
229 0x96f3b83d
230 }
231
David Brown43643dd2019-01-11 15:43:28 -0700232 /// Retrieve the header flags for this configuration. This can be called at any time.
233 fn get_flags(&self) -> u32 {
234 self.flags
235 }
David Brown187dd882017-07-11 11:15:23 -0600236
237 /// Add bytes to the covered hash.
David Brown43643dd2019-01-11 15:43:28 -0700238 fn add_bytes(&mut self, bytes: &[u8]) {
David Brown4243ab02017-07-11 12:24:23 -0600239 self.payload.extend_from_slice(bytes);
David Brown187dd882017-07-11 11:15:23 -0600240 }
241
David Brown7a81c4b2019-07-29 15:20:21 -0600242 fn protect_size(&self) -> u16 {
243 if self.protect_size == 0 {
244 0
245 } else {
246 // Include the protected size, as well as the TLV header.
247 4 + self.protect_size
248 }
249 }
250
251 fn add_dependency(&mut self, id: u8, version: &ImageVersion) {
252 let my_size = 4 + 4 + 8;
253 self.protect_size += my_size;
254 self.size += my_size;
255 self.dependencies.push(Dependency {
256 id: id,
257 version: version.clone(),
258 });
259 }
260
David Brown187dd882017-07-11 11:15:23 -0600261 /// Compute the TLV given the specified block of data.
David Brown43643dd2019-01-11 15:43:28 -0700262 fn make_tlv(self: Box<Self>) -> Vec<u8> {
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300263 let mut protected_tlv: Vec<u8> = vec![];
David Brown187dd882017-07-11 11:15:23 -0600264
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300265 if self.protect_size > 0 {
266 protected_tlv.push(0x08);
267 protected_tlv.push(0x69);
268 protected_tlv.write_u16::<LittleEndian>(self.protect_size()).unwrap();
269 for dep in &self.dependencies {
David Brown69721182019-12-04 14:50:52 -0700270 protected_tlv.write_u16::<LittleEndian>(TlvKinds::DEPENDENCY as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700271 protected_tlv.write_u16::<LittleEndian>(12).unwrap();
David Brownf5b33d82017-09-01 10:58:27 -0600272
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300273 // The dependency.
274 protected_tlv.push(dep.id);
275 for _ in 0 .. 3 {
276 protected_tlv.push(0);
277 }
278 protected_tlv.push(dep.version.major);
279 protected_tlv.push(dep.version.minor);
280 protected_tlv.write_u16::<LittleEndian>(dep.version.revision).unwrap();
281 protected_tlv.write_u32::<LittleEndian>(dep.version.build_num).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600282 }
David Brown7a81c4b2019-07-29 15:20:21 -0600283 }
284
285 // Ring does the signature itself, which means that it must be
286 // given a full, contiguous payload. Although this does help from
287 // a correct usage perspective, it is fairly stupid from an
288 // efficiency view. If this is shown to be a performance issue
289 // with the tests, the protected data could be appended to the
290 // payload, and then removed after the signature is done. For now,
291 // just make a signed payload.
292 let mut sig_payload = self.payload.clone();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300293 sig_payload.extend_from_slice(&protected_tlv);
294
295 let mut result: Vec<u8> = vec![];
296
297 // add back signed payload
298 result.extend_from_slice(&protected_tlv);
299
300 // add non-protected payload
301 result.push(0x07);
302 result.push(0x69);
303 result.write_u16::<LittleEndian>(self.get_size()).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600304
David Brown187dd882017-07-11 11:15:23 -0600305 if self.kinds.contains(&TlvKinds::SHA256) {
David Brown7a81c4b2019-07-29 15:20:21 -0600306 let hash = digest::digest(&digest::SHA256, &sig_payload);
David Brown8054ce22017-07-11 12:12:09 -0600307 let hash = hash.as_ref();
David Brown187dd882017-07-11 11:15:23 -0600308
David Brown8054ce22017-07-11 12:12:09 -0600309 assert!(hash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700310 result.write_u16::<LittleEndian>(TlvKinds::SHA256 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700311 result.write_u16::<LittleEndian>(32).unwrap();
David Brown8054ce22017-07-11 12:12:09 -0600312 result.extend_from_slice(hash);
David Brown187dd882017-07-11 11:15:23 -0600313 }
314
Fabio Utzig39297432019-05-08 18:51:10 -0300315 if self.kinds.contains(&TlvKinds::RSA2048) ||
316 self.kinds.contains(&TlvKinds::RSA3072) {
317
318 let is_rsa2048 = self.kinds.contains(&TlvKinds::RSA2048);
319
David Brown43cda332017-09-01 09:53:23 -0600320 // Output the hash of the public key.
Fabio Utzig39297432019-05-08 18:51:10 -0300321 let hash = if is_rsa2048 {
322 digest::digest(&digest::SHA256, RSA_PUB_KEY)
323 } else {
324 digest::digest(&digest::SHA256, RSA3072_PUB_KEY)
325 };
David Brown43cda332017-09-01 09:53:23 -0600326 let hash = hash.as_ref();
327
328 assert!(hash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700329 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700330 result.write_u16::<LittleEndian>(32).unwrap();
David Brown43cda332017-09-01 09:53:23 -0600331 result.extend_from_slice(hash);
332
David Brown7e701d82017-07-11 13:24:25 -0600333 // For now assume PSS.
Fabio Utzig39297432019-05-08 18:51:10 -0300334 let key_bytes = if is_rsa2048 {
335 pem::parse(include_bytes!("../../root-rsa-2048.pem").as_ref()).unwrap()
336 } else {
337 pem::parse(include_bytes!("../../root-rsa-3072.pem").as_ref()).unwrap()
338 };
David Brown7e701d82017-07-11 13:24:25 -0600339 assert_eq!(key_bytes.tag, "RSA PRIVATE KEY");
Fabio Utzig90f449e2019-10-24 07:43:53 -0300340 let key_pair = RsaKeyPair::from_der(&key_bytes.contents).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600341 let rng = rand::SystemRandom::new();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300342 let mut signature = vec![0; key_pair.public_modulus_len()];
Fabio Utzig39297432019-05-08 18:51:10 -0300343 if is_rsa2048 {
344 assert_eq!(signature.len(), 256);
345 } else {
346 assert_eq!(signature.len(), 384);
347 }
David Brown7a81c4b2019-07-29 15:20:21 -0600348 key_pair.sign(&RSA_PSS_SHA256, &rng, &sig_payload, &mut signature).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600349
Fabio Utzig39297432019-05-08 18:51:10 -0300350 if is_rsa2048 {
David Brown69721182019-12-04 14:50:52 -0700351 result.write_u16::<LittleEndian>(TlvKinds::RSA2048 as u16).unwrap();
Fabio Utzig39297432019-05-08 18:51:10 -0300352 } else {
David Brown69721182019-12-04 14:50:52 -0700353 result.write_u16::<LittleEndian>(TlvKinds::RSA3072 as u16).unwrap();
Fabio Utzig39297432019-05-08 18:51:10 -0300354 }
David Brown91d68632019-07-29 14:32:13 -0600355 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600356 result.extend_from_slice(&signature);
357 }
358
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200359 if self.kinds.contains(&TlvKinds::ECDSA256) {
360 let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY);
361 let keyhash = keyhash.as_ref();
362
363 assert!(keyhash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700364 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700365 result.write_u16::<LittleEndian>(32).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200366 result.extend_from_slice(keyhash);
367
Fabio Utzig05ab0142018-07-10 09:15:28 -0300368 let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap();
369 assert_eq!(key_bytes.tag, "PRIVATE KEY");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200370
Fabio Utzig05ab0142018-07-10 09:15:28 -0300371 let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300372 &key_bytes.contents).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300373 let rng = rand::SystemRandom::new();
Fabio Utzig90f449e2019-10-24 07:43:53 -0300374 let signature = key_pair.sign(&rng, &sig_payload).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200375
David Brown69721182019-12-04 14:50:52 -0700376 result.write_u16::<LittleEndian>(TlvKinds::ECDSA256 as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300377
378 // signature must be padded...
379 let mut signature = signature.as_ref().to_vec();
380 while signature.len() < 72 {
381 signature.push(0);
382 signature[1] += 1;
383 }
384
David Brown91d68632019-07-29 14:32:13 -0600385 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300386 result.extend_from_slice(signature.as_ref());
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200387 }
388
Fabio Utzig97710282019-05-24 17:44:49 -0300389 if self.kinds.contains(&TlvKinds::ED25519) {
390 let keyhash = digest::digest(&digest::SHA256, ED25519_PUB_KEY);
391 let keyhash = keyhash.as_ref();
392
393 assert!(keyhash.len() == 32);
David Brown69721182019-12-04 14:50:52 -0700394 result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700395 result.write_u16::<LittleEndian>(32).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300396 result.extend_from_slice(keyhash);
397
David Brown7a81c4b2019-07-29 15:20:21 -0600398 let hash = digest::digest(&digest::SHA256, &sig_payload);
Fabio Utzig97710282019-05-24 17:44:49 -0300399 let hash = hash.as_ref();
400 assert!(hash.len() == 32);
401
402 let key_bytes = pem::parse(include_bytes!("../../root-ed25519.pem").as_ref()).unwrap();
403 assert_eq!(key_bytes.tag, "PRIVATE KEY");
404
Fabio Utzig90f449e2019-10-24 07:43:53 -0300405 let key_pair = Ed25519KeyPair::from_seed_and_public_key(
406 &key_bytes.contents[16..48], &ED25519_PUB_KEY[12..44]).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300407 let signature = key_pair.sign(&hash);
408
David Brown69721182019-12-04 14:50:52 -0700409 result.write_u16::<LittleEndian>(TlvKinds::ED25519 as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300410
411 let signature = signature.as_ref().to_vec();
David Brown91d68632019-07-29 14:32:13 -0600412 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300413 result.extend_from_slice(signature.as_ref());
414 }
415
Fabio Utzig1e48b912018-09-18 09:04:18 -0300416 if self.kinds.contains(&TlvKinds::ENCRSA2048) {
417 let key_bytes = pem::parse(include_bytes!("../../enc-rsa2048-pub.pem")
418 .as_ref()).unwrap();
419 assert_eq!(key_bytes.tag, "PUBLIC KEY");
420
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300421 let cipherkey = self.get_enc_key();
422 let cipherkey = cipherkey.as_slice();
423 let encbuf = match c::rsa_oaep_encrypt(&key_bytes.contents, cipherkey) {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300424 Ok(v) => v,
425 Err(_) => panic!("Failed to encrypt secret key"),
426 };
427
428 assert!(encbuf.len() == 256);
David Brown69721182019-12-04 14:50:52 -0700429 result.write_u16::<LittleEndian>(TlvKinds::ENCRSA2048 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700430 result.write_u16::<LittleEndian>(256).unwrap();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300431 result.extend_from_slice(&encbuf);
432 }
433
434 if self.kinds.contains(&TlvKinds::ENCKW128) {
435 let key_bytes = base64::decode(
436 include_str!("../../enc-aes128kw.b64").trim()).unwrap();
437
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300438 let cipherkey = self.get_enc_key();
439 let cipherkey = cipherkey.as_slice();
440 let encbuf = match c::kw_encrypt(&key_bytes, cipherkey) {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300441 Ok(v) => v,
442 Err(_) => panic!("Failed to encrypt secret key"),
443 };
444
445 assert!(encbuf.len() == 24);
David Brown69721182019-12-04 14:50:52 -0700446 result.write_u16::<LittleEndian>(TlvKinds::ENCKW128 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700447 result.write_u16::<LittleEndian>(24).unwrap();
Fabio Utzig1e48b912018-09-18 09:04:18 -0300448 result.extend_from_slice(&encbuf);
449 }
450
Fabio Utzig90f449e2019-10-24 07:43:53 -0300451 if self.kinds.contains(&TlvKinds::ENCEC256) {
452 let key_bytes = pem::parse(include_bytes!("../../enc-ec256-pub.pem").as_ref()).unwrap();
453 assert_eq!(key_bytes.tag, "PUBLIC KEY");
454
455 let rng = rand::SystemRandom::new();
456 let pk = match agreement::EphemeralPrivateKey::generate(&agreement::ECDH_P256, &rng) {
457 Ok(v) => v,
458 Err(_) => panic!("Failed to generate ephemeral keypair"),
459 };
460
461 let pubk = match pk.compute_public_key() {
462 Ok(pubk) => pubk,
463 Err(_) => panic!("Failed computing ephemeral public key"),
464 };
465
466 let peer_pubk = agreement::UnparsedPublicKey::new(&agreement::ECDH_P256, &key_bytes.contents[26..]);
467
468 #[derive(Debug, PartialEq)]
469 struct OkmLen<T: core::fmt::Debug + PartialEq>(T);
470
471 impl hkdf::KeyType for OkmLen<usize> {
472 fn len(&self) -> usize {
473 self.0
474 }
475 }
476
477 let derived_key = match agreement::agree_ephemeral(
478 pk, &peer_pubk, ring::error::Unspecified, |shared| {
479 let salt = hkdf::Salt::new(hkdf::HKDF_SHA256, &[]);
480 let prk = salt.extract(&shared);
481 let okm = match prk.expand(&[b"MCUBoot_ECIES_v1"], OkmLen(48)) {
482 Ok(okm) => okm,
483 Err(_) => panic!("Failed building HKDF OKM"),
484 };
485 let mut buf = [0u8; 48];
486 match okm.fill(&mut buf) {
487 Ok(_) => Ok(buf),
488 Err(_) => panic!("Failed generating HKDF output"),
489 }
490 },
491 ) {
492 Ok(v) => v,
493 Err(_) => panic!("Failed building HKDF"),
494 };
495
496 let key = GenericArray::from_slice(&derived_key[..16]);
497 let nonce = GenericArray::from_slice(&[0; 16]);
498 let mut cipher = Aes128Ctr::new(&key, &nonce);
499 let mut cipherkey = self.get_enc_key();
500 cipher.apply_keystream(&mut cipherkey);
501
502 let key = hmac::Key::new(hmac::HMAC_SHA256, &derived_key[16..]);
503 let tag = hmac::sign(&key, &cipherkey);
504
505 let mut buf = vec![];
506 buf.append(&mut pubk.as_ref().to_vec());
507 buf.append(&mut tag.as_ref().to_vec());
508 buf.append(&mut cipherkey);
509
510 assert!(buf.len() == 113);
David Brown69721182019-12-04 14:50:52 -0700511 result.write_u16::<LittleEndian>(TlvKinds::ENCEC256 as u16).unwrap();
David Brown4fae8b82019-12-05 11:26:59 -0700512 result.write_u16::<LittleEndian>(113).unwrap();
Fabio Utzig90f449e2019-10-24 07:43:53 -0300513 result.extend_from_slice(&buf);
514 }
515
David Brown187dd882017-07-11 11:15:23 -0600516 result
517 }
Fabio Utzig90f449e2019-10-24 07:43:53 -0300518
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300519 fn generate_enc_key(&mut self) {
520 let rng = rand::SystemRandom::new();
521 let mut buf = vec![0u8; AES_KEY_LEN];
522 match rng.fill(&mut buf) {
523 Err(_) => panic!("Error generating encrypted key"),
524 Ok(_) => (),
525 }
526 info!("New encryption key: {:02x?}", buf);
527 self.enc_key = buf;
Fabio Utzig90f449e2019-10-24 07:43:53 -0300528 }
529
530 fn get_enc_key(&self) -> Vec<u8> {
Fabio Utzige84f0ef2019-11-22 12:29:32 -0300531 if self.enc_key.len() != AES_KEY_LEN {
532 panic!("No random key was generated");
533 }
534 self.enc_key.clone()
Fabio Utzig90f449e2019-10-24 07:43:53 -0300535 }
David Brown187dd882017-07-11 11:15:23 -0600536}
David Brown43cda332017-09-01 09:53:23 -0600537
538include!("rsa_pub_key-rs.txt");
Fabio Utzig39297432019-05-08 18:51:10 -0300539include!("rsa3072_pub_key-rs.txt");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200540include!("ecdsa_pub_key-rs.txt");
Fabio Utzig97710282019-05-24 17:44:49 -0300541include!("ed25519_pub_key-rs.txt");