1 /*
2  * Copyright (c) 2020, 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 <common/fdt_wrappers.h>
11 #include <drivers/auth/mbedtls/mbedtls_config.h>
12 #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 */
20 static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC(
21 			AUTH_PARAM_SIG, 0);
22 static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC(
23 			AUTH_PARAM_SIG_ALG, 0);
24 static 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 */
28 static const auth_img_desc_t *cot_desc[MAX_NUMBER_IDS];
29 /* array of CoT descriptors */
30 static auth_img_desc_t auth_img_descs[MAX_NUMBER_IDS];
31 
32 /* array of authentication methods structures */
33 static auth_method_desc_t auth_methods[MAX_NUMBER_IDS * AUTH_METHOD_NUM];
34 static OBJECT_POOL_ARRAY(auth_methods_pool, auth_methods);
35 
36 /* array of authentication params structures */
37 static auth_param_desc_t auth_params[MAX_NUMBER_IDS * COT_MAX_VERIFIED_PARAMS];
38 static OBJECT_POOL_ARRAY(auth_params_pool, auth_params);
39 
40 /* array of authentication param type structures */
41 static auth_param_type_desc_t auth_param_type_descs[MAX_NUMBER_IDS];
42 static 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  */
52 static unsigned char oids[(MAX_NUMBER_IDS * 2)][MAX_OID_NAME_LEN];
53 static 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  */
60 static unsigned char hash_auth_bufs[20][HASH_DER_LEN];
61 static OBJECT_POOL_ARRAY(hash_auth_buf_pool, hash_auth_bufs);
62 static unsigned char pk_auth_bufs[12][PK_DER_LEN];
63 static 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  ******************************************************************************/
update_parent_auth_data(const auth_img_desc_t * auth_desc,auth_param_type_desc_t * type_desc,unsigned int auth_buf_size)73 static 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  ******************************************************************************/
get_auth_param_type_desc(unsigned int img_id,auth_param_type_desc_t ** type_desc,unsigned int * buf_size)118 static 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  ******************************************************************************/
set_auth_method(auth_method_type_t auth_method_type,char * oid,auth_method_desc_t * auth_method)149 static 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  ******************************************************************************/
get_oid(const void * dtb,int node,const char * prop,char ** oid)189 static 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  ******************************************************************************/
populate_and_set_auth_methods(const void * dtb,int node,unsigned int img_id,img_type_t type,bool root_certificate)222 static 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  ******************************************************************************/
get_parent_img_id(const void * dtb,int node,unsigned int * parent_img_id)285 static 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  ******************************************************************************/
set_desc_data(const void * dtb,int node,img_type_t type)321 static 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  ******************************************************************************/
populate_manifest_descs(const void * dtb)375 static 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  ******************************************************************************/
populate_image_descs(const void * dtb)410 static 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  ******************************************************************************/
fconf_populate_cot_descs(uintptr_t config)445 static 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 
496 FCONF_REGISTER_POPULATOR(TB_FW, cot_desc, fconf_populate_cot_descs);
497 REGISTER_COT(cot_desc);
498