1 // Copyright 2023, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 //! This module implements a retry version for multiple DICE functions that
16 //! require preallocated output buffer. When running without std the allocation
17 //! of this buffer may fail and callers will see Error::MemoryAllocationError.
18 //! When running with std, allocation may fail.
19
20 use crate::bcc::{bcc_format_config_descriptor, bcc_main_flow, BccHandover, DiceConfigValues};
21 use crate::dice::{
22 dice_main_flow, Cdi, CdiValues, DiceArtifacts, InputValues, CDI_SIZE, PRIVATE_KEY_SEED_SIZE,
23 PRIVATE_KEY_SIZE,
24 };
25 use crate::error::{DiceError, Result};
26 use crate::ops::{generate_certificate, sign_cose_sign1, sign_cose_sign1_with_cdi_leaf_priv};
27 #[cfg(feature = "multialg")]
28 use crate::{
29 ops::{sign_cose_sign1_multialg, sign_cose_sign1_with_cdi_leaf_priv_multialg},
30 KeyAlgorithm,
31 };
32 use alloc::vec::Vec;
33 #[cfg(feature = "serde_derive")]
34 use serde_derive::{Deserialize, Serialize};
35
36 /// Artifacts stores a set of dice artifacts comprising CDI_ATTEST, CDI_SEAL,
37 /// and the BCC formatted attestation certificate chain.
38 /// As we align with the DICE standards today, this is the certificate chain
39 /// is also called DICE certificate chain.
40 #[derive(Debug)]
41 #[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
42 pub struct OwnedDiceArtifacts {
43 /// CDI Values.
44 cdi_values: CdiValues,
45 /// Boot Certificate Chain.
46 bcc: Vec<u8>,
47 }
48
49 impl DiceArtifacts for OwnedDiceArtifacts {
cdi_attest(&self) -> &[u8; CDI_SIZE]50 fn cdi_attest(&self) -> &[u8; CDI_SIZE] {
51 &self.cdi_values.cdi_attest
52 }
53
cdi_seal(&self) -> &[u8; CDI_SIZE]54 fn cdi_seal(&self) -> &[u8; CDI_SIZE] {
55 &self.cdi_values.cdi_seal
56 }
57
bcc(&self) -> Option<&[u8]>58 fn bcc(&self) -> Option<&[u8]> {
59 Some(&self.bcc)
60 }
61 }
62
63 impl TryFrom<BccHandover<'_>> for OwnedDiceArtifacts {
64 type Error = DiceError;
65
try_from(artifacts: BccHandover<'_>) -> Result<Self>66 fn try_from(artifacts: BccHandover<'_>) -> Result<Self> {
67 let cdi_attest = artifacts.cdi_attest().to_vec().try_into().unwrap();
68 let cdi_seal = artifacts.cdi_seal().to_vec().try_into().unwrap();
69 let bcc = artifacts
70 .bcc()
71 .map(|bcc_slice| bcc_slice.to_vec())
72 .ok_or(DiceError::DiceChainNotFound)?;
73 Ok(OwnedDiceArtifacts { cdi_values: CdiValues { cdi_attest, cdi_seal }, bcc })
74 }
75 }
76
77 /// Retries the given function with bigger measured buffer size.
retry_with_measured_buffer<F>(mut f: F) -> Result<Vec<u8>> where F: FnMut(&mut Vec<u8>) -> Result<usize>,78 fn retry_with_measured_buffer<F>(mut f: F) -> Result<Vec<u8>>
79 where
80 F: FnMut(&mut Vec<u8>) -> Result<usize>,
81 {
82 let mut buffer = Vec::new();
83 match f(&mut buffer) {
84 Err(DiceError::BufferTooSmall(actual_size)) => {
85 #[cfg(not(feature = "std"))]
86 buffer.try_reserve_exact(actual_size).map_err(|_| DiceError::MemoryAllocationError)?;
87
88 buffer.resize(actual_size, 0);
89 f(&mut buffer)?;
90 }
91 Err(e) => return Err(e),
92 Ok(_) => {}
93 };
94 Ok(buffer)
95 }
96
97 /// Formats a configuration descriptor following the BCC's specification.
retry_bcc_format_config_descriptor(values: &DiceConfigValues) -> Result<Vec<u8>>98 pub fn retry_bcc_format_config_descriptor(values: &DiceConfigValues) -> Result<Vec<u8>> {
99 retry_with_measured_buffer(|buffer| bcc_format_config_descriptor(values, buffer))
100 }
101
102 /// Executes the main BCC flow.
103 ///
104 /// Given a full set of input values along with the current BCC and CDI values,
105 /// computes the next CDI values and matching updated BCC.
retry_bcc_main_flow( current_cdi_attest: &Cdi, current_cdi_seal: &Cdi, bcc: &[u8], input_values: &InputValues, ) -> Result<OwnedDiceArtifacts>106 pub fn retry_bcc_main_flow(
107 current_cdi_attest: &Cdi,
108 current_cdi_seal: &Cdi,
109 bcc: &[u8],
110 input_values: &InputValues,
111 ) -> Result<OwnedDiceArtifacts> {
112 let mut next_cdi_values = CdiValues::default();
113 let next_bcc = retry_with_measured_buffer(|next_bcc| {
114 bcc_main_flow(
115 current_cdi_attest,
116 current_cdi_seal,
117 bcc,
118 input_values,
119 &mut next_cdi_values,
120 next_bcc,
121 )
122 })?;
123 Ok(OwnedDiceArtifacts { cdi_values: next_cdi_values, bcc: next_bcc })
124 }
125
126 /// Executes the main DICE flow.
127 ///
128 /// Given a full set of input values and the current CDI values, computes the
129 /// next CDI values and a matching certificate.
retry_dice_main_flow( current_cdi_attest: &Cdi, current_cdi_seal: &Cdi, input_values: &InputValues, ) -> Result<(CdiValues, Vec<u8>)>130 pub fn retry_dice_main_flow(
131 current_cdi_attest: &Cdi,
132 current_cdi_seal: &Cdi,
133 input_values: &InputValues,
134 ) -> Result<(CdiValues, Vec<u8>)> {
135 let mut next_cdi_values = CdiValues::default();
136 let next_cdi_certificate = retry_with_measured_buffer(|next_cdi_certificate| {
137 dice_main_flow(
138 current_cdi_attest,
139 current_cdi_seal,
140 input_values,
141 next_cdi_certificate,
142 &mut next_cdi_values,
143 )
144 })?;
145 Ok((next_cdi_values, next_cdi_certificate))
146 }
147
148 /// Generates an X.509 certificate from the given `subject_private_key_seed` and
149 /// `input_values`, and signed by `authority_private_key_seed`.
150 /// The subject private key seed is supplied here so the implementation can choose
151 /// between asymmetric mechanisms, for example ECDSA vs Ed25519.
152 /// Returns the generated certificate.
retry_generate_certificate( subject_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE], authority_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE], input_values: &InputValues, ) -> Result<Vec<u8>>153 pub fn retry_generate_certificate(
154 subject_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE],
155 authority_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE],
156 input_values: &InputValues,
157 ) -> Result<Vec<u8>> {
158 retry_with_measured_buffer(|certificate| {
159 generate_certificate(
160 subject_private_key_seed,
161 authority_private_key_seed,
162 input_values,
163 certificate,
164 )
165 })
166 }
167
168 /// Signs a message with the given private key and returns the signature
169 /// as an encoded CoseSign1 object.
retry_sign_cose_sign1( message: &[u8], aad: &[u8], private_key: &[u8; PRIVATE_KEY_SIZE], ) -> Result<Vec<u8>>170 pub fn retry_sign_cose_sign1(
171 message: &[u8],
172 aad: &[u8],
173 private_key: &[u8; PRIVATE_KEY_SIZE],
174 ) -> Result<Vec<u8>> {
175 retry_with_measured_buffer(|encoded_signature| {
176 sign_cose_sign1(message, aad, private_key, encoded_signature)
177 })
178 }
179
180 /// Multialg variant of `retry_sign_cose_sign1`.
181 #[cfg(feature = "multialg")]
retry_sign_cose_sign1_multialg( message: &[u8], aad: &[u8], private_key: &[u8; PRIVATE_KEY_SIZE], key_algorithm: KeyAlgorithm, ) -> Result<Vec<u8>>182 pub fn retry_sign_cose_sign1_multialg(
183 message: &[u8],
184 aad: &[u8],
185 private_key: &[u8; PRIVATE_KEY_SIZE],
186 key_algorithm: KeyAlgorithm,
187 ) -> Result<Vec<u8>> {
188 retry_with_measured_buffer(|encoded_signature| {
189 sign_cose_sign1_multialg(message, aad, private_key, encoded_signature, key_algorithm)
190 })
191 }
192
193 /// Signs a message with the given the private key derived from the
194 /// CDI Attest of the given `dice_artifacts` and returns the signature
195 /// as an encoded CoseSign1 object.
retry_sign_cose_sign1_with_cdi_leaf_priv( message: &[u8], aad: &[u8], dice_artifacts: &dyn DiceArtifacts, ) -> Result<Vec<u8>>196 pub fn retry_sign_cose_sign1_with_cdi_leaf_priv(
197 message: &[u8],
198 aad: &[u8],
199 dice_artifacts: &dyn DiceArtifacts,
200 ) -> Result<Vec<u8>> {
201 retry_with_measured_buffer(|encoded_signature| {
202 sign_cose_sign1_with_cdi_leaf_priv(message, aad, dice_artifacts, encoded_signature)
203 })
204 }
205
206 /// Multialg variant of `retry_sign_cose_sign1_with_cdi_leaf_priv`.
207 #[cfg(feature = "multialg")]
retry_sign_cose_sign1_with_cdi_leaf_priv_multialg( message: &[u8], aad: &[u8], dice_artifacts: &dyn DiceArtifacts, key_algorithm: KeyAlgorithm, ) -> Result<Vec<u8>>208 pub fn retry_sign_cose_sign1_with_cdi_leaf_priv_multialg(
209 message: &[u8],
210 aad: &[u8],
211 dice_artifacts: &dyn DiceArtifacts,
212 key_algorithm: KeyAlgorithm,
213 ) -> Result<Vec<u8>> {
214 retry_with_measured_buffer(|encoded_signature| {
215 sign_cose_sign1_with_cdi_leaf_priv_multialg(
216 message,
217 aad,
218 dice_artifacts,
219 encoded_signature,
220 key_algorithm,
221 )
222 })
223 }
224