1 use crate::dice::Payload; 2 use crate::publickey::PublicKey; 3 use anyhow::Result; 4 use std::collections::HashSet; 5 use std::fmt::{self, Display, Formatter}; 6 use thiserror::Error; 7 8 /// Enumeration of the different forms that a DICE chain can take. 9 pub enum ChainForm { 10 /// A proper DICE chain with multiple layers of trust. 11 Proper(Chain), 12 /// A degenerate DICE chain consisting of a single self-signed certificate. 13 Degenerate(DegenerateChain), 14 } 15 16 /// Represents a DICE chain. This consists of the root public key (which signs the first 17 /// certificate), followed by a chain of certificates. 18 #[derive(Debug)] 19 pub struct Chain { 20 root_public_key: PublicKey, 21 payloads: Vec<Payload>, 22 } 23 24 #[derive(Error, Debug, PartialEq, Eq)] 25 pub(crate) enum ValidationError { 26 #[error("no payloads")] 27 NoPayloads, 28 #[error("issuer `{1}` is not previous subject `{2}` in payload {0}")] 29 IssuerMismatch(usize, String, String), 30 #[error("repeated subject in payload {0}")] 31 RepeatedSubject(usize, String), 32 #[error("repeated key in payload {0}")] 33 RepeatedKey(usize), 34 } 35 36 impl Chain { 37 /// Builds a [`Chain`] after checking that it is well-formed. The issuer of each entry must be 38 /// equal to the subject of the previous entry. The chain is not allowed to contain any 39 /// repeated subjects or subject public keys as that would suggest something untoward has 40 /// happened. validate( root_public_key: PublicKey, payloads: Vec<Payload>, ) -> Result<Self, ValidationError>41 pub(crate) fn validate( 42 root_public_key: PublicKey, 43 payloads: Vec<Payload>, 44 ) -> Result<Self, ValidationError> { 45 if payloads.is_empty() { 46 return Err(ValidationError::NoPayloads); 47 } 48 49 let mut subjects = HashSet::with_capacity(payloads.len()); 50 let mut keys = HashSet::with_capacity(1 + payloads.len()); 51 keys.insert(root_public_key.to_pem()); 52 53 let mut previous_subject: Option<&str> = None; 54 for (n, payload) in payloads.iter().enumerate() { 55 if let Some(previous_subject) = previous_subject { 56 if payload.issuer() != previous_subject { 57 return Err(ValidationError::IssuerMismatch( 58 n, 59 payload.issuer().to_string(), 60 previous_subject.to_string(), 61 )); 62 } 63 } 64 if subjects.replace(payload.subject()).is_some() { 65 return Err(ValidationError::RepeatedSubject(n, payload.subject().to_string())); 66 } 67 if keys.replace(payload.subject_public_key().to_pem()).is_some() { 68 return Err(ValidationError::RepeatedKey(n)); 69 } 70 previous_subject = Some(payload.subject()); 71 } 72 73 Ok(Self { root_public_key, payloads }) 74 } 75 76 /// Get the root public key which verifies the first certificate in the chain. root_public_key(&self) -> &PublicKey77 pub fn root_public_key(&self) -> &PublicKey { 78 &self.root_public_key 79 } 80 81 /// Get the payloads of the certificates in the chain, from root to leaf. payloads(&self) -> &[Payload]82 pub fn payloads(&self) -> &[Payload] { 83 &self.payloads 84 } 85 86 /// Get the payload from the final certificate in the chain. leaf(&self) -> &Payload87 pub fn leaf(&self) -> &Payload { 88 // There is always at least one payload. 89 self.payloads.last().unwrap() 90 } 91 } 92 93 impl Display for Chain { fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>94 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { 95 writeln!(f, "Root public key:")?; 96 writeln!(f, "{}", self.root_public_key.to_pem())?; 97 for (i, payload) in self.payloads.iter().enumerate() { 98 writeln!(f, "Cert {}:", i)?; 99 writeln!(f, "{}", payload)?; 100 } 101 Ok(()) 102 } 103 } 104 105 #[derive(Error, Debug, PartialEq, Eq)] 106 pub(crate) enum DegenerateChainError { 107 #[error("issuer empty")] 108 IssuerEmpty, 109 #[error("subject empty")] 110 SubjectEmpty, 111 } 112 113 /// A degenerate DICE chain. These chains consist of a single, self-signed certificate and the 114 /// entries contain less information than usual. They are expected from devices that haven't 115 /// implemented everything necessary to produce a proper DICE Chain. 116 #[derive(Debug)] 117 pub struct DegenerateChain { 118 issuer: String, 119 subject: String, 120 subject_public_key: PublicKey, 121 } 122 123 impl DegenerateChain { new<I: Into<String>, S: Into<String>>( issuer: I, subject: S, subject_public_key: PublicKey, ) -> Result<Self, DegenerateChainError>124 pub(crate) fn new<I: Into<String>, S: Into<String>>( 125 issuer: I, 126 subject: S, 127 subject_public_key: PublicKey, 128 ) -> Result<Self, DegenerateChainError> { 129 let issuer = issuer.into(); 130 let subject = subject.into(); 131 if issuer.is_empty() { 132 return Err(DegenerateChainError::IssuerEmpty); 133 } 134 if subject.is_empty() { 135 return Err(DegenerateChainError::SubjectEmpty); 136 } 137 Ok(Self { issuer, subject, subject_public_key }) 138 } 139 140 /// Gets the issuer of the degenerate chain. issuer(&self) -> &str141 pub fn issuer(&self) -> &str { 142 &self.issuer 143 } 144 145 /// Gets the subject of the degenerate chain. subject(&self) -> &str146 pub fn subject(&self) -> &str { 147 &self.subject 148 } 149 150 /// Gets the public key of the degenerate chain. public_key(&self) -> &PublicKey151 pub fn public_key(&self) -> &PublicKey { 152 &self.subject_public_key 153 } 154 } 155 156 impl Display for DegenerateChain { fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>157 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { 158 writeln!(f, "Public key:")?; 159 writeln!(f, "{}", self.public_key().to_pem())?; 160 writeln!(f, "Issuer: {}", self.issuer)?; 161 writeln!(f, "Subject: {}", self.subject)?; 162 Ok(()) 163 } 164 } 165 166 #[cfg(test)] 167 mod tests { 168 use super::*; 169 use crate::dice::{DiceMode, PayloadBuilder}; 170 use crate::publickey::testkeys::{PrivateKey, ED25519_KEY_PEM, P256_KEY_PEM, P384_KEY_PEM}; 171 172 #[test] chain_validate_valid()173 fn chain_validate_valid() { 174 let root_public_key = PrivateKey::from_pem(P256_KEY_PEM[0]).public_key(); 175 let keys = P256_KEY_PEM[1..4].iter().copied().enumerate(); 176 let payloads = keys.map(|(n, key)| valid_payload(n, key).build().unwrap()).collect(); 177 Chain::validate(root_public_key, payloads).unwrap(); 178 } 179 180 #[test] chain_validate_valid_with_mixed_kinds_of_key()181 fn chain_validate_valid_with_mixed_kinds_of_key() { 182 let root_public_key = PrivateKey::from_pem(ED25519_KEY_PEM[0]).public_key(); 183 let keys = [P256_KEY_PEM[0], P384_KEY_PEM[0]].into_iter().enumerate(); 184 let payloads = keys.map(|(n, key)| valid_payload(n, key).build().unwrap()).collect(); 185 Chain::validate(root_public_key, payloads).unwrap(); 186 } 187 188 #[test] chain_validate_fails_without_payloads()189 fn chain_validate_fails_without_payloads() { 190 let root_public_key = PrivateKey::from_pem(P256_KEY_PEM[0]).public_key(); 191 let payloads = Vec::new(); 192 let err = Chain::validate(root_public_key, payloads).unwrap_err(); 193 assert_eq!(err, ValidationError::NoPayloads); 194 } 195 196 #[test] chain_validate_fails_when_root_key_repeated()197 fn chain_validate_fails_when_root_key_repeated() { 198 let key = P256_KEY_PEM[0]; 199 let root_public_key = PrivateKey::from_pem(key).public_key(); 200 let payloads = vec![valid_payload(0, key).build().unwrap()]; 201 let err = Chain::validate(root_public_key, payloads).unwrap_err(); 202 assert_eq!(err, ValidationError::RepeatedKey(0)); 203 } 204 205 #[test] chain_validate_fails_with_repeated_subject_public_keys()206 fn chain_validate_fails_with_repeated_subject_public_keys() { 207 let repeated_key = P256_KEY_PEM[0]; 208 let root_public_key = PrivateKey::from_pem(ED25519_KEY_PEM[0]).public_key(); 209 let payloads = vec![ 210 valid_payload(0, repeated_key).build().unwrap(), 211 valid_payload(1, repeated_key).build().unwrap(), 212 ]; 213 let err = Chain::validate(root_public_key, payloads).unwrap_err(); 214 assert_eq!(err, ValidationError::RepeatedKey(1)); 215 } 216 217 #[test] chain_validate_fails_with_repeated_subjects()218 fn chain_validate_fails_with_repeated_subjects() { 219 let keys = &P256_KEY_PEM[..3]; 220 let repeated = "match"; 221 let root_public_key = PrivateKey::from_pem(ED25519_KEY_PEM[0]).public_key(); 222 let payloads = vec![ 223 valid_payload(0, keys[0]).subject(repeated).build().unwrap(), 224 valid_payload(1, keys[1]).issuer(repeated).build().unwrap(), 225 valid_payload(2, keys[2]).subject(repeated).build().unwrap(), 226 ]; 227 let err = Chain::validate(root_public_key, payloads).unwrap_err(); 228 assert_eq!(err, ValidationError::RepeatedSubject(2, repeated.into())); 229 } 230 231 #[test] chain_validate_fails_with_mismatching_issuer_and_subject()232 fn chain_validate_fails_with_mismatching_issuer_and_subject() { 233 let expected = "expected"; 234 let wrong = "wrong"; 235 let root_public_key = PrivateKey::from_pem(P256_KEY_PEM[0]).public_key(); 236 let payloads = vec![ 237 valid_payload(0, P256_KEY_PEM[1]).subject(expected).build().unwrap(), 238 valid_payload(1, P256_KEY_PEM[2]).issuer(wrong).build().unwrap(), 239 ]; 240 let err = Chain::validate(root_public_key, payloads).unwrap_err(); 241 assert_eq!(err, ValidationError::IssuerMismatch(1, wrong.into(), expected.into())); 242 } 243 valid_payload(index: usize, pem: &str) -> PayloadBuilder244 fn valid_payload(index: usize, pem: &str) -> PayloadBuilder { 245 PayloadBuilder::with_subject_public_key(PrivateKey::from_pem(pem).public_key()) 246 .issuer(format!("component {}", index)) 247 .subject(format!("component {}", index + 1)) 248 .mode(DiceMode::Normal) 249 .code_hash(vec![0; 64]) 250 .authority_hash(vec![0; 64]) 251 } 252 253 #[test] degenerate_chain_valid()254 fn degenerate_chain_valid() { 255 let key = PrivateKey::from_pem(ED25519_KEY_PEM[0]).public_key(); 256 DegenerateChain::new("issuer", "subject", key).unwrap(); 257 } 258 259 #[test] degenerate_chain_empty_issuer()260 fn degenerate_chain_empty_issuer() { 261 let key = PrivateKey::from_pem(ED25519_KEY_PEM[0]).public_key(); 262 let err = DegenerateChain::new("", "subject", key).unwrap_err(); 263 assert_eq!(err, DegenerateChainError::IssuerEmpty); 264 } 265 266 #[test] degenerate_chain_empty_subject()267 fn degenerate_chain_empty_subject() { 268 let key = PrivateKey::from_pem(ED25519_KEY_PEM[0]).public_key(); 269 let err = DegenerateChain::new("issuer", "", key).unwrap_err(); 270 assert_eq!(err, DegenerateChainError::SubjectEmpty); 271 } 272 } 273