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 /// Returns whether the payload has an RKP VM marker. has_rkpvm_marker(&self) -> bool87 pub fn has_rkpvm_marker(&self) -> bool { 88 self.config_desc.rkp_vm_marker() 89 } 90 } 91 92 impl Display for Payload { fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>93 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { 94 writeln!(f, "Issuer: {}", self.issuer)?; 95 writeln!(f, "Subject: {}", self.subject)?; 96 writeln!(f, "Mode: {:?}", self.mode)?; 97 if let Some(code_desc) = &self.code_desc { 98 writeln!(f, "Code Desc: {}", hex::encode(code_desc))?; 99 } 100 writeln!(f, "Code Hash: {}", hex::encode(&self.code_hash))?; 101 if let Some(config_hash) = &self.config_hash { 102 writeln!(f, "Config Hash: {}", hex::encode(config_hash))?; 103 } 104 if let Some(authority_desc) = &self.authority_desc { 105 writeln!(f, "Authority Desc: {}", hex::encode(authority_desc))?; 106 } 107 writeln!(f, "Authority Hash: {}", hex::encode(&self.authority_hash))?; 108 writeln!(f, "Config Desc {{")?; 109 write!(f, "{}", &self.config_desc)?; 110 writeln!(f, "}}")?; 111 Ok(()) 112 } 113 } 114 115 impl fmt::Debug for Payload { fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>116 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { 117 let mut debug = f.debug_struct("Payload"); 118 debug.field("Issuer", &self.issuer); 119 debug.field("Subject", &self.subject); 120 debug.field("Mode", &self.mode); 121 if let Some(code_desc) = &self.code_desc { 122 debug.field("Code Desc", &hex::encode(code_desc)); 123 } 124 debug.field("Code Hash", &hex::encode(&self.code_hash)); 125 if let Some(config_hash) = &self.config_hash { 126 debug.field("Config Hash", &hex::encode(config_hash)); 127 } 128 if let Some(authority_desc) = &self.authority_desc { 129 debug.field("Authority Desc", &hex::encode(authority_desc)); 130 } 131 debug.field("Authority Hash", &hex::encode(&self.authority_hash)); 132 debug.field("Config Desc", &self.config_desc); 133 debug.finish() 134 } 135 } 136 137 #[derive(Error, Debug, PartialEq, Eq)] 138 pub(crate) enum PayloadBuilderError { 139 #[error("issuer empty")] 140 IssuerEmpty, 141 #[error("subject empty")] 142 SubjectEmpty, 143 } 144 145 pub(crate) struct PayloadBuilder(Payload); 146 147 impl PayloadBuilder { 148 /// Constructs a new builder with the given subject public key. with_subject_public_key(subject_public_key: PublicKey) -> Self149 pub fn with_subject_public_key(subject_public_key: PublicKey) -> Self { 150 Self(Payload { 151 issuer: Default::default(), 152 subject: Default::default(), 153 subject_public_key, 154 mode: Default::default(), 155 code_desc: Default::default(), 156 code_hash: Default::default(), 157 config_desc: Default::default(), 158 config_hash: Default::default(), 159 authority_desc: Default::default(), 160 authority_hash: Default::default(), 161 }) 162 } 163 164 /// Builds the [`Payload`] after validating the issuer and subject. build(self) -> Result<Payload, PayloadBuilderError>165 pub fn build(self) -> Result<Payload, PayloadBuilderError> { 166 if self.0.issuer.is_empty() { 167 return Err(PayloadBuilderError::IssuerEmpty); 168 } 169 if self.0.subject.is_empty() { 170 return Err(PayloadBuilderError::SubjectEmpty); 171 } 172 Ok(self.0) 173 } 174 175 /// Sets the issuer of the payload. 176 #[must_use] issuer<S: Into<String>>(mut self, issuer: S) -> Self177 pub fn issuer<S: Into<String>>(mut self, issuer: S) -> Self { 178 self.0.issuer = issuer.into(); 179 self 180 } 181 182 /// Sets the subject of the payload. 183 #[must_use] subject<S: Into<String>>(mut self, subject: S) -> Self184 pub fn subject<S: Into<String>>(mut self, subject: S) -> Self { 185 self.0.subject = subject.into(); 186 self 187 } 188 189 /// Sets the mode of the payload. 190 #[must_use] mode(mut self, mode: DiceMode) -> Self191 pub fn mode(mut self, mode: DiceMode) -> Self { 192 self.0.mode = mode; 193 self 194 } 195 196 /// Sets the code descriptor of the payload. 197 #[must_use] code_desc(mut self, code_desc: Option<Vec<u8>>) -> Self198 pub fn code_desc(mut self, code_desc: Option<Vec<u8>>) -> Self { 199 self.0.code_desc = code_desc; 200 self 201 } 202 203 /// Sets the code hash of the payload. 204 #[must_use] code_hash(mut self, code_hash: Vec<u8>) -> Self205 pub fn code_hash(mut self, code_hash: Vec<u8>) -> Self { 206 self.0.code_hash = code_hash; 207 self 208 } 209 210 /// Sets the configuration descriptor of the payload. 211 #[must_use] config_desc(mut self, config_desc: ConfigDesc) -> Self212 pub fn config_desc(mut self, config_desc: ConfigDesc) -> Self { 213 self.0.config_desc = config_desc; 214 self 215 } 216 217 /// Sets the configuration hash of the payload. 218 #[must_use] config_hash(mut self, config_hash: Option<Vec<u8>>) -> Self219 pub fn config_hash(mut self, config_hash: Option<Vec<u8>>) -> Self { 220 self.0.config_hash = config_hash; 221 self 222 } 223 224 /// Sets the authority descriptor of the payload. 225 #[must_use] authority_desc(mut self, authority_desc: Option<Vec<u8>>) -> Self226 pub fn authority_desc(mut self, authority_desc: Option<Vec<u8>>) -> Self { 227 self.0.authority_desc = authority_desc; 228 self 229 } 230 231 /// Sets the authority hash of the payload. 232 #[must_use] authority_hash(mut self, authority_hash: Vec<u8>) -> Self233 pub fn authority_hash(mut self, authority_hash: Vec<u8>) -> Self { 234 self.0.authority_hash = authority_hash; 235 self 236 } 237 } 238 239 /// Version of the component from the configuration descriptor. 240 #[derive(Debug, Clone, PartialEq, Eq)] 241 pub enum ComponentVersion { 242 /// An integer component version number. 243 Integer(i64), 244 /// A free-form string component version. 245 String(String), 246 } 247 248 impl Display for ComponentVersion { fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>249 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { 250 match self { 251 ComponentVersion::Integer(n) => write!(f, "{n}")?, 252 ComponentVersion::String(s) => write!(f, "{s}")?, 253 } 254 Ok(()) 255 } 256 } 257 258 /// Fields from the configuration descriptor. 259 #[derive(Debug, Default, Clone, PartialEq, Eq)] 260 pub struct ConfigDesc { 261 component_name: Option<String>, 262 component_instance_name: Option<String>, 263 component_version: Option<ComponentVersion>, 264 resettable: bool, 265 security_version: Option<u64>, 266 rkp_vm_marker: bool, 267 extensions: Vec<(String, String)>, 268 } 269 270 impl ConfigDesc { 271 /// Gets the component name. component_name(&self) -> Option<&str>272 pub fn component_name(&self) -> Option<&str> { 273 self.component_name.as_deref() 274 } 275 276 /// Gets the component instance name. component_instance_name(&self) -> Option<&str>277 pub fn component_instance_name(&self) -> Option<&str> { 278 self.component_instance_name.as_deref() 279 } 280 281 /// Gets the component version. component_version(&self) -> Option<&ComponentVersion>282 pub fn component_version(&self) -> Option<&ComponentVersion> { 283 self.component_version.as_ref() 284 } 285 286 /// Returns whether the component is factory resettable. resettable(&self) -> bool287 pub fn resettable(&self) -> bool { 288 self.resettable 289 } 290 291 /// Gets the security version. security_version(&self) -> Option<u64>292 pub fn security_version(&self) -> Option<u64> { 293 self.security_version 294 } 295 296 /// Returns whether the component may be part of an RPK VM. rkp_vm_marker(&self) -> bool297 pub fn rkp_vm_marker(&self) -> bool { 298 self.rkp_vm_marker 299 } 300 301 /// Return any extensions present in the descriptor. extensions(&self) -> &[(String, String)]302 pub fn extensions(&self) -> &[(String, String)] { 303 &self.extensions 304 } 305 } 306 307 impl Display for ConfigDesc { fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>308 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { 309 if let Some(component_name) = &self.component_name { 310 writeln!(f, "Component Name: {}", component_name)?; 311 } 312 if let Some(component_instance_name) = &self.component_instance_name { 313 writeln!(f, "Component Instance Name: {}", component_instance_name)?; 314 } 315 if let Some(component_version) = &self.component_version { 316 writeln!(f, "Component Version: {}", component_version)?; 317 } 318 if self.resettable { 319 writeln!(f, "Resettable")?; 320 } 321 if let Some(security_version) = &self.security_version { 322 writeln!(f, "Security Version: {}", security_version)?; 323 } 324 if self.rkp_vm_marker { 325 writeln!(f, "RKP VM Marker")?; 326 } 327 for (key, value) in &self.extensions { 328 writeln!(f, "{key}: {value}")?; 329 } 330 Ok(()) 331 } 332 } 333 334 pub(crate) struct ConfigDescBuilder(ConfigDesc); 335 336 impl ConfigDescBuilder { 337 /// Constructs a new builder with default values. new() -> Self338 pub fn new() -> Self { 339 Self(ConfigDesc::default()) 340 } 341 342 /// Builds the [`ConfigDesc`]. build(self) -> ConfigDesc343 pub fn build(self) -> ConfigDesc { 344 self.0 345 } 346 347 /// Sets the component name. 348 #[must_use] component_name(mut self, name: Option<String>) -> Self349 pub fn component_name(mut self, name: Option<String>) -> Self { 350 self.0.component_name = name; 351 self 352 } 353 354 /// Sets the component instance name. 355 #[must_use] component_instance_name(mut self, name: Option<String>) -> Self356 pub fn component_instance_name(mut self, name: Option<String>) -> Self { 357 self.0.component_instance_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 valid_payload() -> PayloadBuilder449 fn valid_payload() -> PayloadBuilder { 450 let key = PrivateKey::from_pem(P256_KEY_PEM[0]).public_key(); 451 PayloadBuilder::with_subject_public_key(key) 452 .issuer("issuer") 453 .subject("subject") 454 .code_hash(vec![1; 64]) 455 .authority_hash(vec![2; 64]) 456 } 457 } 458