blob: ae59d8c9604b9ec12673749115e9ae4ce8d5870b [file] [log] [blame]
Manish V Badarkhe39317ab2020-07-23 10:43:57 +01001/*
Manish V Badarkheabf1b8d2022-01-27 13:50:23 +00002 * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
Manish V Badarkhe39317ab2020-07-23 10:43:57 +01003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8#include <stddef.h>
9
10#include <common/fdt_wrappers.h>
Manish V Badarkheabf1b8d2022-01-27 13:50:23 +000011#include MBEDTLS_CONFIG_FILE
Manish V Badarkhe39317ab2020-07-23 10:43:57 +010012#include <drivers/auth/auth_mod.h>
13#include <lib/fconf/fconf.h>
14#include <lib/object_pool.h>
15#include <libfdt.h>
16
17#include <tools_share/tbbr_oid.h>
18
19/* static structures used during authentication process */
20static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC(
21 AUTH_PARAM_SIG, 0);
22static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC(
23 AUTH_PARAM_SIG_ALG, 0);
24static auth_param_type_desc_t raw_data = AUTH_PARAM_TYPE_DESC(
25 AUTH_PARAM_RAW_DATA, 0);
26
27/* pointers to an array of CoT descriptors */
28static const auth_img_desc_t *cot_desc[MAX_NUMBER_IDS];
29/* array of CoT descriptors */
30static auth_img_desc_t auth_img_descs[MAX_NUMBER_IDS];
31
32/* array of authentication methods structures */
33static auth_method_desc_t auth_methods[MAX_NUMBER_IDS * AUTH_METHOD_NUM];
34static OBJECT_POOL_ARRAY(auth_methods_pool, auth_methods);
35
36/* array of authentication params structures */
37static auth_param_desc_t auth_params[MAX_NUMBER_IDS * COT_MAX_VERIFIED_PARAMS];
38static OBJECT_POOL_ARRAY(auth_params_pool, auth_params);
39
40/* array of authentication param type structures */
41static auth_param_type_desc_t auth_param_type_descs[MAX_NUMBER_IDS];
42static OBJECT_POOL_ARRAY(auth_param_type_descs_pool, auth_param_type_descs);
43
44/*
45 * array of OIDs
46 * Object IDs are used to search hash, pk, counter values in certificate.
47 * As per binding we have below 2 combinations:
48 * 1. Certificates are validated using nv-cntr and pk
49 * 2. Raw images are authenticated using hash
50 * Hence in worst case, there are maximum 2 OIDs per image/certificate
51 */
52static unsigned char oids[(MAX_NUMBER_IDS * 2)][MAX_OID_NAME_LEN];
53static OBJECT_POOL_ARRAY(oid_pool, oids);
54
55/* An array of auth buffer which holds hashes and pk
56 * ToDo: Size decided with the current number of images and
57 * certificates which are available in CoT. Size of these buffers bound to
58 * increase in the future on the addition of images/certificates.
59 */
60static unsigned char hash_auth_bufs[20][HASH_DER_LEN];
61static OBJECT_POOL_ARRAY(hash_auth_buf_pool, hash_auth_bufs);
62static unsigned char pk_auth_bufs[12][PK_DER_LEN];
63static OBJECT_POOL_ARRAY(pk_auth_buf_pool, pk_auth_bufs);
64
65/*******************************************************************************
66 * update_parent_auth_data() - Update authentication data structure
67 * @auth_desc[in]: Pointer to the auth image descriptor
68 * @type_desc[in]: Pointer to authentication parameter
69 * @auth_buf_size[in]: Buffer size to hold pk or hash
70 *
71 * Return 0 on success or an error value otherwise.
72 ******************************************************************************/
73static int update_parent_auth_data(const auth_img_desc_t *auth_desc,
74 auth_param_type_desc_t *type_desc,
75 unsigned int auth_buf_size)
76{
77 unsigned int i;
78 auth_param_desc_t *auth_data = &auth_desc->authenticated_data[0];
79 unsigned char *auth_buf;
80
81 for (i = 0U; i < COT_MAX_VERIFIED_PARAMS; i++) {
82 if (auth_data[i].type_desc == type_desc) {
83 return 0;
84 }
85 if (auth_data[i].type_desc == NULL) {
86 break;
87 }
88 }
89
90 if (auth_buf_size == HASH_DER_LEN) {
91 auth_buf = pool_alloc(&hash_auth_buf_pool);
92 } else if (auth_buf_size == PK_DER_LEN) {
93 auth_buf = pool_alloc(&pk_auth_buf_pool);
94 } else {
95 return -1;
96 }
97
98 if (i < COT_MAX_VERIFIED_PARAMS) {
99 auth_data[i].type_desc = type_desc;
100 auth_data[i].data.ptr = auth_buf;
101 auth_data[i].data.len = auth_buf_size;
102 } else {
103 ERROR("Out of authentication data array\n");
104 return -1;
105 }
106
107 return 0;
108}
109
110/*******************************************************************************
111 * get_auth_param_type_desc() - Get pointer of authentication parameter
112 * @img_id[in]: Image Id
113 * @type_desc[out]: Pointer to authentication parameter
114 * @buf_size[out]: Buffer size which hold hash/pk
115 *
116 * Return 0 on success or an error value otherwise.
117 ******************************************************************************/
118static int get_auth_param_type_desc(unsigned int img_id,
119 auth_param_type_desc_t **type_desc,
120 unsigned int *buf_size)
121{
122 auth_method_desc_t *img_auth_method = NULL;
123 img_type_t type = auth_img_descs[img_id].img_type;
124
125 if (type == IMG_CERT) {
126 img_auth_method =
127 &auth_img_descs[img_id].img_auth_methods[AUTH_METHOD_SIG];
128 *type_desc = img_auth_method->param.sig.pk;
129 *buf_size = PK_DER_LEN;
130 } else if (type == IMG_RAW) {
131 img_auth_method =
132 &auth_img_descs[img_id].img_auth_methods[AUTH_METHOD_HASH];
133 *type_desc = img_auth_method->param.hash.hash;
134 *buf_size = HASH_DER_LEN;
135 } else {
136 return -1;
137 }
138
139 return 0;
140}
141
142/*******************************************************************************
143 * set_auth_method() - Update global auth image descriptors with authentication
144 * method data
145 * @auth_method_type[in]: Type of authentication method
146 * @oid[in]: Object Idetifier for pk/hash search
147 * @auth_method[in]: Pointer to authentication method to set
148 ******************************************************************************/
149static void set_auth_method(auth_method_type_t auth_method_type, char *oid,
150 auth_method_desc_t *auth_method)
151{
152 auth_param_type_t auth_param_type = AUTH_PARAM_NONE;
153 auth_param_type_desc_t *auth_param_type_desc;
154
155 assert(auth_method != NULL);
156
157 auth_param_type_desc = pool_alloc(&auth_param_type_descs_pool);
158 auth_method->type = auth_method_type;
159
160 if (auth_method_type == AUTH_METHOD_SIG) {
161 auth_param_type = AUTH_PARAM_PUB_KEY;
162 auth_method->param.sig.sig = &sig;
163 auth_method->param.sig.alg = &sig_alg;
164 auth_method->param.sig.data = &raw_data;
165 auth_method->param.sig.pk = auth_param_type_desc;
166 } else if (auth_method_type == AUTH_METHOD_HASH) {
167 auth_param_type = AUTH_PARAM_HASH;
168 auth_method->param.hash.data = &raw_data;
169 auth_method->param.hash.hash = auth_param_type_desc;
170 } else if (auth_method_type == AUTH_METHOD_NV_CTR) {
171 auth_param_type = AUTH_PARAM_NV_CTR;
172 auth_method->param.nv_ctr.cert_nv_ctr = auth_param_type_desc;
173 auth_method->param.nv_ctr.plat_nv_ctr = auth_param_type_desc;
174 }
175
176 auth_param_type_desc->type = auth_param_type;
177 auth_param_type_desc->cookie = (void *)oid;
178}
179
180/*******************************************************************************
181 * get_oid() - get object identifier from device tree
182 * @dtb[in]: Pointer to the device tree blob in memory
183 * @node[in]: Offset of the node
184 * @prop[in]: Property to read from the given node
185 * @oid[out]: Object Indentifier of key/hash/nv-counter in certificate
186 *
187 * Return 0 on success or an error value otherwise.
188 ******************************************************************************/
189static int get_oid(const void *dtb, int node, const char *prop, char **oid)
190{
191 uint32_t phandle;
192 int rc;
193
194 rc = fdt_read_uint32(dtb, node, prop, &phandle);
195 if (rc < 0) {
196 return rc;
197 }
198
199 node = fdt_node_offset_by_phandle(dtb, phandle);
200 if (node < 0) {
201 return node;
202 }
203
204 *oid = pool_alloc(&oid_pool);
205 rc = fdtw_read_string(dtb, node, "oid", *oid, MAX_OID_NAME_LEN);
206
207 return rc;
208}
209
210/*******************************************************************************
211 * populate_and_set_auth_methods() - Populate auth method parameters from
212 * device tree and set authentication method
213 * structure.
214 * @dtb[in]: Pointer to the device tree blob in memory
215 * @node[in]: Offset of the node
216 * @img_id[in]: Image identifier
217 * @type[in]: Type of image
218 * @root_certificate[in]:Root certificate (authenticated by ROTPK)
219 *
220 * Return 0 on success or an error value otherwise.
221 ******************************************************************************/
222static int populate_and_set_auth_methods(const void *dtb, int node,
223 unsigned int img_id, img_type_t type,
224 bool root_certificate)
225{
226 auth_method_type_t auth_method_type = AUTH_METHOD_NONE;
227 int rc;
228 char *oid = NULL;
229
230 auth_method_desc_t *auth_method = pool_alloc_n(&auth_methods_pool,
231 AUTH_METHOD_NUM);
232
233 /*
234 * This is as per binding document where certificates are
235 * verified by signature and images are verified by hash.
236 */
237 if (type == IMG_CERT) {
238 if (root_certificate) {
239 oid = NULL;
240 } else {
241 rc = get_oid(dtb, node, "signing-key", &oid);
242 if (rc < 0) {
243 ERROR("FCONF: Can't read %s property\n",
244 "signing-key");
245 return rc;
246 }
247 }
248 auth_method_type = AUTH_METHOD_SIG;
249 } else if (type == IMG_RAW) {
250 rc = get_oid(dtb, node, "hash", &oid);
251 if (rc < 0) {
252 ERROR("FCONF: Can't read %s property\n",
253 "hash");
254 return rc;
255 }
256 auth_method_type = AUTH_METHOD_HASH;
257 } else {
258 return -1;
259 }
260
261 set_auth_method(auth_method_type, oid,
262 &auth_method[auth_method_type]);
263
264 /* Retrieve the optional property */
265 rc = get_oid(dtb, node, "antirollback-counter", &oid);
266 if (rc == 0) {
267 auth_method_type = AUTH_METHOD_NV_CTR;
268 set_auth_method(auth_method_type, oid,
269 &auth_method[auth_method_type]);
270 }
271
272 auth_img_descs[img_id].img_auth_methods = &auth_method[0];
273
274 return 0;
275}
276
277/*******************************************************************************
278 * get_parent_img_id() - Get parent image id for given child node
279 * @dtb[in]: Pointer to the device tree blob in memory
280 * @node[in]: Offset of the child node
281 * @parent_img_id[out]: Image id of parent
282 *
283 * Return 0 on success or an error value otherwise.
284 ******************************************************************************/
285static int get_parent_img_id(const void *dtb, int node,
286 unsigned int *parent_img_id)
287{
288 uint32_t phandle;
289 int err;
290
291 err = fdt_read_uint32(dtb, node, "parent", &phandle);
292 if (err < 0) {
293 ERROR("FCONF: Could not read %s property in node\n",
294 "parent");
295 return err;
296 }
297
298 node = fdt_node_offset_by_phandle(dtb, phandle);
299 if (node < 0) {
300 ERROR("FCONF: Failed to locate node using its phandle\n");
301 return node;
302 }
303
304 err = fdt_read_uint32(dtb, node, "image-id", parent_img_id);
305 if (err < 0) {
306 ERROR("FCONF: Could not read %s property in node\n",
307 "image-id");
308 }
309
310 return err;
311}
312
313/*******************************************************************************
314 * set_desc_data() - Update data in descriptor's structure
315 * @dtb[in]: Pointer to the device tree blob in memory
316 * @node[in]: Offset of the node
317 * @type[in]: Type of image (RAW/CERT)
318 *
319 * Return 0 on success or an error value otherwise.
320 ******************************************************************************/
321static int set_desc_data(const void *dtb, int node, img_type_t type)
322{
323 int rc;
324 bool root_certificate = false;
325 unsigned int img_id, parent_img_id;
326
327 rc = fdt_read_uint32(dtb, node, "image-id", &img_id);
328 if (rc < 0) {
329 ERROR("FCONF: Can't find property %s in node\n",
330 "image-id");
331 return rc;
332 }
333
334 if (fdt_getprop(dtb, node, "root-certificate",
335 NULL) != NULL) {
336 root_certificate = true;
337 }
338
339 if (!root_certificate) {
340 rc = get_parent_img_id(dtb, node, &parent_img_id);
341 if (rc < 0) {
342 return rc;
343 }
344 auth_img_descs[img_id].parent = &auth_img_descs[parent_img_id];
345 }
346
347 auth_img_descs[img_id].img_id = img_id;
348 auth_img_descs[img_id].img_type = type;
349
350 rc = populate_and_set_auth_methods(dtb, node, img_id, type,
351 root_certificate);
352 if (rc < 0) {
353 return rc;
354 }
355
356 if (type == IMG_CERT) {
357 auth_param_desc_t *auth_param =
358 pool_alloc_n(&auth_params_pool,
359 COT_MAX_VERIFIED_PARAMS);
360 auth_img_descs[img_id].authenticated_data = &auth_param[0];
361 }
362
363 cot_desc[img_id] = &auth_img_descs[img_id];
364
365 return rc;
366}
367
368/*******************************************************************************
369 * populate_manifest_descs() - Populate CoT descriptors and update global
370 * certificate structures
371 * @dtb[in]: Pointer to the device tree blob in memory
372 *
373 * Return 0 on success or an error value otherwise.
374 ******************************************************************************/
375static int populate_manifest_descs(const void *dtb)
376{
377 int node, child;
378 int rc;
379
380 /*
381 * Assert the node offset points to "arm, cert-descs"
382 * compatible property
383 */
384 const char *compatible_str = "arm, cert-descs";
385
386 node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
387 if (node < 0) {
388 ERROR("FCONF: Can't find %s compatible in node\n",
389 compatible_str);
390 return node;
391 }
392
393 fdt_for_each_subnode(child, dtb, node) {
394 rc = set_desc_data(dtb, child, IMG_CERT);
395 if (rc < 0) {
396 return rc;
397 }
398 }
399
400 return 0;
401}
402
403/*******************************************************************************
404 * populate_image_descs() - Populate CoT descriptors and update global
405 * image descriptor structures.
406 * @dtb[in]: Pointer to the device tree blob in memory
407 *
408 * Return 0 on success or an error value otherwise.
409 ******************************************************************************/
410static int populate_image_descs(const void *dtb)
411{
412 int node, child;
413 int rc;
414
415 /*
416 * Assert the node offset points to "arm, img-descs"
417 * compatible property
418 */
419 const char *compatible_str = "arm, img-descs";
420
421 node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
422 if (node < 0) {
423 ERROR("FCONF: Can't find %s compatible in node\n",
424 compatible_str);
425 return node;
426 }
427
428 fdt_for_each_subnode(child, dtb, node) {
429 rc = set_desc_data(dtb, child, IMG_RAW);
430 if (rc < 0) {
431 return rc;
432 }
433 }
434
435 return 0;
436}
437
438/*******************************************************************************
439 * fconf_populate_cot_descs() - Populate CoT descriptors and update global
440 * structures
441 * @config[in]: Pointer to the device tree blob in memory
442 *
443 * Return 0 on success or an error value otherwise.
444 ******************************************************************************/
445static int fconf_populate_cot_descs(uintptr_t config)
446{
447 auth_param_type_desc_t *type_desc = NULL;
448 unsigned int auth_buf_size = 0U;
449 int rc;
450
451 /* As libfdt uses void *, we can't avoid this cast */
452 const void *dtb = (void *)config;
453
454 /* populate manifest descs information */
455 rc = populate_manifest_descs(dtb);
456 if (rc < 0) {
457 ERROR("FCONF: population of %s descs failed %d\n",
458 "manifest", rc);
459 return rc;
460 }
461
462 /* populate image descs information */
463 rc = populate_image_descs(dtb);
464 if (rc < 0) {
465 ERROR("FCONF: population of %s descs failed %d\n",
466 "images", rc);
467 return rc;
468 }
469
470 /* update parent's authentication data */
471 for (unsigned int i = 0U; i < MAX_NUMBER_IDS; i++) {
472 if (auth_img_descs[i].parent != NULL) {
473 rc = get_auth_param_type_desc(i,
474 &type_desc,
475 &auth_buf_size);
476 if (rc < 0) {
477 ERROR("FCONF: failed to get auth data %d\n",
478 rc);
479 return rc;
480 }
481
482 rc = update_parent_auth_data(auth_img_descs[i].parent,
483 type_desc,
484 auth_buf_size);
485 if (rc < 0) {
486 ERROR("FCONF: auth data update failed %d\n",
487 rc);
488 return rc;
489 }
490 }
491 }
492
493 return rc;
494}
495
496FCONF_REGISTER_POPULATOR(TB_FW, cot_desc, fconf_populate_cot_descs);
497REGISTER_COT(cot_desc);