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