1 // Copyright 2020 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/dice.h"
22 #include "dice/known_test_values.h"
23 #include "dice/ops.h"
24 #include "dice/ops/trait/cose.h"
25 #include "dice/test_framework.h"
26 #include "dice/test_utils.h"
27 #include "dice/utils.h"
28 #include "pw_string/format.h"
29
30 namespace {
31
32 using dice::test::CertificateType_Cbor;
33 using dice::test::DeriveFakeInputValue;
34 using dice::test::DiceStateForTest;
35 using dice::test::KeyType_Ed25519;
36 using dice::test::VerifyCoseSign1;
37
TEST(DiceOpsTest,KnownAnswerZeroInput)38 TEST(DiceOpsTest, KnownAnswerZeroInput) {
39 DiceStateForTest current_state = {};
40 DiceStateForTest next_state = {};
41 DiceInputValues input_values = {};
42 DiceResult result = DiceMainFlow(
43 NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
44 sizeof(next_state.certificate), next_state.certificate,
45 &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
46 EXPECT_EQ(kDiceResultOk, result);
47 DumpState(CertificateType_Cbor, KeyType_Ed25519, "zero_input", next_state);
48 // Both CDI values and the certificate should be deterministic.
49 EXPECT_EQ(0, memcmp(next_state.cdi_attest,
50 dice::test::kExpectedCdiAttest_ZeroInput, DICE_CDI_SIZE));
51 EXPECT_EQ(0, memcmp(next_state.cdi_seal,
52 dice::test::kExpectedCdiSeal_ZeroInput, DICE_CDI_SIZE));
53 ASSERT_EQ(sizeof(dice::test::kExpectedCborEd25519Cert_ZeroInput),
54 next_state.certificate_size);
55 EXPECT_EQ(0, memcmp(dice::test::kExpectedCborEd25519Cert_ZeroInput,
56 next_state.certificate, next_state.certificate_size));
57 }
58
TEST(DiceOpsTest,KnownAnswerZeroInputMeasurement)59 TEST(DiceOpsTest, KnownAnswerZeroInputMeasurement) {
60 DiceStateForTest current_state = {};
61 DiceStateForTest next_state = {};
62 DiceInputValues input_values = {};
63 ASSERT_LE(sizeof(dice::test::kExpectedCborEd25519Cert_ZeroInput) / 2,
64 sizeof(next_state.certificate));
65 DiceResult result = DiceMainFlow(
66 NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
67 sizeof(dice::test::kExpectedCborEd25519Cert_ZeroInput) / 2,
68 next_state.certificate, &next_state.certificate_size,
69 next_state.cdi_attest, next_state.cdi_seal);
70 EXPECT_EQ(kDiceResultBufferTooSmall, result);
71 EXPECT_EQ(sizeof(dice::test::kExpectedCborEd25519Cert_ZeroInput),
72 next_state.certificate_size);
73 }
74
TEST(DiceOpsTest,KnownAnswerHashOnlyInput)75 TEST(DiceOpsTest, KnownAnswerHashOnlyInput) {
76 DiceStateForTest current_state = {};
77 DeriveFakeInputValue("cdi_attest", DICE_CDI_SIZE, current_state.cdi_attest);
78 DeriveFakeInputValue("cdi_seal", DICE_CDI_SIZE, current_state.cdi_seal);
79 DiceStateForTest next_state = {};
80 DiceInputValues input_values = {};
81 DeriveFakeInputValue("code_hash", DICE_HASH_SIZE, input_values.code_hash);
82 DeriveFakeInputValue("authority_hash", DICE_HASH_SIZE,
83 input_values.authority_hash);
84 input_values.config_type = kDiceConfigTypeInline;
85 DeriveFakeInputValue("inline_config", DICE_INLINE_CONFIG_SIZE,
86 input_values.config_value);
87
88 DiceResult result = DiceMainFlow(
89 NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
90 sizeof(next_state.certificate), next_state.certificate,
91 &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
92 EXPECT_EQ(kDiceResultOk, result);
93 DumpState(CertificateType_Cbor, KeyType_Ed25519, "hash_only_input",
94 next_state);
95 // Both CDI values and the certificate should be deterministic.
96 EXPECT_EQ(
97 0, memcmp(next_state.cdi_attest,
98 dice::test::kExpectedCdiAttest_HashOnlyInput, DICE_CDI_SIZE));
99 EXPECT_EQ(
100 0, memcmp(next_state.cdi_seal, dice::test::kExpectedCdiSeal_HashOnlyInput,
101 DICE_CDI_SIZE));
102 ASSERT_EQ(sizeof(dice::test::kExpectedCborEd25519Cert_HashOnlyInput),
103 next_state.certificate_size);
104 EXPECT_EQ(0, memcmp(dice::test::kExpectedCborEd25519Cert_HashOnlyInput,
105 next_state.certificate, next_state.certificate_size));
106 }
107
TEST(DiceOpsTest,KnownAnswerDescriptorInput)108 TEST(DiceOpsTest, KnownAnswerDescriptorInput) {
109 DiceStateForTest current_state = {};
110 DeriveFakeInputValue("cdi_attest", DICE_CDI_SIZE, current_state.cdi_attest);
111 DeriveFakeInputValue("cdi_seal", DICE_CDI_SIZE, current_state.cdi_seal);
112
113 DiceStateForTest next_state = {};
114
115 DiceInputValues input_values = {};
116 DeriveFakeInputValue("code_hash", DICE_HASH_SIZE, input_values.code_hash);
117 uint8_t code_descriptor[100];
118 DeriveFakeInputValue("code_desc", sizeof(code_descriptor), code_descriptor);
119 input_values.code_descriptor = code_descriptor;
120 input_values.code_descriptor_size = sizeof(code_descriptor);
121
122 uint8_t config_descriptor[40];
123 DeriveFakeInputValue("config_desc", sizeof(config_descriptor),
124 config_descriptor);
125 input_values.config_descriptor = config_descriptor;
126 input_values.config_descriptor_size = sizeof(config_descriptor);
127 input_values.config_type = kDiceConfigTypeDescriptor;
128
129 DeriveFakeInputValue("authority_hash", DICE_HASH_SIZE,
130 input_values.authority_hash);
131 uint8_t authority_descriptor[65];
132 DeriveFakeInputValue("authority_desc", sizeof(authority_descriptor),
133 authority_descriptor);
134 input_values.authority_descriptor = authority_descriptor;
135 input_values.authority_descriptor_size = sizeof(authority_descriptor);
136
137 DiceResult result = DiceMainFlow(
138 NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
139 sizeof(next_state.certificate), next_state.certificate,
140 &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
141 EXPECT_EQ(kDiceResultOk, result);
142 DumpState(CertificateType_Cbor, KeyType_Ed25519, "descriptor_input",
143 next_state);
144 // Both CDI values and the certificate should be deterministic.
145 EXPECT_EQ(
146 0, memcmp(next_state.cdi_attest,
147 dice::test::kExpectedCdiAttest_DescriptorInput, DICE_CDI_SIZE));
148 EXPECT_EQ(
149 0, memcmp(next_state.cdi_seal,
150 dice::test::kExpectedCdiSeal_DescriptorInput, DICE_CDI_SIZE));
151 ASSERT_EQ(sizeof(dice::test::kExpectedCborEd25519Cert_DescriptorInput),
152 next_state.certificate_size);
153 EXPECT_EQ(0, memcmp(dice::test::kExpectedCborEd25519Cert_DescriptorInput,
154 next_state.certificate, next_state.certificate_size));
155 }
156
TEST(DiceOpsTest,NonZeroMode)157 TEST(DiceOpsTest, NonZeroMode) {
158 constexpr size_t kModeOffsetInCert = 315;
159 DiceStateForTest current_state = {};
160 DiceStateForTest next_state = {};
161 DiceInputValues input_values = {};
162 input_values.mode = kDiceModeDebug;
163 DiceResult result = DiceMainFlow(
164 NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
165 sizeof(next_state.certificate), next_state.certificate,
166 &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
167 EXPECT_EQ(kDiceResultOk, result);
168 EXPECT_EQ(kDiceModeDebug, next_state.certificate[kModeOffsetInCert]);
169 }
170
TEST(DiceOpsTest,LargeInputs)171 TEST(DiceOpsTest, LargeInputs) {
172 constexpr uint8_t kBigBuffer[1024 * 1024] = {};
173 DiceStateForTest current_state = {};
174 DiceStateForTest next_state = {};
175 DiceInputValues input_values = {};
176 input_values.code_descriptor = kBigBuffer;
177 input_values.code_descriptor_size = sizeof(kBigBuffer);
178 DiceResult result = DiceMainFlow(
179 NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
180 sizeof(next_state.certificate), next_state.certificate,
181 &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
182 EXPECT_EQ(kDiceResultBufferTooSmall, result);
183 }
184
TEST(DiceOpsTest,LargeDescriptor)185 TEST(DiceOpsTest, LargeDescriptor) {
186 DiceStateForTest current_state = {};
187 DiceStateForTest next_state = {};
188 DiceInputValues input_values = {};
189
190 uint8_t config_descriptor[10 * 1000];
191 DeriveFakeInputValue("config_desc", sizeof(config_descriptor),
192 config_descriptor);
193 input_values.config_descriptor = config_descriptor;
194 input_values.config_descriptor_size = sizeof(config_descriptor);
195 input_values.config_type = kDiceConfigTypeDescriptor;
196
197 uint8_t next_certificate[20 * 1000];
198 size_t next_certificate_size = 0;
199 size_t buffer_size = 0;
200
201 DiceResult result = DiceMainFlow(
202 NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
203 buffer_size, next_certificate, &next_certificate_size,
204 next_state.cdi_attest, next_state.cdi_seal);
205 EXPECT_EQ(kDiceResultBufferTooSmall, result);
206
207 // If this fails, the test is wrong, and we need to make next_certificate
208 // bigger.
209 ASSERT_LE(next_certificate_size, sizeof(next_certificate));
210
211 buffer_size = next_certificate_size - 1;
212 result = DiceMainFlow(NULL, current_state.cdi_attest, current_state.cdi_seal,
213 &input_values, buffer_size, next_certificate,
214 &next_certificate_size, next_state.cdi_attest,
215 next_state.cdi_seal);
216 EXPECT_EQ(kDiceResultBufferTooSmall, result);
217
218 buffer_size = next_certificate_size;
219 result = DiceMainFlow(NULL, current_state.cdi_attest, current_state.cdi_seal,
220 &input_values, buffer_size, next_certificate,
221 &next_certificate_size, next_state.cdi_attest,
222 next_state.cdi_seal);
223 EXPECT_EQ(kDiceResultOk, result);
224 }
225
TEST(DiceOpsTest,InvalidConfigType)226 TEST(DiceOpsTest, InvalidConfigType) {
227 DiceStateForTest current_state = {};
228 DiceStateForTest next_state = {};
229 DiceInputValues input_values = {};
230 input_values.config_type = (DiceConfigType)55;
231 DiceResult result = DiceMainFlow(
232 NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
233 sizeof(next_state.certificate), next_state.certificate,
234 &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
235 EXPECT_EQ(kDiceResultInvalidInput, result);
236 }
237
TEST(DiceOpsTest,CoseSignAndEncodeSign1)238 TEST(DiceOpsTest, CoseSignAndEncodeSign1) {
239 DiceStateForTest current_state = {};
240 DiceStateForTest next_state = {};
241 DiceInputValues input_values = {};
242 DiceResult result = DiceMainFlow(
243 NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
244 sizeof(next_state.certificate), next_state.certificate,
245 &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
246 ASSERT_EQ(kDiceResultOk, result);
247
248 uint8_t private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE];
249 result = DiceDeriveCdiPrivateKeySeed(NULL, next_state.cdi_attest,
250 private_key_seed);
251 ASSERT_EQ(kDiceResultOk, result);
252
253 uint8_t private_key[DICE_PRIVATE_KEY_SIZE];
254 uint8_t public_key[DICE_PUBLIC_KEY_SIZE];
255 result = DiceKeypairFromSeed(NULL, private_key_seed, public_key, private_key);
256 ASSERT_EQ(kDiceResultOk, result);
257
258 uint8_t encoded_public_key[DICE_PUBLIC_KEY_SIZE + 32];
259 size_t encoded_public_key_size = 0;
260 result =
261 DiceCoseEncodePublicKey(NULL, public_key, sizeof(encoded_public_key),
262 encoded_public_key, &encoded_public_key_size);
263 ASSERT_EQ(kDiceResultOk, result);
264
265 uint8_t payload[500];
266 DeriveFakeInputValue("payload", sizeof(payload), payload);
267
268 uint8_t aad[100];
269 DeriveFakeInputValue("aad", sizeof(aad), aad);
270
271 uint8_t sign1[1000];
272 size_t sign1_size;
273 result = DiceCoseSignAndEncodeSign1(NULL, payload, sizeof(payload), aad,
274 sizeof(aad), private_key, sizeof(sign1),
275 sign1, &sign1_size);
276 ASSERT_EQ(kDiceResultOk, result);
277
278 EXPECT_TRUE(VerifyCoseSign1(sign1, sign1_size, aad, sizeof(aad),
279 encoded_public_key, encoded_public_key_size,
280 payload, sizeof(payload)));
281 }
282
TEST(DiceOpsTest,PartialCertChain)283 TEST(DiceOpsTest, PartialCertChain) {
284 constexpr size_t kNumLayers = 7;
285 DiceStateForTest states[kNumLayers + 1] = {};
286 DiceInputValues inputs[kNumLayers] = {};
287 for (size_t i = 0; i < kNumLayers; ++i) {
288 char seed[40];
289 pw::string::Format(seed, "code_hash_%zu", i);
290 DeriveFakeInputValue(seed, DICE_HASH_SIZE, inputs[i].code_hash);
291 pw::string::Format(seed, "authority_hash_%zu", i);
292 DeriveFakeInputValue(seed, DICE_HASH_SIZE, inputs[i].authority_hash);
293 inputs[i].config_type = kDiceConfigTypeInline;
294 pw::string::Format(seed, "inline_config_%zu", i);
295 DeriveFakeInputValue(seed, DICE_INLINE_CONFIG_SIZE, inputs[i].config_value);
296 inputs[i].mode = kDiceModeNormal;
297 EXPECT_EQ(
298 kDiceResultOk,
299 DiceMainFlow(/*context=*/NULL, states[i].cdi_attest, states[i].cdi_seal,
300 &inputs[i], sizeof(states[i + 1].certificate),
301 states[i + 1].certificate, &states[i + 1].certificate_size,
302 states[i + 1].cdi_attest, states[i + 1].cdi_seal));
303 char suffix[40];
304 pw::string::Format(suffix, "part_cert_chain_%zu", i);
305 DumpState(CertificateType_Cbor, KeyType_Ed25519, suffix, states[i + 1]);
306 }
307 // Use the first derived CDI cert as the 'root' of partial chain.
308 EXPECT_TRUE(dice::test::VerifyCertificateChain(
309 CertificateType_Cbor, states[1].certificate, states[1].certificate_size,
310 &states[2], kNumLayers - 1, /*is_partial_chain=*/true));
311 }
312
TEST(DiceOpsTest,FullCertChain)313 TEST(DiceOpsTest, FullCertChain) {
314 constexpr size_t kNumLayers = 7;
315 DiceStateForTest states[kNumLayers + 1] = {};
316 DiceInputValues inputs[kNumLayers] = {};
317 for (size_t i = 0; i < kNumLayers; ++i) {
318 char seed[40];
319 pw::string::Format(seed, "code_hash_%zu", i);
320 DeriveFakeInputValue(seed, DICE_HASH_SIZE, inputs[i].code_hash);
321 pw::string::Format(seed, "authority_hash_%zu", i);
322 DeriveFakeInputValue(seed, DICE_HASH_SIZE, inputs[i].authority_hash);
323 inputs[i].config_type = kDiceConfigTypeInline;
324 pw::string::Format(seed, "inline_config_%zu", i);
325 DeriveFakeInputValue(seed, DICE_INLINE_CONFIG_SIZE, inputs[i].config_value);
326 inputs[i].mode = kDiceModeNormal;
327 EXPECT_EQ(
328 kDiceResultOk,
329 DiceMainFlow(/*context=*/NULL, states[i].cdi_attest, states[i].cdi_seal,
330 &inputs[i], sizeof(states[i + 1].certificate),
331 states[i + 1].certificate, &states[i + 1].certificate_size,
332 states[i + 1].cdi_attest, states[i + 1].cdi_seal));
333 char suffix[40];
334 pw::string::Format(suffix, "full_cert_chain_%zu", i);
335 DumpState(CertificateType_Cbor, KeyType_Ed25519, suffix, states[i + 1]);
336 }
337 // Use a fake self-signed UDS cert as the 'root'.
338 uint8_t root_certificate[dice::test::kTestCertSize];
339 size_t root_certificate_size = 0;
340 dice::test::CreateFakeUdsCertificate(
341 NULL, states[0].cdi_attest, CertificateType_Cbor, KeyType_Ed25519,
342 root_certificate, &root_certificate_size);
343 EXPECT_TRUE(dice::test::VerifyCertificateChain(
344 CertificateType_Cbor, root_certificate, root_certificate_size, &states[1],
345 kNumLayers, /*is_partial_chain=*/false));
346 }
347
348 } // namespace
349