1*60b67249SAndroid Build Coastguard Worker // Copyright 2020 Google LLC
2*60b67249SAndroid Build Coastguard Worker //
3*60b67249SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*60b67249SAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*60b67249SAndroid Build Coastguard Worker // the License at
6*60b67249SAndroid Build Coastguard Worker //
7*60b67249SAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*60b67249SAndroid Build Coastguard Worker //
9*60b67249SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*60b67249SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*60b67249SAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*60b67249SAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*60b67249SAndroid Build Coastguard Worker // the License.
14*60b67249SAndroid Build Coastguard Worker
15*60b67249SAndroid Build Coastguard Worker #include <stddef.h>
16*60b67249SAndroid Build Coastguard Worker #include <stdint.h>
17*60b67249SAndroid Build Coastguard Worker #include <stdio.h>
18*60b67249SAndroid Build Coastguard Worker
19*60b67249SAndroid Build Coastguard Worker #include <memory>
20*60b67249SAndroid Build Coastguard Worker
21*60b67249SAndroid Build Coastguard Worker #include "dice/dice.h"
22*60b67249SAndroid Build Coastguard Worker #include "dice/known_test_values.h"
23*60b67249SAndroid Build Coastguard Worker #include "dice/test_framework.h"
24*60b67249SAndroid Build Coastguard Worker #include "dice/test_utils.h"
25*60b67249SAndroid Build Coastguard Worker #include "dice/utils.h"
26*60b67249SAndroid Build Coastguard Worker #include "pw_string/format.h"
27*60b67249SAndroid Build Coastguard Worker
28*60b67249SAndroid Build Coastguard Worker namespace {
29*60b67249SAndroid Build Coastguard Worker
30*60b67249SAndroid Build Coastguard Worker using dice::test::CertificateType_X509;
31*60b67249SAndroid Build Coastguard Worker using dice::test::DeriveFakeInputValue;
32*60b67249SAndroid Build Coastguard Worker using dice::test::DiceStateForTest;
33*60b67249SAndroid Build Coastguard Worker using dice::test::KeyType_Ed25519;
34*60b67249SAndroid Build Coastguard Worker
TEST(DiceOpsTest,KnownAnswerZeroInput)35*60b67249SAndroid Build Coastguard Worker TEST(DiceOpsTest, KnownAnswerZeroInput) {
36*60b67249SAndroid Build Coastguard Worker DiceStateForTest current_state = {};
37*60b67249SAndroid Build Coastguard Worker DiceStateForTest next_state = {};
38*60b67249SAndroid Build Coastguard Worker DiceInputValues input_values = {};
39*60b67249SAndroid Build Coastguard Worker DiceResult result = DiceMainFlow(
40*60b67249SAndroid Build Coastguard Worker NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
41*60b67249SAndroid Build Coastguard Worker sizeof(next_state.certificate), next_state.certificate,
42*60b67249SAndroid Build Coastguard Worker &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
43*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(kDiceResultOk, result);
44*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(0, memcmp(next_state.cdi_attest,
45*60b67249SAndroid Build Coastguard Worker dice::test::kExpectedCdiAttest_ZeroInput, DICE_CDI_SIZE));
46*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(0, memcmp(next_state.cdi_seal,
47*60b67249SAndroid Build Coastguard Worker dice::test::kExpectedCdiSeal_ZeroInput, DICE_CDI_SIZE));
48*60b67249SAndroid Build Coastguard Worker ASSERT_EQ(sizeof(dice::test::kExpectedX509Ed25519Cert_ZeroInput),
49*60b67249SAndroid Build Coastguard Worker next_state.certificate_size);
50*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(0, memcmp(dice::test::kExpectedX509Ed25519Cert_ZeroInput,
51*60b67249SAndroid Build Coastguard Worker next_state.certificate, next_state.certificate_size));
52*60b67249SAndroid Build Coastguard Worker }
53*60b67249SAndroid Build Coastguard Worker
TEST(DiceOpsTest,KnownAnswerHashOnlyInput)54*60b67249SAndroid Build Coastguard Worker TEST(DiceOpsTest, KnownAnswerHashOnlyInput) {
55*60b67249SAndroid Build Coastguard Worker DiceStateForTest current_state = {};
56*60b67249SAndroid Build Coastguard Worker DeriveFakeInputValue("cdi_attest", DICE_CDI_SIZE, current_state.cdi_attest);
57*60b67249SAndroid Build Coastguard Worker DeriveFakeInputValue("cdi_seal", DICE_CDI_SIZE, current_state.cdi_seal);
58*60b67249SAndroid Build Coastguard Worker DiceStateForTest next_state = {};
59*60b67249SAndroid Build Coastguard Worker DiceInputValues input_values = {};
60*60b67249SAndroid Build Coastguard Worker DeriveFakeInputValue("code_hash", DICE_HASH_SIZE, input_values.code_hash);
61*60b67249SAndroid Build Coastguard Worker DeriveFakeInputValue("authority_hash", DICE_HASH_SIZE,
62*60b67249SAndroid Build Coastguard Worker input_values.authority_hash);
63*60b67249SAndroid Build Coastguard Worker input_values.config_type = kDiceConfigTypeInline;
64*60b67249SAndroid Build Coastguard Worker DeriveFakeInputValue("inline_config", DICE_INLINE_CONFIG_SIZE,
65*60b67249SAndroid Build Coastguard Worker input_values.config_value);
66*60b67249SAndroid Build Coastguard Worker
67*60b67249SAndroid Build Coastguard Worker DiceResult result = DiceMainFlow(
68*60b67249SAndroid Build Coastguard Worker NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
69*60b67249SAndroid Build Coastguard Worker sizeof(next_state.certificate), next_state.certificate,
70*60b67249SAndroid Build Coastguard Worker &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
71*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(kDiceResultOk, result);
72*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(
73*60b67249SAndroid Build Coastguard Worker 0, memcmp(next_state.cdi_attest,
74*60b67249SAndroid Build Coastguard Worker dice::test::kExpectedCdiAttest_HashOnlyInput, DICE_CDI_SIZE));
75*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(
76*60b67249SAndroid Build Coastguard Worker 0, memcmp(next_state.cdi_seal, dice::test::kExpectedCdiSeal_HashOnlyInput,
77*60b67249SAndroid Build Coastguard Worker DICE_CDI_SIZE));
78*60b67249SAndroid Build Coastguard Worker ASSERT_EQ(sizeof(dice::test::kExpectedX509Ed25519Cert_HashOnlyInput),
79*60b67249SAndroid Build Coastguard Worker next_state.certificate_size);
80*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(0, memcmp(dice::test::kExpectedX509Ed25519Cert_HashOnlyInput,
81*60b67249SAndroid Build Coastguard Worker next_state.certificate, next_state.certificate_size));
82*60b67249SAndroid Build Coastguard Worker }
83*60b67249SAndroid Build Coastguard Worker
TEST(DiceOpsTest,WithCodeDescriptor)84*60b67249SAndroid Build Coastguard Worker TEST(DiceOpsTest, WithCodeDescriptor) {
85*60b67249SAndroid Build Coastguard Worker DiceStateForTest current_state = {};
86*60b67249SAndroid Build Coastguard Worker DiceStateForTest next_state = {};
87*60b67249SAndroid Build Coastguard Worker DiceInputValues input_values = {};
88*60b67249SAndroid Build Coastguard Worker uint8_t descriptor[] = {0, 1, 2, 3};
89*60b67249SAndroid Build Coastguard Worker input_values.code_descriptor = descriptor;
90*60b67249SAndroid Build Coastguard Worker input_values.code_descriptor_size = sizeof(descriptor);
91*60b67249SAndroid Build Coastguard Worker DiceResult result = DiceMainFlow(
92*60b67249SAndroid Build Coastguard Worker NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
93*60b67249SAndroid Build Coastguard Worker sizeof(next_state.certificate), next_state.certificate,
94*60b67249SAndroid Build Coastguard Worker &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
95*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(kDiceResultInvalidInput, result);
96*60b67249SAndroid Build Coastguard Worker }
97*60b67249SAndroid Build Coastguard Worker
TEST(DiceOpsTest,WithConfigDescriptor)98*60b67249SAndroid Build Coastguard Worker TEST(DiceOpsTest, WithConfigDescriptor) {
99*60b67249SAndroid Build Coastguard Worker DiceStateForTest current_state = {};
100*60b67249SAndroid Build Coastguard Worker DiceStateForTest next_state = {};
101*60b67249SAndroid Build Coastguard Worker DiceInputValues input_values = {};
102*60b67249SAndroid Build Coastguard Worker uint8_t descriptor[] = {0, 1, 2, 3};
103*60b67249SAndroid Build Coastguard Worker input_values.config_descriptor = descriptor;
104*60b67249SAndroid Build Coastguard Worker input_values.config_descriptor_size = sizeof(descriptor);
105*60b67249SAndroid Build Coastguard Worker input_values.config_type = kDiceConfigTypeDescriptor;
106*60b67249SAndroid Build Coastguard Worker DiceResult result = DiceMainFlow(
107*60b67249SAndroid Build Coastguard Worker NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
108*60b67249SAndroid Build Coastguard Worker sizeof(next_state.certificate), next_state.certificate,
109*60b67249SAndroid Build Coastguard Worker &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
110*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(kDiceResultInvalidInput, result);
111*60b67249SAndroid Build Coastguard Worker }
112*60b67249SAndroid Build Coastguard Worker
TEST(DiceOpsTest,WithAuthorityDescriptor)113*60b67249SAndroid Build Coastguard Worker TEST(DiceOpsTest, WithAuthorityDescriptor) {
114*60b67249SAndroid Build Coastguard Worker DiceStateForTest current_state = {};
115*60b67249SAndroid Build Coastguard Worker DiceStateForTest next_state = {};
116*60b67249SAndroid Build Coastguard Worker DiceInputValues input_values = {};
117*60b67249SAndroid Build Coastguard Worker uint8_t descriptor[] = {0, 1, 2, 3};
118*60b67249SAndroid Build Coastguard Worker input_values.authority_descriptor = descriptor;
119*60b67249SAndroid Build Coastguard Worker input_values.authority_descriptor_size = sizeof(descriptor);
120*60b67249SAndroid Build Coastguard Worker DiceResult result = DiceMainFlow(
121*60b67249SAndroid Build Coastguard Worker NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
122*60b67249SAndroid Build Coastguard Worker sizeof(next_state.certificate), next_state.certificate,
123*60b67249SAndroid Build Coastguard Worker &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
124*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(kDiceResultInvalidInput, result);
125*60b67249SAndroid Build Coastguard Worker }
126*60b67249SAndroid Build Coastguard Worker
TEST(DiceOpsTest,NonZeroMode)127*60b67249SAndroid Build Coastguard Worker TEST(DiceOpsTest, NonZeroMode) {
128*60b67249SAndroid Build Coastguard Worker constexpr size_t kModeOffsetInCert = 0x233;
129*60b67249SAndroid Build Coastguard Worker DiceStateForTest current_state = {};
130*60b67249SAndroid Build Coastguard Worker DiceStateForTest next_state = {};
131*60b67249SAndroid Build Coastguard Worker DiceInputValues input_values = {};
132*60b67249SAndroid Build Coastguard Worker input_values.mode = kDiceModeDebug;
133*60b67249SAndroid Build Coastguard Worker DiceResult result = DiceMainFlow(
134*60b67249SAndroid Build Coastguard Worker NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
135*60b67249SAndroid Build Coastguard Worker sizeof(next_state.certificate), next_state.certificate,
136*60b67249SAndroid Build Coastguard Worker &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
137*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(kDiceResultOk, result);
138*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(kDiceModeDebug, next_state.certificate[kModeOffsetInCert]);
139*60b67249SAndroid Build Coastguard Worker }
140*60b67249SAndroid Build Coastguard Worker
TEST(DiceOpsTest,SmallCertBuffer)141*60b67249SAndroid Build Coastguard Worker TEST(DiceOpsTest, SmallCertBuffer) {
142*60b67249SAndroid Build Coastguard Worker DiceStateForTest current_state = {};
143*60b67249SAndroid Build Coastguard Worker DiceStateForTest next_state = {};
144*60b67249SAndroid Build Coastguard Worker DiceInputValues input_values = {};
145*60b67249SAndroid Build Coastguard Worker DiceResult result = DiceMainFlow(
146*60b67249SAndroid Build Coastguard Worker NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
147*60b67249SAndroid Build Coastguard Worker 12 /* too small */, next_state.certificate, &next_state.certificate_size,
148*60b67249SAndroid Build Coastguard Worker next_state.cdi_attest, next_state.cdi_seal);
149*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(kDiceResultBufferTooSmall, result);
150*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(sizeof(dice::test::kExpectedX509Ed25519Cert_ZeroInput),
151*60b67249SAndroid Build Coastguard Worker next_state.certificate_size);
152*60b67249SAndroid Build Coastguard Worker }
153*60b67249SAndroid Build Coastguard Worker
TEST(DiceOpsTest,InvalidConfigType)154*60b67249SAndroid Build Coastguard Worker TEST(DiceOpsTest, InvalidConfigType) {
155*60b67249SAndroid Build Coastguard Worker DiceStateForTest current_state = {};
156*60b67249SAndroid Build Coastguard Worker DiceStateForTest next_state = {};
157*60b67249SAndroid Build Coastguard Worker DiceInputValues input_values = {};
158*60b67249SAndroid Build Coastguard Worker input_values.config_type = (DiceConfigType)55;
159*60b67249SAndroid Build Coastguard Worker DiceResult result = DiceMainFlow(
160*60b67249SAndroid Build Coastguard Worker NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
161*60b67249SAndroid Build Coastguard Worker sizeof(next_state.certificate), next_state.certificate,
162*60b67249SAndroid Build Coastguard Worker &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
163*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(kDiceResultInvalidInput, result);
164*60b67249SAndroid Build Coastguard Worker }
165*60b67249SAndroid Build Coastguard Worker
TEST(DiceOpsTest,PartialCertChain)166*60b67249SAndroid Build Coastguard Worker TEST(DiceOpsTest, PartialCertChain) {
167*60b67249SAndroid Build Coastguard Worker constexpr size_t kNumLayers = 7;
168*60b67249SAndroid Build Coastguard Worker DiceStateForTest states[kNumLayers + 1] = {};
169*60b67249SAndroid Build Coastguard Worker DiceInputValues inputs[kNumLayers] = {};
170*60b67249SAndroid Build Coastguard Worker for (size_t i = 0; i < kNumLayers; ++i) {
171*60b67249SAndroid Build Coastguard Worker char seed[40];
172*60b67249SAndroid Build Coastguard Worker pw::string::Format(seed, "code_hash_%zu", i);
173*60b67249SAndroid Build Coastguard Worker DeriveFakeInputValue(seed, DICE_HASH_SIZE, inputs[i].code_hash);
174*60b67249SAndroid Build Coastguard Worker pw::string::Format(seed, "authority_hash_%zu", i);
175*60b67249SAndroid Build Coastguard Worker DeriveFakeInputValue(seed, DICE_HASH_SIZE, inputs[i].authority_hash);
176*60b67249SAndroid Build Coastguard Worker inputs[i].config_type = kDiceConfigTypeInline;
177*60b67249SAndroid Build Coastguard Worker pw::string::Format(seed, "inline_config_%zu", i);
178*60b67249SAndroid Build Coastguard Worker DeriveFakeInputValue(seed, DICE_INLINE_CONFIG_SIZE, inputs[i].config_value);
179*60b67249SAndroid Build Coastguard Worker inputs[i].mode = kDiceModeNormal;
180*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(
181*60b67249SAndroid Build Coastguard Worker kDiceResultOk,
182*60b67249SAndroid Build Coastguard Worker DiceMainFlow(/*context=*/NULL, states[i].cdi_attest, states[i].cdi_seal,
183*60b67249SAndroid Build Coastguard Worker &inputs[i], sizeof(states[i + 1].certificate),
184*60b67249SAndroid Build Coastguard Worker states[i + 1].certificate, &states[i + 1].certificate_size,
185*60b67249SAndroid Build Coastguard Worker states[i + 1].cdi_attest, states[i + 1].cdi_seal));
186*60b67249SAndroid Build Coastguard Worker }
187*60b67249SAndroid Build Coastguard Worker // Use the first derived CDI cert as the 'root' of partial chain.
188*60b67249SAndroid Build Coastguard Worker EXPECT_TRUE(dice::test::VerifyCertificateChain(
189*60b67249SAndroid Build Coastguard Worker CertificateType_X509, states[1].certificate, states[1].certificate_size,
190*60b67249SAndroid Build Coastguard Worker &states[2], kNumLayers - 1, /*is_partial_chain=*/true));
191*60b67249SAndroid Build Coastguard Worker }
192*60b67249SAndroid Build Coastguard Worker
TEST(DiceOpsTest,FullCertChain)193*60b67249SAndroid Build Coastguard Worker TEST(DiceOpsTest, FullCertChain) {
194*60b67249SAndroid Build Coastguard Worker constexpr size_t kNumLayers = 7;
195*60b67249SAndroid Build Coastguard Worker DiceStateForTest states[kNumLayers + 1] = {};
196*60b67249SAndroid Build Coastguard Worker DiceInputValues inputs[kNumLayers] = {};
197*60b67249SAndroid Build Coastguard Worker for (size_t i = 0; i < kNumLayers; ++i) {
198*60b67249SAndroid Build Coastguard Worker char seed[40];
199*60b67249SAndroid Build Coastguard Worker pw::string::Format(seed, "code_hash_%zu", i);
200*60b67249SAndroid Build Coastguard Worker DeriveFakeInputValue(seed, DICE_HASH_SIZE, inputs[i].code_hash);
201*60b67249SAndroid Build Coastguard Worker pw::string::Format(seed, "authority_hash_%zu", i);
202*60b67249SAndroid Build Coastguard Worker DeriveFakeInputValue(seed, DICE_HASH_SIZE, inputs[i].authority_hash);
203*60b67249SAndroid Build Coastguard Worker inputs[i].config_type = kDiceConfigTypeInline;
204*60b67249SAndroid Build Coastguard Worker pw::string::Format(seed, "inline_config_%zu", i);
205*60b67249SAndroid Build Coastguard Worker DeriveFakeInputValue(seed, DICE_INLINE_CONFIG_SIZE, inputs[i].config_value);
206*60b67249SAndroid Build Coastguard Worker inputs[i].mode = kDiceModeNormal;
207*60b67249SAndroid Build Coastguard Worker EXPECT_EQ(
208*60b67249SAndroid Build Coastguard Worker kDiceResultOk,
209*60b67249SAndroid Build Coastguard Worker DiceMainFlow(/*context=*/NULL, states[i].cdi_attest, states[i].cdi_seal,
210*60b67249SAndroid Build Coastguard Worker &inputs[i], sizeof(states[i + 1].certificate),
211*60b67249SAndroid Build Coastguard Worker states[i + 1].certificate, &states[i + 1].certificate_size,
212*60b67249SAndroid Build Coastguard Worker states[i + 1].cdi_attest, states[i + 1].cdi_seal));
213*60b67249SAndroid Build Coastguard Worker }
214*60b67249SAndroid Build Coastguard Worker // Use a fake self-signed UDS cert as the 'root'.
215*60b67249SAndroid Build Coastguard Worker uint8_t root_certificate[dice::test::kTestCertSize];
216*60b67249SAndroid Build Coastguard Worker size_t root_certificate_size = 0;
217*60b67249SAndroid Build Coastguard Worker dice::test::CreateFakeUdsCertificate(
218*60b67249SAndroid Build Coastguard Worker NULL, states[0].cdi_attest, CertificateType_X509, KeyType_Ed25519,
219*60b67249SAndroid Build Coastguard Worker root_certificate, &root_certificate_size);
220*60b67249SAndroid Build Coastguard Worker EXPECT_TRUE(dice::test::VerifyCertificateChain(
221*60b67249SAndroid Build Coastguard Worker CertificateType_X509, root_certificate, root_certificate_size, &states[1],
222*60b67249SAndroid Build Coastguard Worker kNumLayers,
223*60b67249SAndroid Build Coastguard Worker /*is_partial_chain=*/false));
224*60b67249SAndroid Build Coastguard Worker }
225*60b67249SAndroid Build Coastguard Worker
226*60b67249SAndroid Build Coastguard Worker } // namespace
227