blob: 1b07e61817689c94679f8b3ea73e856bd015ef44 [file] [log] [blame]
Janis Danisevskis13356b22021-10-20 09:44:12 -07001// Copyright 2021, 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//! Implements safe wrappers around the public API of libopen-dice.
16//! ## Example:
17//! ```
18//! use diced_open_dice_cbor as dice;
19//!
20//! let context = dice::dice::OpenDiceCborContext::new()
21//! let parent_cdi_attest = [1u8, dice::CDI_SIZE];
22//! let parent_cdi_seal = [2u8, dice::CDI_SIZE];
23//! let input_values = dice::InputValuesOwned {
24//! code_hash: [3u8, dice::HASH_SIZE],
25//! config: dice::ConfigOwned::Descriptor("My descriptor".as_bytes().to_vec()),
26//! authority_hash: [0u8, dice::HASH_SIZE],
27//! mode: dice::Mode::Normal,
28//! hidden: [0u8, dice::HIDDEN_SIZE],
29//! };
30//! let (cdi_attest, cdi_seal, cert_chain) = context
31//! .main_flow(&parent_cdi_attest, &parent_cdi_seal, &input_values)?;
32//! ```
33
34use keystore2_crypto::{zvec, ZVec};
Janis Danisevskis2cef73f2021-11-03 15:02:48 -070035use open_dice_bcc_bindgen::BccMainFlow;
Janis Danisevskis13356b22021-10-20 09:44:12 -070036use open_dice_cbor_bindgen::{
37 DiceConfigType, DiceDeriveCdiCertificateId, DiceDeriveCdiPrivateKeySeed,
38 DiceGenerateCertificate, DiceHash, DiceInputValues, DiceKdf, DiceKeypairFromSeed, DiceMainFlow,
39 DiceMode, DiceResult, DiceSign, DiceVerify, DICE_CDI_SIZE, DICE_HASH_SIZE, DICE_HIDDEN_SIZE,
40 DICE_ID_SIZE, DICE_INLINE_CONFIG_SIZE, DICE_PRIVATE_KEY_SEED_SIZE, DICE_PRIVATE_KEY_SIZE,
41 DICE_PUBLIC_KEY_SIZE, DICE_SIGNATURE_SIZE,
42};
43use open_dice_cbor_bindgen::{
44 DiceConfigType_kDiceConfigTypeDescriptor as DICE_CONFIG_TYPE_DESCRIPTOR,
45 DiceConfigType_kDiceConfigTypeInline as DICE_CONFIG_TYPE_INLINE,
46 DiceMode_kDiceModeDebug as DICE_MODE_DEBUG,
47 DiceMode_kDiceModeMaintenance as DICE_MODE_RECOVERY,
48 DiceMode_kDiceModeNormal as DICE_MODE_NORMAL,
49 DiceMode_kDiceModeNotInitialized as DICE_MODE_NOT_CONFIGURED,
50 DiceResult_kDiceResultBufferTooSmall as DICE_RESULT_BUFFER_TOO_SMALL,
51 DiceResult_kDiceResultInvalidInput as DICE_RESULT_INVALID_INPUT,
52 DiceResult_kDiceResultOk as DICE_RESULT_OK,
53 DiceResult_kDiceResultPlatformError as DICE_RESULT_PLATFORM_ERROR,
54};
Janis Danisevskis2cef73f2021-11-03 15:02:48 -070055use std::ffi::{c_void, NulError};
Janis Danisevskis13356b22021-10-20 09:44:12 -070056
57/// The size of a DICE hash.
58pub const HASH_SIZE: usize = DICE_HASH_SIZE as usize;
59/// The size of the DICE hidden value.
60pub const HIDDEN_SIZE: usize = DICE_HIDDEN_SIZE as usize;
61/// The size of a DICE inline config.
62pub const INLINE_CONFIG_SIZE: usize = DICE_INLINE_CONFIG_SIZE as usize;
63/// The size of a private key seed.
64pub const PRIVATE_KEY_SEED_SIZE: usize = DICE_PRIVATE_KEY_SEED_SIZE as usize;
65/// The size of a CDI.
66pub const CDI_SIZE: usize = DICE_CDI_SIZE as usize;
67/// The size of an ID.
68pub const ID_SIZE: usize = DICE_ID_SIZE as usize;
69/// The size of a private key.
70pub const PRIVATE_KEY_SIZE: usize = DICE_PRIVATE_KEY_SIZE as usize;
71/// The size of a public key.
72pub const PUBLIC_KEY_SIZE: usize = DICE_PUBLIC_KEY_SIZE as usize;
73/// The size of a signature.
74pub const SIGNATURE_SIZE: usize = DICE_SIGNATURE_SIZE as usize;
75
76/// Open dice wrapper error type.
77#[derive(Debug, thiserror::Error, PartialEq)]
78pub enum Error {
79 /// The libopen-dice backend reported InvalidInput.
80 #[error("Open dice backend: Invalid input")]
81 InvalidInput,
82 /// The libopen-dice backend reported BufferTooSmall.
83 #[error("Open dice backend: Buffer too small")]
84 BufferTooSmall,
85 /// The libopen-dice backend reported PlatformError.
86 #[error("Open dice backend: Platform error")]
87 PlatformError,
88 /// The libopen-dice backend reported an error that is outside of the defined range of errors.
89 /// The returned error code is embedded in this value.
90 #[error("Open dice backend returned an unexpected error code: {0:?}")]
91 Unexpected(u32),
92
93 /// The allocation of a ZVec failed. Most likely due to a failure during the call to mlock.
94 #[error("ZVec allocation failed")]
95 ZVec(#[from] zvec::Error),
Janis Danisevskis2cef73f2021-11-03 15:02:48 -070096
97 /// Functions that have to convert str to CString may fail if the string has an interior
98 /// nul byte.
99 #[error("Input string has an interior nul byte.")]
100 CStrNulError(#[from] NulError),
Janis Danisevskis13356b22021-10-20 09:44:12 -0700101}
102
103/// Open dice result type.
104pub type Result<T> = std::result::Result<T, Error>;
105
106impl From<DiceResult> for Error {
107 fn from(result: DiceResult) -> Self {
108 match result {
109 DICE_RESULT_INVALID_INPUT => Error::InvalidInput,
110 DICE_RESULT_BUFFER_TOO_SMALL => Error::BufferTooSmall,
111 DICE_RESULT_PLATFORM_ERROR => Error::PlatformError,
112 r => Error::Unexpected(r),
113 }
114 }
115}
116
117fn check_result(result: DiceResult) -> Result<()> {
118 if result == DICE_RESULT_OK {
119 Ok(())
120 } else {
121 Err(result.into())
122 }
123}
124
125/// Configuration descriptor for dice input values.
126#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
127pub enum Config<'a> {
128 /// A reference to an inline descriptor.
129 Inline(&'a [u8; INLINE_CONFIG_SIZE]),
130 /// A reference to a free form descriptor that will be hashed by the implementation.
131 Descriptor(&'a [u8]),
132}
133
134enum ConfigOwned {
135 Inline([u8; INLINE_CONFIG_SIZE]),
136 Descriptor(Vec<u8>),
137}
138
139impl Config<'_> {
140 fn get_type(&self) -> DiceConfigType {
141 match self {
142 Self::Inline(_) => DICE_CONFIG_TYPE_INLINE,
143 Self::Descriptor(_) => DICE_CONFIG_TYPE_DESCRIPTOR,
144 }
145 }
146
147 fn get_inline(&self) -> [u8; INLINE_CONFIG_SIZE] {
148 match self {
149 Self::Inline(inline) => **inline,
150 _ => [0u8; INLINE_CONFIG_SIZE],
151 }
152 }
153
154 fn get_descriptor_as_ptr(&self) -> *const u8 {
155 match self {
156 Self::Descriptor(descriptor) => descriptor.as_ptr(),
157 _ => std::ptr::null(),
158 }
159 }
160
161 fn get_descriptor_size(&self) -> usize {
162 match self {
163 Self::Descriptor(descriptor) => descriptor.len(),
164 _ => 0,
165 }
166 }
167}
168
169impl From<Config<'_>> for ConfigOwned {
170 fn from(config: Config) -> Self {
171 match config {
172 Config::Inline(inline) => ConfigOwned::Inline(*inline),
173 Config::Descriptor(descriptor) => ConfigOwned::Descriptor(descriptor.to_owned()),
174 }
175 }
176}
177
178/// DICE modes as defined here:
179/// https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/specification.md#mode-value-details
180#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
181pub enum Mode {
182 /// See documentation linked above.
183 NotConfigured = 0,
184 /// See documentation linked above.
185 Normal = 1,
186 /// See documentation linked above.
187 Debug = 2,
188 /// See documentation linked above.
189 Recovery = 3,
190}
191
192impl Mode {
193 fn get_internal(&self) -> DiceMode {
194 match self {
195 Self::NotConfigured => DICE_MODE_NOT_CONFIGURED,
196 Self::Normal => DICE_MODE_NORMAL,
197 Self::Debug => DICE_MODE_DEBUG,
198 Self::Recovery => DICE_MODE_RECOVERY,
199 }
200 }
201}
202
203/// This trait allows API users to supply DICE input values without copying.
204pub trait InputValues {
205 /// Returns the code hash.
206 fn code_hash(&self) -> &[u8; HASH_SIZE];
207 /// Returns the config.
208 fn config(&self) -> Config;
209 /// Returns the authority hash.
210 fn authority_hash(&self) -> &[u8; HASH_SIZE];
211 /// Returns the authority descriptor.
212 fn authority_descriptor(&self) -> Option<&[u8]>;
213 /// Returns the mode.
214 fn mode(&self) -> Mode;
215 /// Returns the hidden value.
216 fn hidden(&self) -> &[u8; HIDDEN_SIZE];
217}
218
219/// An owning convenience type implementing `InputValues`.
220pub struct InputValuesOwned {
221 code_hash: [u8; HASH_SIZE],
222 config: ConfigOwned,
223 authority_hash: [u8; HASH_SIZE],
224 authority_descriptor: Option<Vec<u8>>,
225 mode: Mode,
226 hidden: [u8; HIDDEN_SIZE],
227}
228
229impl InputValuesOwned {
230 /// Construct a new instance of InputValuesOwned.
231 pub fn new(
232 code_hash: [u8; HASH_SIZE],
233 config: Config,
234 authority_hash: [u8; HASH_SIZE],
235 authority_descriptor: Option<Vec<u8>>,
236 mode: Mode,
237 hidden: [u8; HIDDEN_SIZE],
238 ) -> Self {
239 Self {
240 code_hash,
241 config: config.into(),
242 authority_hash,
243 authority_descriptor,
244 mode,
245 hidden,
246 }
247 }
248}
249
250impl InputValues for InputValuesOwned {
251 fn code_hash(&self) -> &[u8; HASH_SIZE] {
252 &self.code_hash
253 }
254 fn config(&self) -> Config {
255 match &self.config {
256 ConfigOwned::Inline(inline) => Config::Inline(inline),
257 ConfigOwned::Descriptor(descriptor) => Config::Descriptor(descriptor.as_slice()),
258 }
259 }
260 fn authority_hash(&self) -> &[u8; HASH_SIZE] {
261 &self.authority_hash
262 }
263 fn authority_descriptor(&self) -> Option<&[u8]> {
264 self.authority_descriptor.as_deref()
265 }
266 fn mode(&self) -> Mode {
267 self.mode
268 }
269 fn hidden(&self) -> &[u8; HIDDEN_SIZE] {
270 &self.hidden
271 }
272}
273
274fn call_with_input_values<T: InputValues + ?Sized, F, R>(input_values: &T, f: F) -> Result<R>
275where
276 F: FnOnce(*const DiceInputValues) -> Result<R>,
277{
278 let input_values = DiceInputValues {
279 code_hash: *input_values.code_hash(),
280 code_descriptor: std::ptr::null(),
281 code_descriptor_size: 0,
282 config_type: input_values.config().get_type(),
283 config_value: input_values.config().get_inline(),
284 config_descriptor: input_values.config().get_descriptor_as_ptr(),
285 config_descriptor_size: input_values.config().get_descriptor_size(),
286 authority_hash: *input_values.authority_hash(),
287 authority_descriptor: input_values
288 .authority_descriptor()
289 .map_or_else(std::ptr::null, <[u8]>::as_ptr),
290 authority_descriptor_size: input_values.authority_descriptor().map_or(0, <[u8]>::len),
291 mode: input_values.mode().get_internal(),
292 hidden: *input_values.hidden(),
293 };
294
295 f(&input_values as *const DiceInputValues)
296}
297
298/// Multiple of the open dice function required preallocated output buffer
299/// which may be too small, this function implements the retry logic to handle
300/// too small buffer allocations.
301/// The callback `F` must expect a mutable reference to a buffer and a size hint
302/// field. The callback is called repeatedly as long as it returns
303/// `Err(Error::BufferTooSmall)`. If the size hint remains 0, the buffer size is
304/// doubled with each iteration. If the size hint is set by the callback, the buffer
305/// will be set to accommodate at least this many bytes.
306/// If the callback returns `Ok(())`, the buffer is truncated to the size hint
307/// exactly.
308/// The function panics if the callback returns `Ok(())` and the size hint is
309/// larger than the buffer size.
310fn retry_while_adjusting_output_buffer<F>(mut f: F) -> Result<Vec<u8>>
311where
312 F: FnMut(&mut Vec<u8>, &mut usize) -> Result<()>,
313{
314 let mut buffer = vec![0; INITIAL_OUT_BUFFER_SIZE];
315 let mut actual_size: usize = 0;
316 loop {
317 match f(&mut buffer, &mut actual_size) {
318 // If Error::BufferTooSmall was returned, the allocated certificate
319 // buffer was to small for the output. So the buffer is resized to the actual
320 // size, and a second attempt is made with the new buffer.
321 Err(Error::BufferTooSmall) => {
322 let new_size = if actual_size == 0 {
323 // Due to an off spec implementation of open dice cbor, actual size
324 // does not return the required size if the buffer was too small. So
325 // we have to try and approach it gradually.
326 buffer.len() * 2
327 } else {
328 actual_size
329 };
330 buffer.resize(new_size, 0);
331 continue;
332 }
333 Err(e) => return Err(e),
334 Ok(()) => {
335 if actual_size > buffer.len() {
336 panic!(
337 "actual_size larger than buffer size: open-dice function
338 may have written past the end of the buffer."
339 );
340 }
341 // Truncate the certificate buffer to the actual size because it may be
342 // smaller than the original allocation.
343 buffer.truncate(actual_size);
344 return Ok(buffer);
345 }
346 }
347 }
348}
349
350/// Some libopen-dice variants use a context. Developers that want to customize these
351/// bindings may want to implement their own Context factory that creates a context
352/// useable by their preferred backend.
353pub trait Context {
354 /// # Safety
355 /// The return value of get_context is passed to any open dice function.
356 /// Implementations must explain why the context pointer returned is safe
357 /// to be used by the open dice library.
358 unsafe fn get_context(&mut self) -> *mut c_void;
359}
360
361impl<T: Context + Send> ContextImpl for T {}
362
363/// This represents a context for the open dice library. The wrapped open dice instance, which
364/// is based on boringssl and cbor, does not use a context, so that this type is empty.
365#[derive(Default)]
366pub struct OpenDiceCborContext();
367
368impl OpenDiceCborContext {
369 /// Construct a new instance of OpenDiceCborContext.
370 pub fn new() -> Self {
371 Default::default()
372 }
373}
374
375impl Context for OpenDiceCborContext {
376 unsafe fn get_context(&mut self) -> *mut c_void {
377 // # Safety
378 // The open dice cbor implementation does not use a context. It is safe
379 // to return NULL.
380 std::ptr::null_mut()
381 }
382}
383
384/// Type alias for ZVec indicating that it holds a CDI_ATTEST secret.
385pub type CdiAttest = ZVec;
386
387/// Type alias for ZVec indicating that it holds a CDI_SEAL secret.
388pub type CdiSeal = ZVec;
389
390/// Type alias for Vec<u8> indicating that it hold a DICE certificate.
391pub type Cert = Vec<u8>;
392
Janis Danisevskis2cef73f2021-11-03 15:02:48 -0700393/// Type alias for Vec<u8> indicating that it holds a BCC certificate chain.
394pub type Bcc = Vec<u8>;
395
Janis Danisevskis13356b22021-10-20 09:44:12 -0700396const INITIAL_OUT_BUFFER_SIZE: usize = 1024;
397
398/// ContextImpl is a mixin trait that implements the safe wrappers around the open dice
399/// library calls. Implementations must implement Context::get_context(). As of
400/// this writing, the only implementation is OpenDiceCborContext, which returns NULL.
401pub trait ContextImpl: Context + Send {
402 /// Safe wrapper around open-dice DiceDeriveCdiPrivateKeySeed, see open dice
403 /// documentation for details.
404 fn derive_cdi_private_key_seed(&mut self, cdi_attest: &[u8; CDI_SIZE]) -> Result<ZVec> {
405 let mut seed = ZVec::new(PRIVATE_KEY_SEED_SIZE)?;
406 // SAFETY:
407 // * The first context argument may be NULL and is unused by the wrapped
408 // implementation.
409 // * The second argument is expected to be a const array of size CDI_SIZE.
410 // * The third argument is expected to be a non const array of size
411 // PRIVATE_KEY_SEED_SIZE which is fulfilled if the call to ZVec::new above
412 // succeeds.
413 // * No pointers are expected to be valid beyond the scope of the function
414 // call.
415 check_result(unsafe {
416 DiceDeriveCdiPrivateKeySeed(self.get_context(), cdi_attest.as_ptr(), seed.as_mut_ptr())
417 })?;
418 Ok(seed)
419 }
420
421 /// Safe wrapper around open-dice DiceDeriveCdiCertificateId, see open dice
422 /// documentation for details.
423 fn derive_cdi_certificate_id(&mut self, cdi_public_key: &[u8]) -> Result<ZVec> {
424 let mut id = ZVec::new(ID_SIZE)?;
425 // SAFETY:
426 // * The first context argument may be NULL and is unused by the wrapped
427 // implementation.
428 // * The second argument is expected to be a const array with a size given by the
429 // third argument.
430 // * The fourth argument is expected to be a non const array of size
431 // ID_SIZE which is fulfilled if the call to ZVec::new above succeeds.
432 // * No pointers are expected to be valid beyond the scope of the function
433 // call.
434 check_result(unsafe {
435 DiceDeriveCdiCertificateId(
436 self.get_context(),
437 cdi_public_key.as_ptr(),
438 cdi_public_key.len(),
439 id.as_mut_ptr(),
440 )
441 })?;
442 Ok(id)
443 }
444
445 /// Safe wrapper around open-dice DiceMainFlow, see open dice
446 /// documentation for details.
447 /// Returns a tuple of:
448 /// * The next attestation CDI,
449 /// * the next seal CDI, and
450 /// * the next attestation certificate.
451 /// `(next_attest_cdi, next_seal_cdi, next_attestation_cert)`
452 fn main_flow<T: InputValues + ?Sized>(
453 &mut self,
454 current_cdi_attest: &[u8; CDI_SIZE],
455 current_cdi_seal: &[u8; CDI_SIZE],
456 input_values: &T,
457 ) -> Result<(CdiAttest, CdiSeal, Cert)> {
458 let mut next_attest = CdiAttest::new(CDI_SIZE)?;
459 let mut next_seal = CdiSeal::new(CDI_SIZE)?;
460
461 // SAFETY (DiceMainFlow):
462 // * The first context argument may be NULL and is unused by the wrapped
463 // implementation.
464 // * The second argument and the third argument are const arrays of size CDI_SIZE.
465 // This is fulfilled as per the definition of the arguments `current_cdi_attest`
466 // and `current_cdi_seal.
467 // * The fourth argument is a pointer to `DiceInputValues`. It, and its indirect
468 // references must be valid for the duration of the function call which
469 // is guaranteed by `call_with_input_values` which puts `DiceInputValues`
470 // on the stack and initializes it from the `input_values` argument which
471 // implements the `InputValues` trait.
472 // * The fifth and sixth argument are the length of and the pointer to the
473 // allocated certificate buffer respectively. They are used to return
474 // the generated certificate.
475 // * The seventh argument is a pointer to a mutable usize object. It is
476 // used to return the actual size of the output certificate.
477 // * The eighth argument and the ninth argument are pointers to mutable buffers of size
478 // CDI_SIZE. This is fulfilled if the allocation above succeeded.
479 // * No pointers are expected to be valid beyond the scope of the function
480 // call.
481 call_with_input_values(input_values, |input_values| {
482 let cert = retry_while_adjusting_output_buffer(|cert, actual_size| {
483 check_result(unsafe {
484 DiceMainFlow(
485 self.get_context(),
486 current_cdi_attest.as_ptr(),
487 current_cdi_seal.as_ptr(),
488 input_values,
489 cert.len(),
490 cert.as_mut_ptr(),
491 actual_size as *mut _,
492 next_attest.as_mut_ptr(),
493 next_seal.as_mut_ptr(),
494 )
495 })
496 })?;
497 Ok((next_attest, next_seal, cert))
498 })
499 }
500
501 /// Safe wrapper around open-dice DiceHash, see open dice
502 /// documentation for details.
503 fn hash(&mut self, input: &[u8]) -> Result<Vec<u8>> {
504 let mut output: Vec<u8> = vec![0; HASH_SIZE];
505
506 // SAFETY:
507 // * The first context argument may be NULL and is unused by the wrapped
508 // implementation.
509 // * The second argument and the third argument are the pointer to and length of the given
510 // input buffer respectively.
511 // * The fourth argument must be a pointer to a mutable buffer of size HASH_SIZE
512 // which is fulfilled by the allocation above.
513 check_result(unsafe {
514 DiceHash(self.get_context(), input.as_ptr(), input.len(), output.as_mut_ptr())
515 })?;
516 Ok(output)
517 }
518
519 /// Safe wrapper around open-dice DiceKdf, see open dice
520 /// documentation for details.
521 fn kdf(&mut self, length: usize, input_key: &[u8], salt: &[u8], info: &[u8]) -> Result<ZVec> {
522 let mut output = ZVec::new(length)?;
523
524 // SAFETY:
525 // * The first context argument may be NULL and is unused by the wrapped
526 // implementation.
527 // * The second argument is primitive.
528 // * The third argument and the fourth argument are the pointer to and length of the given
529 // input key.
530 // * The fifth argument and the sixth argument are the pointer to and length of the given
531 // salt.
532 // * The seventh argument and the eighth argument are the pointer to and length of the
533 // given info field.
534 // * The ninth argument is a pointer to the output buffer which must have the
535 // length given by the `length` argument (see second argument). This is
536 // fulfilled if the allocation of `output` succeeds.
537 // * All pointers must be valid for the duration of the function call, but not
538 // longer.
539 check_result(unsafe {
540 DiceKdf(
541 self.get_context(),
542 length,
543 input_key.as_ptr(),
544 input_key.len(),
545 salt.as_ptr(),
546 salt.len(),
547 info.as_ptr(),
548 info.len(),
549 output.as_mut_ptr(),
550 )
551 })?;
552 Ok(output)
553 }
554
555 /// Safe wrapper around open-dice DiceKeyPairFromSeed, see open dice
556 /// documentation for details.
557 fn keypair_from_seed(&mut self, seed: &[u8; PRIVATE_KEY_SEED_SIZE]) -> Result<(Vec<u8>, ZVec)> {
558 let mut private_key = ZVec::new(PRIVATE_KEY_SIZE)?;
559 let mut public_key = vec![0u8; PUBLIC_KEY_SIZE];
560
561 // SAFETY:
562 // * The first context argument may be NULL and is unused by the wrapped
563 // implementation.
564 // * The second argument is a pointer to a const buffer of size `PRIVATE_KEY_SEED_SIZE`
565 // fulfilled by the definition of the argument.
566 // * The third argument and the fourth argument are mutable buffers of size
567 // `PRIVATE_KEY_SIZE` and `PUBLIC_KEY_SIZE` respectively. This is fulfilled by the
568 // allocations above.
569 // * All pointers must be valid for the duration of the function call but not beyond.
570 check_result(unsafe {
571 DiceKeypairFromSeed(
572 self.get_context(),
573 seed.as_ptr(),
574 public_key.as_mut_ptr(),
575 private_key.as_mut_ptr(),
576 )
577 })?;
578 Ok((public_key, private_key))
579 }
580
581 /// Safe wrapper around open-dice DiceSign, see open dice
582 /// documentation for details.
583 fn sign(&mut self, message: &[u8], private_key: &[u8; PRIVATE_KEY_SIZE]) -> Result<Vec<u8>> {
584 let mut signature = vec![0u8; SIGNATURE_SIZE];
585
586 // SAFETY:
587 // * The first context argument may be NULL and is unused by the wrapped
588 // implementation.
589 // * The second argument and the third argument are the pointer to and length of the given
590 // message buffer.
591 // * The fourth argument is a const buffer of size `PRIVATE_KEY_SIZE`. This is fulfilled
592 // by the definition of `private key`.
593 // * The fifth argument is mutable buffer of size `SIGNATURE_SIZE`. This is fulfilled
594 // by the allocation above.
595 // * All pointers must be valid for the duration of the function call but not beyond.
596 check_result(unsafe {
597 DiceSign(
598 self.get_context(),
599 message.as_ptr(),
600 message.len(),
601 private_key.as_ptr(),
602 signature.as_mut_ptr(),
603 )
604 })?;
605 Ok(signature)
606 }
607
608 /// Safe wrapper around open-dice DiceVerify, see open dice
609 /// documentation for details.
610 fn verify(
611 &mut self,
612 message: &[u8],
613 signature: &[u8; SIGNATURE_SIZE],
614 public_key: &[u8; PUBLIC_KEY_SIZE],
615 ) -> Result<()> {
616 // SAFETY:
617 // * The first context argument may be NULL and is unused by the wrapped
618 // implementation.
619 // * The second argument and the third argument are the pointer to and length of the given
620 // message buffer.
621 // * The fourth argument is a const buffer of size `SIGNATURE_SIZE`. This is fulfilled
622 // by the definition of `signature`.
623 // * The fifth argument is a const buffer of size `PUBLIC_KEY_SIZE`. This is fulfilled
624 // by the definition of `public_key`.
625 // * All pointers must be valid for the duration of the function call but not beyond.
626 check_result(unsafe {
627 DiceVerify(
628 self.get_context(),
629 message.as_ptr(),
630 message.len(),
631 signature.as_ptr(),
632 public_key.as_ptr(),
633 )
634 })
635 }
636
637 /// Safe wrapper around open-dice DiceGenerateCertificate, see open dice
638 /// documentation for details.
639 fn generate_certificate<T: InputValues>(
640 &mut self,
641 subject_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE],
642 authority_private_key_seed: &[u8; PRIVATE_KEY_SEED_SIZE],
643 input_values: &T,
644 ) -> Result<Vec<u8>> {
645 // SAFETY (DiceMainFlow):
646 // * The first context argument may be NULL and is unused by the wrapped
647 // implementation.
648 // * The second argument and the third argument are const arrays of size
649 // `PRIVATE_KEY_SEED_SIZE`. This is fulfilled as per the definition of the arguments.
650 // * The fourth argument is a pointer to `DiceInputValues` it, and its indirect
651 // references must be valid for the duration of the function call which
652 // is guaranteed by `call_with_input_values` which puts `DiceInputValues`
653 // on the stack and initializes it from the `input_values` argument which
654 // implements the `InputValues` trait.
655 // * The fifth argument and the sixth argument are the length of and the pointer to the
656 // allocated certificate buffer respectively. They are used to return
657 // the generated certificate.
Janis Danisevskis2cef73f2021-11-03 15:02:48 -0700658 // * The seventh argument is a pointer to a mutable usize object. It is
Janis Danisevskis13356b22021-10-20 09:44:12 -0700659 // used to return the actual size of the output certificate.
660 // * All pointers must be valid for the duration of the function call but not beyond.
661 call_with_input_values(input_values, |input_values| {
662 let cert = retry_while_adjusting_output_buffer(|cert, actual_size| {
663 check_result(unsafe {
664 DiceGenerateCertificate(
665 self.get_context(),
666 subject_private_key_seed.as_ptr(),
667 authority_private_key_seed.as_ptr(),
668 input_values,
Janis Danisevskis2cef73f2021-11-03 15:02:48 -0700669 cert.len(),
Janis Danisevskis13356b22021-10-20 09:44:12 -0700670 cert.as_mut_ptr(),
671 actual_size as *mut _,
672 )
673 })
674 })?;
675 Ok(cert)
676 })
677 }
Janis Danisevskis2cef73f2021-11-03 15:02:48 -0700678
679 /// Safe wrapper around open-dice BccDiceMainFlow, see open dice
680 /// documentation for details.
681 /// Returns a tuple of:
682 /// * The next attestation CDI,
683 /// * the next seal CDI, and
684 /// * the next bcc adding the new certificate to the given bcc.
685 /// `(next_attest_cdi, next_seal_cdi, next_bcc)`
686 fn bcc_main_flow<T: InputValues + ?Sized>(
687 &mut self,
688 current_cdi_attest: &[u8; CDI_SIZE],
689 current_cdi_seal: &[u8; CDI_SIZE],
690 bcc: &[u8],
691 input_values: &T,
692 ) -> Result<(CdiAttest, CdiSeal, Bcc)> {
693 let mut next_attest = CdiAttest::new(CDI_SIZE)?;
694 let mut next_seal = CdiSeal::new(CDI_SIZE)?;
695
696 // SAFETY (BccMainFlow):
697 // * The first context argument may be NULL and is unused by the wrapped
698 // implementation.
699 // * The second argument and the third argument are const arrays of size CDI_SIZE.
700 // This is fulfilled as per the definition of the arguments `current_cdi_attest`
701 // and `current_cdi_seal`.
702 // * The fourth argument and the fifth argument are the pointer to and size of the buffer
703 // holding the current bcc.
704 // * The sixth argument is a pointer to `DiceInputValues` it, and its indirect
705 // references must be valid for the duration of the function call which
706 // is guaranteed by `call_with_input_values` which puts `DiceInputValues`
707 // on the stack and initializes it from the `input_values` argument which
708 // implements the `InputValues` trait.
709 // * The seventh argument and the eighth argument are the length of and the pointer to the
710 // allocated certificate buffer respectively. They are used to return the generated
711 // certificate.
712 // * The ninth argument is a pointer to a mutable usize object. It is
713 // used to return the actual size of the output certificate.
714 // * The tenth argument and the eleventh argument are pointers to mutable buffers of
715 // size CDI_SIZE. This is fulfilled if the allocation above succeeded.
716 // * No pointers are expected to be valid beyond the scope of the function
717 // call.
718 call_with_input_values(input_values, |input_values| {
719 let next_bcc = retry_while_adjusting_output_buffer(|next_bcc, actual_size| {
720 check_result(unsafe {
721 BccMainFlow(
722 self.get_context(),
723 current_cdi_attest.as_ptr(),
724 current_cdi_seal.as_ptr(),
725 bcc.as_ptr(),
726 bcc.len(),
727 input_values,
728 next_bcc.len(),
729 next_bcc.as_mut_ptr(),
730 actual_size as *mut _,
731 next_attest.as_mut_ptr(),
732 next_seal.as_mut_ptr(),
733 )
734 })
735 })?;
736 Ok((next_attest, next_seal, next_bcc))
737 })
738 }
739}
740
741/// This submodule provides additional support for the Boot Certificate Chain (BCC)
742/// specification.
743/// See https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
744pub mod bcc {
745 use super::{check_result, retry_while_adjusting_output_buffer, Result};
746 use open_dice_bcc_bindgen::{
747 BccConfigValues, BccFormatConfigDescriptor, BCC_INPUT_COMPONENT_NAME,
748 BCC_INPUT_COMPONENT_VERSION, BCC_INPUT_RESETTABLE,
749 };
750 use std::ffi::CString;
751
752 /// Safe wrapper around BccFormatConfigDescriptor, see open dice documentation for details.
753 pub fn format_config_descriptor(
754 component_name: Option<&str>,
755 component_version: Option<u64>,
756 resettable: bool,
757 ) -> Result<Vec<u8>> {
758 let component_name = match component_name {
759 Some(n) => Some(CString::new(n)?),
760 None => None,
761 };
762 let input = BccConfigValues {
763 inputs: if component_name.is_some() { BCC_INPUT_COMPONENT_NAME } else { 0 }
764 | if component_version.is_some() { BCC_INPUT_COMPONENT_VERSION } else { 0 }
765 | if resettable { BCC_INPUT_RESETTABLE } else { 0 },
766 // SAFETY: The as_ref() in the line below is vital to keep the component_name object
767 // alive. Removing as_ref will move the component_name and the pointer will
768 // become invalid after this statement.
769 component_name: component_name.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
770 component_version: component_version.unwrap_or(0),
771 };
772
773 // SAFETY:
774 // * The first argument is a pointer to the BccConfigValues input assembled above.
775 // It and its indirections must be valid for the duration of the function call.
776 // * The second argument and the third argument are the length of and the pointer to the
777 // allocated output buffer respectively. The buffer must be at least as long
778 // as indicated by the size argument.
779 // * The forth argument is a pointer to the actual size returned by the function.
780 // * All pointers must be valid for the duration of the function call but not beyond.
781 retry_while_adjusting_output_buffer(|config_descriptor, actual_size| {
782 check_result(unsafe {
783 BccFormatConfigDescriptor(
784 &input as *const BccConfigValues,
785 config_descriptor.len(),
786 config_descriptor.as_mut_ptr(),
787 actual_size as *mut _,
788 )
789 })
790 })
791 }
Janis Danisevskis13356b22021-10-20 09:44:12 -0700792}