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