blob: 716ad09b280b2e7db66a1f70d10bac87ce99cd3f [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
David Brownc3898d62019-08-05 14:20:02 -060091#[derive(Debug)]
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 Brown43cda332017-09-01 09:53:23 -0600117 flags: 0,
David Brown187dd882017-07-11 11:15:23 -0600118 kinds: vec![TlvKinds::SHA256],
119 size: 4 + 32,
David Brown7a81c4b2019-07-29 15:20:21 -0600120 protect_size: 0,
David Brown4243ab02017-07-11 12:24:23 -0600121 payload: vec![],
David Brown7a81c4b2019-07-29 15:20:21 -0600122 dependencies: vec![],
Fabio Utzig90f449e2019-10-24 07:43:53 -0300123 enc_key: vec![],
David Brown187dd882017-07-11 11:15:23 -0600124 }
125 }
126
David Brown7e701d82017-07-11 13:24:25 -0600127 #[allow(dead_code)]
128 pub fn new_rsa_pss() -> TlvGen {
129 TlvGen {
David Brown43cda332017-09-01 09:53:23 -0600130 flags: 0,
Fabio Utzig754438d2018-12-14 06:39:58 -0200131 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048],
132 size: 4 + 32 + 4 + 32 + 4 + 256,
David Brown7a81c4b2019-07-29 15:20:21 -0600133 protect_size: 0,
David Brown7e701d82017-07-11 13:24:25 -0600134 payload: vec![],
David Brown7a81c4b2019-07-29 15:20:21 -0600135 dependencies: vec![],
Fabio Utzig90f449e2019-10-24 07:43:53 -0300136 enc_key: vec![],
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 {
143 flags: 0,
144 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA3072],
145 size: 4 + 32 + 4 + 32 + 4 + 384,
David Brown7a81c4b2019-07-29 15:20:21 -0600146 protect_size: 0,
Fabio Utzig39297432019-05-08 18:51:10 -0300147 payload: vec![],
David Brown7a81c4b2019-07-29 15:20:21 -0600148 dependencies: vec![],
Fabio Utzig90f449e2019-10-24 07:43:53 -0300149 enc_key: vec![],
Fabio Utzig39297432019-05-08 18:51:10 -0300150 }
151 }
152
153 #[allow(dead_code)]
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200154 pub fn new_ecdsa() -> TlvGen {
155 TlvGen {
156 flags: 0,
Fabio Utzig754438d2018-12-14 06:39:58 -0200157 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256],
158 size: 4 + 32 + 4 + 32 + 4 + 72,
David Brown7a81c4b2019-07-29 15:20:21 -0600159 protect_size: 0,
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200160 payload: vec![],
David Brown7a81c4b2019-07-29 15:20:21 -0600161 dependencies: vec![],
Fabio Utzig90f449e2019-10-24 07:43:53 -0300162 enc_key: vec![],
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200163 }
164 }
165
Fabio Utzig1e48b912018-09-18 09:04:18 -0300166 #[allow(dead_code)]
Fabio Utzig97710282019-05-24 17:44:49 -0300167 pub fn new_ed25519() -> TlvGen {
168 TlvGen {
169 flags: 0,
170 kinds: vec![TlvKinds::SHA256, TlvKinds::ED25519],
171 size: 4 + 32 + 4 + 32 + 4 + 64,
David Brown7a81c4b2019-07-29 15:20:21 -0600172 protect_size: 0,
Fabio Utzig97710282019-05-24 17:44:49 -0300173 payload: vec![],
David Brown7a81c4b2019-07-29 15:20:21 -0600174 dependencies: vec![],
Fabio Utzig90f449e2019-10-24 07:43:53 -0300175 enc_key: vec![],
Fabio Utzig97710282019-05-24 17:44:49 -0300176 }
177 }
178
179 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300180 pub fn new_enc_rsa() -> TlvGen {
181 TlvGen {
182 flags: TlvFlags::ENCRYPTED as u32,
183 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
184 size: 4 + 32 + 4 + 256,
David Brown7a81c4b2019-07-29 15:20:21 -0600185 protect_size: 0,
Fabio Utzig1e48b912018-09-18 09:04:18 -0300186 payload: vec![],
David Brown7a81c4b2019-07-29 15:20:21 -0600187 dependencies: vec![],
Fabio Utzig90f449e2019-10-24 07:43:53 -0300188 enc_key: vec![],
Fabio Utzig1e48b912018-09-18 09:04:18 -0300189 }
190 }
191
192 #[allow(dead_code)]
Fabio Utzig754438d2018-12-14 06:39:58 -0200193 pub fn new_sig_enc_rsa() -> TlvGen {
194 TlvGen {
195 flags: TlvFlags::ENCRYPTED as u32,
196 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCRSA2048],
197 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 256,
David Brown7a81c4b2019-07-29 15:20:21 -0600198 protect_size: 0,
Fabio Utzig754438d2018-12-14 06:39:58 -0200199 payload: vec![],
David Brown7a81c4b2019-07-29 15:20:21 -0600200 dependencies: vec![],
Fabio Utzig90f449e2019-10-24 07:43:53 -0300201 enc_key: vec![],
Fabio Utzig754438d2018-12-14 06:39:58 -0200202 }
203 }
204
205 #[allow(dead_code)]
Fabio Utzig1e48b912018-09-18 09:04:18 -0300206 pub fn new_enc_kw() -> TlvGen {
207 TlvGen {
208 flags: TlvFlags::ENCRYPTED as u32,
209 kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW128],
210 size: 4 + 32 + 4 + 24,
David Brown7a81c4b2019-07-29 15:20:21 -0600211 protect_size: 0,
Fabio Utzig1e48b912018-09-18 09:04:18 -0300212 payload: vec![],
David Brown7a81c4b2019-07-29 15:20:21 -0600213 dependencies: vec![],
Fabio Utzig90f449e2019-10-24 07:43:53 -0300214 enc_key: vec![],
Fabio Utzig1e48b912018-09-18 09:04:18 -0300215 }
216 }
217
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200218 #[allow(dead_code)]
219 pub fn new_rsa_kw() -> TlvGen {
220 TlvGen {
221 flags: TlvFlags::ENCRYPTED as u32,
222 kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCKW128],
223 size: 4 + 32 + 4 + 32 + 4 + 256 + 4 + 24,
David Brown7a81c4b2019-07-29 15:20:21 -0600224 protect_size: 0,
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200225 payload: vec![],
David Brown7a81c4b2019-07-29 15:20:21 -0600226 dependencies: vec![],
Fabio Utzig90f449e2019-10-24 07:43:53 -0300227 enc_key: vec![],
Fabio Utzig251ef1d2018-12-18 17:20:19 -0200228 }
229 }
230
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200231 #[allow(dead_code)]
232 pub fn new_ecdsa_kw() -> TlvGen {
233 TlvGen {
234 flags: TlvFlags::ENCRYPTED as u32,
235 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCKW128],
236 size: 4 + 32 + 4 + 32 + 4 + 72 + 4 + 24,
David Brown7a81c4b2019-07-29 15:20:21 -0600237 protect_size: 0,
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200238 payload: vec![],
David Brown7a81c4b2019-07-29 15:20:21 -0600239 dependencies: vec![],
Fabio Utzig90f449e2019-10-24 07:43:53 -0300240 enc_key: vec![],
241 }
242 }
243
244 #[allow(dead_code)]
245 pub fn new_ecdsa_ecies_p256() -> TlvGen {
246 TlvGen {
247 flags: TlvFlags::ENCRYPTED as u32,
248 kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSA256, TlvKinds::ENCEC256],
249 size: 4 + 32 + 4 + 32 + 4 + 72 + 4 + 113,
250 protect_size: 0,
251 payload: vec![],
252 dependencies: vec![],
253 enc_key: vec![],
Fabio Utzigb4d20c82018-12-27 16:08:39 -0200254 }
255 }
256
David Brown187dd882017-07-11 11:15:23 -0600257 /// Retrieve the size that the TLV will occupy. This can be called at any time.
258 pub fn get_size(&self) -> u16 {
David Brownf5b33d82017-09-01 10:58:27 -0600259 4 + self.size
David Brown187dd882017-07-11 11:15:23 -0600260 }
David Brown43643dd2019-01-11 15:43:28 -0700261}
262
263impl ManifestGen for TlvGen {
David Brownac46e262019-01-11 15:46:18 -0700264 fn get_magic(&self) -> u32 {
265 0x96f3b83d
266 }
267
David Brown43643dd2019-01-11 15:43:28 -0700268 /// Retrieve the header flags for this configuration. This can be called at any time.
269 fn get_flags(&self) -> u32 {
270 self.flags
271 }
David Brown187dd882017-07-11 11:15:23 -0600272
273 /// Add bytes to the covered hash.
David Brown43643dd2019-01-11 15:43:28 -0700274 fn add_bytes(&mut self, bytes: &[u8]) {
David Brown4243ab02017-07-11 12:24:23 -0600275 self.payload.extend_from_slice(bytes);
David Brown187dd882017-07-11 11:15:23 -0600276 }
277
David Brown7a81c4b2019-07-29 15:20:21 -0600278 fn protect_size(&self) -> u16 {
279 if self.protect_size == 0 {
280 0
281 } else {
282 // Include the protected size, as well as the TLV header.
283 4 + self.protect_size
284 }
285 }
286
287 fn add_dependency(&mut self, id: u8, version: &ImageVersion) {
288 let my_size = 4 + 4 + 8;
289 self.protect_size += my_size;
290 self.size += my_size;
291 self.dependencies.push(Dependency {
292 id: id,
293 version: version.clone(),
294 });
295 }
296
David Brown187dd882017-07-11 11:15:23 -0600297 /// Compute the TLV given the specified block of data.
David Brown43643dd2019-01-11 15:43:28 -0700298 fn make_tlv(self: Box<Self>) -> Vec<u8> {
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300299 let mut protected_tlv: Vec<u8> = vec![];
David Brown187dd882017-07-11 11:15:23 -0600300
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300301 if self.protect_size > 0 {
302 protected_tlv.push(0x08);
303 protected_tlv.push(0x69);
304 protected_tlv.write_u16::<LittleEndian>(self.protect_size()).unwrap();
305 for dep in &self.dependencies {
306 protected_tlv.push(TlvKinds::DEPENDENCY as u8);
307 protected_tlv.push(0);
308 protected_tlv.push(12);
309 protected_tlv.push(0);
David Brownf5b33d82017-09-01 10:58:27 -0600310
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300311 // The dependency.
312 protected_tlv.push(dep.id);
313 for _ in 0 .. 3 {
314 protected_tlv.push(0);
315 }
316 protected_tlv.push(dep.version.major);
317 protected_tlv.push(dep.version.minor);
318 protected_tlv.write_u16::<LittleEndian>(dep.version.revision).unwrap();
319 protected_tlv.write_u32::<LittleEndian>(dep.version.build_num).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600320 }
David Brown7a81c4b2019-07-29 15:20:21 -0600321 }
322
323 // Ring does the signature itself, which means that it must be
324 // given a full, contiguous payload. Although this does help from
325 // a correct usage perspective, it is fairly stupid from an
326 // efficiency view. If this is shown to be a performance issue
327 // with the tests, the protected data could be appended to the
328 // payload, and then removed after the signature is done. For now,
329 // just make a signed payload.
330 let mut sig_payload = self.payload.clone();
Fabio Utzigea3d3ab2019-09-11 19:35:33 -0300331 sig_payload.extend_from_slice(&protected_tlv);
332
333 let mut result: Vec<u8> = vec![];
334
335 // add back signed payload
336 result.extend_from_slice(&protected_tlv);
337
338 // add non-protected payload
339 result.push(0x07);
340 result.push(0x69);
341 result.write_u16::<LittleEndian>(self.get_size()).unwrap();
David Brown7a81c4b2019-07-29 15:20:21 -0600342
David Brown187dd882017-07-11 11:15:23 -0600343 if self.kinds.contains(&TlvKinds::SHA256) {
David Brown7a81c4b2019-07-29 15:20:21 -0600344 let hash = digest::digest(&digest::SHA256, &sig_payload);
David Brown8054ce22017-07-11 12:12:09 -0600345 let hash = hash.as_ref();
David Brown187dd882017-07-11 11:15:23 -0600346
David Brown8054ce22017-07-11 12:12:09 -0600347 assert!(hash.len() == 32);
David Brown187dd882017-07-11 11:15:23 -0600348 result.push(TlvKinds::SHA256 as u8);
349 result.push(0);
350 result.push(32);
351 result.push(0);
David Brown8054ce22017-07-11 12:12:09 -0600352 result.extend_from_slice(hash);
David Brown187dd882017-07-11 11:15:23 -0600353 }
354
Fabio Utzig39297432019-05-08 18:51:10 -0300355 if self.kinds.contains(&TlvKinds::RSA2048) ||
356 self.kinds.contains(&TlvKinds::RSA3072) {
357
358 let is_rsa2048 = self.kinds.contains(&TlvKinds::RSA2048);
359
David Brown43cda332017-09-01 09:53:23 -0600360 // Output the hash of the public key.
Fabio Utzig39297432019-05-08 18:51:10 -0300361 let hash = if is_rsa2048 {
362 digest::digest(&digest::SHA256, RSA_PUB_KEY)
363 } else {
364 digest::digest(&digest::SHA256, RSA3072_PUB_KEY)
365 };
David Brown43cda332017-09-01 09:53:23 -0600366 let hash = hash.as_ref();
367
368 assert!(hash.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(hash);
374
David Brown7e701d82017-07-11 13:24:25 -0600375 // For now assume PSS.
Fabio Utzig39297432019-05-08 18:51:10 -0300376 let key_bytes = if is_rsa2048 {
377 pem::parse(include_bytes!("../../root-rsa-2048.pem").as_ref()).unwrap()
378 } else {
379 pem::parse(include_bytes!("../../root-rsa-3072.pem").as_ref()).unwrap()
380 };
David Brown7e701d82017-07-11 13:24:25 -0600381 assert_eq!(key_bytes.tag, "RSA PRIVATE KEY");
Fabio Utzig90f449e2019-10-24 07:43:53 -0300382 let key_pair = RsaKeyPair::from_der(&key_bytes.contents).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600383 let rng = rand::SystemRandom::new();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300384 let mut signature = vec![0; key_pair.public_modulus_len()];
Fabio Utzig39297432019-05-08 18:51:10 -0300385 if is_rsa2048 {
386 assert_eq!(signature.len(), 256);
387 } else {
388 assert_eq!(signature.len(), 384);
389 }
David Brown7a81c4b2019-07-29 15:20:21 -0600390 key_pair.sign(&RSA_PSS_SHA256, &rng, &sig_payload, &mut signature).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600391
Fabio Utzig39297432019-05-08 18:51:10 -0300392 if is_rsa2048 {
393 result.push(TlvKinds::RSA2048 as u8);
394 } else {
395 result.push(TlvKinds::RSA3072 as u8);
396 }
David Brown7e701d82017-07-11 13:24:25 -0600397 result.push(0);
David Brown91d68632019-07-29 14:32:13 -0600398 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
David Brown7e701d82017-07-11 13:24:25 -0600399 result.extend_from_slice(&signature);
400 }
401
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200402 if self.kinds.contains(&TlvKinds::ECDSA256) {
403 let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY);
404 let keyhash = keyhash.as_ref();
405
406 assert!(keyhash.len() == 32);
407 result.push(TlvKinds::KEYHASH as u8);
408 result.push(0);
409 result.push(32);
410 result.push(0);
411 result.extend_from_slice(keyhash);
412
Fabio Utzig05ab0142018-07-10 09:15:28 -0300413 let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap();
414 assert_eq!(key_bytes.tag, "PRIVATE KEY");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200415
Fabio Utzig05ab0142018-07-10 09:15:28 -0300416 let key_pair = EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING,
Fabio Utzig90f449e2019-10-24 07:43:53 -0300417 &key_bytes.contents).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300418 let rng = rand::SystemRandom::new();
Fabio Utzig90f449e2019-10-24 07:43:53 -0300419 let signature = key_pair.sign(&rng, &sig_payload).unwrap();
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200420
421 result.push(TlvKinds::ECDSA256 as u8);
422 result.push(0);
Fabio Utzig05ab0142018-07-10 09:15:28 -0300423
424 // signature must be padded...
425 let mut signature = signature.as_ref().to_vec();
426 while signature.len() < 72 {
427 signature.push(0);
428 signature[1] += 1;
429 }
430
David Brown91d68632019-07-29 14:32:13 -0600431 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig05ab0142018-07-10 09:15:28 -0300432 result.extend_from_slice(signature.as_ref());
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200433 }
434
Fabio Utzig97710282019-05-24 17:44:49 -0300435 if self.kinds.contains(&TlvKinds::ED25519) {
436 let keyhash = digest::digest(&digest::SHA256, ED25519_PUB_KEY);
437 let keyhash = keyhash.as_ref();
438
439 assert!(keyhash.len() == 32);
440 result.push(TlvKinds::KEYHASH as u8);
441 result.push(0);
442 result.push(32);
443 result.push(0);
444 result.extend_from_slice(keyhash);
445
David Brown7a81c4b2019-07-29 15:20:21 -0600446 let hash = digest::digest(&digest::SHA256, &sig_payload);
Fabio Utzig97710282019-05-24 17:44:49 -0300447 let hash = hash.as_ref();
448 assert!(hash.len() == 32);
449
450 let key_bytes = pem::parse(include_bytes!("../../root-ed25519.pem").as_ref()).unwrap();
451 assert_eq!(key_bytes.tag, "PRIVATE KEY");
452
Fabio Utzig90f449e2019-10-24 07:43:53 -0300453 let key_pair = Ed25519KeyPair::from_seed_and_public_key(
454 &key_bytes.contents[16..48], &ED25519_PUB_KEY[12..44]).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300455 let signature = key_pair.sign(&hash);
456
457 result.push(TlvKinds::ED25519 as u8);
458 result.push(0);
459
460 let signature = signature.as_ref().to_vec();
David Brown91d68632019-07-29 14:32:13 -0600461 result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
Fabio Utzig97710282019-05-24 17:44:49 -0300462 result.extend_from_slice(signature.as_ref());
463 }
464
Fabio Utzig1e48b912018-09-18 09:04:18 -0300465 if self.kinds.contains(&TlvKinds::ENCRSA2048) {
466 let key_bytes = pem::parse(include_bytes!("../../enc-rsa2048-pub.pem")
467 .as_ref()).unwrap();
468 assert_eq!(key_bytes.tag, "PUBLIC KEY");
469
470 let encbuf = match c::rsa_oaep_encrypt(&key_bytes.contents, AES_SEC_KEY) {
471 Ok(v) => v,
472 Err(_) => panic!("Failed to encrypt secret key"),
473 };
474
475 assert!(encbuf.len() == 256);
476 result.push(TlvKinds::ENCRSA2048 as u8);
477 result.push(0);
478 result.push(0);
479 result.push(1);
480 result.extend_from_slice(&encbuf);
481 }
482
483 if self.kinds.contains(&TlvKinds::ENCKW128) {
484 let key_bytes = base64::decode(
485 include_str!("../../enc-aes128kw.b64").trim()).unwrap();
486
487 let encbuf = match c::kw_encrypt(&key_bytes, AES_SEC_KEY) {
488 Ok(v) => v,
489 Err(_) => panic!("Failed to encrypt secret key"),
490 };
491
492 assert!(encbuf.len() == 24);
493 result.push(TlvKinds::ENCKW128 as u8);
494 result.push(0);
495 result.push(24);
496 result.push(0);
497 result.extend_from_slice(&encbuf);
498 }
499
Fabio Utzig90f449e2019-10-24 07:43:53 -0300500 if self.kinds.contains(&TlvKinds::ENCEC256) {
501 let key_bytes = pem::parse(include_bytes!("../../enc-ec256-pub.pem").as_ref()).unwrap();
502 assert_eq!(key_bytes.tag, "PUBLIC KEY");
503
504 let rng = rand::SystemRandom::new();
505 let pk = match agreement::EphemeralPrivateKey::generate(&agreement::ECDH_P256, &rng) {
506 Ok(v) => v,
507 Err(_) => panic!("Failed to generate ephemeral keypair"),
508 };
509
510 let pubk = match pk.compute_public_key() {
511 Ok(pubk) => pubk,
512 Err(_) => panic!("Failed computing ephemeral public key"),
513 };
514
515 let peer_pubk = agreement::UnparsedPublicKey::new(&agreement::ECDH_P256, &key_bytes.contents[26..]);
516
517 #[derive(Debug, PartialEq)]
518 struct OkmLen<T: core::fmt::Debug + PartialEq>(T);
519
520 impl hkdf::KeyType for OkmLen<usize> {
521 fn len(&self) -> usize {
522 self.0
523 }
524 }
525
526 let derived_key = match agreement::agree_ephemeral(
527 pk, &peer_pubk, ring::error::Unspecified, |shared| {
528 let salt = hkdf::Salt::new(hkdf::HKDF_SHA256, &[]);
529 let prk = salt.extract(&shared);
530 let okm = match prk.expand(&[b"MCUBoot_ECIES_v1"], OkmLen(48)) {
531 Ok(okm) => okm,
532 Err(_) => panic!("Failed building HKDF OKM"),
533 };
534 let mut buf = [0u8; 48];
535 match okm.fill(&mut buf) {
536 Ok(_) => Ok(buf),
537 Err(_) => panic!("Failed generating HKDF output"),
538 }
539 },
540 ) {
541 Ok(v) => v,
542 Err(_) => panic!("Failed building HKDF"),
543 };
544
545 let key = GenericArray::from_slice(&derived_key[..16]);
546 let nonce = GenericArray::from_slice(&[0; 16]);
547 let mut cipher = Aes128Ctr::new(&key, &nonce);
548 let mut cipherkey = self.get_enc_key();
549 cipher.apply_keystream(&mut cipherkey);
550
551 let key = hmac::Key::new(hmac::HMAC_SHA256, &derived_key[16..]);
552 let tag = hmac::sign(&key, &cipherkey);
553
554 let mut buf = vec![];
555 buf.append(&mut pubk.as_ref().to_vec());
556 buf.append(&mut tag.as_ref().to_vec());
557 buf.append(&mut cipherkey);
558
559 assert!(buf.len() == 113);
560 result.push(TlvKinds::ENCEC256 as u8);
561 result.push(0);
562 result.push(113);
563 result.push(0);
564 result.extend_from_slice(&buf);
565 }
566
David Brown187dd882017-07-11 11:15:23 -0600567 result
568 }
Fabio Utzig90f449e2019-10-24 07:43:53 -0300569
570 fn generate_enc_key(&mut self) -> bool {
571 self.enc_key = AES_SEC_KEY.to_vec();
572 true
573 }
574
575 fn get_enc_key(&self) -> Vec<u8> {
576 return self.enc_key.clone();
577 }
David Brown187dd882017-07-11 11:15:23 -0600578}
David Brown43cda332017-09-01 09:53:23 -0600579
580include!("rsa_pub_key-rs.txt");
Fabio Utzig39297432019-05-08 18:51:10 -0300581include!("rsa3072_pub_key-rs.txt");
Fabio Utzig80fde2f2017-12-05 09:25:31 -0200582include!("ecdsa_pub_key-rs.txt");
Fabio Utzig97710282019-05-24 17:44:49 -0300583include!("ed25519_pub_key-rs.txt");