1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //! Support for explicit key chain format & conversion from legacy DiceArtifacts.
18
19 use crate::Error;
20 use ciborium::Value;
21 use coset::{AsCborValue, CborOrdering, CborSerializable, CoseKey};
22 use diced_open_dice::{DiceArtifacts, OwnedDiceArtifacts, CDI_SIZE};
23 use std::fmt;
24
25 const EXPLICIT_KEY_DICE_CERT_CHAIN_VERSION: u64 = 1;
26
27 /// An OwnedDiceArtifactsWithExplicitKey is an OwnedDiceArtifacts that also exposes its
28 /// DICE chain (BCC) in explicit key format.
29 pub struct OwnedDiceArtifactsWithExplicitKey {
30 artifacts: OwnedDiceArtifacts,
31 explicit_key_dice_chain: Option<Vec<u8>>,
32 }
33
34 impl OwnedDiceArtifactsWithExplicitKey {
35 /// Create an OwnedDiceArtifactsWithExplicitKey from OwnedDiceArtifacts.
from_owned_artifacts(artifacts: OwnedDiceArtifacts) -> Result<Self, Error>36 pub fn from_owned_artifacts(artifacts: OwnedDiceArtifacts) -> Result<Self, Error> {
37 let explicit_key_dice_chain = artifacts.bcc().map(to_explicit_chain).transpose()?;
38 Ok(Self { artifacts, explicit_key_dice_chain })
39 }
40
41 /// Get the dice chain in Explicit-key DiceCertChain format.
42 ///
43 /// ExplicitKeyDiceCertChain = [
44 /// 1, ; version,
45 /// DiceCertChainInitialPayload,
46 /// * DiceChainEntry
47 /// ]
48 /// ; Encoded in accordance with Core Deterministic Encoding Requirements [RFC 8949 s4.2.1]
49 /// DiceCertChainInitialPayload = bstr .cbor PubKeyEd25519 /
50 /// bstr .cbor PubKeyECDSA256 /
51 /// bstr .cbor PubKeyECDSA384 ; subjectPublicKey
52 /// Note: Extracted from the spec at ExplicitKeyDiceCertChain.cddl. Keep in sync!
explicit_key_dice_chain(&self) -> Option<&[u8]>53 pub fn explicit_key_dice_chain(&self) -> Option<&[u8]> {
54 self.explicit_key_dice_chain.as_deref()
55 }
56 }
57
58 impl fmt::Debug for OwnedDiceArtifactsWithExplicitKey {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 write!(f, "Sensitive information omitted")
61 }
62 }
63
64 impl DiceArtifacts for OwnedDiceArtifactsWithExplicitKey {
cdi_attest(&self) -> &[u8; CDI_SIZE]65 fn cdi_attest(&self) -> &[u8; CDI_SIZE] {
66 self.artifacts.cdi_attest()
67 }
68
cdi_seal(&self) -> &[u8; CDI_SIZE]69 fn cdi_seal(&self) -> &[u8; CDI_SIZE] {
70 self.artifacts.cdi_seal()
71 }
72
bcc(&self) -> Option<&[u8]>73 fn bcc(&self) -> Option<&[u8]> {
74 self.artifacts.bcc()
75 }
76 }
77
78 // Convert a DICE chain to explicit key format. Note that this method checks if the input is
79 // already in the Explicit-key format & returns it if so. The check is lightweight though.
80 // A twisted incorrect dice chain input may produce incorrect output.
to_explicit_chain(dice_chain_bytes: &[u8]) -> Result<Vec<u8>, Error>81 fn to_explicit_chain(dice_chain_bytes: &[u8]) -> Result<Vec<u8>, Error> {
82 let dice_chain = deserialize_cbor_array(dice_chain_bytes)?;
83 // Check if the dice_chain is already in explicit key format
84 if matches!(&&dice_chain[..], [Value::Integer(_version), Value::Bytes(_public_key), ..]) {
85 return Ok(dice_chain_bytes.to_vec());
86 }
87 let mut res: Vec<Value> = Vec::with_capacity(dice_chain.len() + 1);
88 let mut it = dice_chain.into_iter();
89 res.push(Value::from(EXPLICIT_KEY_DICE_CERT_CHAIN_VERSION));
90 let root_key = it
91 .next()
92 .ok_or(Error::UnexpectedItem("Empty dice chain", "dice_chain with at least 1 node"))?;
93
94 // Canonicalize the root public key as per Core Deterministic Encoding Requirements
95 let mut root_key = CoseKey::from_cbor_value(root_key)?;
96 root_key.canonicalize(CborOrdering::Lexicographic);
97 // Converts to .bstr .cbor COSE_KEY
98 let root_key = root_key.to_vec()?;
99 res.push(Value::Bytes(root_key));
100 res.extend(it);
101 Ok(Value::Array(res).to_vec()?)
102 }
103
deserialize_cbor_array(cbor_array: &[u8]) -> Result<Vec<Value>, Error>104 fn deserialize_cbor_array(cbor_array: &[u8]) -> Result<Vec<Value>, Error> {
105 let value = Value::from_slice(cbor_array)?;
106 value.into_array().map_err(|_| Error::UnexpectedItem("-", "Array"))
107 }
108
109 #[cfg(test)]
110 mod tests {
111 use super::*;
112 use rdroidtest::rdroidtest;
113
114 #[rdroidtest]
implicit_to_explicit_dice_chain_conversion()115 fn implicit_to_explicit_dice_chain_conversion() {
116 const COMPOS_CHAIN_SIZE_LEGACY: usize = 5;
117 let implicit_dice = include_bytes!("../testdata/compos_chain_legacy");
118 let explicit_chain = to_explicit_chain(implicit_dice).unwrap();
119 let chain = Value::from_slice(&explicit_chain).unwrap();
120 let chain_arr = chain.into_array().unwrap();
121 // There is an added node for version in the explicit key format
122 assert_eq!(chain_arr.len(), COMPOS_CHAIN_SIZE_LEGACY + 1);
123 assert_eq!(chain_arr[0].as_integer().unwrap(), EXPLICIT_KEY_DICE_CERT_CHAIN_VERSION.into());
124 assert!(chain_arr[1].is_bytes());
125 }
126
127 #[rdroidtest]
explicit_to_explicit_dice_chain_conversion()128 fn explicit_to_explicit_dice_chain_conversion() {
129 let implicit_dice = include_bytes!("../testdata/compos_chain_legacy");
130 let explicit_chain = to_explicit_chain(implicit_dice).unwrap();
131 let converted_chain = to_explicit_chain(&explicit_chain).unwrap();
132 assert_eq!(explicit_chain, converted_chain);
133 }
134
135 #[rdroidtest]
root_key_deterministic_encoding()136 fn root_key_deterministic_encoding() {
137 // Encoding of
138 // [{"a": 1, 3: -7, 1234: 1, 1: 1}]
139 // Notice the root key map are not ordered (in lexicographic order)!
140 const IMPLICIT_CHAIN: &str = "81A461610103261904D2010101";
141 // Encoding of
142 // [1, h'A4010103261904D201616101']
143 // where A4010103261904D201616101 =
144 // .cbor {1: 1, 3: -7, 1234: 1, "a": 1}
145 // Notice the root key labels are in lexicographic order!
146 const EXPECTED_EXPLICIT_CHAIN: &str = "82014ca4010103261904d201616101";
147
148 let explicit_chain = to_explicit_chain(&hex::decode(IMPLICIT_CHAIN).unwrap()).unwrap();
149 assert_eq!(hex::encode(explicit_chain), EXPECTED_EXPLICIT_CHAIN);
150 }
151 }
152