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