Add a test for CoseSignAndEncodeSign1
This used to be exercised via DiceMainFlow, but it is no longer used
there.
Add a test to make sure it produces a correctly-signed CoseSign1 with
the expected payload.
Change-Id: Ia3f8f8540dab27058964028d6b53af7dc6b2d53e
Reviewed-on: https://pigweed-review.googlesource.com/c/open-dice/+/178650
Commit-Queue: Auto-Submit <auto-submit@pigweed-service-accounts.iam.gserviceaccount.com>
Reviewed-by: Andrew Scull <ascull@google.com>
Pigweed-Auto-Submit: Alan Stokes <alanstokes@google.com>
Presubmit-Verified: CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/include/dice/test_utils.h b/include/dice/test_utils.h
index 70469c4..7e403b9 100644
--- a/include/dice/test_utils.h
+++ b/include/dice/test_utils.h
@@ -58,6 +58,15 @@
uint8_t certificate[kTestCertSize],
size_t* certificate_size);
+// Verify that a single CDI certificate is properly signed with the given key
+// and contains the expected payload.
+bool VerifyCoseSign1(const uint8_t* certificate, size_t certificate_size,
+ const uint8_t* external_aad, size_t external_aad_size,
+ const uint8_t* encoded_public_key,
+ size_t encoded_public_key_size,
+ const uint8_t* expected_payload,
+ size_t expected_payload_size);
+
// Verifies a chain of CDI certificates given by |states| against
// |root_certificate|. If |is_partial_chain| is set, then root_certificate does
// not need to be self signed. For X.509 certificate chains, only the standard
diff --git a/src/cbor_cert_op_test.cc b/src/cbor_cert_op_test.cc
index c94c6c1..46ae094 100644
--- a/src/cbor_cert_op_test.cc
+++ b/src/cbor_cert_op_test.cc
@@ -20,6 +20,8 @@
#include "dice/dice.h"
#include "dice/known_test_values.h"
+#include "dice/ops.h"
+#include "dice/ops/trait/cose.h"
#include "dice/test_framework.h"
#include "dice/test_utils.h"
#include "dice/utils.h"
@@ -31,6 +33,7 @@
using dice::test::DeriveFakeInputValue;
using dice::test::DiceStateForTest;
using dice::test::KeyType_Ed25519;
+using dice::test::VerifyCoseSign1;
TEST(DiceOpsTest, KnownAnswerZeroInput) {
DiceStateForTest current_state = {};
@@ -232,6 +235,51 @@
EXPECT_EQ(kDiceResultInvalidInput, result);
}
+TEST(DiceOpsTest, CoseSignAndEncodeSign1) {
+ DiceStateForTest current_state = {};
+ DiceStateForTest next_state = {};
+ DiceInputValues input_values = {};
+ DiceResult result = DiceMainFlow(
+ NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
+ sizeof(next_state.certificate), next_state.certificate,
+ &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
+ ASSERT_EQ(kDiceResultOk, result);
+
+ uint8_t private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE];
+ result = DiceDeriveCdiPrivateKeySeed(NULL, next_state.cdi_attest,
+ private_key_seed);
+ ASSERT_EQ(kDiceResultOk, result);
+
+ uint8_t private_key[DICE_PRIVATE_KEY_SIZE];
+ uint8_t public_key[DICE_PUBLIC_KEY_SIZE];
+ result = DiceKeypairFromSeed(NULL, private_key_seed, public_key, private_key);
+ ASSERT_EQ(kDiceResultOk, result);
+
+ uint8_t encoded_public_key[DICE_PUBLIC_KEY_SIZE + 32];
+ size_t encoded_public_key_size = 0;
+ result =
+ DiceCoseEncodePublicKey(NULL, public_key, sizeof(encoded_public_key),
+ encoded_public_key, &encoded_public_key_size);
+ ASSERT_EQ(kDiceResultOk, result);
+
+ uint8_t payload[500];
+ DeriveFakeInputValue("payload", sizeof(payload), payload);
+
+ uint8_t aad[100];
+ DeriveFakeInputValue("aad", sizeof(aad), aad);
+
+ uint8_t sign1[1000];
+ size_t sign1_size;
+ result = DiceCoseSignAndEncodeSign1(NULL, payload, sizeof(payload), aad,
+ sizeof(aad), private_key, sizeof(sign1),
+ sign1, &sign1_size);
+ ASSERT_EQ(kDiceResultOk, result);
+
+ EXPECT_TRUE(VerifyCoseSign1(sign1, sign1_size, aad, sizeof(aad),
+ encoded_public_key, encoded_public_key_size,
+ payload, sizeof(payload)));
+}
+
TEST(DiceOpsTest, PartialCertChain) {
constexpr size_t kNumLayers = 7;
DiceStateForTest states[kNumLayers + 1] = {};
diff --git a/src/test_utils.cc b/src/test_utils.cc
index 12663cc..f8899e0 100644
--- a/src/test_utils.cc
+++ b/src/test_utils.cc
@@ -628,13 +628,11 @@
return true;
}
-bool VerifySingleCborCertificate(const uint8_t* certificate,
- size_t certificate_size,
- const cn_cbor* authority_public_key,
- const char authority_id_hex[40],
- bool expect_cdi_certificate,
- ScopedCbor* subject_public_key,
- char subject_id_hex[40]) {
+bool VerifyCoseSign1Signature(const uint8_t* certificate,
+ size_t certificate_size,
+ const uint8_t* external_aad,
+ size_t external_aad_size,
+ const cn_cbor* authority_public_key) {
// Use the COSE-C library to decode and validate.
cose_errback error;
int struct_type = 0;
@@ -643,12 +641,26 @@
if (!sign1) {
return false;
}
- (void)authority_public_key;
+ COSE_Sign1_SetExternal(sign1, external_aad, external_aad_size, &error);
bool result = COSE_Sign1_validate(sign1, authority_public_key, &error);
COSE_Sign1_Free(sign1);
if (!result) {
return false;
}
+ return true;
+}
+
+bool VerifySingleCborCertificate(const uint8_t* certificate,
+ size_t certificate_size,
+ const cn_cbor* authority_public_key,
+ const char authority_id_hex[40],
+ bool expect_cdi_certificate,
+ ScopedCbor* subject_public_key,
+ char subject_id_hex[40]) {
+ if (!VerifyCoseSign1Signature(certificate, certificate_size, /*aad=*/NULL,
+ /*aad_size=*/0, authority_public_key)) {
+ return false;
+ }
ScopedCbor cwt(ExtractCwtFromCborCertificate(certificate, certificate_size));
if (!cwt) {
@@ -785,6 +797,42 @@
DumpToFile(filename, certificate, *certificate_size);
}
+[[maybe_unused]] bool VerifyCoseSign1(
+ const uint8_t* certificate, size_t certificate_size,
+ const uint8_t* external_aad, size_t external_aad_size,
+ const uint8_t* encoded_public_key, size_t encoded_public_key_size,
+ const uint8_t* expected_cwt, size_t expected_cwt_size) {
+ cn_cbor_errback error;
+ ScopedCbor public_key(
+ cn_cbor_decode(encoded_public_key, encoded_public_key_size, &error));
+ if (!public_key) {
+ return false;
+ }
+
+ if (!VerifyCoseSign1Signature(certificate, certificate_size, external_aad,
+ external_aad_size, public_key.get())) {
+ return false;
+ }
+
+ ScopedCbor sign1(cn_cbor_decode(certificate, certificate_size, &error));
+ if (!sign1 || sign1->type != CN_CBOR_ARRAY || sign1->length != 4) {
+ return false;
+ }
+ cn_cbor* payload = cn_cbor_index(sign1.get(), 2);
+ if (!payload || payload->type != CN_CBOR_BYTES) {
+ return false;
+ }
+
+ if (payload->length != expected_cwt_size) {
+ return false;
+ }
+
+ if (memcmp(payload->v.bytes, expected_cwt, expected_cwt_size) != 0) {
+ return false;
+ }
+ return true;
+}
+
bool VerifyCertificateChain(CertificateType cert_type,
const uint8_t* root_certificate,
size_t root_certificate_size,