1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define TLOG_TAG "hwbcc-common"
18
19 #include <cppbor.h>
20 #include <cppbor_parse.h>
21 #include <lib/hwbcc/common/common.h>
22 #include <trusty_unittest.h>
23 #include <array>
24
25 #define CHECK(statement) \
26 do { \
27 if (!(statement)) { \
28 TLOGE("(" STRINGIFY(statement) ") check failed\n"); \
29 return false; \
30 } \
31 } while (0);
32
33 #define CHECK_NOT_NULL(val) CHECK(val != NULL)
34 #define CHECK_EQ(val1, val2) CHECK(val1 == val2)
35
validate_pub_key_ed25519(const cppbor::Map * cose_key,PubKey * out_key)36 static bool validate_pub_key_ed25519(const cppbor::Map* cose_key,
37 PubKey* out_key) {
38 /* This is what we expect. Note that field 4 is different in COSE spec.
39 * PubKeyEd25519 = { // COSE_Key
40 * 1 : 1, // Key type : octet key pair
41 * 3 : AlgorithmEdDSA, // Algorithm : EdDSA
42 * 4 : 2, // Ops: Verify
43 * -1 : 6, // Curve : Ed25519
44 * -2 : bstr // X coordinate, little-endian
45 * }
46 */
47 const cppbor::Int* key_type = cose_key->get(1)->asInt();
48 const cppbor::Int* algorithm = cose_key->get(3)->asInt();
49 const cppbor::Int* curve = cose_key->get(-1)->asInt();
50 const cppbor::Bstr* key = cose_key->get(-2)->asBstr();
51
52 /*
53 * TODO(b/201344393): There are inconsistencies in "ops" field depending on
54 * implementation.
55 *
56 * const cppbor::Int* ops = cose_key->get(4)->asInt();
57 * CHECK_NOT_NULL(ops);
58 * CHECK_EQ(ops->value(), 2);
59 */
60
61 CHECK(cose_key->size() == 5);
62
63 CHECK_NOT_NULL(key_type);
64 CHECK_NOT_NULL(algorithm);
65 CHECK_NOT_NULL(curve);
66 CHECK_NOT_NULL(key);
67
68 CHECK_EQ(key_type->value(), 1);
69 CHECK_EQ(algorithm->value(), -8);
70 CHECK_EQ(curve->value(), 6);
71 CHECK_EQ(key->value().size(), ED25519_PUBLIC_KEY_LEN);
72
73 std::copy(key->value().begin(), key->value().end(), out_key->begin());
74 return true;
75 }
76
validate_protected_params(const cppbor::Bstr * protected_params)77 static bool validate_protected_params(const cppbor::Bstr* protected_params) {
78 auto [parsed_params, _, err_msg] = cppbor::parse(protected_params);
79 CHECK_NOT_NULL(parsed_params);
80
81 const cppbor::Map* params = parsed_params->asMap();
82 CHECK_NOT_NULL(params);
83
84 CHECK_EQ(params->size(), 1);
85
86 const cppbor::Int* algorithm = params->get(1)->asInt();
87 CHECK_EQ(algorithm->value(), -8);
88
89 return true;
90 }
91
validate_subject_key(const cppbor::Bstr * subject_key,PubKey * out_key)92 static bool validate_subject_key(const cppbor::Bstr* subject_key,
93 PubKey* out_key) {
94 auto [parsed_subject_key, _, err_msg] = cppbor::parse(subject_key);
95 CHECK_NOT_NULL(parsed_subject_key);
96
97 const cppbor::Map* cose_key = parsed_subject_key->asMap();
98 CHECK_NOT_NULL(cose_key);
99
100 CHECK(validate_pub_key_ed25519(cose_key, out_key));
101
102 return true;
103 }
104
validate_bcc_payload(const cppbor::Bstr * bcc_payload,PubKey * out_key)105 static bool validate_bcc_payload(const cppbor::Bstr* bcc_payload,
106 PubKey* out_key) {
107 /* This is what we expect:
108 * BccPayload = { // CWT
109 * 1 : tstr, // Issuer
110 * 2 : tstr, // Subject
111 * // See the Open Profile for DICE for details on these fields.
112 * ? -4670545 : bstr, // Code Hash
113 * ? -4670546 : bstr, // Code Descriptor
114 * ? -4670547 : bstr, // Configuration Hash
115 * ? -4670548 : bstr .cbor { // Configuration Descriptor
116 * ? -70002 : tstr, // Component name
117 * ? -70003 : int, // Firmware version
118 * ? -70004 : null, // Resettable
119 * },
120 * ? -4670549 : bstr, // Authority Hash
121 * ? -4670550 : bstr, // Authority Descriptor
122 * ? -4670551 : bstr, // Mode
123 * -4670552 : bstr .cbor PubKeyEd25519 // Subject Public Key
124 * -4670553 : bstr // Key Usage
125 * }
126 */
127 auto [parsed_payload, _, err_msg] = cppbor::parse(bcc_payload);
128 CHECK_NOT_NULL(parsed_payload);
129
130 const cppbor::Map* payload = parsed_payload->asMap();
131 CHECK_NOT_NULL(payload);
132
133 CHECK(payload->size() >= 4);
134
135 const cppbor::Tstr* issuer = payload->get(1)->asTstr();
136 const cppbor::Tstr* subject = payload->get(2)->asTstr();
137 const cppbor::Bstr* subject_key = payload->get(-4670552)->asBstr();
138 const cppbor::Bstr* key_usage = payload->get(-4670553)->asBstr();
139
140 CHECK_NOT_NULL(issuer);
141 CHECK_NOT_NULL(subject);
142 CHECK_NOT_NULL(subject_key);
143 CHECK_NOT_NULL(key_usage);
144
145 CHECK(validate_subject_key(subject_key, out_key));
146
147 return true;
148 }
149
validate_bcc_entry(const cppbor::Array * bcc_entry,const PubKey & prev_key,PubKey * out_key)150 static bool validate_bcc_entry(const cppbor::Array* bcc_entry,
151 const PubKey& prev_key,
152 PubKey* out_key) {
153 /* This is what we expect:
154 * BccEntry = [ // COSE_Sign1 (untagged)
155 * protected : bstr .cbor {
156 * 1 : AlgorithmEdDSA, // Algorithm
157 * },
158 * unprotected: {},
159 * payload: bstr .cbor BccPayload,
160 * signature: bstr .cbor PureEd25519(SigningKey,
161 * bstr .cbor BccEntryInput)
162 * ]
163 *
164 * BccEntryInput = [
165 * context: "Signature1",
166 * protected: bstr .cbor {
167 * 1 : AlgorithmEdDSA, // Algorithm
168 * },
169 * external_aad: bstr .size 0,
170 * payload: bstr .cbor BccPayload
171 * ]
172 */
173 const cppbor::Bstr* protected_params = bcc_entry->get(0)->asBstr();
174 const cppbor::Map* unprotected_params = bcc_entry->get(1)->asMap();
175 const cppbor::Bstr* payload = bcc_entry->get(2)->asBstr();
176 const cppbor::Bstr* signature = bcc_entry->get(3)->asBstr();
177
178 CHECK_EQ(bcc_entry->size(), 4);
179
180 CHECK_NOT_NULL(protected_params);
181 CHECK_NOT_NULL(unprotected_params);
182 CHECK_NOT_NULL(payload);
183 CHECK_NOT_NULL(signature);
184
185 CHECK(validate_protected_params(protected_params));
186 CHECK_EQ(unprotected_params->size(), 0);
187 CHECK(validate_bcc_payload(payload, out_key));
188
189 std::vector<uint8_t> signature_input = cppbor::Array()
190 .add("Signature1")
191 .add(*protected_params)
192 .add(cppbor::Bstr())
193 .add(*payload)
194 .encode();
195
196 int rc = ED25519_verify(signature_input.data(), signature_input.size(),
197 signature->value().data(), prev_key.data());
198 CHECK_EQ(rc, 1);
199
200 return true;
201 }
202
validate_bcc(const uint8_t * bcc,size_t bcc_size,uint8_t dk_pub_key[ED25519_PUBLIC_KEY_LEN],uint8_t km_pub_key[ED25519_PUBLIC_KEY_LEN])203 bool validate_bcc(const uint8_t* bcc,
204 size_t bcc_size,
205 uint8_t dk_pub_key[ED25519_PUBLIC_KEY_LEN],
206 uint8_t km_pub_key[ED25519_PUBLIC_KEY_LEN]) {
207 std::vector<PubKey> keys;
208
209 if (!validate_bcc_impl(bcc, bcc_size, &keys)) {
210 TLOGE("BCC validation failed");
211 return false;
212 }
213
214 if (keys.size() != 2) {
215 TLOGE("BCC validation key vector invalid");
216 return false;
217 }
218
219 std::copy(keys[0].begin(), keys[0].end(), dk_pub_key);
220 std::copy(keys[1].begin(), keys[1].end(), km_pub_key);
221
222 return true;
223 }
224
225 /* TODO: Also validate non-degenerate BCC case */
validate_bcc_impl(const uint8_t * bcc,size_t bcc_size,std::vector<PubKey> * keys)226 bool validate_bcc_impl(const uint8_t* bcc,
227 size_t bcc_size,
228 std::vector<PubKey>* keys) {
229 /* This is what we expect:
230 * Bcc = [
231 * PubKeyEd25519, // DK_pub
232 * + BccEntry, // Root -> leaf (KM_pub)
233 * ]
234 */
235 auto [parsed_bcc, _, err_msg] = cppbor::parse(bcc, bcc_size);
236 CHECK_NOT_NULL(parsed_bcc);
237
238 const cppbor::Array* bcc_array = parsed_bcc->asArray();
239 CHECK_NOT_NULL(bcc_array);
240
241 CHECK_EQ(bcc_array->size(), 2);
242
243 const cppbor::Map* dk_pub = bcc_array->get(0)->asMap();
244 const cppbor::Array* bcc_entry = bcc_array->get(1)->asArray();
245
246 CHECK_NOT_NULL(dk_pub);
247 CHECK_NOT_NULL(bcc_entry);
248
249 PubKey dk_pub_key;
250 PubKey km_pub_key;
251
252 CHECK(validate_pub_key_ed25519(dk_pub, &dk_pub_key));
253 CHECK(validate_bcc_entry(bcc_entry, dk_pub_key, &km_pub_key));
254
255 keys->push_back(dk_pub_key);
256 keys->push_back(km_pub_key);
257
258 return true;
259 }
260
validate_bcc_handover(const uint8_t * bcc_handover,size_t bcc_handover_size,uint8_t next_cdi_attest[DICE_CDI_SIZE],uint8_t next_cdi_seal[DICE_CDI_SIZE])261 bool validate_bcc_handover(const uint8_t* bcc_handover,
262 size_t bcc_handover_size,
263 uint8_t next_cdi_attest[DICE_CDI_SIZE],
264 uint8_t next_cdi_seal[DICE_CDI_SIZE]) {
265 CDI tmp_cdi_attest;
266 CDI tmp_cdi_seal;
267
268 if (!validate_bcc_handover_impl(bcc_handover, bcc_handover_size,
269 &tmp_cdi_attest, &tmp_cdi_seal)) {
270 return false;
271 }
272
273 std::copy(tmp_cdi_attest.begin(), tmp_cdi_attest.end(),
274 &next_cdi_attest[0]);
275 std::copy(tmp_cdi_seal.begin(), tmp_cdi_seal.end(), &next_cdi_seal[0]);
276
277 return true;
278 }
279
validate_bcc_handover_impl(const uint8_t * bcc_handover,size_t bcc_handover_size,CDI * next_cdi_attest,CDI * next_cdi_seal)280 bool validate_bcc_handover_impl(const uint8_t* bcc_handover,
281 size_t bcc_handover_size,
282 CDI* next_cdi_attest,
283 CDI* next_cdi_seal) {
284 /**
285 * This is what we expect:
286 * BccHandover = {
287 * 1 : bstr .size 32, // CDI_Attest
288 * 2 : bstr .size 32, // CDI_Seal
289 * ? 3 : Bcc, // Cert_Chain
290 * }
291 */
292 auto [parsed_bcc_handover, _, err_msg] =
293 cppbor::parse(bcc_handover, bcc_handover_size);
294 CHECK_NOT_NULL(parsed_bcc_handover);
295
296 const cppbor::Map* handover_map = parsed_bcc_handover->asMap();
297 std::vector<uint8_t> cdi_attest = handover_map->get(1)->asBstr()->value();
298 std::vector<uint8_t> cdi_seal = handover_map->get(2)->asBstr()->value();
299
300 std::copy(cdi_attest.begin(), cdi_attest.end(), next_cdi_attest->begin());
301 std::copy(cdi_seal.begin(), cdi_seal.end(), next_cdi_seal->begin());
302
303 return true;
304 }
305