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_BUFFER_SIZE];
254 uint8_t public_key[DICE_PUBLIC_KEY_BUFFER_SIZE];
255 result = DiceKeypairFromSeed(NULL, kDicePrincipalAuthority, private_key_seed,
256 public_key, private_key);
257 ASSERT_EQ(kDiceResultOk, result);
258
259 uint8_t encoded_public_key[DICE_PUBLIC_KEY_BUFFER_SIZE + 32];
260 size_t encoded_public_key_size = 0;
261 result = DiceCoseEncodePublicKey(
262 NULL, kDicePrincipalAuthority, public_key, sizeof(encoded_public_key),
263 encoded_public_key, &encoded_public_key_size);
264 ASSERT_EQ(kDiceResultOk, result);
265
266 uint8_t payload[500];
267 DeriveFakeInputValue("payload", sizeof(payload), payload);
268
269 uint8_t aad[100];
270 DeriveFakeInputValue("aad", sizeof(aad), aad);
271
272 uint8_t sign1[1000];
273 size_t sign1_size;
274 result = DiceCoseSignAndEncodeSign1(NULL, payload, sizeof(payload), aad,
275 sizeof(aad), private_key, sizeof(sign1),
276 sign1, &sign1_size);
277 ASSERT_EQ(kDiceResultOk, result);
278
279 EXPECT_TRUE(VerifyCoseSign1(sign1, sign1_size, aad, sizeof(aad),
280 encoded_public_key, encoded_public_key_size,
281 payload, sizeof(payload)));
282 }
283
TEST(DiceOpsTest,PartialCertChain)284 TEST(DiceOpsTest, PartialCertChain) {
285 constexpr size_t kNumLayers = 7;
286 DiceStateForTest states[kNumLayers + 1] = {};
287 DiceInputValues inputs[kNumLayers] = {};
288 for (size_t i = 0; i < kNumLayers; ++i) {
289 char seed[40];
290 pw::string::Format(seed, "code_hash_%zu", i);
291 DeriveFakeInputValue(seed, DICE_HASH_SIZE, inputs[i].code_hash);
292 pw::string::Format(seed, "authority_hash_%zu", i);
293 DeriveFakeInputValue(seed, DICE_HASH_SIZE, inputs[i].authority_hash);
294 inputs[i].config_type = kDiceConfigTypeInline;
295 pw::string::Format(seed, "inline_config_%zu", i);
296 DeriveFakeInputValue(seed, DICE_INLINE_CONFIG_SIZE, inputs[i].config_value);
297 inputs[i].mode = kDiceModeNormal;
298 EXPECT_EQ(
299 kDiceResultOk,
300 DiceMainFlow(/*context=*/NULL, states[i].cdi_attest, states[i].cdi_seal,
301 &inputs[i], sizeof(states[i + 1].certificate),
302 states[i + 1].certificate, &states[i + 1].certificate_size,
303 states[i + 1].cdi_attest, states[i + 1].cdi_seal));
304 char suffix[40];
305 pw::string::Format(suffix, "part_cert_chain_%zu", i);
306 DumpState(CertificateType_Cbor, KeyType_Ed25519, suffix, states[i + 1]);
307 }
308 // Use the first derived CDI cert as the 'root' of partial chain.
309 EXPECT_TRUE(dice::test::VerifyCertificateChain(
310 CertificateType_Cbor, states[1].certificate, states[1].certificate_size,
311 &states[2], kNumLayers - 1, /*is_partial_chain=*/true));
312 }
313
TEST(DiceOpsTest,FullCertChain)314 TEST(DiceOpsTest, FullCertChain) {
315 constexpr size_t kNumLayers = 7;
316 DiceStateForTest states[kNumLayers + 1] = {};
317 DiceInputValues inputs[kNumLayers] = {};
318 for (size_t i = 0; i < kNumLayers; ++i) {
319 char seed[40];
320 pw::string::Format(seed, "code_hash_%zu", i);
321 DeriveFakeInputValue(seed, DICE_HASH_SIZE, inputs[i].code_hash);
322 pw::string::Format(seed, "authority_hash_%zu", i);
323 DeriveFakeInputValue(seed, DICE_HASH_SIZE, inputs[i].authority_hash);
324 inputs[i].config_type = kDiceConfigTypeInline;
325 pw::string::Format(seed, "inline_config_%zu", i);
326 DeriveFakeInputValue(seed, DICE_INLINE_CONFIG_SIZE, inputs[i].config_value);
327 inputs[i].mode = kDiceModeNormal;
328 EXPECT_EQ(
329 kDiceResultOk,
330 DiceMainFlow(/*context=*/NULL, states[i].cdi_attest, states[i].cdi_seal,
331 &inputs[i], sizeof(states[i + 1].certificate),
332 states[i + 1].certificate, &states[i + 1].certificate_size,
333 states[i + 1].cdi_attest, states[i + 1].cdi_seal));
334 char suffix[40];
335 pw::string::Format(suffix, "full_cert_chain_%zu", i);
336 DumpState(CertificateType_Cbor, KeyType_Ed25519, suffix, states[i + 1]);
337 }
338 // Use a fake self-signed UDS cert as the 'root'.
339 uint8_t root_certificate[dice::test::kTestCertSize];
340 size_t root_certificate_size = 0;
341 dice::test::CreateFakeUdsCertificate(
342 NULL, states[0].cdi_attest, CertificateType_Cbor, KeyType_Ed25519,
343 root_certificate, &root_certificate_size);
344 EXPECT_TRUE(dice::test::VerifyCertificateChain(
345 CertificateType_Cbor, root_certificate, root_certificate_size, &states[1],
346 kNumLayers, /*is_partial_chain=*/false));
347 }
348
349 } // namespace
350