Add BCC functions

The Boot Certificate Chain (BCC) is an application of the Open Profile
for DICE that is used by Android. The BCC conforms to the Open Profile
for DICE standard and goes on to specify more strictly details such as
the configuration descriptor.

There is also an example of a data format used to pass the BCC between
boot stages. This BCC handover format encodes the CDIs as well as the
BCC.

Change-Id: Ib32bb0fba317cf5320d60e8479eb0484a6f90c71
Reviewed-on: https://pigweed-review.googlesource.com/c/open-dice/+/65402
Commit-Queue: Andrew Scull <ascull@google.com>
Pigweed-Auto-Submit: Andrew Scull <ascull@google.com>
Reviewed-by: Darren Krahn <dkrahn@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index af1a1fc..fa15140 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -303,6 +303,7 @@
     ":mbedtls_ops_test",
     ":template_cbor_cert_op_test",
     ":template_cert_op_test",
+    "//src/android:bcc_test",
   ]
 }
 
@@ -315,6 +316,7 @@
     ":mbedtls_ops_fuzzer",
     ":template_cbor_cert_op_fuzzer",
     ":template_cert_op_fuzzer",
+    "//src/android:bcc_fuzzer",
   ]
 }
 
@@ -451,5 +453,6 @@
     ":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.