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