Rebrand from BCC to the Android Profile for DICE
Rename symbols and reword documentation to reflect Android's closer
alignment to DICE. Move Android parts out of their own directory and use
a `DiceAndroid` prefix for symbols.
Bug: 293659743
Change-Id: I24f4023797769f6eb822ac7715ddb38dadd9cf81
Reviewed-on: https://pigweed-review.googlesource.com/c/open-dice/+/164490
Reviewed-by: Darren Krahn <dkrahn@google.com>
Commit-Queue: Andrew Scull <ascull@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index a21b3d5..655230c 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -366,8 +366,32 @@
]
}
+pw_static_library("dice_android") {
+ public = [
+ "//include/dice/dice.h",
+ "//include/dice/utils.h",
+ ]
+ sources = [ "src/android.c" ]
+ deps = [
+ ":cbor_reader",
+ ":cbor_writer",
+ ":dice_with_cbor_ed25519_cert",
+ ]
+}
+
+pw_test("android_test") {
+ sources = [ "src/android_test.cc" ]
+ deps = [ ":dice_android" ]
+}
+
+pw_executable("android_fuzzer") {
+ sources = [ "src/android_fuzzer.cc" ]
+ deps = [ ":dice_android" ]
+}
+
pw_test_group("tests") {
tests = [
+ ":android_test",
":boringssl_ed25519_ops_test",
":cbor_ed25519_cert_op_test",
":cbor_p384_cert_op_test",
@@ -377,12 +401,12 @@
":mbedtls_ops_test",
":template_cbor_ed25519_cert_op_test",
":template_cert_op_test",
- "//src/android:bcc_test",
]
}
group("fuzzers") {
deps = [
+ ":android_fuzzer",
":boringssl_ed25519_ops_fuzzer",
":boringssl_p384_ops_fuzzer",
":cbor_ed25519_cert_op_fuzzer",
@@ -391,7 +415,6 @@
":mbedtls_ops_fuzzer",
":template_cbor_ed25519_cert_op_fuzzer",
":template_cert_op_fuzzer",
- "//src/android:bcc_fuzzer",
]
}
@@ -529,6 +552,7 @@
group("optimized_libs") {
deps = [
+ ":dice_android",
":dice_standalone",
":dice_with_boringssl_ed25519_ops",
":dice_with_cbor_ed25519_cert",
@@ -538,7 +562,6 @@
":dice_with_x509_template_cert",
":executable_size_report",
":library_size_report",
- "//src/android:bcc",
]
}
diff --git a/include/dice/android.h b/include/dice/android.h
new file mode 100644
index 0000000..69d87a1
--- /dev/null
+++ b/include/dice/android.h
@@ -0,0 +1,108 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef DICE_ANDROID_H_
+#define DICE_ANDROID_H_
+
+#include <stdbool.h>
+
+#include "dice/dice.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DICE_ANDROID_CONFIG_COMPONENT_NAME (1 << 0)
+#define DICE_ANDROID_CONFIG_COMPONENT_VERSION (1 << 1)
+#define DICE_ANDROID_CONFIG_RESETTABLE (1 << 2)
+
+// Contains the input values used to construct the Android Profile for DICE
+// configuration descriptor. Optional fields are selected in the |inputs|
+// bitfield.
+//
+// Fields:
+// configs: A bitfield selecting the config fields to include.
+// component_name: Name of the component.
+// component_version: Version of the component.
+typedef struct DiceAndroidConfigValues_ {
+ uint32_t configs;
+ const char* component_name;
+ uint64_t component_version;
+} DiceAndroidConfigValues;
+
+// Formats a configuration descriptor following the Android Profile for DICE
+// specification. On success, |actual_size| is set to the number of bytes used.
+// If kDiceResultBufferTooSmall is returned |actual_size| will be set to the
+// required size of the buffer.
+DiceResult DiceAndroidFormatConfigDescriptor(
+ const DiceAndroidConfigValues* config_values, size_t buffer_size,
+ uint8_t* buffer, size_t* actual_size);
+
+// Executes the main Android DICE flow.
+//
+// Call this instead of DiceMainFlow when the next certificate should be
+// appended to an existing Android DICE chain. However, when using
+// the Android DICE handover format, use DiceAndroidHandoverMainFlow instead.
+//
+// Given the current CDIs, a full set of input values, and the current Android
+// DICE chain, computes the next CDIs and the extended DICE chain. On success,
+// |actual_size| is set to the number of bytes used. If
+// kDiceResultBufferTooSmall is returned |actual_size| will be set to the
+// required size of the buffer.
+DiceResult DiceAndroidMainFlow(void* context,
+ const uint8_t current_cdi_attest[DICE_CDI_SIZE],
+ const uint8_t current_cdi_seal[DICE_CDI_SIZE],
+ const uint8_t* chain, size_t chain_size,
+ const DiceInputValues* input_values,
+ size_t buffer_size, uint8_t* buffer,
+ size_t* actual_size,
+ uint8_t next_cdi_attest[DICE_CDI_SIZE],
+ uint8_t next_cdi_seal[DICE_CDI_SIZE]);
+
+// Executes the main Android DICE handover flow.
+//
+// Call this instead of DiceAndroidMainFlow when using the Android DICE handover
+// format to combine the Android DICE chain and CDIs in a single CBOR object.
+//
+// Given a full set of input values and the current Android DICE handover
+// object, computes the handover data for the next stage. On success,
+// |actual_size| is set to the number of bytes used. If
+// kDiceResultBufferTooSmall is returned |actual_size| will be set to the
+// required size of the buffer.
+//
+// Using the Android DICE handover object is one option for passing the values
+// between boot stages. Passing the bytes between stages is a problem left to
+// the caller.
+DiceResult DiceAndroidHandoverMainFlow(void* context, const uint8_t* handover,
+ size_t handover_size,
+ const DiceInputValues* input_values,
+ size_t buffer_size, uint8_t* buffer,
+ size_t* actual_size);
+
+// Parses an Android DICE handover object to extract the fields.
+//
+// Given a pointer to an Android DICE handover object, returns pointers to the
+// CDIs and DICE chain. If the DICE chain is not included in the handover
+// object, the pointer is NULL and the size is 0.
+DiceResult DiceAndroidHandoverParse(const uint8_t* handover,
+ size_t handover_size,
+ const uint8_t** cdi_attest,
+ const uint8_t** cdi_seal,
+ const uint8_t** chain, size_t* chain_size);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // DICE_ANDROID_H_
diff --git a/include/dice/android/bcc.h b/include/dice/android/bcc.h
deleted file mode 100644
index 366c51f..0000000
--- a/include/dice/android/bcc.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-#ifndef DICE_ANDROID_BCC_H_
-#define DICE_ANDROID_BCC_H_
-
-#include <stdbool.h>
-
-#include "dice/dice.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define BCC_INPUT_COMPONENT_NAME (1 << 0)
-#define BCC_INPUT_COMPONENT_VERSION (1 << 1)
-#define BCC_INPUT_RESETTABLE (1 << 2)
-
-// Contains the input values used to construct the BCC configuration
-// descriptor. Optional fields are selected in the |inputs| bitfield.
-//
-// Fields:
-// inputs: A bitfield selecting which BCC inputs to include.
-// component_name: Optional. Name of firmware component / boot stage.
-// component_version: Optional. Version of firmware component / boot stage.
-typedef struct BccConfigValues_ {
- uint32_t inputs;
- const char* component_name;
- uint64_t component_version;
-} BccConfigValues;
-
-// Formats a configuration descriptor following the BCC's specification. On
-// success, |actual_size| is set to the number of bytes used. If
-// kDiceResultBufferTooSmall is returned |actual_size| will be set to the
-// required size of the buffer.
-DiceResult BccFormatConfigDescriptor(const BccConfigValues* input_values,
- size_t buffer_size, uint8_t* buffer,
- size_t* actual_size);
-
-// Executes the main BCC flow.
-//
-// Call this instead of DiceMainFlow when the next certificate should be
-// appended to an existing boot certificate chain (BCC). However, when using
-// the BCC handover format, use BccHandoverMainFlow instead.
-//
-// Given a full set of input values along with the current BCC and CDI values,
-// computes the next CDI values and matching updated BCC. On success,
-// |actual_size| is set to the number of bytes used. If
-// kDiceResultBufferTooSmall is returned |actual_size| will be set to the
-// required size of the buffer.
-DiceResult BccMainFlow(void* context,
- const uint8_t current_cdi_attest[DICE_CDI_SIZE],
- const uint8_t current_cdi_seal[DICE_CDI_SIZE],
- const uint8_t* bcc, size_t bcc_size,
- const DiceInputValues* input_values, size_t buffer_size,
- uint8_t* buffer, size_t* actual_size,
- uint8_t next_cdi_attest[DICE_CDI_SIZE],
- uint8_t next_cdi_seal[DICE_CDI_SIZE]);
-
-// Executes the main BCC handover flow.
-//
-// Call this instead of BccMainFlow when using the BCC handover format to
-// combine the BCC and CDIs in a single CBOR object.
-//
-// Given a full set of input values and the current BCC handover data, computes
-// the next BCC handover data. On success, |actual_size| is set to the number
-// of bytes used. If kDiceResultBufferTooSmall is returned |actual_size| will
-// be set to the required size of the buffer.
-//
-// Using a CBOR object to bundle is one option for passing the values passed
-// between boot stages. This function can take the current boot stage's bundle
-// and produce a bundle for the next stage. Passing the bundle between stages
-// is a problem left to the caller.
-DiceResult BccHandoverMainFlow(void* context, const uint8_t* bcc_handover,
- size_t bcc_handover_size,
- const DiceInputValues* input_values,
- size_t buffer_size, uint8_t* buffer,
- size_t* actual_size);
-
-// Parses a BCC handover to extract the fields.
-//
-// Given a pointer to a BCC handover, pointers to the CDIs and, optionally, the
-// BCC in the buffer are returned. If the BCC is not included in the handover,
-// the pointer is NULL and the size is 0.
-DiceResult BccHandoverParse(const uint8_t* bcc_handover,
- size_t bcc_handover_size,
- const uint8_t** cdi_attest,
- const uint8_t** cdi_seal, const uint8_t** bcc,
- size_t* bcc_size);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // DICE_ANDROID_BCC_H_
diff --git a/src/android.c b/src/android.c
new file mode 100644
index 0000000..f3d1b2d
--- /dev/null
+++ b/src/android.c
@@ -0,0 +1,314 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+// The Android Profile for DICE is a specialization of the Open Profile for DICE
+// that is used by Android. More details can be found in the remote key
+// provisioning (RKP) documentation linked below.
+//
+// https://cs.android.com/android/platform/superproject/+/main:hardware/interfaces/security/rkp/README.md
+
+#include "dice/android.h"
+
+#include <string.h>
+
+#include "dice/cbor_reader.h"
+#include "dice/cbor_writer.h"
+#include "dice/dice.h"
+#include "dice/ops.h"
+#include "dice/ops/trait/cose.h"
+
+// Completely gratuitous bit twiddling.
+static size_t PopulationCount(uint32_t n) {
+ n = n - ((n >> 1) & 0x55555555);
+ n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
+ return (((n + (n >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
+}
+
+DiceResult DiceAndroidFormatConfigDescriptor(
+ const DiceAndroidConfigValues* config_values, size_t buffer_size,
+ uint8_t* buffer, size_t* actual_size) {
+ static const int64_t kComponentNameLabel = -70002;
+ static const int64_t kComponentVersionLabel = -70003;
+ static const int64_t kResettableLabel = -70004;
+
+ // AndroidConfigDescriptor = {
+ // ? -70002 : tstr, ; Component name
+ // ? -70003 : int, ; Component version
+ // ? -70004 : null, ; Resettable
+ // }
+ struct CborOut out;
+ CborOutInit(buffer, buffer_size, &out);
+ CborWriteMap(PopulationCount(config_values->configs), &out);
+ if (config_values->configs & DICE_ANDROID_CONFIG_COMPONENT_NAME &&
+ config_values->component_name) {
+ CborWriteInt(kComponentNameLabel, &out);
+ CborWriteTstr(config_values->component_name, &out);
+ }
+ if (config_values->configs & DICE_ANDROID_CONFIG_COMPONENT_VERSION) {
+ CborWriteInt(kComponentVersionLabel, &out);
+ CborWriteUint(config_values->component_version, &out);
+ }
+ if (config_values->configs & DICE_ANDROID_CONFIG_RESETTABLE) {
+ CborWriteInt(kResettableLabel, &out);
+ CborWriteNull(&out);
+ }
+ *actual_size = CborOutSize(&out);
+ if (CborOutOverflowed(&out)) {
+ return kDiceResultBufferTooSmall;
+ }
+ return kDiceResultOk;
+}
+
+DiceResult DiceAndroidMainFlow(void* context,
+ const uint8_t current_cdi_attest[DICE_CDI_SIZE],
+ const uint8_t current_cdi_seal[DICE_CDI_SIZE],
+ const uint8_t* chain, size_t chain_size,
+ const DiceInputValues* input_values,
+ size_t buffer_size, uint8_t* buffer,
+ size_t* actual_size,
+ uint8_t next_cdi_attest[DICE_CDI_SIZE],
+ uint8_t next_cdi_seal[DICE_CDI_SIZE]) {
+ DiceResult result;
+ enum CborReadResult res;
+ struct CborIn in;
+ size_t chain_item_count;
+
+ // The Android DICE chain has a more detailed internal structure, but those
+ // details aren't relevant to the work of this function.
+ //
+ // DiceCertChain = [
+ // COSE_Key, ; Root public key
+ // + COSE_Sign1, ; DICE chain entries
+ // ]
+ CborInInit(chain, chain_size, &in);
+ res = CborReadArray(&in, &chain_item_count);
+ if (res != CBOR_READ_RESULT_OK) {
+ return kDiceResultInvalidInput;
+ }
+
+ if (chain_item_count < 2 || chain_item_count == SIZE_MAX) {
+ // There should at least be the public key and one entry.
+ return kDiceResultInvalidInput;
+ }
+
+ // Measure the existing chain entries.
+ size_t chain_items_offset = CborInOffset(&in);
+ for (size_t chain_pos = 0; chain_pos < chain_item_count; ++chain_pos) {
+ res = CborReadSkip(&in);
+ if (res != CBOR_READ_RESULT_OK) {
+ return kDiceResultInvalidInput;
+ }
+ }
+ size_t chain_items_size = CborInOffset(&in) - chain_items_offset;
+
+ // Copy to the new buffer, with space in the chain for one more entry.
+ struct CborOut out;
+ CborOutInit(buffer, buffer_size, &out);
+ CborWriteArray(chain_item_count + 1, &out);
+ if (CborOutOverflowed(&out) ||
+ chain_items_size > buffer_size - CborOutSize(&out)) {
+ // Continue with an empty buffer to measure the required size.
+ buffer_size = 0;
+ } else {
+ memcpy(buffer + CborOutSize(&out), chain + chain_items_offset,
+ chain_items_size);
+ buffer += CborOutSize(&out) + chain_items_size;
+ buffer_size -= CborOutSize(&out) + chain_items_size;
+ }
+
+ size_t certificate_size;
+ result = DiceMainFlow(context, current_cdi_attest, current_cdi_seal,
+ input_values, buffer_size, buffer, &certificate_size,
+ next_cdi_attest, next_cdi_seal);
+ *actual_size = CborOutSize(&out) + chain_items_size + certificate_size;
+ return result;
+}
+
+static DiceResult DiceAndroidMainFlowWithNewDiceChain(
+ void* context, const uint8_t current_cdi_attest[DICE_CDI_SIZE],
+ const uint8_t current_cdi_seal[DICE_CDI_SIZE],
+ const DiceInputValues* input_values, size_t buffer_size, uint8_t* buffer,
+ size_t* chain_size, uint8_t next_cdi_attest[DICE_CDI_SIZE],
+ uint8_t next_cdi_seal[DICE_CDI_SIZE]) {
+ uint8_t current_cdi_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE];
+ uint8_t attestation_public_key[DICE_PUBLIC_KEY_SIZE];
+ uint8_t attestation_private_key[DICE_PRIVATE_KEY_SIZE];
+ // Derive an asymmetric private key seed from the current attestation CDI
+ // value.
+ DiceResult result = DiceDeriveCdiPrivateKeySeed(context, current_cdi_attest,
+ current_cdi_private_key_seed);
+ if (result != kDiceResultOk) {
+ goto out;
+ }
+ // Derive attestation key pair.
+ result = DiceKeypairFromSeed(context, current_cdi_private_key_seed,
+ attestation_public_key, attestation_private_key);
+ if (result != kDiceResultOk) {
+ goto out;
+ }
+
+ // Consruct the DICE chain from the attestation public key and the next CDI
+ // certificate.
+ struct CborOut out;
+ CborOutInit(buffer, buffer_size, &out);
+ CborWriteArray(2, &out);
+ size_t encoded_size_used = CborOutSize(&out);
+ if (CborOutOverflowed(&out)) {
+ // Continue with an empty buffer to measure the required size.
+ buffer_size = 0;
+ } else {
+ buffer += encoded_size_used;
+ buffer_size -= encoded_size_used;
+ }
+
+ size_t encoded_pub_key_size = 0;
+ result = DiceCoseEncodePublicKey(context, attestation_public_key, buffer_size,
+ buffer, &encoded_pub_key_size);
+ if (result == kDiceResultOk) {
+ buffer += encoded_pub_key_size;
+ buffer_size -= encoded_pub_key_size;
+ } else if (result == kDiceResultBufferTooSmall) {
+ // Continue with an empty buffer to measure the required size.
+ buffer_size = 0;
+ } else {
+ goto out;
+ }
+
+ result = DiceMainFlow(context, current_cdi_attest, current_cdi_seal,
+ input_values, buffer_size, buffer, chain_size,
+ next_cdi_attest, next_cdi_seal);
+ *chain_size += encoded_size_used + encoded_pub_key_size;
+ if (result != kDiceResultOk) {
+ return result;
+ }
+
+out:
+ DiceClearMemory(context, sizeof(current_cdi_private_key_seed),
+ current_cdi_private_key_seed);
+ DiceClearMemory(context, sizeof(attestation_private_key),
+ attestation_private_key);
+
+ return result;
+}
+
+// AndroidDiceHandover = {
+// 1 : bstr .size 32, ; CDI_Attest
+// 2 : bstr .size 32, ; CDI_Seal
+// ? 3 : DiceCertChain, ; Android DICE chain
+// }
+static const int64_t kCdiAttestLabel = 1;
+static const int64_t kCdiSealLabel = 2;
+static const int64_t kDiceChainLabel = 3;
+
+DiceResult DiceAndroidHandoverMainFlow(void* context, const uint8_t* handover,
+ size_t handover_size,
+ const DiceInputValues* input_values,
+ size_t buffer_size, uint8_t* buffer,
+ size_t* actual_size) {
+ DiceResult result;
+ const uint8_t* current_cdi_attest;
+ const uint8_t* current_cdi_seal;
+ const uint8_t* chain;
+ size_t chain_size;
+
+ result =
+ DiceAndroidHandoverParse(handover, handover_size, ¤t_cdi_attest,
+ ¤t_cdi_seal, &chain, &chain_size);
+ if (result != kDiceResultOk) {
+ return kDiceResultInvalidInput;
+ }
+
+ // Write the new handover data.
+ struct CborOut out;
+ CborOutInit(buffer, buffer_size, &out);
+ CborWriteMap(/*num_pairs=*/3, &out);
+ CborWriteInt(kCdiAttestLabel, &out);
+ uint8_t* next_cdi_attest = CborAllocBstr(DICE_CDI_SIZE, &out);
+ CborWriteInt(kCdiSealLabel, &out);
+ uint8_t* next_cdi_seal = CborAllocBstr(DICE_CDI_SIZE, &out);
+ CborWriteInt(kDiceChainLabel, &out);
+
+ uint8_t ignored_cdi_attest[DICE_CDI_SIZE];
+ uint8_t ignored_cdi_seal[DICE_CDI_SIZE];
+ if (CborOutOverflowed(&out)) {
+ // Continue with an empty buffer and placeholders for the output CDIs to
+ // measure the required size.
+ buffer_size = 0;
+ next_cdi_attest = ignored_cdi_attest;
+ next_cdi_seal = ignored_cdi_seal;
+ } else {
+ buffer += CborOutSize(&out);
+ buffer_size -= CborOutSize(&out);
+ }
+
+ if (chain_size != 0) {
+ // If the DICE chain is present in the handover, append the next certificate
+ // to the existing DICE chain.
+ result = DiceAndroidMainFlow(context, current_cdi_attest, current_cdi_seal,
+ chain, chain_size, input_values, buffer_size,
+ buffer, &chain_size, next_cdi_attest,
+ next_cdi_seal);
+ } else {
+ // If DICE chain is not present in the handover, construct the DICE chain
+ // from the public key derived from the current CDI attest and the next CDI
+ // certificate.
+ result = DiceAndroidMainFlowWithNewDiceChain(
+ context, current_cdi_attest, current_cdi_seal, input_values,
+ buffer_size, buffer, &chain_size, next_cdi_attest, next_cdi_seal);
+ }
+ *actual_size = CborOutSize(&out) + chain_size;
+ return result;
+}
+
+DiceResult DiceAndroidHandoverParse(const uint8_t* handover,
+ size_t handover_size,
+ const uint8_t** cdi_attest,
+ const uint8_t** cdi_seal,
+ const uint8_t** chain, size_t* chain_size) {
+ // Extract details from the handover data.
+ struct CborIn in;
+ int64_t label;
+ size_t num_pairs;
+ size_t item_size;
+ CborInInit(handover, handover_size, &in);
+ if (CborReadMap(&in, &num_pairs) != CBOR_READ_RESULT_OK || num_pairs < 2 ||
+ // Read the attestation CDI.
+ CborReadInt(&in, &label) != CBOR_READ_RESULT_OK ||
+ label != kCdiAttestLabel ||
+ CborReadBstr(&in, &item_size, cdi_attest) != CBOR_READ_RESULT_OK ||
+ item_size != DICE_CDI_SIZE ||
+ // Read the sealing CDI.
+ CborReadInt(&in, &label) != CBOR_READ_RESULT_OK ||
+ label != kCdiSealLabel ||
+ CborReadBstr(&in, &item_size, cdi_seal) != CBOR_READ_RESULT_OK ||
+ item_size != DICE_CDI_SIZE) {
+ return kDiceResultInvalidInput;
+ }
+
+ *chain = NULL;
+ *chain_size = 0;
+ if (num_pairs >= 3 && CborReadInt(&in, &label) == CBOR_READ_RESULT_OK) {
+ if (label == kDiceChainLabel) {
+ // Calculate the DICE chain size, if it is present in the handover object.
+ size_t chain_start = CborInOffset(&in);
+ if (CborReadSkip(&in) != CBOR_READ_RESULT_OK) {
+ return kDiceResultInvalidInput;
+ }
+ *chain = handover + chain_start;
+ *chain_size = CborInOffset(&in) - chain_start;
+ }
+ }
+
+ return kDiceResultOk;
+}
diff --git a/src/android/BUILD.gn b/src/android/BUILD.gn
deleted file mode 100644
index cc0ff45..0000000
--- a/src/android/BUILD.gn
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright 2021 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not
-# use this file except in compliance with the License. You may obtain a copy of
-# the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations under
-# the License.
-
-import("//build_overrides/pigweed.gni")
-import("$dir_pw_build/target_types.gni")
-import("$dir_pw_unit_test/test.gni")
-
-pw_source_set("bcc") {
- public = [
- "//include/dice/dice.h",
- "//include/dice/utils.h",
- ]
- sources = [ "bcc.c" ]
- deps = [
- "//:cbor_reader",
- "//:cbor_writer",
- "//:dice_with_cbor_ed25519_cert",
- ]
-}
-
-pw_test("bcc_test") {
- sources = [ "bcc_test.cc" ]
- deps = [ ":bcc" ]
-}
-
-pw_executable("bcc_fuzzer") {
- sources = [ "bcc_fuzzer.cc" ]
- deps = [ ":bcc" ]
-}
diff --git a/src/android/README.md b/src/android/README.md
deleted file mode 100644
index c9b308f..0000000
--- a/src/android/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# The Boot Certificate Chain (BCC)
-
-The Boot Certificate Chain (BCC) is an application of the Open Profile for DICE
-used by Android that conforms to the specification and goes further to more
-strictly define the configuration descriptor.
-
-A [CDDL](https://tools.ietf.org/html/rfc8610) definition of the BCC can be found
-in the
-[KeyMint AIDL definitions](https://cs.android.com/android/platform/superproject/+/main:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl).
diff --git a/src/android/bcc.c b/src/android/bcc.c
deleted file mode 100644
index 262e6d3..0000000
--- a/src/android/bcc.c
+++ /dev/null
@@ -1,305 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-#include "dice/android/bcc.h"
-
-#include <string.h>
-
-#include "dice/cbor_reader.h"
-#include "dice/cbor_writer.h"
-#include "dice/dice.h"
-#include "dice/ops.h"
-#include "dice/ops/trait/cose.h"
-
-// Completely gratuitous bit twiddling.
-static size_t PopulationCount(uint32_t n) {
- n = n - ((n >> 1) & 0x55555555);
- n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
- return (((n + (n >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
-}
-
-DiceResult BccFormatConfigDescriptor(const BccConfigValues* input_values,
- size_t buffer_size, uint8_t* buffer,
- size_t* actual_size) {
- static const int64_t kComponentNameLabel = -70002;
- static const int64_t kComponentVersionLabel = -70003;
- static const int64_t kResettableLabel = -70004;
-
- // BccConfigDescriptor = {
- // ? -70002 : tstr, ; Component name
- // ? -70003 : int, ; Component version
- // ? -70004 : null, ; Resettable
- // }
- struct CborOut out;
- CborOutInit(buffer, buffer_size, &out);
- CborWriteMap(PopulationCount(input_values->inputs), &out);
- if (input_values->inputs & BCC_INPUT_COMPONENT_NAME &&
- input_values->component_name) {
- CborWriteInt(kComponentNameLabel, &out);
- CborWriteTstr(input_values->component_name, &out);
- }
- if (input_values->inputs & BCC_INPUT_COMPONENT_VERSION) {
- CborWriteInt(kComponentVersionLabel, &out);
- CborWriteUint(input_values->component_version, &out);
- }
- if (input_values->inputs & BCC_INPUT_RESETTABLE) {
- CborWriteInt(kResettableLabel, &out);
- CborWriteNull(&out);
- }
- *actual_size = CborOutSize(&out);
- if (CborOutOverflowed(&out)) {
- return kDiceResultBufferTooSmall;
- }
- return kDiceResultOk;
-}
-
-DiceResult BccMainFlow(void* context,
- const uint8_t current_cdi_attest[DICE_CDI_SIZE],
- const uint8_t current_cdi_seal[DICE_CDI_SIZE],
- const uint8_t* bcc, size_t bcc_size,
- const DiceInputValues* input_values, size_t buffer_size,
- uint8_t* buffer, size_t* actual_size,
- uint8_t next_cdi_attest[DICE_CDI_SIZE],
- uint8_t next_cdi_seal[DICE_CDI_SIZE]) {
- DiceResult result;
- enum CborReadResult res;
- struct CborIn in;
- size_t bcc_item_count;
-
- // The BCC has a more detailed internal structure, but those details aren't
- // relevant to the work of this function.
- //
- // Bcc = [
- // COSE_Key, ; Root public key
- // + COSE_Sign1, ; Bcc entries
- // ]
- CborInInit(bcc, bcc_size, &in);
- res = CborReadArray(&in, &bcc_item_count);
- if (res != CBOR_READ_RESULT_OK) {
- return kDiceResultInvalidInput;
- }
-
- if (bcc_item_count < 2 || bcc_item_count == SIZE_MAX) {
- // There should at least be the public key and one entry.
- return kDiceResultInvalidInput;
- }
-
- // Measure the existing BCC entries.
- size_t bcc_items_offset = CborInOffset(&in);
- for (size_t bcc_pos = 0; bcc_pos < bcc_item_count; ++bcc_pos) {
- res = CborReadSkip(&in);
- if (res != CBOR_READ_RESULT_OK) {
- return kDiceResultInvalidInput;
- }
- }
- size_t bcc_items_size = CborInOffset(&in) - bcc_items_offset;
-
- // Copy to the new buffer, with space in the BCC for one more entry.
- struct CborOut out;
- CborOutInit(buffer, buffer_size, &out);
- CborWriteArray(bcc_item_count + 1, &out);
- if (CborOutOverflowed(&out) ||
- bcc_items_size > buffer_size - CborOutSize(&out)) {
- // Continue with an empty buffer to measure the required size.
- buffer_size = 0;
- } else {
- memcpy(buffer + CborOutSize(&out), bcc + bcc_items_offset, bcc_items_size);
- buffer += CborOutSize(&out) + bcc_items_size;
- buffer_size -= CborOutSize(&out) + bcc_items_size;
- }
-
- size_t certificate_size;
- result = DiceMainFlow(context, current_cdi_attest, current_cdi_seal,
- input_values, buffer_size, buffer, &certificate_size,
- next_cdi_attest, next_cdi_seal);
- *actual_size = CborOutSize(&out) + bcc_items_size + certificate_size;
- return result;
-}
-
-static DiceResult BccMainFlowWithNewBcc(
- void* context, const uint8_t current_cdi_attest[DICE_CDI_SIZE],
- const uint8_t current_cdi_seal[DICE_CDI_SIZE],
- const DiceInputValues* input_values, size_t buffer_size, uint8_t* buffer,
- size_t* bcc_size, uint8_t next_cdi_attest[DICE_CDI_SIZE],
- uint8_t next_cdi_seal[DICE_CDI_SIZE]) {
- uint8_t current_cdi_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE];
- uint8_t attestation_public_key[DICE_PUBLIC_KEY_SIZE];
- uint8_t attestation_private_key[DICE_PRIVATE_KEY_SIZE];
- // Derive an asymmetric private key seed from the current attestation CDI
- // value.
- DiceResult result = DiceDeriveCdiPrivateKeySeed(context, current_cdi_attest,
- current_cdi_private_key_seed);
- if (result != kDiceResultOk) {
- goto out;
- }
- // Derive attestation key pair.
- result = DiceKeypairFromSeed(context, current_cdi_private_key_seed,
- attestation_public_key, attestation_private_key);
- if (result != kDiceResultOk) {
- goto out;
- }
-
- // Consruct the BCC from the attestation public key and the next CDI
- // certificate.
- struct CborOut out;
- CborOutInit(buffer, buffer_size, &out);
- CborWriteArray(2, &out);
- size_t encoded_size_used = CborOutSize(&out);
- if (CborOutOverflowed(&out)) {
- // Continue with an empty buffer to measure the required size.
- buffer_size = 0;
- } else {
- buffer += encoded_size_used;
- buffer_size -= encoded_size_used;
- }
-
- size_t encoded_pub_key_size = 0;
- result = DiceCoseEncodePublicKey(context, attestation_public_key, buffer_size,
- buffer, &encoded_pub_key_size);
- if (result == kDiceResultOk) {
- buffer += encoded_pub_key_size;
- buffer_size -= encoded_pub_key_size;
- } else if (result == kDiceResultBufferTooSmall) {
- // Continue with an empty buffer to measure the required size.
- buffer_size = 0;
- } else {
- goto out;
- }
-
- result = DiceMainFlow(context, current_cdi_attest, current_cdi_seal,
- input_values, buffer_size, buffer, bcc_size,
- next_cdi_attest, next_cdi_seal);
- *bcc_size += encoded_size_used + encoded_pub_key_size;
- if (result != kDiceResultOk) {
- return result;
- }
-
-out:
- DiceClearMemory(context, sizeof(current_cdi_private_key_seed),
- current_cdi_private_key_seed);
- DiceClearMemory(context, sizeof(attestation_private_key),
- attestation_private_key);
-
- return result;
-}
-
-static const int64_t kCdiAttestLabel = 1;
-static const int64_t kCdiSealLabel = 2;
-static const int64_t kBccLabel = 3;
-
-DiceResult BccHandoverMainFlow(void* context, const uint8_t* bcc_handover,
- size_t bcc_handover_size,
- const DiceInputValues* input_values,
- size_t buffer_size, uint8_t* buffer,
- size_t* actual_size) {
- DiceResult result;
- const uint8_t* current_cdi_attest;
- const uint8_t* current_cdi_seal;
- const uint8_t* bcc;
- size_t bcc_size;
-
- result =
- BccHandoverParse(bcc_handover, bcc_handover_size, ¤t_cdi_attest,
- ¤t_cdi_seal, &bcc, &bcc_size);
- if (result != kDiceResultOk) {
- return kDiceResultInvalidInput;
- }
-
- // Write the new handover data.
- struct CborOut out;
- CborOutInit(buffer, buffer_size, &out);
- CborWriteMap(/*num_pairs=*/3, &out);
- CborWriteInt(kCdiAttestLabel, &out);
- uint8_t* next_cdi_attest = CborAllocBstr(DICE_CDI_SIZE, &out);
- CborWriteInt(kCdiSealLabel, &out);
- uint8_t* next_cdi_seal = CborAllocBstr(DICE_CDI_SIZE, &out);
- CborWriteInt(kBccLabel, &out);
-
- uint8_t ignored_cdi_attest[DICE_CDI_SIZE];
- uint8_t ignored_cdi_seal[DICE_CDI_SIZE];
- if (CborOutOverflowed(&out)) {
- // Continue with an empty buffer and placeholders for the output CDIs to
- // measure the required size.
- buffer_size = 0;
- next_cdi_attest = ignored_cdi_attest;
- next_cdi_seal = ignored_cdi_seal;
- } else {
- buffer += CborOutSize(&out);
- buffer_size -= CborOutSize(&out);
- }
-
- if (bcc_size != 0) {
- // If BCC is present in the bcc_handover, append the next certificate to the
- // existing BCC.
- result = BccMainFlow(context, current_cdi_attest, current_cdi_seal, bcc,
- bcc_size, input_values, buffer_size, buffer, &bcc_size,
- next_cdi_attest, next_cdi_seal);
- } else {
- // If BCC is not present in the bcc_handover, construct BCC from the public
- // key derived from the current CDI attest and the next CDI certificate.
- result = BccMainFlowWithNewBcc(
- context, current_cdi_attest, current_cdi_seal, input_values,
- buffer_size, buffer, &bcc_size, next_cdi_attest, next_cdi_seal);
- }
- *actual_size = CborOutSize(&out) + bcc_size;
- return result;
-}
-
-DiceResult BccHandoverParse(const uint8_t* bcc_handover,
- size_t bcc_handover_size,
- const uint8_t** cdi_attest,
- const uint8_t** cdi_seal, const uint8_t** bcc,
- size_t* bcc_size) {
- // Extract details from the handover data.
- //
- // BccHandover = {
- // 1 : bstr .size 32, ; CDI_Attest
- // 2 : bstr .size 32, ; CDI_Seal
- // ? 3 : Bcc, ; Certificate chain
- // }
- struct CborIn in;
- int64_t label;
- size_t num_pairs;
- size_t item_size;
- CborInInit(bcc_handover, bcc_handover_size, &in);
- if (CborReadMap(&in, &num_pairs) != CBOR_READ_RESULT_OK || num_pairs < 2 ||
- // Read the attestation CDI.
- CborReadInt(&in, &label) != CBOR_READ_RESULT_OK ||
- label != kCdiAttestLabel ||
- CborReadBstr(&in, &item_size, cdi_attest) != CBOR_READ_RESULT_OK ||
- item_size != DICE_CDI_SIZE ||
- // Read the sealing CDI.
- CborReadInt(&in, &label) != CBOR_READ_RESULT_OK ||
- label != kCdiSealLabel ||
- CborReadBstr(&in, &item_size, cdi_seal) != CBOR_READ_RESULT_OK ||
- item_size != DICE_CDI_SIZE) {
- return kDiceResultInvalidInput;
- }
-
- *bcc = NULL;
- *bcc_size = 0;
- if (num_pairs >= 3 && CborReadInt(&in, &label) == CBOR_READ_RESULT_OK) {
- if (label == kBccLabel) {
- // Calculate the BCC size, if the BCC is present in the BccHandover.
- size_t bcc_start = CborInOffset(&in);
- if (CborReadSkip(&in) != CBOR_READ_RESULT_OK) {
- return kDiceResultInvalidInput;
- }
- *bcc = bcc_handover + bcc_start;
- *bcc_size = CborInOffset(&in) - bcc_start;
- }
- }
-
- return kDiceResultOk;
-}
diff --git a/src/android/bcc_test.cc b/src/android/bcc_test.cc
deleted file mode 100644
index ba062b9..0000000
--- a/src/android/bcc_test.cc
+++ /dev/null
@@ -1,309 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-#include "dice/android/bcc.h"
-
-#include "dice/test_framework.h"
-
-namespace {
-
-extern "C" {
-
-TEST(BccConfigTest, NoInputs) {
- BccConfigValues input_values = {};
- uint8_t buffer[10];
- size_t buffer_size;
- DiceResult result = BccFormatConfigDescriptor(&input_values, sizeof(buffer),
- buffer, &buffer_size);
- EXPECT_EQ(kDiceResultOk, result);
- EXPECT_EQ(1u, buffer_size);
- EXPECT_EQ(0xa0, buffer[0]);
-}
-
-TEST(BccConfigTest, NoInputsMeasurement) {
- BccConfigValues input_values = {};
- size_t buffer_size;
- DiceResult result =
- BccFormatConfigDescriptor(&input_values, 0, NULL, &buffer_size);
- EXPECT_EQ(kDiceResultBufferTooSmall, result);
- EXPECT_EQ(1u, buffer_size);
-}
-
-TEST(BccConfigTest, AllInputs) {
- BccConfigValues input_values = {
- .inputs = BCC_INPUT_COMPONENT_NAME | BCC_INPUT_COMPONENT_VERSION |
- BCC_INPUT_RESETTABLE,
- .component_name = "Test Component Name",
- .component_version = 0x232a13dec90f42b5,
- };
- size_t buffer_size;
- DiceResult result =
- BccFormatConfigDescriptor(&input_values, 0, NULL, &buffer_size);
- EXPECT_EQ(kDiceResultBufferTooSmall, result);
- std::vector<uint8_t> buffer(buffer_size);
- const uint8_t expected[] = {
- 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x73, 'T', 'e', 's', 't', ' ',
- 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n', 't', ' ', 'N', 'a',
- 'm', 'e', 0x3a, 0x00, 0x01, 0x11, 0x72, 0x1b, 0x23, 0x2a, 0x13, 0xde,
- 0xc9, 0x0f, 0x42, 0xb5, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6};
- EXPECT_EQ(sizeof(expected), buffer.size());
- result = BccFormatConfigDescriptor(&input_values, buffer.size(),
- buffer.data(), &buffer_size);
- EXPECT_EQ(sizeof(expected), buffer_size);
- EXPECT_EQ(0, memcmp(expected, buffer.data(), buffer.size()));
-}
-
-TEST(BccTest, PreservesPreviousEntries) {
- const uint8_t bcc[] = {
- // Fake BCC with the root public key and two entries.
- 0x83,
- // Fake public key.
- 0xa6, 0x01, 0x02, 0x03, 0x27, 0x04, 0x02, 0x20, 0x01, 0x21, 0x40, 0x22,
- 0x40,
- // Fake BCC entry.
- 0x84, 0x40, 0xa0, 0x40, 0x40,
- // Fake BCC entry.
- 0x84, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40,
- // 8-bytes of trailing data that aren't part of the BCC.
- 0x84, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40};
- const uint8_t fake_cdi_attest[DICE_CDI_SIZE] = {};
- const uint8_t fake_cdi_seal[DICE_CDI_SIZE] = {};
- DiceInputValues input_values = {};
- size_t next_bcc_size;
- uint8_t next_cdi_attest[DICE_CDI_SIZE];
- uint8_t next_cdi_seal[DICE_CDI_SIZE];
- DiceResult result = BccMainFlow(
- /*context=*/NULL, fake_cdi_attest, fake_cdi_seal, bcc, sizeof(bcc),
- &input_values, 0, NULL, &next_bcc_size, next_cdi_attest, next_cdi_seal);
- EXPECT_EQ(kDiceResultBufferTooSmall, result);
- EXPECT_GT(next_bcc_size, sizeof(bcc));
- std::vector<uint8_t> next_bcc(next_bcc_size);
- result =
- BccMainFlow(/*context=*/NULL, fake_cdi_attest, fake_cdi_seal, bcc,
- sizeof(bcc), &input_values, next_bcc.size(), next_bcc.data(),
- &next_bcc_size, next_cdi_attest, next_cdi_seal);
- EXPECT_EQ(kDiceResultOk, result);
- EXPECT_EQ(next_bcc_size, next_bcc.size());
- EXPECT_EQ(0x84, next_bcc[0]);
- EXPECT_NE(0, memcmp(next_bcc.data() + 1, bcc + 1, sizeof(bcc) - 1));
- EXPECT_EQ(0, memcmp(next_bcc.data() + 1, bcc + 1, sizeof(bcc) - 8 - 1));
-}
-
-TEST(BccHandoverTest, PreservesPreviousEntries) {
- const uint8_t bcc_handover[] = {
- 0xa3,
- // CDI attest
- 0x01, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // CDI seal
- 0x02, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // BCC
- 0x03, 0x82, 0xa6, 0x01, 0x02, 0x03, 0x27, 0x04, 0x02, 0x20, 0x01, 0x21,
- 0x40, 0x22, 0x40, 0x84, 0x40, 0xa0, 0x40, 0x40,
- // 8-bytes of trailing data that aren't part of the BCC.
- 0x84, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40};
- DiceInputValues input_values = {};
- size_t next_bcc_handover_size;
- DiceResult result = BccHandoverMainFlow(
- /*context=*/NULL, bcc_handover, sizeof(bcc_handover), &input_values, 0,
- NULL, &next_bcc_handover_size);
- EXPECT_EQ(kDiceResultBufferTooSmall, result);
- EXPECT_GT(next_bcc_handover_size, sizeof(bcc_handover));
- std::vector<uint8_t> next_bcc_handover(next_bcc_handover_size);
- result = BccHandoverMainFlow(
- /*context=*/NULL, bcc_handover, sizeof(bcc_handover), &input_values,
- next_bcc_handover.size(), next_bcc_handover.data(),
- &next_bcc_handover_size);
- EXPECT_EQ(kDiceResultOk, result);
- EXPECT_EQ(next_bcc_handover_size, next_bcc_handover.size());
- EXPECT_EQ(0xa3, next_bcc_handover[0]);
- EXPECT_EQ(0x83, next_bcc_handover[72]);
- EXPECT_NE(0, memcmp(next_bcc_handover.data() + 73, bcc_handover + 73,
- sizeof(bcc_handover) - 73));
- EXPECT_EQ(0, memcmp(next_bcc_handover.data() + 73, bcc_handover + 73,
- sizeof(bcc_handover) - 8 - 73));
-}
-
-TEST(BccHandoverTest, InHandoverWithoutBccOutHandoverWithBcc) {
- const uint8_t bcc_handover[] = {
- 0xa2,
- // CDI attest
- 0x01, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // CDI seal
- 0x02, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // 8-bytes of trailing data that aren't part of the BCC.
- 0x00, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40};
- DiceInputValues input_values = {};
- size_t next_bcc_handover_size;
- DiceResult result = BccHandoverMainFlow(
- /*context=*/NULL, bcc_handover, sizeof(bcc_handover), &input_values, 0,
- NULL, &next_bcc_handover_size);
- EXPECT_EQ(kDiceResultBufferTooSmall, result);
- EXPECT_GT(next_bcc_handover_size, sizeof(bcc_handover));
- std::vector<uint8_t> next_bcc_handover(next_bcc_handover_size);
- result = BccHandoverMainFlow(
- /*context=*/NULL, bcc_handover, sizeof(bcc_handover), &input_values,
- next_bcc_handover.size(), next_bcc_handover.data(),
- &next_bcc_handover_size);
- EXPECT_EQ(kDiceResultOk, result);
- EXPECT_EQ(next_bcc_handover_size, next_bcc_handover.size());
- EXPECT_EQ(0xa3, next_bcc_handover[0]);
-}
-
-TEST(BccHandoverTest, InHandoverWithoutBccButUnknownFieldOutHandoverWithBcc) {
- const uint8_t bcc_handover[] = {
- 0xa3,
- // CDI attest
- 0x01, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // CDI seal
- 0x02, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // Ignored unknown field
- 0x04, 0x01,
- // 8-bytes of trailing data that aren't part of the BCC.
- 0x00, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40};
- DiceInputValues input_values = {};
- size_t next_bcc_handover_size;
- DiceResult result = BccHandoverMainFlow(
- /*context=*/NULL, bcc_handover, sizeof(bcc_handover), &input_values, 0,
- NULL, &next_bcc_handover_size);
- EXPECT_EQ(kDiceResultBufferTooSmall, result);
- EXPECT_GT(next_bcc_handover_size, sizeof(bcc_handover));
- std::vector<uint8_t> next_bcc_handover(next_bcc_handover_size);
- result = BccHandoverMainFlow(
- /*context=*/NULL, bcc_handover, sizeof(bcc_handover), &input_values,
- next_bcc_handover.size(), next_bcc_handover.data(),
- &next_bcc_handover_size);
- EXPECT_EQ(kDiceResultOk, result);
- EXPECT_EQ(next_bcc_handover_size, next_bcc_handover.size());
- EXPECT_EQ(0xa3, next_bcc_handover[0]);
-}
-
-TEST(BccHandoverTest, ParseHandover) {
- const uint8_t bcc_handover[] = {
- 0xa3,
- // CDI attest
- 0x01, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // CDI seal
- 0x02, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // BCC
- 0x03, 0x82, 0xa6, 0x01, 0x02, 0x03, 0x27, 0x04, 0x02, 0x20, 0x01, 0x21,
- 0x40, 0x22, 0x40, 0x84, 0x40, 0xa0, 0x40, 0x40,
- // 8-bytes of trailing data that aren't part of the BCC.
- 0x00, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40};
- const uint8_t *cdi_attest;
- const uint8_t *cdi_seal;
- const uint8_t *bcc;
- size_t bcc_size;
- DiceResult result = BccHandoverParse(bcc_handover, sizeof(bcc_handover),
- &cdi_attest, &cdi_seal, &bcc, &bcc_size);
- EXPECT_EQ(kDiceResultOk, result);
- EXPECT_EQ(bcc_handover + 4, cdi_attest);
- EXPECT_EQ(bcc_handover + 39, cdi_seal);
- EXPECT_EQ(bcc_handover + 72, bcc);
- EXPECT_EQ(19u, bcc_size);
-}
-
-TEST(BccHandoverTest, ParseHandoverWithoutBcc) {
- const uint8_t bcc_handover[] = {
- 0xa2,
- // CDI attest
- 0x01, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // CDI seal
- 0x02, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // 8-bytes of trailing data that aren't part of the BCC.
- 0x00, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40};
- const uint8_t *cdi_attest;
- const uint8_t *cdi_seal;
- const uint8_t *bcc;
- size_t bcc_size;
- DiceResult result = BccHandoverParse(bcc_handover, sizeof(bcc_handover),
- &cdi_attest, &cdi_seal, &bcc, &bcc_size);
- EXPECT_EQ(kDiceResultOk, result);
- EXPECT_EQ(bcc_handover + 4, cdi_attest);
- EXPECT_EQ(bcc_handover + 39, cdi_seal);
- EXPECT_EQ(nullptr, bcc);
- EXPECT_EQ(0u, bcc_size);
-}
-
-TEST(BccHandoverTest, ParseHandoverWithoutBccButUnknownField) {
- const uint8_t bcc_handover[] = {
- 0xa3,
- // CDI attest
- 0x01, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // CDI seal
- 0x02, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // Ignored unknown field
- 0x04, 0x01,
- // 8-bytes of trailing data that aren't part of the BCC.
- 0x00, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40};
- const uint8_t *cdi_attest;
- const uint8_t *cdi_seal;
- const uint8_t *bcc;
- size_t bcc_size;
- DiceResult result = BccHandoverParse(bcc_handover, sizeof(bcc_handover),
- &cdi_attest, &cdi_seal, &bcc, &bcc_size);
- EXPECT_EQ(kDiceResultOk, result);
- EXPECT_EQ(bcc_handover + 4, cdi_attest);
- EXPECT_EQ(bcc_handover + 39, cdi_seal);
- EXPECT_EQ(nullptr, bcc);
- EXPECT_EQ(0u, bcc_size);
-}
-
-TEST(BccHandoverTest, ParseHandoverCdiTooLarge) {
- const uint8_t bcc_handover[] = {
- 0xa2,
- // CDI attest
- 0x01, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // CDI seal
- 0x02, 0x58, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // 8-bytes of trailing data that aren't part of the BCC.
- 0x00, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40};
- const uint8_t *cdi_attest;
- const uint8_t *cdi_seal;
- const uint8_t *bcc;
- size_t bcc_size;
- DiceResult result = BccHandoverParse(bcc_handover, sizeof(bcc_handover),
- &cdi_attest, &cdi_seal, &bcc, &bcc_size);
- EXPECT_EQ(kDiceResultInvalidInput, result);
-}
-}
-
-} // namespace
diff --git a/src/android/bcc_fuzzer.cc b/src/android_fuzzer.cc
similarity index 67%
rename from src/android/bcc_fuzzer.cc
rename to src/android_fuzzer.cc
index 8c4934d..baa0cd2 100644
--- a/src/android/bcc_fuzzer.cc
+++ b/src/android_fuzzer.cc
@@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations under
// the License.
-#include "dice/android/bcc.h"
+#include "dice/android.h"
#include "dice/fuzz_utils.h"
#include "dice/utils.h"
#include "fuzzer/FuzzedDataProvider.h"
@@ -30,21 +30,20 @@
// Prepare the fuzzed inputs.
auto input_values = FuzzedInputValues::ConsumeFrom(fdp);
- auto bcc_handover = ConsumeRandomLengthStringAsBytesFrom(fdp);
+ auto handover = ConsumeRandomLengthStringAsBytesFrom(fdp);
// Initialize output parameters with fuzz data in case they are wrongly being
// read from.
- constexpr size_t kNextBccHandoverBufferSize = 1024;
- auto next_bcc_handover_actual_size = fdp.ConsumeIntegral<size_t>();
- uint8_t next_bcc_handover[kNextBccHandoverBufferSize] = {};
+ constexpr size_t kNextHandoverBufferSize = 1024;
+ auto next_handover_actual_size = fdp.ConsumeIntegral<size_t>();
+ uint8_t next_handover[kNextHandoverBufferSize] = {};
- fdp.ConsumeData(&next_bcc_handover, kNextBccHandoverBufferSize);
+ fdp.ConsumeData(&next_handover, kNextHandoverBufferSize);
// Fuzz the main flow.
- BccHandoverMainFlow(/*context=*/NULL, bcc_handover.data(),
- bcc_handover.size(), input_values,
- kNextBccHandoverBufferSize, next_bcc_handover,
- &next_bcc_handover_actual_size);
+ DiceAndroidHandoverMainFlow(
+ /*context=*/NULL, handover.data(), handover.size(), input_values,
+ kNextHandoverBufferSize, next_handover, &next_handover_actual_size);
return 0;
}
diff --git a/src/android_test.cc b/src/android_test.cc
new file mode 100644
index 0000000..e7bc394
--- /dev/null
+++ b/src/android_test.cc
@@ -0,0 +1,309 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "dice/android.h"
+
+#include "dice/test_framework.h"
+
+namespace {
+
+extern "C" {
+
+TEST(DiceAndroidConfigTest, NoConfigFields) {
+ DiceAndroidConfigValues input_values = {};
+ uint8_t buffer[10];
+ size_t buffer_size;
+ DiceResult result = DiceAndroidFormatConfigDescriptor(
+ &input_values, sizeof(buffer), buffer, &buffer_size);
+ EXPECT_EQ(kDiceResultOk, result);
+ EXPECT_EQ(1u, buffer_size);
+ EXPECT_EQ(0xa0, buffer[0]);
+}
+
+TEST(DiceAndroidConfigTest, NoConfigFieldsMeasurement) {
+ DiceAndroidConfigValues config_values = {};
+ size_t buffer_size;
+ DiceResult result =
+ DiceAndroidFormatConfigDescriptor(&config_values, 0, NULL, &buffer_size);
+ EXPECT_EQ(kDiceResultBufferTooSmall, result);
+ EXPECT_EQ(1u, buffer_size);
+}
+
+TEST(DiceAndroidConfigTest, AllConfigFields) {
+ DiceAndroidConfigValues config_values = {
+ .configs = DICE_ANDROID_CONFIG_COMPONENT_NAME |
+ DICE_ANDROID_CONFIG_COMPONENT_VERSION |
+ DICE_ANDROID_CONFIG_RESETTABLE,
+ .component_name = "Test Component Name",
+ .component_version = 0x232a13dec90f42b5,
+ };
+ size_t buffer_size;
+ DiceResult result =
+ DiceAndroidFormatConfigDescriptor(&config_values, 0, NULL, &buffer_size);
+ EXPECT_EQ(kDiceResultBufferTooSmall, result);
+ std::vector<uint8_t> buffer(buffer_size);
+ const uint8_t expected[] = {
+ 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x73, 'T', 'e', 's', 't', ' ',
+ 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n', 't', ' ', 'N', 'a',
+ 'm', 'e', 0x3a, 0x00, 0x01, 0x11, 0x72, 0x1b, 0x23, 0x2a, 0x13, 0xde,
+ 0xc9, 0x0f, 0x42, 0xb5, 0x3a, 0x00, 0x01, 0x11, 0x73, 0xf6};
+ EXPECT_EQ(sizeof(expected), buffer.size());
+ result = DiceAndroidFormatConfigDescriptor(&config_values, buffer.size(),
+ buffer.data(), &buffer_size);
+ EXPECT_EQ(sizeof(expected), buffer_size);
+ EXPECT_EQ(0, memcmp(expected, buffer.data(), buffer.size()));
+}
+
+TEST(DiceAndroidTest, PreservesPreviousEntries) {
+ const uint8_t chain[] = {
+ // Fake DICE chain with the root public key and two entries.
+ 0x83,
+ // Fake public key.
+ 0xa6, 0x01, 0x02, 0x03, 0x27, 0x04, 0x02, 0x20, 0x01, 0x21, 0x40, 0x22,
+ 0x40,
+ // Fake DICE chain entry.
+ 0x84, 0x40, 0xa0, 0x40, 0x40,
+ // Fake DICE chain entry.
+ 0x84, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40,
+ // 8-bytes of trailing data that aren't part of the DICE chain.
+ 0x84, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40};
+ const uint8_t fake_cdi_attest[DICE_CDI_SIZE] = {};
+ const uint8_t fake_cdi_seal[DICE_CDI_SIZE] = {};
+ DiceInputValues input_values = {};
+ size_t next_chain_size;
+ uint8_t next_cdi_attest[DICE_CDI_SIZE];
+ uint8_t next_cdi_seal[DICE_CDI_SIZE];
+ DiceResult result = DiceAndroidMainFlow(
+ /*context=*/NULL, fake_cdi_attest, fake_cdi_seal, chain, sizeof(chain),
+ &input_values, 0, NULL, &next_chain_size, next_cdi_attest, next_cdi_seal);
+ EXPECT_EQ(kDiceResultBufferTooSmall, result);
+ EXPECT_GT(next_chain_size, sizeof(chain));
+ std::vector<uint8_t> next_chain(next_chain_size);
+ result = DiceAndroidMainFlow(
+ /*context=*/NULL, fake_cdi_attest, fake_cdi_seal, chain, sizeof(chain),
+ &input_values, next_chain.size(), next_chain.data(), &next_chain_size,
+ next_cdi_attest, next_cdi_seal);
+ EXPECT_EQ(kDiceResultOk, result);
+ EXPECT_EQ(next_chain_size, next_chain.size());
+ EXPECT_EQ(0x84, next_chain[0]);
+ EXPECT_NE(0, memcmp(next_chain.data() + 1, chain + 1, sizeof(chain) - 1));
+ EXPECT_EQ(0, memcmp(next_chain.data() + 1, chain + 1, sizeof(chain) - 8 - 1));
+}
+
+TEST(DiceAndroidHandoverTest, PreservesPreviousEntries) {
+ const uint8_t handover[] = {
+ 0xa3,
+ // CDI attest
+ 0x01, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // CDI seal
+ 0x02, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // DICE chain
+ 0x03, 0x82, 0xa6, 0x01, 0x02, 0x03, 0x27, 0x04, 0x02, 0x20, 0x01, 0x21,
+ 0x40, 0x22, 0x40, 0x84, 0x40, 0xa0, 0x40, 0x40,
+ // 8-bytes of trailing data that aren't part of the DICE chain.
+ 0x84, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40};
+ DiceInputValues input_values = {};
+ size_t next_handover_size;
+ DiceResult result = DiceAndroidHandoverMainFlow(
+ /*context=*/NULL, handover, sizeof(handover), &input_values, 0, NULL,
+ &next_handover_size);
+ EXPECT_EQ(kDiceResultBufferTooSmall, result);
+ EXPECT_GT(next_handover_size, sizeof(handover));
+ std::vector<uint8_t> next_handover(next_handover_size);
+ result = DiceAndroidHandoverMainFlow(
+ /*context=*/NULL, handover, sizeof(handover), &input_values,
+ next_handover.size(), next_handover.data(), &next_handover_size);
+ EXPECT_EQ(kDiceResultOk, result);
+ EXPECT_EQ(next_handover_size, next_handover.size());
+ EXPECT_EQ(0xa3, next_handover[0]);
+ EXPECT_EQ(0x83, next_handover[72]);
+ EXPECT_NE(0, memcmp(next_handover.data() + 73, handover + 73,
+ sizeof(handover) - 73));
+ EXPECT_EQ(0, memcmp(next_handover.data() + 73, handover + 73,
+ sizeof(handover) - 8 - 73));
+}
+
+TEST(DiceAndroidHandoverTest,
+ InHandoverWithoutDiceChainOutHandoverWithDiceChain) {
+ const uint8_t handover[] = {
+ 0xa2,
+ // CDI attest
+ 0x01, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // CDI seal
+ 0x02, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // 8-bytes of trailing data that aren't part of the DICE chain.
+ 0x00, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40};
+ DiceInputValues input_values = {};
+ size_t next_handover_size;
+ DiceResult result = DiceAndroidHandoverMainFlow(
+ /*context=*/NULL, handover, sizeof(handover), &input_values, 0, NULL,
+ &next_handover_size);
+ EXPECT_EQ(kDiceResultBufferTooSmall, result);
+ EXPECT_GT(next_handover_size, sizeof(handover));
+ std::vector<uint8_t> next_handover(next_handover_size);
+ result = DiceAndroidHandoverMainFlow(
+ /*context=*/NULL, handover, sizeof(handover), &input_values,
+ next_handover.size(), next_handover.data(), &next_handover_size);
+ EXPECT_EQ(kDiceResultOk, result);
+ EXPECT_EQ(next_handover_size, next_handover.size());
+ EXPECT_EQ(0xa3, next_handover[0]);
+}
+
+TEST(DiceAndroidHandoverTest,
+ InHandoverWithoutDiceChainButUnknownFieldOutHandoverWithDiceChain) {
+ const uint8_t handover[] = {
+ 0xa3,
+ // CDI attest
+ 0x01, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // CDI seal
+ 0x02, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // Ignored unknown field
+ 0x04, 0x01,
+ // 8-bytes of trailing data that aren't part of the DICE chain.
+ 0x00, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40};
+ DiceInputValues input_values = {};
+ size_t next_handover_size;
+ DiceResult result = DiceAndroidHandoverMainFlow(
+ /*context=*/NULL, handover, sizeof(handover), &input_values, 0, NULL,
+ &next_handover_size);
+ EXPECT_EQ(kDiceResultBufferTooSmall, result);
+ EXPECT_GT(next_handover_size, sizeof(handover));
+ std::vector<uint8_t> next_handover(next_handover_size);
+ result = DiceAndroidHandoverMainFlow(
+ /*context=*/NULL, handover, sizeof(handover), &input_values,
+ next_handover.size(), next_handover.data(), &next_handover_size);
+ EXPECT_EQ(kDiceResultOk, result);
+ EXPECT_EQ(next_handover_size, next_handover.size());
+ EXPECT_EQ(0xa3, next_handover[0]);
+}
+
+TEST(DiceAndroidHandoverTest, ParseHandover) {
+ const uint8_t handover[] = {
+ 0xa3,
+ // CDI attest
+ 0x01, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // CDI seal
+ 0x02, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // DICE chain
+ 0x03, 0x82, 0xa6, 0x01, 0x02, 0x03, 0x27, 0x04, 0x02, 0x20, 0x01, 0x21,
+ 0x40, 0x22, 0x40, 0x84, 0x40, 0xa0, 0x40, 0x40,
+ // 8-bytes of trailing data that aren't part of the DICE chain.
+ 0x00, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40};
+ const uint8_t *cdi_attest;
+ const uint8_t *cdi_seal;
+ const uint8_t *chain;
+ size_t chain_size;
+ DiceResult result = DiceAndroidHandoverParse(
+ handover, sizeof(handover), &cdi_attest, &cdi_seal, &chain, &chain_size);
+ EXPECT_EQ(kDiceResultOk, result);
+ EXPECT_EQ(handover + 4, cdi_attest);
+ EXPECT_EQ(handover + 39, cdi_seal);
+ EXPECT_EQ(handover + 72, chain);
+ EXPECT_EQ(19u, chain_size);
+}
+
+TEST(DiceAndroidHandoverTest, ParseHandoverWithoutDiceChain) {
+ const uint8_t handover[] = {
+ 0xa2,
+ // CDI attest
+ 0x01, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // CDI seal
+ 0x02, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // 8-bytes of trailing data that aren't part of the DICE chain.
+ 0x00, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40};
+ const uint8_t *cdi_attest;
+ const uint8_t *cdi_seal;
+ const uint8_t *chain;
+ size_t chain_size;
+ DiceResult result = DiceAndroidHandoverParse(
+ handover, sizeof(handover), &cdi_attest, &cdi_seal, &chain, &chain_size);
+ EXPECT_EQ(kDiceResultOk, result);
+ EXPECT_EQ(handover + 4, cdi_attest);
+ EXPECT_EQ(handover + 39, cdi_seal);
+ EXPECT_EQ(nullptr, chain);
+ EXPECT_EQ(0u, chain_size);
+}
+
+TEST(DiceAndroidHandoverTest, ParseHandoverWithoutDiceChainButUnknownField) {
+ const uint8_t handover[] = {
+ 0xa3,
+ // CDI attest
+ 0x01, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // CDI seal
+ 0x02, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // Ignored unknown field
+ 0x04, 0x01,
+ // 8-bytes of trailing data that aren't part of the DICE chain.
+ 0x00, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40};
+ const uint8_t *cdi_attest;
+ const uint8_t *cdi_seal;
+ const uint8_t *chain;
+ size_t chain_size;
+ DiceResult result = DiceAndroidHandoverParse(
+ handover, sizeof(handover), &cdi_attest, &cdi_seal, &chain, &chain_size);
+ EXPECT_EQ(kDiceResultOk, result);
+ EXPECT_EQ(handover + 4, cdi_attest);
+ EXPECT_EQ(handover + 39, cdi_seal);
+ EXPECT_EQ(nullptr, chain);
+ EXPECT_EQ(0u, chain_size);
+}
+
+TEST(DiceAndroidHandoverTest, ParseHandoverCdiTooLarge) {
+ const uint8_t handover[] = {
+ 0xa2,
+ // CDI attest
+ 0x01, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // CDI seal
+ 0x02, 0x58, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // 8-bytes of trailing data that aren't part of the DICE chain.
+ 0x00, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40};
+ const uint8_t *cdi_attest;
+ const uint8_t *cdi_seal;
+ const uint8_t *chain;
+ size_t chain_size;
+ DiceResult result = DiceAndroidHandoverParse(
+ handover, sizeof(handover), &cdi_attest, &cdi_seal, &chain, &chain_size);
+ EXPECT_EQ(kDiceResultInvalidInput, result);
+}
+}
+
+} // namespace