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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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