blob: a3c1d27e18b74858edb725444d1c456d544c1667 [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 Utzig90f449e2019-10-24 07:43:53 -030017use ring::{digest, rand, agreement, hkdf, hmac};
Fabio Utzig05ab0142018-07-10 09:15:28 -030018use ring::signature::{
19 RsaKeyPair,
20 RSA_PSS_SHA256,
21 EcdsaKeyPair,
22 ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig97710282019-05-24 17:44:49 -030023 Ed25519KeyPair,
Fabio Utzig05ab0142018-07-10 09:15:28 -030024};
Fabio Utzig90f449e2019-10-24 07:43:53 -030025use aes_ctr::{
26 Aes128Ctr,
27 stream_cipher::{
28 generic_array::GenericArray,
29 NewFixStreamCipher,
30 StreamCipherCore,
31 },
32};
Fabio Utzig80fde2f2017-12-05 09:25:31 -020033use mcuboot_sys::c;
David Brown187dd882017-07-11 11:15:23 -060034
David Brown187dd882017-07-11 11:15:23 -060035#[repr(u8)]
David Brownc3898d62019-08-05 14:20:02 -060036#[derive(Copy, Clone, Debug, PartialEq, Eq)]
David Brown187dd882017-07-11 11:15:23 -060037#[allow(dead_code)] // TODO: For now
38pub enum TlvKinds {
David Brown43cda332017-09-01 09:53:23 -060039 KEYHASH = 0x01,
David Brown27648b82017-08-31 10:40:29 -060040 SHA256 = 0x10,
41 RSA2048 = 0x20,
42 ECDSA224 = 0x21,
43 ECDSA256 = 0x22,
Fabio Utzig39297432019-05-08 18:51:10 -030044 RSA3072 = 0x23,
Fabio Utzig97710282019-05-24 17:44:49 -030045 ED25519 = 0x24,
Fabio Utzig1e48b912018-09-18 09:04:18 -030046 ENCRSA2048 = 0x30,
47 ENCKW128 = 0x31,
Fabio Utzig90f449e2019-10-24 07:43:53 -030048 ENCEC256 = 0x32,
David Brown7a81c4b2019-07-29 15:20:21 -060049 DEPENDENCY = 0x40,
Fabio Utzig1e48b912018-09-18 09:04:18 -030050}
51
52#[allow(dead_code, non_camel_case_types)]
53pub enum TlvFlags {
54 PIC = 0x01,
55 NON_BOOTABLE = 0x02,
56 ENCRYPTED = 0x04,
57 RAM_LOAD = 0x20,
David Brown187dd882017-07-11 11:15:23 -060058}
59
David Brown43643dd2019-01-11 15:43:28 -070060/// A generator for manifests. The format of the manifest can be either a
61/// traditional "TLV" or a SUIT-style manifest.
62pub trait ManifestGen {
David Brownac46e262019-01-11 15:46:18 -070063 /// Retrieve the header magic value for this manifest type.
64 fn get_magic(&self) -> u32;
65
David Brown43643dd2019-01-11 15:43:28 -070066 /// Retrieve the flags value for this particular manifest type.
67 fn get_flags(&self) -> u32;
68
David Brown7a81c4b2019-07-29 15:20:21 -060069 /// Retrieve the number of bytes of this manifest that is "protected".
70 /// This field is stored in the outside image header instead of the
71 /// manifest header.
72 fn protect_size(&self) -> u16;
73
74 /// Add a dependency on another image.
75 fn add_dependency(&mut self, id: u8, version: &ImageVersion);
76
David Brown43643dd2019-01-11 15:43:28 -070077 /// Add a sequence of bytes to the payload that the manifest is
78 /// protecting.
79 fn add_bytes(&mut self, bytes: &[u8]);
80
81 /// Construct the manifest for this payload.
82 fn make_tlv(self: Box<Self>) -> Vec<u8>;
Fabio Utzig90f449e2019-10-24 07:43:53 -030083
84 /// TODO: Generate a new encryption random key
85 fn generate_enc_key(&mut self) -> bool;
86
87 /// Return the current encryption key
88 fn get_enc_key(&self) -> Vec<u8>;
David Brown43643dd2019-01-11 15:43:28 -070089}
90
Fabio Utzig9a2b5de2019-11-22 12:50:02 -030091#[derive(Debug, Default)]
David Brown187dd882017-07-11 11:15:23 -060092pub struct TlvGen {
David Brown43cda332017-09-01 09:53:23 -060093 flags: u32,
David Brown187dd882017-07-11 11:15:23 -060094 kinds: Vec<TlvKinds>,
David Brown7a81c4b2019-07-29 15:20:21 -060095 /// The total size of the payload.
David Brown187dd882017-07-11 11:15:23 -060096 size: u16,
David Brown7a81c4b2019-07-29 15:20:21 -060097 /// Extra bytes of the TLV that are protected.
98 protect_size: u16,
David Brown4243ab02017-07-11 12:24:23 -060099 payload: Vec<u8>,
David Brown7a81c4b2019-07-29 15:20:21 -0600100 dependencies: Vec<Dependency>,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300101 enc_key: Vec<u8>,
David Brown7a81c4b2019-07-29 15:20:21 -0600102}
103
David Brownc3898d62019-08-05 14:20:02 -0600104#[derive(Debug)]
David Brown7a81c4b2019-07-29 15:20:21 -0600105struct Dependency {
106 id: u8,
107 version: ImageVersion,
David Brown187dd882017-07-11 11:15:23 -0600108}
109
Fabio Utzig1e48b912018-09-18 09:04:18 -0300110pub const AES_SEC_KEY: &[u8; 16] = b"0123456789ABCDEF";
111
David Brown187dd882017-07-11 11:15:23 -0600112impl TlvGen {
113 /// Construct a new tlv generator that will only contain a hash of the data.
David Brown7e701d82017-07-11 13:24:25 -0600114 #[allow(dead_code)]
David Brown187dd882017-07-11 11:15:23 -0600115 pub fn new_hash_only() -> TlvGen {
116 TlvGen {
David Brown187dd882017-07-11 11:15:23 -0600117 kinds: vec![TlvKinds::SHA256],
118 size: 4 + 32,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300119 ..Default::default()
David Brown187dd882017-07-11 11:15:23 -0600120 }
121 }
122
David Brown7e701d82017-07-11 13:24:25 -0600123 #[allow(dead_code)]
124 pub fn new_rsa_pss() -> TlvGen {
125 TlvGen {
Fabio Utzig754438d2018-12-14 06:39:58 -0200126 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048],
127 size: 4 + 32 + 4 + 32 + 4 + 256,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300128 ..Default::default()
David Brown7e701d82017-07-11 13:24:25 -0600129 }
130 }
131
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200132 #[allow(dead_code)]
Fabio Utzig39297432019-05-08 18:51:10 -0300133 pub fn new_rsa3072_pss() -> TlvGen {
134 TlvGen {
Fabio Utzig39297432019-05-08 18:51:10 -0300135 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA3072],
136 size: 4 + 32 + 4 + 32 + 4 + 384,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300137 ..Default::default()
Fabio Utzig39297432019-05-08 18:51:10 -0300138 }
139 }
140
141 #[allow(dead_code)]
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200142 pub fn new_ecdsa() -> TlvGen {
143 TlvGen {
Fabio Utzig754438d2018-12-14 06:39:58 -0200144 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256],
145 size: 4 + 32 + 4 + 32 + 4 + 72,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300146 ..Default::default()
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200147 }
148 }
149
Fabio Utzig1e48b912018-09-18 09:04:18 -0300150 #[allow(dead_code)]
Fabio Utzig97710282019-05-24 17:44:49 -0300151 pub fn new_ed25519() -> TlvGen {
152 TlvGen {
Fabio Utzig97710282019-05-24 17:44:49 -0300153 kinds: vec![TlvKinds::SHA256, TlvKinds::ED25519],
154 size: 4 + 32 + 4 + 32 + 4 + 64,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300155 ..Default::default()
Fabio Utzig97710282019-05-24 17:44:49 -0300156 }
157 }
158
159 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300160 pub fn new_enc_rsa() -> TlvGen {
161 TlvGen {
162 flags: TlvFlags::ENCRYPTED as u32,
163 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
164 size: 4 + 32 + 4 + 256,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300165 ..Default::default()
Fabio Utzig1e48b912018-09-18 09:04:18 -0300166 }
167 }
168
169 #[allow(dead_code)]
Fabio Utzig754438d2018-12-14 06:39:58 -0200170 pub fn new_sig_enc_rsa() -> TlvGen {
171 TlvGen {
172 flags: TlvFlags::ENCRYPTED as u32,
173 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCRSA2048],
174 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 256,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300175 ..Default::default()
Fabio Utzig754438d2018-12-14 06:39:58 -0200176 }
177 }
178
179 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300180 pub fn new_enc_kw() -> TlvGen {
181 TlvGen {
182 flags: TlvFlags::ENCRYPTED as u32,
183 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW128],
184 size: 4 + 32 + 4 + 24,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300185 ..Default::default()
Fabio Utzig1e48b912018-09-18 09:04:18 -0300186 }
187 }
188
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200189 #[allow(dead_code)]
190 pub fn new_rsa_kw() -> TlvGen {
191 TlvGen {
192 flags: TlvFlags::ENCRYPTED as u32,
193 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCKW128],
194 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 24,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300195 ..Default::default()
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200196 }
197 }
198
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200199 #[allow(dead_code)]
200 pub fn new_ecdsa_kw() -> TlvGen {
201 TlvGen {
202 flags: TlvFlags::ENCRYPTED as u32,
203 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCKW128],
204 size: 4 + 32 + 4 + 32 + 4 + 72 + 4 + 24,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300205 ..Default::default()
Fabio Utzig90f449e2019-10-24 07:43:53 -0300206 }
207 }
208
209 #[allow(dead_code)]
210 pub fn new_ecdsa_ecies_p256() -> TlvGen {
211 TlvGen {
212 flags: TlvFlags::ENCRYPTED as u32,
213 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCEC256],
214 size: 4 + 32 + 4 + 32 + 4 + 72 + 4 + 113,
Fabio Utzig9a2b5de2019-11-22 12:50:02 -0300215 ..Default::default()
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200216 }
217 }
218
David Brown187dd882017-07-11 11:15:23 -0600219 /// Retrieve the size that the TLV will occupy. This can be called at any time.
220 pub fn get_size(&self) -> u16 {
David Brownf5b33d82017-09-01 10:58:27 -0600221 4 + self.size
David Brown187dd882017-07-11 11:15:23 -0600222 }
David Brown43643dd2019-01-11 15:43:28 -0700223}
224
225impl ManifestGen for TlvGen {
David Brownac46e262019-01-11 15:46:18 -0700226 fn get_magic(&self) -> u32 {
227 0x96f3b83d
228 }
229
David Brown43643dd2019-01-11 15:43:28 -0700230 /// Retrieve the header flags for this configuration. This can be called at any time.
231 fn get_flags(&self) -> u32 {
232 self.flags
233 }
David Brown187dd882017-07-11 11:15:23 -0600234
235 /// Add bytes to the covered hash.
David Brown43643dd2019-01-11 15:43:28 -0700236 fn add_bytes(&mut self, bytes: &[u8]) {
David Brown4243ab02017-07-11 12:24:23 -0600237 self.payload.extend_from_slice(bytes);
David Brown187dd882017-07-11 11:15:23 -0600238 }
239
David Brown7a81c4b2019-07-29 15:20:21 -0600240 fn protect_size(&self) -> u16 {
241 if self.protect_size == 0 {
242 0
243 } else {
244 // Include the protected size, as well as the TLV header.
245 4 + self.protect_size
246 }
247 }
248
249 fn add_dependency(&mut self, id: u8, version: &ImageVersion) {
250 let my_size = 4 + 4 + 8;
251 self.protect_size += my_size;
252 self.size += my_size;
253 self.dependencies.push(Dependency {
254 id: id,
255 version: version.clone(),
256 });
257 }
258
David Brown187dd882017-07-11 11:15:23 -0600259 /// Compute the TLV given the specified block of data.
David Brown43643dd2019-01-11 15:43:28 -0700260 fn make_tlv(self: Box<Self>) -> Vec<u8> {
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300261 let mut protected_tlv: Vec<u8> = vec![];
David Brown187dd882017-07-11 11:15:23 -0600262
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300263 if self.protect_size > 0 {
264 protected_tlv.push(0x08);
265 protected_tlv.push(0x69);
266 protected_tlv.write_u16::<LittleEndian>(self.protect_size()).unwrap();
267 for dep in &self.dependencies {
268 protected_tlv.push(TlvKinds::DEPENDENCY as u8);
269 protected_tlv.push(0);
270 protected_tlv.push(12);
271 protected_tlv.push(0);
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 Brown187dd882017-07-11 11:15:23 -0600310 result.push(TlvKinds::SHA256 as u8);
311 result.push(0);
312 result.push(32);
313 result.push(0);
David Brown8054ce22017-07-11 12:12:09 -0600314 result.extend_from_slice(hash);
David Brown187dd882017-07-11 11:15:23 -0600315 }
316
Fabio Utzig39297432019-05-08 18:51:10 -0300317 if self.kinds.contains(&TlvKinds::RSA2048) ||
318 self.kinds.contains(&TlvKinds::RSA3072) {
319
320 let is_rsa2048 = self.kinds.contains(&TlvKinds::RSA2048);
321
David Brown43cda332017-09-01 09:53:23 -0600322 // Output the hash of the public key.
Fabio Utzig39297432019-05-08 18:51:10 -0300323 let hash = if is_rsa2048 {
324 digest::digest(&digest::SHA256, RSA_PUB_KEY)
325 } else {
326 digest::digest(&digest::SHA256, RSA3072_PUB_KEY)
327 };
David Brown43cda332017-09-01 09:53:23 -0600328 let hash = hash.as_ref();
329
330 assert!(hash.len() == 32);
331 result.push(TlvKinds::KEYHASH as u8);
332 result.push(0);
333 result.push(32);
334 result.push(0);
335 result.extend_from_slice(hash);
336
David Brown7e701d82017-07-11 13:24:25 -0600337 // For now assume PSS.
Fabio Utzig39297432019-05-08 18:51:10 -0300338 let key_bytes = if is_rsa2048 {
339 pem::parse(include_bytes!("../../root-rsa-2048.pem").as_ref()).unwrap()
340 } else {
341 pem::parse(include_bytes!("../../root-rsa-3072.pem").as_ref()).unwrap()
342 };
David Brown7e701d82017-07-11 13:24:25 -0600343 assert_eq!(key_bytes.tag, "RSA PRIVATE KEY");
Fabio Utzig90f449e2019-10-24 07:43:53 -0300344 let key_pair = RsaKeyPair::from_der(&key_bytes.contents).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600345 let rng = rand::SystemRandom::new();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300346 let mut signature = vec![0; key_pair.public_modulus_len()];
Fabio Utzig39297432019-05-08 18:51:10 -0300347 if is_rsa2048 {
348 assert_eq!(signature.len(), 256);
349 } else {
350 assert_eq!(signature.len(), 384);
351 }
David Brown7a81c4b2019-07-29 15:20:21 -0600352 key_pair.sign(&RSA_PSS_SHA256, &rng, &sig_payload, &mut signature).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600353
Fabio Utzig39297432019-05-08 18:51:10 -0300354 if is_rsa2048 {
355 result.push(TlvKinds::RSA2048 as u8);
356 } else {
357 result.push(TlvKinds::RSA3072 as u8);
358 }
David Brown7e701d82017-07-11 13:24:25 -0600359 result.push(0);
David Brown91d68632019-07-29 14:32:13 -0600360 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600361 result.extend_from_slice(&signature);
362 }
363
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200364 if self.kinds.contains(&TlvKinds::ECDSA256) {
365 let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY);
366 let keyhash = keyhash.as_ref();
367
368 assert!(keyhash.len() == 32);
369 result.push(TlvKinds::KEYHASH as u8);
370 result.push(0);
371 result.push(32);
372 result.push(0);
373 result.extend_from_slice(keyhash);
374
Fabio Utzig05ab0142018-07-10 09:15:28 -0300375 let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap();
376 assert_eq!(key_bytes.tag, "PRIVATE KEY");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200377
Fabio Utzig05ab0142018-07-10 09:15:28 -0300378 let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300379 &key_bytes.contents).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300380 let rng = rand::SystemRandom::new();
Fabio Utzig90f449e2019-10-24 07:43:53 -0300381 let signature = key_pair.sign(&rng, &sig_payload).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200382
383 result.push(TlvKinds::ECDSA256 as u8);
384 result.push(0);
Fabio Utzig05ab0142018-07-10 09:15:28 -0300385
386 // signature must be padded...
387 let mut signature = signature.as_ref().to_vec();
388 while signature.len() < 72 {
389 signature.push(0);
390 signature[1] += 1;
391 }
392
David Brown91d68632019-07-29 14:32:13 -0600393 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300394 result.extend_from_slice(signature.as_ref());
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200395 }
396
Fabio Utzig97710282019-05-24 17:44:49 -0300397 if self.kinds.contains(&TlvKinds::ED25519) {
398 let keyhash = digest::digest(&digest::SHA256, ED25519_PUB_KEY);
399 let keyhash = keyhash.as_ref();
400
401 assert!(keyhash.len() == 32);
402 result.push(TlvKinds::KEYHASH as u8);
403 result.push(0);
404 result.push(32);
405 result.push(0);
406 result.extend_from_slice(keyhash);
407
David Brown7a81c4b2019-07-29 15:20:21 -0600408 let hash = digest::digest(&digest::SHA256, &sig_payload);
Fabio Utzig97710282019-05-24 17:44:49 -0300409 let hash = hash.as_ref();
410 assert!(hash.len() == 32);
411
412 let key_bytes = pem::parse(include_bytes!("../../root-ed25519.pem").as_ref()).unwrap();
413 assert_eq!(key_bytes.tag, "PRIVATE KEY");
414
Fabio Utzig90f449e2019-10-24 07:43:53 -0300415 let key_pair = Ed25519KeyPair::from_seed_and_public_key(
416 &key_bytes.contents[16..48], &ED25519_PUB_KEY[12..44]).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300417 let signature = key_pair.sign(&hash);
418
419 result.push(TlvKinds::ED25519 as u8);
420 result.push(0);
421
422 let signature = signature.as_ref().to_vec();
David Brown91d68632019-07-29 14:32:13 -0600423 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300424 result.extend_from_slice(signature.as_ref());
425 }
426
Fabio Utzig1e48b912018-09-18 09:04:18 -0300427 if self.kinds.contains(&TlvKinds::ENCRSA2048) {
428 let key_bytes = pem::parse(include_bytes!("../../enc-rsa2048-pub.pem")
429 .as_ref()).unwrap();
430 assert_eq!(key_bytes.tag, "PUBLIC KEY");
431
432 let encbuf = match c::rsa_oaep_encrypt(&key_bytes.contents, AES_SEC_KEY) {
433 Ok(v) => v,
434 Err(_) => panic!("Failed to encrypt secret key"),
435 };
436
437 assert!(encbuf.len() == 256);
438 result.push(TlvKinds::ENCRSA2048 as u8);
439 result.push(0);
440 result.push(0);
441 result.push(1);
442 result.extend_from_slice(&encbuf);
443 }
444
445 if self.kinds.contains(&TlvKinds::ENCKW128) {
446 let key_bytes = base64::decode(
447 include_str!("../../enc-aes128kw.b64").trim()).unwrap();
448
449 let encbuf = match c::kw_encrypt(&key_bytes, AES_SEC_KEY) {
450 Ok(v) => v,
451 Err(_) => panic!("Failed to encrypt secret key"),
452 };
453
454 assert!(encbuf.len() == 24);
455 result.push(TlvKinds::ENCKW128 as u8);
456 result.push(0);
457 result.push(24);
458 result.push(0);
459 result.extend_from_slice(&encbuf);
460 }
461
Fabio Utzig90f449e2019-10-24 07:43:53 -0300462 if self.kinds.contains(&TlvKinds::ENCEC256) {
463 let key_bytes = pem::parse(include_bytes!("../../enc-ec256-pub.pem").as_ref()).unwrap();
464 assert_eq!(key_bytes.tag, "PUBLIC KEY");
465
466 let rng = rand::SystemRandom::new();
467 let pk = match agreement::EphemeralPrivateKey::generate(&agreement::ECDH_P256, &rng) {
468 Ok(v) => v,
469 Err(_) => panic!("Failed to generate ephemeral keypair"),
470 };
471
472 let pubk = match pk.compute_public_key() {
473 Ok(pubk) => pubk,
474 Err(_) => panic!("Failed computing ephemeral public key"),
475 };
476
477 let peer_pubk = agreement::UnparsedPublicKey::new(&agreement::ECDH_P256, &key_bytes.contents[26..]);
478
479 #[derive(Debug, PartialEq)]
480 struct OkmLen<T: core::fmt::Debug + PartialEq>(T);
481
482 impl hkdf::KeyType for OkmLen<usize> {
483 fn len(&self) -> usize {
484 self.0
485 }
486 }
487
488 let derived_key = match agreement::agree_ephemeral(
489 pk, &peer_pubk, ring::error::Unspecified, |shared| {
490 let salt = hkdf::Salt::new(hkdf::HKDF_SHA256, &[]);
491 let prk = salt.extract(&shared);
492 let okm = match prk.expand(&[b"MCUBoot_ECIES_v1"], OkmLen(48)) {
493 Ok(okm) => okm,
494 Err(_) => panic!("Failed building HKDF OKM"),
495 };
496 let mut buf = [0u8; 48];
497 match okm.fill(&mut buf) {
498 Ok(_) => Ok(buf),
499 Err(_) => panic!("Failed generating HKDF output"),
500 }
501 },
502 ) {
503 Ok(v) => v,
504 Err(_) => panic!("Failed building HKDF"),
505 };
506
507 let key = GenericArray::from_slice(&derived_key[..16]);
508 let nonce = GenericArray::from_slice(&[0; 16]);
509 let mut cipher = Aes128Ctr::new(&key, &nonce);
510 let mut cipherkey = self.get_enc_key();
511 cipher.apply_keystream(&mut cipherkey);
512
513 let key = hmac::Key::new(hmac::HMAC_SHA256, &derived_key[16..]);
514 let tag = hmac::sign(&key, &cipherkey);
515
516 let mut buf = vec![];
517 buf.append(&mut pubk.as_ref().to_vec());
518 buf.append(&mut tag.as_ref().to_vec());
519 buf.append(&mut cipherkey);
520
521 assert!(buf.len() == 113);
522 result.push(TlvKinds::ENCEC256 as u8);
523 result.push(0);
524 result.push(113);
525 result.push(0);
526 result.extend_from_slice(&buf);
527 }
528
David Brown187dd882017-07-11 11:15:23 -0600529 result
530 }
Fabio Utzig90f449e2019-10-24 07:43:53 -0300531
532 fn generate_enc_key(&mut self) -> bool {
533 self.enc_key = AES_SEC_KEY.to_vec();
534 true
535 }
536
537 fn get_enc_key(&self) -> Vec<u8> {
538 return self.enc_key.clone();
539 }
David Brown187dd882017-07-11 11:15:23 -0600540}
David Brown43cda332017-09-01 09:53:23 -0600541
542include!("rsa_pub_key-rs.txt");
Fabio Utzig39297432019-05-08 18:51:10 -0300543include!("rsa3072_pub_key-rs.txt");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200544include!("ecdsa_pub_key-rs.txt");
Fabio Utzig97710282019-05-24 17:44:49 -0300545include!("ed25519_pub_key-rs.txt");