aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Scull <ascull@google.com>2021-11-05 12:26:28 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-11-05 12:26:28 +0000
commit746b972f4f95208df6f44fe352fe52447c942660 (patch)
treee2bb105df350d8ffd48959c9de5f6e622972074f
parentb34b2626a687ab030c47d984cce45ac4e4d152fe (diff)
parent82daf838f02f9b6c4832b823e65304e6f43a0a74 (diff)
downloadopen-dice-746b972f4f95208df6f44fe352fe52447c942660.tar.gz
Merge remote-tracking branch 'aosp/upstream-main' into HEAD am: 249e3c5b8d am: 8a8adcd55a am: 6bedce66cf am: 82daf838f0
Original change: https://android-review.googlesource.com/c/platform/external/open-dice/+/1880276 Change-Id: I87465b30e4a44003a2c6cc6e7395729a4ec3beee
-rw-r--r--BUILD.gn3
-rw-r--r--include/dice/android/bcc.h87
-rw-r--r--include/dice/fuzz_utils.h72
-rw-r--r--src/android/BUILD.gn45
-rw-r--r--src/android/README.md8
-rw-r--r--src/android/bcc.c202
-rw-r--r--src/android/bcc_fuzzer.cc50
-rw-r--r--src/android/bcc_test.cc119
-rw-r--r--src/fuzzer.cc53
9 files changed, 589 insertions, 50 deletions
diff --git a/BUILD.gn b/BUILD.gn
index af1a1fc..fa15140 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -303,6 +303,7 @@ pw_test_group("tests") {
":mbedtls_ops_test",
":template_cbor_cert_op_test",
":template_cert_op_test",
+ "//src/android:bcc_test",
]
}
@@ -315,6 +316,7 @@ group("fuzzers") {
":mbedtls_ops_fuzzer",
":template_cbor_cert_op_fuzzer",
":template_cert_op_fuzzer",
+ "//src/android:bcc_fuzzer",
]
}
@@ -451,5 +453,6 @@ group("optimized_libs") {
":dice_with_x509_template_cert",
":executable_size_report",
":library_size_report",
+ "//src/android:bcc",
]
}
diff --git a/include/dice/android/bcc.h b/include/dice/android/bcc.h
new file mode 100644
index 0000000..e3e6c55
--- /dev/null
+++ b/include/dice/android/bcc.h
@@ -0,0 +1,87 @@
+// 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.
+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.
+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.
+//
+// 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);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // DICE_ANDROID_BCC_H_
diff --git a/include/dice/fuzz_utils.h b/include/dice/fuzz_utils.h
new file mode 100644
index 0000000..dfc483d
--- /dev/null
+++ b/include/dice/fuzz_utils.h
@@ -0,0 +1,72 @@
+// 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 <cstdint>
+#include <vector>
+
+#include "dice/dice.h"
+#include "fuzzer/FuzzedDataProvider.h"
+
+namespace dice {
+namespace fuzz {
+
+static inline std::vector<uint8_t> ConsumeRandomLengthStringAsBytesFrom(
+ FuzzedDataProvider& fdp) {
+ auto s = fdp.ConsumeRandomLengthString();
+ return std::vector<uint8_t>(s.begin(), s.end());
+}
+
+struct FuzzedInputValues {
+ static FuzzedInputValues ConsumeFrom(FuzzedDataProvider& fdp) {
+ FuzzedInputValues fiv = {};
+ DiceInputValues& input_values = fiv.input_values_;
+
+ fdp.ConsumeData(&input_values.code_hash, DICE_HASH_SIZE);
+
+ fiv.code_descriptor_ = ConsumeRandomLengthStringAsBytesFrom(fdp);
+ input_values.code_descriptor = fiv.code_descriptor_.data();
+ input_values.code_descriptor_size = fiv.code_descriptor_.size();
+
+ input_values.config_type = (DiceConfigType)fdp.ConsumeIntegralInRange(0, 1);
+
+ fdp.ConsumeData(&input_values.config_value, DICE_INLINE_CONFIG_SIZE);
+
+ fiv.config_descriptor_ = ConsumeRandomLengthStringAsBytesFrom(fdp);
+ input_values.config_descriptor = fiv.config_descriptor_.data();
+ input_values.config_descriptor_size = fiv.config_descriptor_.size();
+
+ fdp.ConsumeData(&input_values.authority_hash, DICE_HASH_SIZE);
+
+ fiv.authority_descriptor_ = ConsumeRandomLengthStringAsBytesFrom(fdp);
+ input_values.authority_descriptor = fiv.authority_descriptor_.data();
+ input_values.authority_descriptor_size = fiv.authority_descriptor_.size();
+
+ input_values.mode = (DiceMode)fdp.ConsumeIntegralInRange(0, 3);
+
+ fdp.ConsumeData(&input_values.hidden, DICE_HIDDEN_SIZE);
+
+ return fiv;
+ }
+
+ operator const DiceInputValues*() const { return &input_values_; }
+
+ std::vector<uint8_t> code_descriptor_;
+ std::vector<uint8_t> config_descriptor_;
+ std::vector<uint8_t> authority_descriptor_;
+
+ DiceInputValues input_values_;
+};
+
+} // namespace fuzz
+} // namespace dice
diff --git a/src/android/BUILD.gn b/src/android/BUILD.gn
new file mode 100644
index 0000000..4cef1b0
--- /dev/null
+++ b/src/android/BUILD.gn
@@ -0,0 +1,45 @@
+# 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") {
+ sources = [ "bcc.c" ]
+ deps = [
+ "//:cbor_reader",
+ "//:cbor_writer",
+ ]
+}
+
+pw_test("bcc_test") {
+ sources = [
+ "bcc_test.cc",
+ ]
+ deps = [
+ ":bcc",
+ "//:dice_with_cbor_cert",
+ ]
+}
+
+pw_executable("bcc_fuzzer") {
+ sources = [
+ "bcc_fuzzer.cc",
+ ]
+ deps = [
+ ":bcc",
+ "//:dice_with_boringssl_ops",
+ ]
+}
diff --git a/src/android/README.md b/src/android/README.md
new file mode 100644
index 0000000..99d9395
--- /dev/null
+++ b/src/android/README.md
@@ -0,0 +1,8 @@
+# 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 int the [KeyMint AIDL definitions](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl).
diff --git a/src/android/bcc.c b/src/android/bcc.c
new file mode 100644
index 0000000..60a98a0
--- /dev/null
+++ b/src/android/bcc.c
@@ -0,0 +1,202 @@
+// 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"
+
+// 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);
+ }
+ if (CborOutOverflowed(&out)) {
+ return kDiceResultBufferTooSmall;
+ }
+ *actual_size = CborOutSize(&out);
+ 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)) {
+ return kDiceResultBufferTooSmall;
+ }
+ memcpy(buffer + CborOutSize(&out), bcc + bcc_items_offset, bcc_items_size);
+
+ size_t certificate_size;
+ result =
+ DiceMainFlow(context, current_cdi_attest, current_cdi_seal, input_values,
+ buffer_size - (CborOutSize(&out) + bcc_items_size),
+ buffer + CborOutSize(&out) + bcc_items_size,
+ &certificate_size, next_cdi_attest, next_cdi_seal);
+ if (result != kDiceResultOk) {
+ return result;
+ }
+
+ *actual_size = CborOutSize(&out) + bcc_items_size + certificate_size;
+ return kDiceResultOk;
+}
+
+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) {
+ static const int64_t kCdiAttestLabel = 1;
+ static const int64_t kCdiSealLabel = 2;
+ static const int64_t kBccLabel = 3;
+
+ DiceResult result;
+ const uint8_t* current_cdi_attest;
+ const uint8_t* current_cdi_seal;
+ const uint8_t* bcc;
+
+ // 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 item_size;
+ CborInInit(bcc_handover, bcc_handover_size, &in);
+ if (CborReadMap(&in, &item_size) != CBOR_READ_RESULT_OK || item_size < 3 ||
+ // Read the attestation CDI.
+ CborReadInt(&in, &label) != CBOR_READ_RESULT_OK ||
+ label != kCdiAttestLabel ||
+ CborReadBstr(&in, &item_size, &current_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, &current_cdi_seal) != CBOR_READ_RESULT_OK ||
+ item_size != DICE_CDI_SIZE ||
+ // Read the BCC.
+ CborReadInt(&in, &label) != CBOR_READ_RESULT_OK || label != kBccLabel) {
+ return kDiceResultInvalidInput;
+ }
+ size_t bcc_start = CborInOffset(&in);
+ bcc = bcc_handover + bcc_start;
+ if (CborReadSkip(&in) != CBOR_READ_RESULT_OK) {
+ return kDiceResultInvalidInput;
+ }
+ size_t bcc_size = CborInOffset(&in) - bcc_start;
+
+ // 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);
+
+ if (CborOutOverflowed(&out) || !next_cdi_attest || !next_cdi_seal) {
+ return kDiceResultBufferTooSmall;
+ }
+
+ result = BccMainFlow(context, current_cdi_attest, current_cdi_seal, bcc,
+ bcc_size, input_values, buffer_size - CborOutSize(&out),
+ buffer + CborOutSize(&out), &bcc_size, next_cdi_attest,
+ next_cdi_seal);
+ if (result != kDiceResultOk) {
+ return result;
+ }
+
+ *actual_size = CborOutSize(&out) + bcc_size;
+ return kDiceResultOk;
+}
diff --git a/src/android/bcc_fuzzer.cc b/src/android/bcc_fuzzer.cc
new file mode 100644
index 0000000..8c4934d
--- /dev/null
+++ b/src/android/bcc_fuzzer.cc
@@ -0,0 +1,50 @@
+// 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/fuzz_utils.h"
+#include "dice/utils.h"
+#include "fuzzer/FuzzedDataProvider.h"
+
+using dice::fuzz::ConsumeRandomLengthStringAsBytesFrom;
+using dice::fuzz::FuzzedInputValues;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ // Exit early if there might not be enough data to fill buffers.
+ if (size < 512) {
+ return 0;
+ }
+
+ FuzzedDataProvider fdp(data, size);
+
+ // Prepare the fuzzed inputs.
+ auto input_values = FuzzedInputValues::ConsumeFrom(fdp);
+ auto bcc_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] = {};
+
+ fdp.ConsumeData(&next_bcc_handover, kNextBccHandoverBufferSize);
+
+ // Fuzz the main flow.
+ BccHandoverMainFlow(/*context=*/NULL, bcc_handover.data(),
+ bcc_handover.size(), input_values,
+ kNextBccHandoverBufferSize, next_bcc_handover,
+ &next_bcc_handover_actual_size);
+
+ return 0;
+}
diff --git a/src/android/bcc_test.cc b/src/android/bcc_test.cc
new file mode 100644
index 0000000..20bea0d
--- /dev/null
+++ b/src/android/bcc_test.cc
@@ -0,0 +1,119 @@
+// 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, AllInputs) {
+ BccConfigValues input_values = {
+ .inputs = BCC_INPUT_COMPONENT_NAME | BCC_INPUT_COMPONENT_VERSION |
+ BCC_INPUT_RESETTABLE,
+ .component_name = "Test Component Name",
+ .component_version = 0x232a13dec90f42b5,
+ };
+ uint8_t buffer[256];
+ size_t buffer_size;
+ DiceResult result = BccFormatConfigDescriptor(&input_values, sizeof(buffer),
+ buffer, &buffer_size);
+ EXPECT_EQ(kDiceResultOk, result);
+ 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);
+ EXPECT_EQ(0, memcmp(expected, buffer, 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 = {};
+ uint8_t next_bcc[2048] = {};
+ 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, sizeof(next_bcc), next_bcc,
+ &next_bcc_size, next_cdi_attest, next_cdi_seal);
+ EXPECT_EQ(kDiceResultOk, result);
+ EXPECT_GT(next_bcc_size, sizeof(bcc));
+ EXPECT_EQ(0x84, next_bcc[0]);
+ EXPECT_NE(0, memcmp(next_bcc + 1, bcc + 1, sizeof(bcc) - 1));
+ EXPECT_EQ(0, memcmp(next_bcc + 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 = {};
+ uint8_t next_bcc_handover[2048] = {};
+ size_t next_bcc_handover_size;
+ DiceResult result = BccHandoverMainFlow(
+ /*context=*/NULL, bcc_handover, sizeof(bcc_handover), &input_values,
+ sizeof(next_bcc_handover), next_bcc_handover, &next_bcc_handover_size);
+ EXPECT_EQ(kDiceResultOk, result);
+ EXPECT_GT(next_bcc_handover_size, sizeof(bcc_handover));
+ EXPECT_EQ(0xa3, next_bcc_handover[0]);
+ EXPECT_EQ(0x83, next_bcc_handover[72]);
+ EXPECT_NE(0, memcmp(next_bcc_handover + 73, bcc_handover + 73,
+ sizeof(bcc_handover) - 73));
+ EXPECT_EQ(0, memcmp(next_bcc_handover + 73, bcc_handover + 73,
+ sizeof(bcc_handover) - 8 - 73));
+}
+}
+
+} // namespace
diff --git a/src/fuzzer.cc b/src/fuzzer.cc
index 8acb01e..71de9a1 100644
--- a/src/fuzzer.cc
+++ b/src/fuzzer.cc
@@ -13,59 +13,12 @@
// the License.
#include "dice/dice.h"
+#include "dice/fuzz_utils.h"
#include "dice/utils.h"
#include "fuzzer/FuzzedDataProvider.h"
-namespace {
-
-std::vector<uint8_t> ConsumeRandomLengthStringAsBytesFrom(
- FuzzedDataProvider& fdp) {
- auto s = fdp.ConsumeRandomLengthString();
- return std::vector<uint8_t>(s.begin(), s.end());
-}
-
-struct FuzzedInputValues {
- static FuzzedInputValues ConsumeFrom(FuzzedDataProvider& fdp) {
- FuzzedInputValues fiv = {};
- DiceInputValues& input_values = fiv.input_values_;
-
- fdp.ConsumeData(&input_values.code_hash, DICE_HASH_SIZE);
-
- fiv.code_descriptor_ = ConsumeRandomLengthStringAsBytesFrom(fdp);
- input_values.code_descriptor = fiv.code_descriptor_.data();
- input_values.code_descriptor_size = fiv.code_descriptor_.size();
-
- input_values.config_type = (DiceConfigType)fdp.ConsumeIntegralInRange(0, 1);
-
- fdp.ConsumeData(&input_values.config_value, DICE_INLINE_CONFIG_SIZE);
-
- fiv.config_descriptor_ = ConsumeRandomLengthStringAsBytesFrom(fdp);
- input_values.config_descriptor = fiv.config_descriptor_.data();
- input_values.config_descriptor_size = fiv.config_descriptor_.size();
-
- fdp.ConsumeData(&input_values.authority_hash, DICE_HASH_SIZE);
-
- fiv.authority_descriptor_ = ConsumeRandomLengthStringAsBytesFrom(fdp);
- input_values.authority_descriptor = fiv.authority_descriptor_.data();
- input_values.authority_descriptor_size = fiv.authority_descriptor_.size();
-
- input_values.mode = (DiceMode)fdp.ConsumeIntegralInRange(0, 3);
-
- fdp.ConsumeData(&input_values.hidden, DICE_HIDDEN_SIZE);
-
- return fiv;
- }
-
- operator const DiceInputValues*() const { return &input_values_; }
-
- std::vector<uint8_t> code_descriptor_;
- std::vector<uint8_t> config_descriptor_;
- std::vector<uint8_t> authority_descriptor_;
-
- DiceInputValues input_values_;
-};
-
-} // namespace
+using dice::fuzz::ConsumeRandomLengthStringAsBytesFrom;
+using dice::fuzz::FuzzedInputValues;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Exit early if there might not be enough data to fill buffers.