1 use crate::publickey::PublicKey;
2 use std::fmt::{self, Display, Formatter};
3 use thiserror::Error;
4 
5 /// Enumeration of modes used in the DICE chain payloads.
6 #[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
7 pub enum DiceMode {
8     /// This mode also acts as a catch-all for configurations which do not fit the other modes and
9     /// invalid modes.
10     #[default]
11     NotConfigured,
12     /// The device is operating normally under secure configuration.
13     Normal,
14     /// At least one criteria for [`Normal`] is not met and the device is not in a secure state.
15     Debug,
16     /// A recovery or maintenance mode of some kind.
17     Recovery,
18 }
19 
20 /// The payload of a DICE chain entry.
21 #[derive(Clone, Eq, PartialEq)]
22 pub struct Payload {
23     issuer: String,
24     subject: String,
25     subject_public_key: PublicKey,
26     mode: DiceMode,
27     code_desc: Option<Vec<u8>>,
28     code_hash: Vec<u8>,
29     config_desc: ConfigDesc,
30     config_hash: Option<Vec<u8>>,
31     authority_desc: Option<Vec<u8>>,
32     authority_hash: Vec<u8>,
33 }
34 
35 impl Payload {
36     /// Gets the issuer of the payload.
issuer(&self) -> &str37     pub fn issuer(&self) -> &str {
38         &self.issuer
39     }
40 
41     /// Gets the subject of the payload.
subject(&self) -> &str42     pub fn subject(&self) -> &str {
43         &self.subject
44     }
45 
46     /// Gets the subject public key of the payload.
subject_public_key(&self) -> &PublicKey47     pub fn subject_public_key(&self) -> &PublicKey {
48         &self.subject_public_key
49     }
50 
51     /// Gets the mode of the payload.
mode(&self) -> DiceMode52     pub fn mode(&self) -> DiceMode {
53         self.mode
54     }
55 
56     /// Gets the code descriptor of the payload.
code_desc(&self) -> Option<&[u8]>57     pub fn code_desc(&self) -> Option<&[u8]> {
58         self.code_desc.as_deref()
59     }
60 
61     /// Gets the code hash of the payload.
code_hash(&self) -> &[u8]62     pub fn code_hash(&self) -> &[u8] {
63         &self.code_hash
64     }
65 
66     /// Gets the configuration descriptor of the payload.
config_desc(&self) -> &ConfigDesc67     pub fn config_desc(&self) -> &ConfigDesc {
68         &self.config_desc
69     }
70 
71     /// Gets the configuration hash of the payload.
config_hash(&self) -> Option<&[u8]>72     pub fn config_hash(&self) -> Option<&[u8]> {
73         self.config_hash.as_deref()
74     }
75 
76     /// Gets the authority descriptor of the payload.
authority_desc(&self) -> Option<&[u8]>77     pub fn authority_desc(&self) -> Option<&[u8]> {
78         self.authority_desc.as_deref()
79     }
80 
81     /// Gets the authority hash of the payload.
authority_hash(&self) -> &[u8]82     pub fn authority_hash(&self) -> &[u8] {
83         &self.authority_hash
84     }
85 }
86 
87 impl Display for Payload {
fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>88     fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
89         writeln!(f, "Issuer: {}", self.issuer)?;
90         writeln!(f, "Subject: {}", self.subject)?;
91         writeln!(f, "Mode: {:?}", self.mode)?;
92         if let Some(code_desc) = &self.code_desc {
93             writeln!(f, "Code Desc: {}", hex::encode(code_desc))?;
94         }
95         writeln!(f, "Code Hash: {}", hex::encode(&self.code_hash))?;
96         if let Some(config_hash) = &self.config_hash {
97             writeln!(f, "Config Hash: {}", hex::encode(config_hash))?;
98         }
99         if let Some(authority_desc) = &self.authority_desc {
100             writeln!(f, "Authority Desc: {}", hex::encode(authority_desc))?;
101         }
102         writeln!(f, "Authority Hash: {}", hex::encode(&self.authority_hash))?;
103         writeln!(f, "Config Desc {{")?;
104         write!(f, "{}", &self.config_desc)?;
105         writeln!(f, "}}")?;
106         Ok(())
107     }
108 }
109 
110 impl fmt::Debug for Payload {
fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>111     fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
112         let mut debug = f.debug_struct("Payload");
113         debug.field("Issuer", &self.issuer);
114         debug.field("Subject", &self.subject);
115         debug.field("Mode", &self.mode);
116         if let Some(code_desc) = &self.code_desc {
117             debug.field("Code Desc", &hex::encode(code_desc));
118         }
119         debug.field("Code Hash", &hex::encode(&self.code_hash));
120         if let Some(config_hash) = &self.config_hash {
121             debug.field("Config Hash", &hex::encode(config_hash));
122         }
123         if let Some(authority_desc) = &self.authority_desc {
124             debug.field("Authority Desc", &hex::encode(authority_desc));
125         }
126         debug.field("Authority Hash", &hex::encode(&self.authority_hash));
127         debug.field("Config Desc", &self.config_desc);
128         debug.finish()
129     }
130 }
131 
132 #[derive(Error, Debug, PartialEq, Eq)]
133 pub(crate) enum PayloadBuilderError {
134     #[error("issuer empty")]
135     IssuerEmpty,
136     #[error("subject empty")]
137     SubjectEmpty,
138     #[error("bad code hash size, actual: {0}, expected: 32, 48, or 64")]
139     CodeHashSize(usize),
140     #[error("bad config hash size, actual: {0}, expected: {1}")]
141     ConfigHashSize(usize, usize),
142     #[error("bad authority hash size, actual: {0}, expected: {1}")]
143     AuthorityHashSize(usize, usize),
144 }
145 
146 pub(crate) struct PayloadBuilder(Payload);
147 
148 impl PayloadBuilder {
149     /// Constructs a new builder with the given subject public key.
with_subject_public_key(subject_public_key: PublicKey) -> Self150     pub fn with_subject_public_key(subject_public_key: PublicKey) -> Self {
151         Self(Payload {
152             issuer: Default::default(),
153             subject: Default::default(),
154             subject_public_key,
155             mode: Default::default(),
156             code_desc: Default::default(),
157             code_hash: Default::default(),
158             config_desc: Default::default(),
159             config_hash: Default::default(),
160             authority_desc: Default::default(),
161             authority_hash: Default::default(),
162         })
163     }
164 
165     /// Builds the [`Payload`] after validating the fields.
build(self) -> Result<Payload, PayloadBuilderError>166     pub fn build(self) -> Result<Payload, PayloadBuilderError> {
167         if self.0.issuer.is_empty() {
168             return Err(PayloadBuilderError::IssuerEmpty);
169         }
170         if self.0.subject.is_empty() {
171             return Err(PayloadBuilderError::SubjectEmpty);
172         }
173         let used_hash_size = self.0.code_hash.len();
174         if ![32, 48, 64].contains(&used_hash_size) {
175             return Err(PayloadBuilderError::CodeHashSize(used_hash_size));
176         }
177         if let Some(ref config_hash) = self.0.config_hash {
178             if config_hash.len() != used_hash_size {
179                 return Err(PayloadBuilderError::ConfigHashSize(config_hash.len(), used_hash_size));
180             }
181         }
182         if self.0.authority_hash.len() != used_hash_size {
183             return Err(PayloadBuilderError::AuthorityHashSize(
184                 self.0.authority_hash.len(),
185                 used_hash_size,
186             ));
187         }
188         Ok(self.0)
189     }
190 
191     /// Sets the issuer of the payload.
192     #[must_use]
issuer<S: Into<String>>(mut self, issuer: S) -> Self193     pub fn issuer<S: Into<String>>(mut self, issuer: S) -> Self {
194         self.0.issuer = issuer.into();
195         self
196     }
197 
198     /// Sets the subject of the payload.
199     #[must_use]
subject<S: Into<String>>(mut self, subject: S) -> Self200     pub fn subject<S: Into<String>>(mut self, subject: S) -> Self {
201         self.0.subject = subject.into();
202         self
203     }
204 
205     /// Sets the mode of the payload.
206     #[must_use]
mode(mut self, mode: DiceMode) -> Self207     pub fn mode(mut self, mode: DiceMode) -> Self {
208         self.0.mode = mode;
209         self
210     }
211 
212     /// Sets the code descriptor of the payload.
213     #[must_use]
code_desc(mut self, code_desc: Option<Vec<u8>>) -> Self214     pub fn code_desc(mut self, code_desc: Option<Vec<u8>>) -> Self {
215         self.0.code_desc = code_desc;
216         self
217     }
218 
219     /// Sets the code hash of the payload.
220     #[must_use]
code_hash(mut self, code_hash: Vec<u8>) -> Self221     pub fn code_hash(mut self, code_hash: Vec<u8>) -> Self {
222         self.0.code_hash = code_hash;
223         self
224     }
225 
226     /// Sets the configuration descriptor of the payload.
227     #[must_use]
config_desc(mut self, config_desc: ConfigDesc) -> Self228     pub fn config_desc(mut self, config_desc: ConfigDesc) -> Self {
229         self.0.config_desc = config_desc;
230         self
231     }
232 
233     /// Sets the configuration hash of the payload.
234     #[must_use]
config_hash(mut self, config_hash: Option<Vec<u8>>) -> Self235     pub fn config_hash(mut self, config_hash: Option<Vec<u8>>) -> Self {
236         self.0.config_hash = config_hash;
237         self
238     }
239 
240     /// Sets the authority descriptor of the payload.
241     #[must_use]
authority_desc(mut self, authority_desc: Option<Vec<u8>>) -> Self242     pub fn authority_desc(mut self, authority_desc: Option<Vec<u8>>) -> Self {
243         self.0.authority_desc = authority_desc;
244         self
245     }
246 
247     /// Sets the authority hash of the payload.
248     #[must_use]
authority_hash(mut self, authority_hash: Vec<u8>) -> Self249     pub fn authority_hash(mut self, authority_hash: Vec<u8>) -> Self {
250         self.0.authority_hash = authority_hash;
251         self
252     }
253 }
254 
255 /// Version of the component from the configuration descriptor.
256 #[derive(Debug, Clone, PartialEq, Eq)]
257 pub enum ComponentVersion {
258     /// An integer component version number.
259     Integer(i64),
260     /// A free-form string component version.
261     String(String),
262 }
263 
264 impl Display for ComponentVersion {
fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>265     fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
266         match self {
267             ComponentVersion::Integer(n) => write!(f, "{n}")?,
268             ComponentVersion::String(s) => write!(f, "{s}")?,
269         }
270         Ok(())
271     }
272 }
273 
274 /// Fields from the configuration descriptor.
275 #[derive(Debug, Default, Clone, PartialEq, Eq)]
276 pub struct ConfigDesc {
277     component_name: Option<String>,
278     component_version: Option<ComponentVersion>,
279     resettable: bool,
280     security_version: Option<u64>,
281     rkp_vm_marker: bool,
282     extensions: Vec<(String, String)>,
283 }
284 
285 impl ConfigDesc {
286     /// Gets the component name.
component_name(&self) -> Option<&str>287     pub fn component_name(&self) -> Option<&str> {
288         self.component_name.as_deref()
289     }
290 
291     /// Gets the component version.
component_version(&self) -> Option<&ComponentVersion>292     pub fn component_version(&self) -> Option<&ComponentVersion> {
293         self.component_version.as_ref()
294     }
295 
296     /// Returns whether the component is factory resettable.
resettable(&self) -> bool297     pub fn resettable(&self) -> bool {
298         self.resettable
299     }
300 
301     /// Gets the security version.
security_version(&self) -> Option<u64>302     pub fn security_version(&self) -> Option<u64> {
303         self.security_version
304     }
305 
306     /// Returns whether the component may be part of an RPK VM.
rkp_vm_marker(&self) -> bool307     pub fn rkp_vm_marker(&self) -> bool {
308         self.rkp_vm_marker
309     }
310 
311     /// Return any extensions present in the descriptor.
extensions(&self) -> &[(String, String)]312     pub fn extensions(&self) -> &[(String, String)] {
313         &self.extensions
314     }
315 }
316 
317 impl Display for ConfigDesc {
fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>318     fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
319         if let Some(component_name) = &self.component_name {
320             writeln!(f, "Component Name: {}", component_name)?;
321         }
322         if let Some(component_version) = &self.component_version {
323             writeln!(f, "Component Version: {}", component_version)?;
324         }
325         if self.resettable {
326             writeln!(f, "Resettable")?;
327         }
328         if let Some(security_version) = &self.security_version {
329             writeln!(f, "Security Version: {}", security_version)?;
330         }
331         if self.rkp_vm_marker {
332             writeln!(f, "RKP VM Marker")?;
333         }
334         for (key, value) in &self.extensions {
335             writeln!(f, "{key}: {value}")?;
336         }
337         Ok(())
338     }
339 }
340 
341 pub(crate) struct ConfigDescBuilder(ConfigDesc);
342 
343 impl ConfigDescBuilder {
344     /// Constructs a new builder with default values.
new() -> Self345     pub fn new() -> Self {
346         Self(ConfigDesc::default())
347     }
348 
349     /// Builds the [`ConfigDesc`].
build(self) -> ConfigDesc350     pub fn build(self) -> ConfigDesc {
351         self.0
352     }
353 
354     /// Sets the component name.
355     #[must_use]
component_name(mut self, name: Option<String>) -> Self356     pub fn component_name(mut self, name: Option<String>) -> Self {
357         self.0.component_name = name;
358         self
359     }
360 
361     /// Sets the component version.
362     #[must_use]
component_version(mut self, version: Option<ComponentVersion>) -> Self363     pub fn component_version(mut self, version: Option<ComponentVersion>) -> Self {
364         self.0.component_version = version;
365         self
366     }
367 
368     /// Sets whether the component is factory resettable.
369     #[must_use]
resettable(mut self, resettable: bool) -> Self370     pub fn resettable(mut self, resettable: bool) -> Self {
371         self.0.resettable = resettable;
372         self
373     }
374 
375     /// Sets the security version.
376     #[must_use]
security_version(mut self, version: Option<u64>) -> Self377     pub fn security_version(mut self, version: Option<u64>) -> Self {
378         self.0.security_version = version;
379         self
380     }
381 
382     /// Sets whether the component may be part of an RKP VM.
383     #[must_use]
rkp_vm_marker(mut self, rkp_vm_marker: bool) -> Self384     pub fn rkp_vm_marker(mut self, rkp_vm_marker: bool) -> Self {
385         self.0.rkp_vm_marker = rkp_vm_marker;
386         self
387     }
388 
389     /// Sets the extension key/value pairs.
390     #[must_use]
extensions(mut self, extensions: Vec<(String, String)>) -> Self391     pub fn extensions(mut self, extensions: Vec<(String, String)>) -> Self {
392         self.0.extensions = extensions;
393         self
394     }
395 }
396 
397 #[cfg(test)]
398 mod tests {
399     use super::*;
400     use crate::publickey::testkeys::{PrivateKey, P256_KEY_PEM};
401 
402     #[test]
payload_builder_valid()403     fn payload_builder_valid() {
404         valid_payload().build().unwrap();
405     }
406 
407     #[test]
payload_builder_valid_512_bit_hashes()408     fn payload_builder_valid_512_bit_hashes() {
409         valid_payload()
410             .code_hash(vec![1; 64])
411             .authority_hash(vec![2; 64])
412             .config_hash(Some(vec![3; 64]))
413             .build()
414             .unwrap();
415     }
416 
417     #[test]
payload_builder_valid_384_bit_hashes()418     fn payload_builder_valid_384_bit_hashes() {
419         valid_payload()
420             .code_hash(vec![1; 48])
421             .authority_hash(vec![2; 48])
422             .config_hash(Some(vec![3; 48]))
423             .build()
424             .unwrap();
425     }
426 
427     #[test]
payload_builder_valid_256_bit_hashes()428     fn payload_builder_valid_256_bit_hashes() {
429         valid_payload()
430             .code_hash(vec![1; 32])
431             .authority_hash(vec![2; 32])
432             .config_hash(Some(vec![3; 32]))
433             .build()
434             .unwrap();
435     }
436 
437     #[test]
payload_builder_empty_issuer()438     fn payload_builder_empty_issuer() {
439         let err = valid_payload().issuer("").build().unwrap_err();
440         assert_eq!(err, PayloadBuilderError::IssuerEmpty);
441     }
442 
443     #[test]
payload_builder_empty_subject()444     fn payload_builder_empty_subject() {
445         let err = valid_payload().subject("").build().unwrap_err();
446         assert_eq!(err, PayloadBuilderError::SubjectEmpty);
447     }
448 
449     #[test]
payload_builder_bad_code_hash_size()450     fn payload_builder_bad_code_hash_size() {
451         let err = valid_payload().code_hash(vec![1; 16]).build().unwrap_err();
452         assert_eq!(err, PayloadBuilderError::CodeHashSize(16));
453     }
454 
455     #[test]
payload_builder_bad_authority_hash_size()456     fn payload_builder_bad_authority_hash_size() {
457         let err = valid_payload().authority_hash(vec![1; 16]).build().unwrap_err();
458         assert_eq!(err, PayloadBuilderError::AuthorityHashSize(16, 64));
459     }
460 
461     #[test]
payload_builder_inconsistent_authority_hash_size()462     fn payload_builder_inconsistent_authority_hash_size() {
463         let err =
464             valid_payload().code_hash(vec![1; 32]).authority_hash(vec![1; 64]).build().unwrap_err();
465         assert_eq!(err, PayloadBuilderError::AuthorityHashSize(64, 32));
466     }
467 
468     #[test]
payload_builder_bad_config_hash_size()469     fn payload_builder_bad_config_hash_size() {
470         let err = valid_payload().config_hash(Some(vec![1; 16])).build().unwrap_err();
471         assert_eq!(err, PayloadBuilderError::ConfigHashSize(16, 64));
472     }
473 
474     #[test]
payload_builder_inconsistent_config_hash_size()475     fn payload_builder_inconsistent_config_hash_size() {
476         let err = valid_payload()
477             .code_hash(vec![1; 64])
478             .config_hash(Some(vec![1; 32]))
479             .build()
480             .unwrap_err();
481         assert_eq!(err, PayloadBuilderError::ConfigHashSize(32, 64));
482     }
483 
valid_payload() -> PayloadBuilder484     fn valid_payload() -> PayloadBuilder {
485         let key = PrivateKey::from_pem(P256_KEY_PEM[0]).public_key();
486         PayloadBuilder::with_subject_public_key(key)
487             .issuer("issuer")
488             .subject("subject")
489             .code_hash(vec![1; 64])
490             .authority_hash(vec![2; 64])
491     }
492 }
493