• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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