Update BccHandoverMainFlow to handle BccHandovers where Bcc is absent.
For privacy reasons, Bcc might be absent in BccHandover in some cases.
E.g. aosp/2025443
This CL updates BccHandoverMainFlow to handle such BccHandovers and
to produce BccHandover to the next stage.
Bug: 220375452
Test: A new test is added to test bcc-handover without bcc given as
input to BccHandoverMainFlow.
Change-Id: I72bf06beb134a262acd6d2851170a7a415551adc
Reviewed-on: https://pigweed-review.googlesource.com/c/open-dice/+/88200
Reviewed-by: Andrew Scull <ascull@google.com>
Reviewed-by: Darren Krahn <dkrahn@google.com>
Commit-Queue: Hasini Gunasinghe <hasinitg@google.com>
diff --git a/src/android/BUILD.gn b/src/android/BUILD.gn
index 4cef1b0..dd8bdbc 100644
--- a/src/android/BUILD.gn
+++ b/src/android/BUILD.gn
@@ -21,6 +21,7 @@
deps = [
"//:cbor_reader",
"//:cbor_writer",
+ "//:dice_with_cbor_cert",
]
}
@@ -30,7 +31,6 @@
]
deps = [
":bcc",
- "//:dice_with_cbor_cert",
]
}
@@ -40,6 +40,5 @@
]
deps = [
":bcc",
- "//:dice_with_boringssl_ops",
]
}
diff --git a/src/android/bcc.c b/src/android/bcc.c
index 60a98a0..1990e5c 100644
--- a/src/android/bcc.c
+++ b/src/android/bcc.c
@@ -18,7 +18,9 @@
#include "dice/cbor_reader.h"
#include "dice/cbor_writer.h"
+#include "dice/ops/trait/cose.h"
#include "dice/dice.h"
+#include "dice/ops.h"
// Completely gratuitous bit twiddling.
static size_t PopulationCount(uint32_t n) {
@@ -127,6 +129,69 @@
return kDiceResultOk;
}
+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);
+ if (CborOutOverflowed(&out)) {
+ result = kDiceResultBufferTooSmall;
+ goto out;
+ }
+ size_t encoded_size_used = CborOutSize(&out);
+ 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) {
+ goto out;
+ }
+
+ buffer += encoded_pub_key_size;
+ buffer_size -= encoded_pub_key_size;
+
+ result = DiceMainFlow(context, current_cdi_attest, current_cdi_seal,
+ input_values, buffer_size, buffer, bcc_size,
+ next_cdi_attest, next_cdi_seal);
+ if (result != kDiceResultOk) {
+ return result;
+ }
+ bcc_size += encoded_size_used + encoded_pub_key_size;
+
+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;
+}
+
DiceResult BccHandoverMainFlow(void* context, const uint8_t* bcc_handover,
size_t bcc_handover_size,
const DiceInputValues* input_values,
@@ -146,13 +211,13 @@
// BccHandover = {
// 1 : bstr .size 32, ; CDI_Attest
// 2 : bstr .size 32, ; CDI_Seal
- // 3 : Bcc, ; Certificate chain
+ // ? 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 ||
+ if (CborReadMap(&in, &item_size) != CBOR_READ_RESULT_OK || item_size < 2 ||
// Read the attestation CDI.
CborReadInt(&in, &label) != CBOR_READ_RESULT_OK ||
label != kCdiAttestLabel ||
@@ -163,17 +228,23 @@
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) {
+ item_size != DICE_CDI_SIZE) {
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 = 0;
+ // Calculate the BCC size, if the BCC is present in the BccHandover.
+ if (CborReadInt(&in, &label) == CBOR_READ_RESULT_OK) {
+ if (label != kBccLabel) {
+ return kDiceResultInvalidInput;
+ }
+ size_t bcc_start = CborInOffset(&in);
+ bcc = bcc_handover + bcc_start;
+ if (CborReadSkip(&in) != CBOR_READ_RESULT_OK) {
+ return kDiceResultInvalidInput;
+ }
+ bcc_size = CborInOffset(&in) - bcc_start;
}
- size_t bcc_size = CborInOffset(&in) - bcc_start;
// Write the new handover data.
struct CborOut out;
@@ -189,14 +260,24 @@
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;
+ 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 - CborOutSize(&out),
+ buffer + CborOutSize(&out), &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 - 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_test.cc b/src/android/bcc_test.cc
index 20bea0d..44dce5b 100644
--- a/src/android/bcc_test.cc
+++ b/src/android/bcc_test.cc
@@ -114,6 +114,29 @@
EXPECT_EQ(0, memcmp(next_bcc_handover + 73, bcc_handover + 73,
sizeof(bcc_handover) - 8 - 73));
}
+
+TEST(BccHandoverNoCertTest, 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,
+ };
+ DiceInputValues input_values = {};
+ uint8_t next_bcc_handover[1024] = {};
+ 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]);
+}
}
} // namespace