diff options
author | Andrew Scull <ascull@google.com> | 2021-11-05 12:26:28 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-11-05 12:26:28 +0000 |
commit | 746b972f4f95208df6f44fe352fe52447c942660 (patch) | |
tree | e2bb105df350d8ffd48959c9de5f6e622972074f | |
parent | b34b2626a687ab030c47d984cce45ac4e4d152fe (diff) | |
parent | 82daf838f02f9b6c4832b823e65304e6f43a0a74 (diff) | |
download | open-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.gn | 3 | ||||
-rw-r--r-- | include/dice/android/bcc.h | 87 | ||||
-rw-r--r-- | include/dice/fuzz_utils.h | 72 | ||||
-rw-r--r-- | src/android/BUILD.gn | 45 | ||||
-rw-r--r-- | src/android/README.md | 8 | ||||
-rw-r--r-- | src/android/bcc.c | 202 | ||||
-rw-r--r-- | src/android/bcc_fuzzer.cc | 50 | ||||
-rw-r--r-- | src/android/bcc_test.cc | 119 | ||||
-rw-r--r-- | src/fuzzer.cc | 53 |
9 files changed, 589 insertions, 50 deletions
@@ -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, ¤t_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, ¤t_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. |