1 use crate::dice::Payload;
2 use crate::publickey::PublicKey;
3 use crate::session::RkpInstance;
4 use anyhow::Result;
5 use std::collections::HashSet;
6 use std::fmt::{self, Display, Formatter};
7 use thiserror::Error;
8
9 /// The minimum number of RKP VM markers required in a valid [RKP VM DICE chain][rkpvm-chain].
10 ///
11 /// An RKP VM chain must have a continuous presence of RKP VM markers, starting from a DICE
12 /// certificate derived in the TEE and extending to the leaf DICE certificate.
13 /// Therefore, a valid RKP VM chain should have at least two DICE certificates with RKP VM markers:
14 ///
15 /// * One added in the pVM (managed by Android).
16 /// * One added in the TEE (managed by vendors).
17 ///
18 /// [rkpvm-chain]: https://android.googlesource.com/platform/packages/modules/Virtualization/+/main/docs/vm_remote_attestation.md
19 const RKPVM_CHAIN_MIN_MARKER_NUM: usize = 2;
20
21 /// Enumeration of the different forms that a DICE chain can take.
22 #[derive(Clone, Debug, Eq, PartialEq)]
23 pub enum ChainForm {
24 /// A proper DICE chain with multiple layers of trust.
25 Proper(Chain),
26 /// A degenerate DICE chain consisting of a single self-signed certificate.
27 Degenerate(DegenerateChain),
28 }
29
30 /// Represents a DICE chain. This consists of the root public key (which signs the first
31 /// certificate), followed by a chain of certificates.
32 #[derive(Clone, Eq, PartialEq)]
33 pub struct Chain {
34 root_public_key: PublicKey,
35 payloads: Vec<Payload>,
36 }
37
38 #[derive(Error, Debug, PartialEq, Eq)]
39 pub(crate) enum ValidationError {
40 #[error("no payloads")]
41 NoPayloads,
42 #[error("issuer `{1}` is not previous subject `{2}` in payload {0}")]
43 IssuerMismatch(usize, String, String),
44 #[error("repeated subject in payload {0}")]
45 RepeatedSubject(usize, String),
46 #[error("repeated key in payload {0}")]
47 RepeatedKey(usize),
48 #[error("RKP VM chain has discontinuous marker at the {0}th payload")]
49 RkpVmChainHasDiscontinuousMarker(usize),
50 #[error(
51 "RKP VM chain does not have enough RKP VM markers. \
52 Minimal marker number:{RKPVM_CHAIN_MIN_MARKER_NUM}, actual marker number:{0}"
53 )]
54 NotEnoughRkpVmMarker(usize),
55 #[error("non RKP VM chain should not have continuous RKP VM markers")]
56 UnexpectedRkpVmMarkers,
57 }
58
59 impl ChainForm {
leaf_public_key(&self) -> &PublicKey60 pub(crate) fn leaf_public_key(&self) -> &PublicKey {
61 match self {
62 Self::Proper(chain) => chain.leaf().subject_public_key(),
63 Self::Degenerate(degenerate) => degenerate.public_key(),
64 }
65 }
66
67 /// Return the length of the chain.
length(&self) -> usize68 pub fn length(&self) -> usize {
69 match self {
70 ChainForm::Proper(chain) => chain.payloads.len(),
71 ChainForm::Degenerate(_) => 1,
72 }
73 }
74 }
75
76 impl Chain {
77 /// Builds a [`Chain`] after checking that it is well-formed. The issuer of each entry must be
78 /// equal to the subject of the previous entry. The chain is not allowed to contain any
79 /// repeated subjects or subject public keys as that would suggest something untoward has
80 /// happened.
81 ///
82 /// Additionally, `rkp_instance` provides additional context for the validation of the chain
83 /// according to the instance-specific chain validation rules.
84 ///
85 /// * AVF instance: The chain is validated against the RKP VM chain validation rules.
86 /// * Non-AVF instances: The chain must not contain RKP VM markers that conform to the RKP VM
87 /// chain validation rules.
validate( root_public_key: PublicKey, payloads: Vec<Payload>, rkp_instance: RkpInstance, ) -> Result<Self, ValidationError>88 pub(crate) fn validate(
89 root_public_key: PublicKey,
90 payloads: Vec<Payload>,
91 rkp_instance: RkpInstance,
92 ) -> Result<Self, ValidationError> {
93 if payloads.is_empty() {
94 return Err(ValidationError::NoPayloads);
95 }
96
97 let mut subjects = HashSet::with_capacity(payloads.len());
98 let mut keys = HashSet::with_capacity(1 + payloads.len());
99 keys.insert(root_public_key.to_pem());
100
101 let mut previous_subject: Option<&str> = None;
102 for (n, payload) in payloads.iter().enumerate() {
103 if let Some(previous_subject) = previous_subject {
104 if payload.issuer() != previous_subject {
105 return Err(ValidationError::IssuerMismatch(
106 n,
107 payload.issuer().to_string(),
108 previous_subject.to_string(),
109 ));
110 }
111 }
112 if subjects.replace(payload.subject()).is_some() {
113 return Err(ValidationError::RepeatedSubject(n, payload.subject().to_string()));
114 }
115 if keys.replace(payload.subject_public_key().to_pem()).is_some() {
116 return Err(ValidationError::RepeatedKey(n));
117 }
118 previous_subject = Some(payload.subject());
119 }
120 match rkp_instance {
121 RkpInstance::Avf => validate_rkpvm_chain(&payloads),
122 _ => validate_non_rkpvm_chain(&payloads),
123 }?;
124 Ok(Self { root_public_key, payloads })
125 }
126
127 /// Get the root public key which verifies the first certificate in the chain.
root_public_key(&self) -> &PublicKey128 pub fn root_public_key(&self) -> &PublicKey {
129 &self.root_public_key
130 }
131
132 /// Get the payloads of the certificates in the chain, from root to leaf.
payloads(&self) -> &[Payload]133 pub fn payloads(&self) -> &[Payload] {
134 &self.payloads
135 }
136
137 /// Get the payload from the final certificate in the chain.
leaf(&self) -> &Payload138 pub fn leaf(&self) -> &Payload {
139 // There is always at least one payload.
140 self.payloads.last().unwrap()
141 }
142 }
143
validate_rkpvm_chain(payloads: &[Payload]) -> Result<(), ValidationError>144 fn validate_rkpvm_chain(payloads: &[Payload]) -> Result<(), ValidationError> {
145 let mut rkpvm_marker_count = 0;
146 for (i, payload) in payloads.iter().enumerate() {
147 if payload.has_rkpvm_marker() {
148 rkpvm_marker_count += 1;
149 } else if rkpvm_marker_count > 0 {
150 return Err(ValidationError::RkpVmChainHasDiscontinuousMarker(i));
151 }
152 }
153 if rkpvm_marker_count < RKPVM_CHAIN_MIN_MARKER_NUM {
154 return Err(ValidationError::NotEnoughRkpVmMarker(rkpvm_marker_count));
155 }
156 Ok(())
157 }
158
159 /// Validates a DICE chain that is not associated with an RKP VM.
160 ///
161 /// While non-RKP VM DICE chains might contain RKP VM markers in some vendor DICE certificates
162 /// (e.g., Microdroid pVM DICE chain), they should not have a continuous presence of markers up to
163 /// the last certificate in the chain.
validate_non_rkpvm_chain(payloads: &[Payload]) -> Result<(), ValidationError>164 fn validate_non_rkpvm_chain(payloads: &[Payload]) -> Result<(), ValidationError> {
165 validate_rkpvm_chain(payloads).map_or(Ok(()), |_| Err(ValidationError::UnexpectedRkpVmMarkers))
166 }
167
168 impl Display for Chain {
fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>169 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
170 writeln!(f, "Root public key:")?;
171 writeln!(f, "{}", self.root_public_key.to_pem())?;
172 for (i, payload) in self.payloads.iter().enumerate() {
173 writeln!(f, "Cert {}:", i)?;
174 writeln!(f, "{}", payload)?;
175 }
176 Ok(())
177 }
178 }
179
180 impl fmt::Debug for Chain {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result181 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
182 let mut debug = fmt.debug_struct("Chain");
183 debug.field("Root public key", &self.root_public_key.to_pem());
184 for (i, payload) in self.payloads.iter().enumerate() {
185 debug.field(&format!("DICE Certificate[{i}]"), payload);
186 }
187 debug.finish()
188 }
189 }
190
191 #[derive(Error, Debug, PartialEq, Eq)]
192 pub(crate) enum DegenerateChainError {
193 #[error("issuer empty")]
194 IssuerEmpty,
195 #[error("subject empty")]
196 SubjectEmpty,
197 }
198
199 /// A degenerate DICE chain. These chains consist of a single, self-signed certificate and the
200 /// entries contain less information than usual. They are expected from devices that haven't
201 /// implemented everything necessary to produce a proper DICE Chain.
202 #[derive(Clone, Debug, Eq, PartialEq)]
203 pub struct DegenerateChain {
204 issuer: String,
205 subject: String,
206 subject_public_key: PublicKey,
207 }
208
209 impl DegenerateChain {
new<I: Into<String>, S: Into<String>>( issuer: I, subject: S, subject_public_key: PublicKey, ) -> Result<Self, DegenerateChainError>210 pub(crate) fn new<I: Into<String>, S: Into<String>>(
211 issuer: I,
212 subject: S,
213 subject_public_key: PublicKey,
214 ) -> Result<Self, DegenerateChainError> {
215 let issuer = issuer.into();
216 let subject = subject.into();
217 if issuer.is_empty() {
218 return Err(DegenerateChainError::IssuerEmpty);
219 }
220 if subject.is_empty() {
221 return Err(DegenerateChainError::SubjectEmpty);
222 }
223 Ok(Self { issuer, subject, subject_public_key })
224 }
225
226 /// Gets the issuer of the degenerate chain.
issuer(&self) -> &str227 pub fn issuer(&self) -> &str {
228 &self.issuer
229 }
230
231 /// Gets the subject of the degenerate chain.
subject(&self) -> &str232 pub fn subject(&self) -> &str {
233 &self.subject
234 }
235
236 /// Gets the public key of the degenerate chain.
public_key(&self) -> &PublicKey237 pub fn public_key(&self) -> &PublicKey {
238 &self.subject_public_key
239 }
240 }
241
242 impl Display for DegenerateChain {
fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>243 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
244 writeln!(f, "Public key:")?;
245 writeln!(f, "{}", self.public_key().to_pem())?;
246 writeln!(f, "Issuer: {}", self.issuer)?;
247 writeln!(f, "Subject: {}", self.subject)?;
248 Ok(())
249 }
250 }
251
252 #[cfg(test)]
253 mod tests {
254 use super::*;
255 use crate::dice::{ConfigDescBuilder, DiceMode, PayloadBuilder};
256 use crate::publickey::testkeys::{PrivateKey, ED25519_KEY_PEM, P256_KEY_PEM, P384_KEY_PEM};
257
258 #[test]
chain_validate_valid()259 fn chain_validate_valid() {
260 let root_public_key = PrivateKey::from_pem(P256_KEY_PEM[0]).public_key();
261 let keys = P256_KEY_PEM[1..4].iter().copied().enumerate();
262 let payloads = keys.map(|(n, key)| valid_payload(n, key).build().unwrap()).collect();
263 Chain::validate(root_public_key, payloads, RkpInstance::Default).unwrap();
264 }
265
266 #[test]
chain_validate_valid_with_mixed_kinds_of_key()267 fn chain_validate_valid_with_mixed_kinds_of_key() {
268 let root_public_key = PrivateKey::from_pem(ED25519_KEY_PEM[0]).public_key();
269 let keys = [P256_KEY_PEM[0], P384_KEY_PEM[0]].into_iter().enumerate();
270 let payloads = keys.map(|(n, key)| valid_payload(n, key).build().unwrap()).collect();
271 Chain::validate(root_public_key, payloads, RkpInstance::Default).unwrap();
272 }
273
274 #[test]
chain_validate_fails_without_payloads()275 fn chain_validate_fails_without_payloads() {
276 let root_public_key = PrivateKey::from_pem(P256_KEY_PEM[0]).public_key();
277 let payloads = Vec::new();
278 let err = Chain::validate(root_public_key, payloads, RkpInstance::Default).unwrap_err();
279 assert_eq!(err, ValidationError::NoPayloads);
280 }
281
282 #[test]
chain_validate_fails_when_root_key_repeated()283 fn chain_validate_fails_when_root_key_repeated() {
284 let key = P256_KEY_PEM[0];
285 let root_public_key = PrivateKey::from_pem(key).public_key();
286 let payloads = vec![valid_payload(0, key).build().unwrap()];
287 let err = Chain::validate(root_public_key, payloads, RkpInstance::Default).unwrap_err();
288 assert_eq!(err, ValidationError::RepeatedKey(0));
289 }
290
291 #[test]
chain_validate_fails_with_repeated_subject_public_keys()292 fn chain_validate_fails_with_repeated_subject_public_keys() {
293 let repeated_key = P256_KEY_PEM[0];
294 let root_public_key = PrivateKey::from_pem(ED25519_KEY_PEM[0]).public_key();
295 let payloads = vec![
296 valid_payload(0, repeated_key).build().unwrap(),
297 valid_payload(1, repeated_key).build().unwrap(),
298 ];
299 let err = Chain::validate(root_public_key, payloads, RkpInstance::Default).unwrap_err();
300 assert_eq!(err, ValidationError::RepeatedKey(1));
301 }
302
303 #[test]
chain_validate_fails_with_repeated_subjects()304 fn chain_validate_fails_with_repeated_subjects() {
305 let keys = &P256_KEY_PEM[..3];
306 let repeated = "match";
307 let root_public_key = PrivateKey::from_pem(ED25519_KEY_PEM[0]).public_key();
308 let payloads = vec![
309 valid_payload(0, keys[0]).subject(repeated).build().unwrap(),
310 valid_payload(1, keys[1]).issuer(repeated).build().unwrap(),
311 valid_payload(2, keys[2]).subject(repeated).build().unwrap(),
312 ];
313 let err = Chain::validate(root_public_key, payloads, RkpInstance::Default).unwrap_err();
314 assert_eq!(err, ValidationError::RepeatedSubject(2, repeated.into()));
315 }
316
317 #[test]
chain_validate_fails_with_mismatching_issuer_and_subject()318 fn chain_validate_fails_with_mismatching_issuer_and_subject() {
319 let expected = "expected";
320 let wrong = "wrong";
321 let root_public_key = PrivateKey::from_pem(P256_KEY_PEM[0]).public_key();
322 let payloads = vec![
323 valid_payload(0, P256_KEY_PEM[1]).subject(expected).build().unwrap(),
324 valid_payload(1, P256_KEY_PEM[2]).issuer(wrong).build().unwrap(),
325 ];
326 let err = Chain::validate(root_public_key, payloads, RkpInstance::Default).unwrap_err();
327 assert_eq!(err, ValidationError::IssuerMismatch(1, wrong.into(), expected.into()));
328 }
329
330 #[test]
non_rkpvm_chain_validate_with_discontinuous_markers()331 fn non_rkpvm_chain_validate_with_discontinuous_markers() {
332 let root_public_key = PrivateKey::from_pem(P256_KEY_PEM[0]).public_key();
333 let config_desc = ConfigDescBuilder::new().rkp_vm_marker(true).build();
334 // This chain resembles a Microdroid pVM DICE chain where vendors add RKP VM markers in
335 // the vendor part of the chain, while pVM does not.
336 let payloads = vec![
337 valid_payload(0, P256_KEY_PEM[1]).build().unwrap(),
338 valid_payload(1, P256_KEY_PEM[2]).config_desc(config_desc.clone()).build().unwrap(),
339 valid_payload(2, P256_KEY_PEM[3]).build().unwrap(),
340 ];
341 Chain::validate(root_public_key, payloads, RkpInstance::Default).unwrap();
342 }
343
344 #[test]
non_rkpvm_chain_validate_fails_with_continuous_markers()345 fn non_rkpvm_chain_validate_fails_with_continuous_markers() {
346 let root_public_key = PrivateKey::from_pem(P256_KEY_PEM[0]).public_key();
347 let config_desc = ConfigDescBuilder::new().rkp_vm_marker(true).build();
348 let payloads = vec![
349 valid_payload(0, P256_KEY_PEM[1]).build().unwrap(),
350 valid_payload(1, P256_KEY_PEM[2]).config_desc(config_desc.clone()).build().unwrap(),
351 valid_payload(2, P256_KEY_PEM[3]).config_desc(config_desc.clone()).build().unwrap(),
352 ];
353 let err = Chain::validate(root_public_key, payloads, RkpInstance::Default).unwrap_err();
354 assert_eq!(err, ValidationError::UnexpectedRkpVmMarkers);
355 }
356
357 #[test]
rkpvm_chain_validate_with_continuous_markers()358 fn rkpvm_chain_validate_with_continuous_markers() {
359 let root_public_key = PrivateKey::from_pem(P256_KEY_PEM[0]).public_key();
360 let config_desc = ConfigDescBuilder::new().rkp_vm_marker(true).build();
361 let payloads = vec![
362 valid_payload(0, P256_KEY_PEM[1]).build().unwrap(),
363 valid_payload(1, P256_KEY_PEM[2]).config_desc(config_desc.clone()).build().unwrap(),
364 valid_payload(2, P256_KEY_PEM[3]).config_desc(config_desc.clone()).build().unwrap(),
365 ];
366 Chain::validate(root_public_key, payloads, RkpInstance::Avf).unwrap();
367 }
368
369 #[test]
rkpvm_chain_validate_fails_with_no_marker()370 fn rkpvm_chain_validate_fails_with_no_marker() {
371 let root_public_key = PrivateKey::from_pem(P256_KEY_PEM[0]).public_key();
372 let payloads = vec![valid_payload(0, P256_KEY_PEM[1]).build().unwrap()];
373 let err = Chain::validate(root_public_key, payloads, RkpInstance::Avf).unwrap_err();
374 assert_eq!(err, ValidationError::NotEnoughRkpVmMarker(0));
375 }
376
377 #[test]
rkpvm_chain_validate_fails_with_not_enough_markers()378 fn rkpvm_chain_validate_fails_with_not_enough_markers() {
379 let root_public_key = PrivateKey::from_pem(P256_KEY_PEM[0]).public_key();
380 let config_desc = ConfigDescBuilder::new().rkp_vm_marker(true).build();
381 let payloads = vec![
382 valid_payload(0, P256_KEY_PEM[1]).build().unwrap(),
383 valid_payload(1, P256_KEY_PEM[2]).config_desc(config_desc).build().unwrap(),
384 ];
385 let err = Chain::validate(root_public_key, payloads, RkpInstance::Avf).unwrap_err();
386 assert_eq!(err, ValidationError::NotEnoughRkpVmMarker(1));
387 }
388
389 #[test]
rkpvm_chain_validate_fails_with_discontinous_markers()390 fn rkpvm_chain_validate_fails_with_discontinous_markers() {
391 let root_public_key = PrivateKey::from_pem(P256_KEY_PEM[0]).public_key();
392 let config_desc = ConfigDescBuilder::new().rkp_vm_marker(true).build();
393 let payloads = vec![
394 valid_payload(0, P256_KEY_PEM[1]).config_desc(config_desc.clone()).build().unwrap(),
395 valid_payload(1, P256_KEY_PEM[2]).build().unwrap(),
396 valid_payload(2, P256_KEY_PEM[3]).config_desc(config_desc.clone()).build().unwrap(),
397 ];
398 let err = Chain::validate(root_public_key, payloads, RkpInstance::Avf).unwrap_err();
399 assert_eq!(err, ValidationError::RkpVmChainHasDiscontinuousMarker(1));
400 }
401
402 #[test]
rkpvm_chain_validate_fails_last_payload_has_no_marker()403 fn rkpvm_chain_validate_fails_last_payload_has_no_marker() {
404 let root_public_key = PrivateKey::from_pem(P256_KEY_PEM[0]).public_key();
405 let config_desc = ConfigDescBuilder::new().rkp_vm_marker(true).build();
406 let payloads = vec![
407 valid_payload(0, P256_KEY_PEM[1]).config_desc(config_desc.clone()).build().unwrap(),
408 valid_payload(1, P256_KEY_PEM[2]).config_desc(config_desc.clone()).build().unwrap(),
409 valid_payload(2, P256_KEY_PEM[3]).build().unwrap(),
410 ];
411 let err = Chain::validate(root_public_key, payloads, RkpInstance::Avf).unwrap_err();
412 assert_eq!(err, ValidationError::RkpVmChainHasDiscontinuousMarker(2));
413 }
414
valid_payload(index: usize, pem: &str) -> PayloadBuilder415 fn valid_payload(index: usize, pem: &str) -> PayloadBuilder {
416 PayloadBuilder::with_subject_public_key(PrivateKey::from_pem(pem).public_key())
417 .issuer(format!("component {}", index))
418 .subject(format!("component {}", index + 1))
419 .mode(DiceMode::Normal)
420 .code_hash(vec![0; 64])
421 .authority_hash(vec![0; 64])
422 }
423
424 #[test]
degenerate_chain_valid()425 fn degenerate_chain_valid() {
426 let key = PrivateKey::from_pem(ED25519_KEY_PEM[0]).public_key();
427 DegenerateChain::new("issuer", "issuer", key).unwrap();
428 }
429
430 #[test]
degenerate_chain_empty_issuer()431 fn degenerate_chain_empty_issuer() {
432 let key = PrivateKey::from_pem(ED25519_KEY_PEM[0]).public_key();
433 let err = DegenerateChain::new("", "subject", key).unwrap_err();
434 assert_eq!(err, DegenerateChainError::IssuerEmpty);
435 }
436
437 #[test]
degenerate_chain_empty_subject()438 fn degenerate_chain_empty_subject() {
439 let key = PrivateKey::from_pem(ED25519_KEY_PEM[0]).public_key();
440 let err = DegenerateChain::new("issuer", "", key).unwrap_err();
441 assert_eq!(err, DegenerateChainError::SubjectEmpty);
442 }
443 }
444