1 /*
2  * Copyright (c) 2020-2024, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <stddef.h>
9 
10 #include <mbedtls/version.h>
11 
12 #include <common/fdt_wrappers.h>
13 #include <common/tbbr/cot_def.h>
14 #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 */
22 static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC(
23 			AUTH_PARAM_SIG, 0);
24 static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC(
25 			AUTH_PARAM_SIG_ALG, 0);
26 static 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 */
30 static const auth_img_desc_t *cot_desc[MAX_NUMBER_IDS];
31 /* array of CoT descriptors */
32 static auth_img_desc_t auth_img_descs[MAX_NUMBER_IDS];
33 
34 /* array of authentication methods structures */
35 static auth_method_desc_t auth_methods[MAX_NUMBER_IDS * AUTH_METHOD_NUM];
36 static OBJECT_POOL_ARRAY(auth_methods_pool, auth_methods);
37 
38 /* array of authentication params structures */
39 static auth_param_desc_t auth_params[MAX_NUMBER_IDS * COT_MAX_VERIFIED_PARAMS];
40 static OBJECT_POOL_ARRAY(auth_params_pool, auth_params);
41 
42 /* array of authentication param type structures */
43 static auth_param_type_desc_t auth_param_type_descs[MAX_NUMBER_IDS];
44 static 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  */
54 static unsigned char oids[(MAX_NUMBER_IDS * 2)][MAX_OID_NAME_LEN];
55 static 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  */
62 static unsigned char hash_auth_bufs[20][HASH_DER_LEN];
63 static OBJECT_POOL_ARRAY(hash_auth_buf_pool, hash_auth_bufs);
64 static unsigned char pk_auth_bufs[12][PK_DER_LEN];
65 static 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  ******************************************************************************/
update_parent_auth_data(const auth_img_desc_t * auth_desc,auth_param_type_desc_t * type_desc,unsigned int auth_buf_size)75 static 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  ******************************************************************************/
get_auth_param_type_desc(unsigned int img_id,auth_param_type_desc_t ** type_desc,unsigned int * buf_size)120 static 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  ******************************************************************************/
set_auth_method(auth_method_type_t auth_method_type,char * oid,auth_method_desc_t * auth_method)151 static 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  ******************************************************************************/
get_oid(const void * dtb,int node,const char * prop,char ** oid)191 static 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  ******************************************************************************/
populate_and_set_auth_methods(const void * dtb,int node,unsigned int img_id,img_type_t type,bool root_certificate)224 static 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 		rc = get_oid(dtb, node, "signing-key", &oid);
241 		if (rc < 0) {
242 			/*
243 			 * The signing-key property is optional in root
244 			 * certificates, mandatory otherwise.
245 			 */
246 			if (root_certificate) {
247 				oid = NULL;
248 			} else {
249 				ERROR("FCONF: Can't read %s property\n",
250 						"signing-key");
251 				return rc;
252 			}
253 		}
254 		auth_method_type = AUTH_METHOD_SIG;
255 	} else if (type == IMG_RAW) {
256 		rc = get_oid(dtb, node, "hash", &oid);
257 		if (rc < 0) {
258 			ERROR("FCONF: Can't read %s property\n",
259 				"hash");
260 			return rc;
261 		}
262 		auth_method_type = AUTH_METHOD_HASH;
263 	} else {
264 		return -1;
265 	}
266 
267 	set_auth_method(auth_method_type, oid,
268 			&auth_method[auth_method_type]);
269 
270 	/* Retrieve the optional property */
271 	rc = get_oid(dtb, node, "antirollback-counter", &oid);
272 	if (rc == 0) {
273 		auth_method_type = AUTH_METHOD_NV_CTR;
274 		set_auth_method(auth_method_type, oid,
275 				&auth_method[auth_method_type]);
276 	}
277 
278 	auth_img_descs[img_id].img_auth_methods = &auth_method[0];
279 
280 	return 0;
281 }
282 
283 /*******************************************************************************
284  * get_parent_img_id() - Get parent image id for given child node
285  * @dtb[in]:		Pointer to the device tree blob in memory
286  * @node[in]:		Offset of the child node
287  * @parent_img_id[out]:	Image id of parent
288  *
289  * Return 0 on success or an error value otherwise.
290  ******************************************************************************/
get_parent_img_id(const void * dtb,int node,unsigned int * parent_img_id)291 static int get_parent_img_id(const void *dtb, int node,
292 			     unsigned int *parent_img_id)
293 {
294 	uint32_t phandle;
295 	int err;
296 
297 	err = fdt_read_uint32(dtb, node, "parent", &phandle);
298 	if (err < 0) {
299 		ERROR("FCONF: Could not read %s property in node\n",
300 			"parent");
301 		return err;
302 	}
303 
304 	node = fdt_node_offset_by_phandle(dtb, phandle);
305 	if (node < 0) {
306 		ERROR("FCONF: Failed to locate node using its phandle\n");
307 		return node;
308 	}
309 
310 	err = fdt_read_uint32(dtb, node, "image-id", parent_img_id);
311 	if (err < 0) {
312 		ERROR("FCONF: Could not read %s property in node\n",
313 			"image-id");
314 	}
315 
316 	return err;
317 }
318 
319 /*******************************************************************************
320  * set_desc_data() - Update data in descriptor's structure
321  * @dtb[in]:	Pointer to the device tree blob in memory
322  * @node[in]:	Offset of the node
323  * @type[in]:	Type of image (RAW/CERT)
324  *
325  * Return 0 on success or an error value otherwise.
326  ******************************************************************************/
set_desc_data(const void * dtb,int node,img_type_t type)327 static int set_desc_data(const void *dtb, int node, img_type_t type)
328 {
329 	int rc;
330 	bool root_certificate = false;
331 	unsigned int img_id, parent_img_id;
332 
333 	rc = fdt_read_uint32(dtb, node, "image-id", &img_id);
334 	if (rc < 0) {
335 		ERROR("FCONF: Can't find property %s in node\n",
336 			"image-id");
337 		return rc;
338 	}
339 
340 	if (fdt_getprop(dtb, node, "root-certificate",
341 					NULL) != NULL) {
342 		root_certificate = true;
343 	}
344 
345 	if (!root_certificate) {
346 		rc = get_parent_img_id(dtb, node, &parent_img_id);
347 		if (rc < 0) {
348 			return rc;
349 		}
350 		auth_img_descs[img_id].parent = &auth_img_descs[parent_img_id];
351 	}
352 
353 	auth_img_descs[img_id].img_id = img_id;
354 	auth_img_descs[img_id].img_type = type;
355 
356 	rc = populate_and_set_auth_methods(dtb, node, img_id, type,
357 				root_certificate);
358 	if (rc < 0) {
359 		return rc;
360 	}
361 
362 	if (type == IMG_CERT) {
363 		auth_param_desc_t *auth_param =
364 			pool_alloc_n(&auth_params_pool,
365 					COT_MAX_VERIFIED_PARAMS);
366 		auth_img_descs[img_id].authenticated_data = &auth_param[0];
367 	}
368 
369 	cot_desc[img_id] = &auth_img_descs[img_id];
370 
371 	return rc;
372 }
373 
374 /*******************************************************************************
375  * populate_manifest_descs() - Populate CoT descriptors and update global
376  *			       certificate structures
377  * @dtb[in]:	Pointer to the device tree blob in memory
378  *
379  * Return 0 on success or an error value otherwise.
380  ******************************************************************************/
populate_manifest_descs(const void * dtb)381 static int populate_manifest_descs(const void *dtb)
382 {
383 	int node, child;
384 	int rc;
385 
386 	/*
387 	 * Assert the node offset points to "arm, cert-descs"
388 	 * compatible property
389 	 */
390 	const char *compatible_str = "arm, cert-descs";
391 
392 	node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
393 	if (node < 0) {
394 		ERROR("FCONF: Can't find %s compatible in node\n",
395 			compatible_str);
396 		return node;
397 	}
398 
399 	fdt_for_each_subnode(child, dtb, node) {
400 		rc = set_desc_data(dtb, child, IMG_CERT);
401 		if (rc < 0) {
402 			return rc;
403 		}
404 	}
405 
406 	return 0;
407 }
408 
409 /*******************************************************************************
410  * populate_image_descs() - Populate CoT descriptors and update global
411  *			    image descriptor structures.
412  * @dtb[in]:	Pointer to the device tree blob in memory
413  *
414  * Return 0 on success or an error value otherwise.
415  ******************************************************************************/
populate_image_descs(const void * dtb)416 static int populate_image_descs(const void *dtb)
417 {
418 	int node, child;
419 	int rc;
420 
421 	/*
422 	 * Assert the node offset points to "arm, img-descs"
423 	 * compatible property
424 	 */
425 	const char *compatible_str = "arm, img-descs";
426 
427 	node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
428 	if (node < 0) {
429 		ERROR("FCONF: Can't find %s compatible in node\n",
430 			compatible_str);
431 		return node;
432 	}
433 
434 	fdt_for_each_subnode(child, dtb, node) {
435 		rc = set_desc_data(dtb, child, IMG_RAW);
436 		if (rc < 0) {
437 			return rc;
438 		}
439 	}
440 
441 	return 0;
442 }
443 
444 /*******************************************************************************
445  * fconf_populate_cot_descs() - Populate CoT descriptors and update global
446  *				structures
447  * @config[in]:	Pointer to the device tree blob in memory
448  *
449  * Return 0 on success or an error value otherwise.
450  ******************************************************************************/
fconf_populate_cot_descs(uintptr_t config)451 static int fconf_populate_cot_descs(uintptr_t config)
452 {
453 	auth_param_type_desc_t *type_desc = NULL;
454 	unsigned int auth_buf_size = 0U;
455 	int rc;
456 
457 	/* As libfdt uses void *, we can't avoid this cast */
458 	const void *dtb = (void *)config;
459 
460 	/* populate manifest descs information */
461 	rc = populate_manifest_descs(dtb);
462 	if (rc < 0) {
463 		ERROR("FCONF: population of %s descs failed %d\n",
464 			"manifest", rc);
465 		return rc;
466 	}
467 
468 	/* populate image descs information */
469 	rc = populate_image_descs(dtb);
470 	if (rc < 0) {
471 		ERROR("FCONF: population of %s descs failed %d\n",
472 			"images", rc);
473 		return rc;
474 	}
475 
476 	/* update parent's authentication data */
477 	for (unsigned int i = 0U; i < MAX_NUMBER_IDS; i++) {
478 		if (auth_img_descs[i].parent != NULL) {
479 			rc = get_auth_param_type_desc(i,
480 						&type_desc,
481 						&auth_buf_size);
482 			if (rc < 0) {
483 				ERROR("FCONF: failed to get auth data %d\n",
484 					rc);
485 				return rc;
486 			}
487 
488 			rc = update_parent_auth_data(auth_img_descs[i].parent,
489 						type_desc,
490 						auth_buf_size);
491 			if (rc < 0) {
492 				ERROR("FCONF: auth data update failed %d\n",
493 					rc);
494 				return rc;
495 			}
496 		}
497 	}
498 
499 	return rc;
500 }
501 
502 FCONF_REGISTER_POPULATOR(TB_FW, cot_desc, fconf_populate_cot_descs);
503 REGISTER_COT(cot_desc);
504