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 mirrors the content in open-dice/include/dice/ops.h
16 //! It contains the set of functions that implement various operations that the
17 //! main DICE functions depend on.
18
19 use crate::dice::{
20 context, derive_cdi_private_key_seed, DiceArtifacts, Hash, InputValues, PrivateKey, HASH_SIZE,
21 PRIVATE_KEY_SEED_SIZE, PRIVATE_KEY_SIZE, VM_KEY_ALGORITHM,
22 };
23 use crate::error::{check_result, DiceError, Result};
24 #[cfg(feature = "multialg")]
25 use crate::KeyAlgorithm;
26 use alloc::{vec, vec::Vec};
27 #[cfg(feature = "multialg")]
28 use open_dice_cbor_bindgen::DiceContext_;
29 use open_dice_cbor_bindgen::{
30 DiceCoseSignAndEncodeSign1, DiceGenerateCertificate, DiceHash, DiceKdf, DiceKeypairFromSeed,
31 DicePrincipal, DiceSign, DiceVerify,
32 };
33 #[cfg(feature = "multialg")]
34 use std::ffi::c_void;
35 use std::ptr;
36
37 /// Hashes the provided input using DICE's hash function `DiceHash`.
hash(input: &[u8]) -> Result<Hash>38 pub fn hash(input: &[u8]) -> Result<Hash> {
39 let mut output: Hash = [0; HASH_SIZE];
40 check_result(
41 // SAFETY: DiceHash takes a sized input buffer and writes to a constant-sized output
42 // buffer. The first argument context is not used in this function.
43 unsafe {
44 DiceHash(
45 ptr::null_mut(), // context
46 input.as_ptr(),
47 input.len(),
48 output.as_mut_ptr(),
49 )
50 },
51 output.len(),
52 )?;
53 Ok(output)
54 }
55
56 /// An implementation of HKDF-SHA512. Derives a key of `derived_key.len()` bytes from `ikm`, `salt`,
57 /// and `info`. The derived key is written to the `derived_key`.
kdf(ikm: &[u8], salt: &[u8], info: &[u8], derived_key: &mut [u8]) -> Result<()>58 pub fn kdf(ikm: &[u8], salt: &[u8], info: &[u8], derived_key: &mut [u8]) -> Result<()> {
59 check_result(
60 // SAFETY: The function writes to the `derived_key`, within the given bounds, and only
61 // reads the input values. The first argument context is not used in this function.
62 unsafe {
63 DiceKdf(
64 ptr::null_mut(), // context
65 derived_key.len(),
66 ikm.as_ptr(),
67 ikm.len(),
68 salt.as_ptr(),
69 salt.len(),
70 info.as_ptr(),
71 info.len(),
72 derived_key.as_mut_ptr(),
73 )
74 },
75 derived_key.len(),
76 )
77 }
78
79 /// Deterministically generates a public and private key pair from `seed`.
80 /// Since this is deterministic, `seed` is as sensitive as a private key and can
81 /// be used directly as the private key.
keypair_from_seed(seed: &[u8; PRIVATE_KEY_SEED_SIZE]) -> Result<(Vec<u8>, PrivateKey)>82 pub fn keypair_from_seed(seed: &[u8; PRIVATE_KEY_SEED_SIZE]) -> Result<(Vec<u8>, PrivateKey)> {
83 let mut public_key = vec![0u8; VM_KEY_ALGORITHM.public_key_size()];
84 let mut private_key = PrivateKey::default();
85 // This function is used with an open-dice config that uses the same algorithms for the
86 // subject and authority. Therefore, the principal is irrelevant in this context as this
87 // function only derives the key pair cryptographically without caring about which
88 // principal it is for. Hence, we arbitrarily set it to `DicePrincipal::kDicePrincipalSubject`.
89 let principal = DicePrincipal::kDicePrincipalSubject;
90 check_result(
91 // SAFETY: The function writes to the `public_key` and `private_key` within the given
92 // bounds, and only reads the `seed`.
93 // The first argument is a pointer to a valid |DiceContext_| object for multi-alg open-dice
94 // and a null pointer otherwise.
95 unsafe {
96 DiceKeypairFromSeed(
97 context(),
98 principal,
99 seed.as_ptr(),
100 public_key.as_mut_ptr(),
101 private_key.as_mut_ptr(),
102 )
103 },
104 public_key.len(),
105 )?;
106 Ok((public_key, private_key))
107 }
108
109 /// Deterministically generates a public and private key pair from `seed` and `key_algorithm`.
110 /// Since this is deterministic, `seed` is as sensitive as a private key and can
111 /// be used directly as the private key.
112 #[cfg(feature = "multialg")]
keypair_from_seed_multialg( seed: &[u8; PRIVATE_KEY_SEED_SIZE], key_algorithm: KeyAlgorithm, ) -> Result<(Vec<u8>, PrivateKey)>113 pub fn keypair_from_seed_multialg(
114 seed: &[u8; PRIVATE_KEY_SEED_SIZE],
115 key_algorithm: KeyAlgorithm,
116 ) -> Result<(Vec<u8>, PrivateKey)> {
117 let mut public_key = vec![0u8; key_algorithm.public_key_size()];
118 let mut private_key = PrivateKey::default();
119 // This function is used with an open-dice config that uses the same algorithms for the
120 // subject and authority. Therefore, the principal is irrelevant in this context as this
121 // function only derives the key pair cryptographically without caring about which
122 // principal it is for. Hence, we arbitrarily set it to `DicePrincipal::kDicePrincipalSubject`.
123 let principal = DicePrincipal::kDicePrincipalSubject;
124 let context = DiceContext_ {
125 authority_algorithm: key_algorithm.into(),
126 subject_algorithm: key_algorithm.into(),
127 };
128 check_result(
129 // SAFETY: The function writes to the `public_key` and `private_key` within the given
130 // bounds, and only reads the `seed`.
131 // The first argument is a pointer to a valid |DiceContext_| object for multi-alg
132 // open-dice.
133 unsafe {
134 DiceKeypairFromSeed(
135 &context as *const DiceContext_ as *mut c_void,
136 principal,
137 seed.as_ptr(),
138 public_key.as_mut_ptr(),
139 private_key.as_mut_ptr(),
140 )
141 },
142 public_key.len(),
143 )?;
144 Ok((public_key, private_key))
145 }
146
147 /// Derives the CDI_Leaf_Priv from the provided `dice_artifacts`.
148 ///
149 /// The corresponding public key is included in the leaf certificate of the DICE chain
150 /// contained in `dice_artifacts`.
151 ///
152 /// Refer to the following documentation for more information about CDI_Leaf_Priv:
153 ///
154 /// security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
derive_cdi_leaf_priv(dice_artifacts: &dyn DiceArtifacts) -> Result<PrivateKey>155 pub fn derive_cdi_leaf_priv(dice_artifacts: &dyn DiceArtifacts) -> Result<PrivateKey> {
156 let cdi_priv_key_seed = derive_cdi_private_key_seed(dice_artifacts.cdi_attest())?;
157 let (_, private_key) = keypair_from_seed(cdi_priv_key_seed.as_array())?;
158 Ok(private_key)
159 }
160
161 /// Multialg variant of `derive_cdi_leaf_priv`.
162 #[cfg(feature = "multialg")]
derive_cdi_leaf_priv_multialg( dice_artifacts: &dyn DiceArtifacts, key_algorithm: KeyAlgorithm, ) -> Result<PrivateKey>163 pub fn derive_cdi_leaf_priv_multialg(
164 dice_artifacts: &dyn DiceArtifacts,
165 key_algorithm: KeyAlgorithm,
166 ) -> Result<PrivateKey> {
167 let cdi_priv_key_seed = derive_cdi_private_key_seed(dice_artifacts.cdi_attest())?;
168 let (_, private_key) = keypair_from_seed_multialg(cdi_priv_key_seed.as_array(), key_algorithm)?;
169 Ok(private_key)
170 }
171
172 /// Signs the `message` with the given `private_key` using `DiceSign`.
sign(message: &[u8], private_key: &[u8; PRIVATE_KEY_SIZE]) -> Result<Vec<u8>>173 pub fn sign(message: &[u8], private_key: &[u8; PRIVATE_KEY_SIZE]) -> Result<Vec<u8>> {
174 let mut signature = vec![0u8; VM_KEY_ALGORITHM.signature_size()];
175 check_result(
176 // SAFETY: The function writes to the `signature` within the given bounds, and only reads
177 // the message and the private key.
178 // The first argument is a pointer to a valid |DiceContext_| object for multi-alg open-dice
179 // and a null pointer otherwise.
180 unsafe {
181 DiceSign(
182 context(),
183 message.as_ptr(),
184 message.len(),
185 private_key.as_ptr(),
186 signature.as_mut_ptr(),
187 )
188 },
189 signature.len(),
190 )?;
191 Ok(signature)
192 }
193
194 /// Signs the `message` with the given `private_key` and places a `CoseSign1` encoded
195 /// object in `encoded_signature`. Uses `DiceCoseSignAndEncodeSign1`.
196 ///
197 /// Returns the actual size of encoded_signature on success.
sign_cose_sign1( message: &[u8], aad: &[u8], private_key: &[u8; PRIVATE_KEY_SIZE], encoded_signature: &mut [u8], ) -> Result<usize>198 pub fn sign_cose_sign1(
199 message: &[u8],
200 aad: &[u8],
201 private_key: &[u8; PRIVATE_KEY_SIZE],
202 encoded_signature: &mut [u8],
203 ) -> Result<usize> {
204 let mut encoded_signature_actual_size = 0;
205
206 check_result(
207 // SAFETY: The function writes to `encoded_signature` and `encoded_signature_actual_size`
208 // within the given bounds. It only reads `message`, `aad`, and `private_key` within their
209 // given bounds.
210 //
211 // The first argument is a pointer to a valid |DiceContext_| object for multi-alg open-dice
212 // and a null pointer otherwise.
213 unsafe {
214 DiceCoseSignAndEncodeSign1(
215 context(),
216 message.as_ptr(),
217 message.len(),
218 aad.as_ptr(),
219 aad.len(),
220 private_key.as_ptr(),
221 encoded_signature.len(),
222 encoded_signature.as_mut_ptr(),
223 &mut encoded_signature_actual_size,
224 )
225 },
226 encoded_signature_actual_size,
227 )?;
228 Ok(encoded_signature_actual_size)
229 }
230
231 /// Multialg variant of `sign_cose_sign1`.
232 #[cfg(feature = "multialg")]
sign_cose_sign1_multialg( message: &[u8], aad: &[u8], private_key: &[u8; PRIVATE_KEY_SIZE], encoded_signature: &mut [u8], key_algorithm: KeyAlgorithm, ) -> Result<usize>233 pub fn sign_cose_sign1_multialg(
234 message: &[u8],
235 aad: &[u8],
236 private_key: &[u8; PRIVATE_KEY_SIZE],
237 encoded_signature: &mut [u8],
238 key_algorithm: KeyAlgorithm,
239 ) -> Result<usize> {
240 let mut encoded_signature_actual_size = 0;
241 let context = DiceContext_ {
242 authority_algorithm: key_algorithm.into(),
243 subject_algorithm: key_algorithm.into(),
244 };
245 check_result(
246 // SAFETY: The function writes to `encoded_signature` and `encoded_signature_actual_size`
247 // within the given bounds. It only reads `message`, `aad`, and `private_key` within their
248 // given bounds.
249 //
250 // The first argument is a pointer to a valid |DiceContext_| object for multi-alg
251 // open-dice.
252 unsafe {
253 DiceCoseSignAndEncodeSign1(
254 &context as *const DiceContext_ as *mut c_void,
255 message.as_ptr(),
256 message.len(),
257 aad.as_ptr(),
258 aad.len(),
259 private_key.as_ptr(),
260 encoded_signature.len(),
261 encoded_signature.as_mut_ptr(),
262 &mut encoded_signature_actual_size,
263 )
264 },
265 encoded_signature_actual_size,
266 )?;
267 Ok(encoded_signature_actual_size)
268 }
269
270 /// Signs the `message` with a private key derived from the given `dice_artifacts`
271 /// CDI Attest. On success, places a `CoseSign1` encoded object in `encoded_signature`.
272 /// Uses `DiceCoseSignAndEncodeSign1`.
273 ///
274 /// Returns the actual size of encoded_signature on success.
sign_cose_sign1_with_cdi_leaf_priv( message: &[u8], aad: &[u8], dice_artifacts: &dyn DiceArtifacts, encoded_signature: &mut [u8], ) -> Result<usize>275 pub fn sign_cose_sign1_with_cdi_leaf_priv(
276 message: &[u8],
277 aad: &[u8],
278 dice_artifacts: &dyn DiceArtifacts,
279 encoded_signature: &mut [u8],
280 ) -> Result<usize> {
281 let private_key = derive_cdi_leaf_priv(dice_artifacts)?;
282 sign_cose_sign1(message, aad, private_key.as_array(), encoded_signature)
283 }
284
285 /// Multialg variant of `sign_cose_sign1_with_cdi_leaf_priv`.
286 #[cfg(feature = "multialg")]
sign_cose_sign1_with_cdi_leaf_priv_multialg( message: &[u8], aad: &[u8], dice_artifacts: &dyn DiceArtifacts, encoded_signature: &mut [u8], key_algorithm: KeyAlgorithm, ) -> Result<usize>287 pub fn sign_cose_sign1_with_cdi_leaf_priv_multialg(
288 message: &[u8],
289 aad: &[u8],
290 dice_artifacts: &dyn DiceArtifacts,
291 encoded_signature: &mut [u8],
292 key_algorithm: KeyAlgorithm,
293 ) -> Result<usize> {
294 let private_key = derive_cdi_leaf_priv_multialg(dice_artifacts, key_algorithm)?;
295 sign_cose_sign1_multialg(message, aad, private_key.as_array(), encoded_signature, key_algorithm)
296 }
297
298 /// Verifies the `signature` of the `message` with the given `public_key` using `DiceVerify`.
verify(message: &[u8], signature: &[u8], public_key: &[u8]) -> Result<()>299 pub fn verify(message: &[u8], signature: &[u8], public_key: &[u8]) -> Result<()> {
300 if signature.len() != VM_KEY_ALGORITHM.signature_size()
301 || public_key.len() != VM_KEY_ALGORITHM.public_key_size()
302 {
303 return Err(DiceError::InvalidInput);
304 }
305 check_result(
306 // SAFETY: only reads the messages, signature and public key as constant values.
307 // The first argument is a pointer to a valid |DiceContext_| object for multi-alg open-dice
308 // and a null pointer otherwise.
309 unsafe {
310 DiceVerify(
311 context(),
312 message.as_ptr(),
313 message.len(),
314 signature.as_ptr(),
315 public_key.as_ptr(),
316 )
317 },
318 0,
319 )
320 }
321
322 /// Multialg variant of `verify`.
323 #[cfg(feature = "multialg")]
verify_multialg( message: &[u8], signature: &[u8], public_key: &[u8], key_algorithm: KeyAlgorithm, ) -> Result<()>324 pub fn verify_multialg(
325 message: &[u8],
326 signature: &[u8],
327 public_key: &[u8],
328 key_algorithm: KeyAlgorithm,
329 ) -> Result<()> {
330 if signature.len() != key_algorithm.signature_size()
331 || public_key.len() != key_algorithm.public_key_size()
332 {
333 return Err(DiceError::InvalidInput);
334 }
335 let context = DiceContext_ {
336 authority_algorithm: key_algorithm.into(),
337 subject_algorithm: key_algorithm.into(),
338 };
339 check_result(
340 // SAFETY: only reads the messages, signature and public key as constant values.
341 // The first argument is a pointer to a valid |DiceContext_| object for multi-alg
342 // open-dice.
343 unsafe {
344 DiceVerify(
345 &context as *const DiceContext_ as *mut c_void,
346 message.as_ptr(),
347 message.len(),
348 signature.as_ptr(),
349 public_key.as_ptr(),
350 )
351 },
352 0,
353 )
354 }
355
356 /// Generates an X.509 certificate from the given `subject_private_key_seed` and
357 /// `input_values`, and signed by `authority_private_key_seed`.
358 /// The subject private key seed is supplied here so the implementation can choose
359 /// between asymmetric mechanisms, for example ECDSA vs Ed25519.
360 /// Returns the actual size of the generated certificate.
generate_certificate( subject_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE], authority_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE], input_values: &InputValues, certificate: &mut [u8], ) -> Result<usize>361 pub fn generate_certificate(
362 subject_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE],
363 authority_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE],
364 input_values: &InputValues,
365 certificate: &mut [u8],
366 ) -> Result<usize> {
367 let mut certificate_actual_size = 0;
368 check_result(
369 // SAFETY: The function writes to the `certificate` within the given bounds, and only reads
370 // the input values and the key seeds.
371 // The first argument is a pointer to a valid |DiceContext_| object for multi-alg open-dice
372 // and a null pointer otherwise.
373 unsafe {
374 DiceGenerateCertificate(
375 context(),
376 subject_private_key_seed.as_ptr(),
377 authority_private_key_seed.as_ptr(),
378 input_values.as_ptr(),
379 certificate.len(),
380 certificate.as_mut_ptr(),
381 &mut certificate_actual_size,
382 )
383 },
384 certificate_actual_size,
385 )?;
386 Ok(certificate_actual_size)
387 }
388