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/test_framework.h"
24 #include "dice/test_utils.h"
25 #include "dice/utils.h"
26 #include "pw_string/format.h"
27
28 namespace {
29
30 using dice::test::CertificateType_X509;
31 using dice::test::DeriveFakeInputValue;
32 using dice::test::DiceStateForTest;
33 using dice::test::DumpState;
34 using dice::test::KeyType_P256_COMPRESSED;
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_X509, KeyType_P256_COMPRESSED, "zero_input",
46 next_state);
47 // Both CDI values and the certificate should be deterministic.
48 EXPECT_EQ(0, memcmp(next_state.cdi_attest,
49 dice::test::kExpectedCdiAttest_ZeroInput, DICE_CDI_SIZE));
50 EXPECT_EQ(0, memcmp(next_state.cdi_seal,
51 dice::test::kExpectedCdiSeal_ZeroInput, DICE_CDI_SIZE));
52 ASSERT_EQ(sizeof(dice::test::kExpectedX509P256Cert_ZeroInput),
53 next_state.certificate_size);
54 EXPECT_EQ(0, memcmp(dice::test::kExpectedX509P256Cert_ZeroInput,
55 next_state.certificate, next_state.certificate_size));
56 }
57
TEST(DiceOpsTest,KnownAnswerHashOnlyInput)58 TEST(DiceOpsTest, KnownAnswerHashOnlyInput) {
59 DiceStateForTest current_state = {};
60 DeriveFakeInputValue("cdi_attest", DICE_CDI_SIZE, current_state.cdi_attest);
61 DeriveFakeInputValue("cdi_seal", DICE_CDI_SIZE, current_state.cdi_seal);
62 DiceStateForTest next_state = {};
63 DiceInputValues input_values = {};
64 DeriveFakeInputValue("code_hash", DICE_HASH_SIZE, input_values.code_hash);
65 DeriveFakeInputValue("authority_hash", DICE_HASH_SIZE,
66 input_values.authority_hash);
67 input_values.config_type = kDiceConfigTypeInline;
68 DeriveFakeInputValue("inline_config", DICE_INLINE_CONFIG_SIZE,
69 input_values.config_value);
70
71 DiceResult result = DiceMainFlow(
72 NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
73 sizeof(next_state.certificate), next_state.certificate,
74 &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
75 EXPECT_EQ(kDiceResultOk, result);
76 DumpState(CertificateType_X509, KeyType_P256_COMPRESSED, "hash_only_input",
77 next_state);
78 // Both CDI values and the certificate should be deterministic.
79 EXPECT_EQ(
80 0, memcmp(next_state.cdi_attest,
81 dice::test::kExpectedCdiAttest_HashOnlyInput, DICE_CDI_SIZE));
82 EXPECT_EQ(
83 0, memcmp(next_state.cdi_seal, dice::test::kExpectedCdiSeal_HashOnlyInput,
84 DICE_CDI_SIZE));
85 ASSERT_EQ(sizeof(dice::test::kExpectedX509P256Cert_HashOnlyInput),
86 next_state.certificate_size);
87 EXPECT_EQ(0, memcmp(dice::test::kExpectedX509P256Cert_HashOnlyInput,
88 next_state.certificate, next_state.certificate_size));
89 }
90
TEST(DiceOpsTest,KnownAnswerDescriptorInput)91 TEST(DiceOpsTest, KnownAnswerDescriptorInput) {
92 DiceStateForTest current_state = {};
93 DeriveFakeInputValue("cdi_attest", DICE_CDI_SIZE, current_state.cdi_attest);
94 DeriveFakeInputValue("cdi_seal", DICE_CDI_SIZE, current_state.cdi_seal);
95
96 DiceStateForTest next_state = {};
97
98 DiceInputValues input_values = {};
99 DeriveFakeInputValue("code_hash", DICE_HASH_SIZE, input_values.code_hash);
100 uint8_t code_descriptor[100];
101 DeriveFakeInputValue("code_desc", sizeof(code_descriptor), code_descriptor);
102 input_values.code_descriptor = code_descriptor;
103 input_values.code_descriptor_size = sizeof(code_descriptor);
104
105 uint8_t config_descriptor[40];
106 DeriveFakeInputValue("config_desc", sizeof(config_descriptor),
107 config_descriptor);
108 input_values.config_descriptor = config_descriptor;
109 input_values.config_descriptor_size = sizeof(config_descriptor);
110 input_values.config_type = kDiceConfigTypeDescriptor;
111
112 DeriveFakeInputValue("authority_hash", DICE_HASH_SIZE,
113 input_values.authority_hash);
114 uint8_t authority_descriptor[65];
115 DeriveFakeInputValue("authority_desc", sizeof(authority_descriptor),
116 authority_descriptor);
117 input_values.authority_descriptor = authority_descriptor;
118 input_values.authority_descriptor_size = sizeof(authority_descriptor);
119
120 DiceResult result = DiceMainFlow(
121 NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
122 sizeof(next_state.certificate), next_state.certificate,
123 &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
124 EXPECT_EQ(kDiceResultOk, result);
125 DumpState(CertificateType_X509, KeyType_P256_COMPRESSED, "descriptor_input",
126 next_state);
127 // Both CDI values and the certificate should be deterministic.
128 EXPECT_EQ(
129 0, memcmp(next_state.cdi_attest,
130 dice::test::kExpectedCdiAttest_DescriptorInput, DICE_CDI_SIZE));
131 EXPECT_EQ(
132 0, memcmp(next_state.cdi_seal,
133 dice::test::kExpectedCdiSeal_DescriptorInput, DICE_CDI_SIZE));
134 ASSERT_EQ(sizeof(dice::test::kExpectedX509P256Cert_DescriptorInput),
135 next_state.certificate_size);
136 EXPECT_EQ(0, memcmp(dice::test::kExpectedX509P256Cert_DescriptorInput,
137 next_state.certificate, next_state.certificate_size));
138 }
139
TEST(DiceOpsTest,NonZeroMode)140 TEST(DiceOpsTest, NonZeroMode) {
141 constexpr size_t kModeOffsetInCert = 0x26a;
142 DiceStateForTest current_state = {};
143 DiceStateForTest next_state = {};
144 DiceInputValues input_values = {};
145 input_values.mode = kDiceModeDebug;
146 DiceResult result = DiceMainFlow(
147 NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
148 sizeof(next_state.certificate), next_state.certificate,
149 &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
150 EXPECT_EQ(kDiceResultOk, result);
151 EXPECT_EQ(kDiceModeDebug, next_state.certificate[kModeOffsetInCert]);
152 }
153
TEST(DiceOpsTest,LargeInputs)154 TEST(DiceOpsTest, LargeInputs) {
155 constexpr uint8_t kBigBuffer[1024 * 1024] = {};
156 DiceStateForTest current_state = {};
157 DiceStateForTest next_state = {};
158 DiceInputValues input_values = {};
159 input_values.code_descriptor = kBigBuffer;
160 input_values.code_descriptor_size = sizeof(kBigBuffer);
161 DiceResult result = DiceMainFlow(
162 NULL, current_state.cdi_attest, current_state.cdi_seal, &input_values,
163 sizeof(next_state.certificate), next_state.certificate,
164 &next_state.certificate_size, next_state.cdi_attest, next_state.cdi_seal);
165 EXPECT_EQ(kDiceResultBufferTooSmall, result);
166 }
167
TEST(DiceOpsTest,InvalidConfigType)168 TEST(DiceOpsTest, InvalidConfigType) {
169 DiceStateForTest current_state = {};
170 DiceStateForTest next_state = {};
171 DiceInputValues input_values = {};
172 input_values.config_type = (DiceConfigType)55;
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(kDiceResultInvalidInput, result);
178 }
179
TEST(DiceOpsTest,PartialCertChain)180 TEST(DiceOpsTest, PartialCertChain) {
181 constexpr size_t kNumLayers = 7;
182 DiceStateForTest states[kNumLayers + 1] = {};
183 DiceInputValues inputs[kNumLayers] = {};
184 for (size_t i = 0; i < kNumLayers; ++i) {
185 char seed[40];
186 pw::string::Format(seed, "code_hash_%zu", i);
187 DeriveFakeInputValue(seed, DICE_HASH_SIZE, inputs[i].code_hash);
188 pw::string::Format(seed, "authority_hash_%zu", i);
189 DeriveFakeInputValue(seed, DICE_HASH_SIZE, inputs[i].authority_hash);
190 inputs[i].config_type = kDiceConfigTypeInline;
191 pw::string::Format(seed, "inline_config_%zu", i);
192 DeriveFakeInputValue(seed, DICE_INLINE_CONFIG_SIZE, inputs[i].config_value);
193 inputs[i].mode = kDiceModeNormal;
194 EXPECT_EQ(
195 kDiceResultOk,
196 DiceMainFlow(/*context=*/NULL, states[i].cdi_attest, states[i].cdi_seal,
197 &inputs[i], sizeof(states[i + 1].certificate),
198 states[i + 1].certificate, &states[i + 1].certificate_size,
199 states[i + 1].cdi_attest, states[i + 1].cdi_seal));
200 char suffix[40];
201 pw::string::Format(suffix, "part_cert_chain_%zu", i);
202 DumpState(CertificateType_X509, KeyType_P256_COMPRESSED, suffix,
203 states[i + 1]);
204 }
205 // Use the first derived CDI cert as the 'root' of partial chain.
206 EXPECT_TRUE(dice::test::VerifyCertificateChain(
207 CertificateType_X509, states[1].certificate, states[1].certificate_size,
208 &states[2], kNumLayers - 1, /*is_partial_chain=*/true));
209 }
210
TEST(DiceOpsTest,FullCertChain)211 TEST(DiceOpsTest, FullCertChain) {
212 constexpr size_t kNumLayers = 7;
213 DiceStateForTest states[kNumLayers + 1] = {};
214 DiceInputValues inputs[kNumLayers] = {};
215 for (size_t i = 0; i < kNumLayers; ++i) {
216 char seed[40];
217 pw::string::Format(seed, "code_hash_%zu", i);
218 DeriveFakeInputValue(seed, DICE_HASH_SIZE, inputs[i].code_hash);
219 pw::string::Format(seed, "authority_hash_%zu", i);
220 DeriveFakeInputValue(seed, DICE_HASH_SIZE, inputs[i].authority_hash);
221 inputs[i].config_type = kDiceConfigTypeInline;
222 pw::string::Format(seed, "inline_config_%zu", i);
223 DeriveFakeInputValue(seed, DICE_INLINE_CONFIG_SIZE, inputs[i].config_value);
224 inputs[i].mode = kDiceModeNormal;
225 EXPECT_EQ(
226 kDiceResultOk,
227 DiceMainFlow(/*context=*/NULL, states[i].cdi_attest, states[i].cdi_seal,
228 &inputs[i], sizeof(states[i + 1].certificate),
229 states[i + 1].certificate, &states[i + 1].certificate_size,
230 states[i + 1].cdi_attest, states[i + 1].cdi_seal));
231 char suffix[40];
232 pw::string::Format(suffix, "full_cert_chain_%zu", i);
233 DumpState(CertificateType_X509, KeyType_P256_COMPRESSED, suffix,
234 states[i + 1]);
235 }
236 // Use a fake self-signed UDS cert as the 'root'.
237 uint8_t root_certificate[dice::test::kTestCertSize];
238 size_t root_certificate_size = 0;
239 dice::test::CreateFakeUdsCertificate(
240 NULL, states[0].cdi_attest, dice::test::CertificateType_X509,
241 dice::test::KeyType_P256_COMPRESSED, root_certificate,
242 &root_certificate_size);
243 EXPECT_TRUE(dice::test::VerifyCertificateChain(
244 CertificateType_X509, root_certificate, root_certificate_size, &states[1],
245 kNumLayers,
246 /*is_partial_chain=*/false));
247 }
248 } // namespace
249