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