1 /* 2 * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <stdint.h> 9 #include <string.h> 10 11 #include <platform_def.h> 12 13 #include <common/debug.h> 14 #include <common/tbbr/cot_def.h> 15 #include <drivers/auth/auth_common.h> 16 #include <drivers/auth/auth_mod.h> 17 #include <drivers/auth/crypto_mod.h> 18 #include <drivers/auth/img_parser_mod.h> 19 #include <drivers/fwu/fwu.h> 20 #include <lib/fconf/fconf_tbbr_getter.h> 21 #include <plat/common/platform.h> 22 23 #include <tools_share/zero_oid.h> 24 25 /* ASN.1 tags */ 26 #define ASN1_INTEGER 0x02 27 28 #pragma weak plat_set_nv_ctr2 29 30 static int cmp_auth_param_type_desc(const auth_param_type_desc_t *a, 31 const auth_param_type_desc_t *b) 32 { 33 if ((a->type == b->type) && (a->cookie == b->cookie)) { 34 return 0; 35 } 36 return 1; 37 } 38 39 /* 40 * This function obtains the requested authentication parameter data from the 41 * information extracted from the parent image after its authentication. 42 */ 43 static int auth_get_param(const auth_param_type_desc_t *param_type_desc, 44 const auth_img_desc_t *img_desc, 45 void **param, unsigned int *len) 46 { 47 int i; 48 49 if (img_desc->authenticated_data == NULL) 50 return 1; 51 52 for (i = 0 ; i < COT_MAX_VERIFIED_PARAMS ; i++) { 53 if (0 == cmp_auth_param_type_desc(param_type_desc, 54 img_desc->authenticated_data[i].type_desc)) { 55 *param = img_desc->authenticated_data[i].data.ptr; 56 *len = img_desc->authenticated_data[i].data.len; 57 return 0; 58 } 59 } 60 61 return 1; 62 } 63 64 /* 65 * Authenticate an image by matching the data hash 66 * 67 * This function implements 'AUTH_METHOD_HASH'. To authenticate an image using 68 * this method, the image must contain: 69 * 70 * - The data to calculate the hash from 71 * 72 * The parent image must contain: 73 * 74 * - The hash to be matched with (including hash algorithm) 75 * 76 * For a successful authentication, both hashes must match. The function calls 77 * the crypto-module to check this matching. 78 * 79 * Parameters: 80 * param: parameters to perform the hash authentication 81 * img_desc: pointer to image descriptor so we can know the image type 82 * and parent image 83 * img: pointer to image in memory 84 * img_len: length of image (in bytes) 85 * 86 * Return: 87 * 0 = success, Otherwise = error 88 */ 89 static int auth_hash(const auth_method_param_hash_t *param, 90 const auth_img_desc_t *img_desc, 91 void *img, unsigned int img_len) 92 { 93 void *data_ptr, *hash_der_ptr; 94 unsigned int data_len, hash_der_len; 95 int rc; 96 97 /* Get the hash from the parent image. This hash will be DER encoded 98 * and contain the hash algorithm */ 99 rc = auth_get_param(param->hash, img_desc->parent, 100 &hash_der_ptr, &hash_der_len); 101 if (rc != 0) { 102 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 103 __func__, __LINE__, rc); 104 return rc; 105 } 106 107 /* Get the data to be hashed from the current image */ 108 rc = img_parser_get_auth_param(img_desc->img_type, param->data, 109 img, img_len, &data_ptr, &data_len); 110 if (rc != 0) { 111 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 112 __func__, __LINE__, rc); 113 return rc; 114 } 115 116 /* Ask the crypto module to verify this hash */ 117 rc = crypto_mod_verify_hash(data_ptr, data_len, 118 hash_der_ptr, hash_der_len); 119 if (rc != 0) { 120 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 121 __func__, __LINE__, rc); 122 return rc; 123 } 124 125 return 0; 126 } 127 128 /* 129 * Authenticate by digital signature 130 * 131 * This function implements 'AUTH_METHOD_SIG'. To authenticate an image using 132 * this method, the image must contain: 133 * 134 * - Data to be signed 135 * - Signature 136 * - Signature algorithm 137 * 138 * We rely on the image parser module to extract this data from the image. 139 * The parent image must contain: 140 * 141 * - Public key (or a hash of it) 142 * 143 * If the parent image contains only a hash of the key, we will try to obtain 144 * the public key from the image itself (i.e. self-signed certificates). In that 145 * case, the signature verification is considered just an integrity check and 146 * the authentication is established by calculating the hash of the key and 147 * comparing it with the hash obtained from the parent. 148 * 149 * If the image has no parent (NULL), it means it has to be authenticated using 150 * the ROTPK stored in the platform. Again, this ROTPK could be the key itself 151 * or a hash of it. 152 * 153 * Return: 0 = success, Otherwise = error 154 */ 155 static int auth_signature(const auth_method_param_sig_t *param, 156 const auth_img_desc_t *img_desc, 157 void *img, unsigned int img_len) 158 { 159 void *data_ptr, *pk_ptr, *cnv_pk_ptr, *pk_plat_ptr, *sig_ptr, *sig_alg_ptr, *pk_oid; 160 unsigned int data_len, pk_len, cnv_pk_len, pk_plat_len, sig_len, sig_alg_len; 161 unsigned int flags = 0; 162 int rc; 163 164 /* Get the data to be signed from current image */ 165 rc = img_parser_get_auth_param(img_desc->img_type, param->data, 166 img, img_len, &data_ptr, &data_len); 167 if (rc != 0) { 168 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 169 __func__, __LINE__, rc); 170 return rc; 171 } 172 173 /* Get the signature from current image */ 174 rc = img_parser_get_auth_param(img_desc->img_type, param->sig, 175 img, img_len, &sig_ptr, &sig_len); 176 if (rc != 0) { 177 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 178 __func__, __LINE__, rc); 179 return rc; 180 } 181 182 /* Get the signature algorithm from current image */ 183 rc = img_parser_get_auth_param(img_desc->img_type, param->alg, 184 img, img_len, &sig_alg_ptr, &sig_alg_len); 185 if (rc != 0) { 186 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 187 __func__, __LINE__, rc); 188 return rc; 189 } 190 191 /* Get the public key from the parent. If there is no parent (NULL), 192 * the certificate has been signed with the ROTPK, so we have to get 193 * the PK from the platform */ 194 if (img_desc->parent != NULL) { 195 rc = auth_get_param(param->pk, img_desc->parent, 196 &pk_ptr, &pk_len); 197 if (rc != 0) { 198 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 199 __func__, __LINE__, rc); 200 return rc; 201 } 202 } else { 203 /* 204 * Root certificates are signed with the ROTPK, so we have to 205 * get it from the platform. 206 */ 207 rc = plat_get_rotpk_info(param->pk->cookie, &pk_plat_ptr, 208 &pk_plat_len, &flags); 209 if (rc != 0) { 210 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 211 __func__, __LINE__, rc); 212 return rc; 213 } 214 215 assert(is_rotpk_flags_valid(flags)); 216 217 /* Also retrieve the key from the image. */ 218 rc = img_parser_get_auth_param(img_desc->img_type, 219 param->pk, img, img_len, 220 &pk_ptr, &pk_len); 221 if (rc != 0) { 222 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 223 __func__, __LINE__, rc); 224 return rc; 225 } 226 227 /* 228 * Validate the certificate's key against the platform ROTPK. 229 * 230 * Platform may store key in one of the following way - 231 * 1. Hash of ROTPK 232 * 2. Hash if prefixed, suffixed or modified ROTPK 233 * 3. Full ROTPK 234 */ 235 if ((flags & ROTPK_NOT_DEPLOYED) != 0U) { 236 NOTICE("ROTPK is not deployed on platform. " 237 "Skipping ROTPK verification.\n"); 238 } else if ((flags & ROTPK_IS_HASH) != 0U) { 239 /* 240 * platform may store the hash of a prefixed, 241 * suffixed or modified pk 242 */ 243 rc = crypto_mod_convert_pk(pk_ptr, pk_len, &cnv_pk_ptr, &cnv_pk_len); 244 if (rc != 0) { 245 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 246 __func__, __LINE__, rc); 247 return rc; 248 } 249 250 /* 251 * The hash of the certificate's public key must match 252 * the hash of the ROTPK. 253 */ 254 rc = crypto_mod_verify_hash(cnv_pk_ptr, cnv_pk_len, 255 pk_plat_ptr, pk_plat_len); 256 if (rc != 0) { 257 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 258 __func__, __LINE__, rc); 259 return rc; 260 } 261 } else { 262 /* Platform supports full ROTPK */ 263 if ((pk_len != pk_plat_len) || 264 (memcmp(pk_plat_ptr, pk_ptr, pk_len) != 0)) { 265 ERROR("plat and cert ROTPK len mismatch\n"); 266 return -1; 267 } 268 } 269 270 /* 271 * Set Zero-OID for ROTPK(subject key) as a the certificate 272 * does not hold Key-OID information for ROTPK. 273 */ 274 if (param->pk->cookie != NULL) { 275 pk_oid = param->pk->cookie; 276 } else { 277 pk_oid = ZERO_OID; 278 } 279 280 /* 281 * Public key is verified at this stage, notify platform 282 * to measure and publish it. 283 */ 284 rc = plat_mboot_measure_key(pk_oid, pk_ptr, pk_len); 285 if (rc != 0) { 286 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 287 __func__, __LINE__, rc); 288 } 289 } 290 291 /* Ask the crypto module to verify the signature */ 292 rc = crypto_mod_verify_signature(data_ptr, data_len, 293 sig_ptr, sig_len, 294 sig_alg_ptr, sig_alg_len, 295 pk_ptr, pk_len); 296 if (rc != 0) { 297 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 298 __func__, __LINE__, rc); 299 return rc; 300 } 301 302 return 0; 303 } 304 305 /* 306 * Authenticate by Non-Volatile counter 307 * 308 * To protect the system against rollback, the platform includes a non-volatile 309 * counter whose value can only be increased. All certificates include a counter 310 * value that should not be lower than the value stored in the platform. If the 311 * value is larger, the counter in the platform must be updated to the new value 312 * (provided it has been authenticated). 313 * 314 * Return: 0 = success, Otherwise = error 315 * Returns additionally, 316 * cert_nv_ctr -> NV counter value present in the certificate 317 * need_nv_ctr_upgrade = 0 -> platform NV counter upgrade is not needed 318 * need_nv_ctr_upgrade = 1 -> platform NV counter upgrade is needed 319 */ 320 static int auth_nvctr(const auth_method_param_nv_ctr_t *param, 321 const auth_img_desc_t *img_desc, 322 void *img, unsigned int img_len, 323 unsigned int *cert_nv_ctr, 324 bool *need_nv_ctr_upgrade) 325 { 326 unsigned char *p; 327 void *data_ptr = NULL; 328 unsigned int data_len, len, i; 329 unsigned int plat_nv_ctr; 330 int rc; 331 bool is_trial_run = false; 332 333 /* Get the counter value from current image. The AM expects the IPM 334 * to return the counter value as a DER encoded integer */ 335 rc = img_parser_get_auth_param(img_desc->img_type, param->cert_nv_ctr, 336 img, img_len, &data_ptr, &data_len); 337 if (rc != 0) { 338 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 339 __func__, __LINE__, rc); 340 return rc; 341 } 342 343 /* Parse the DER encoded integer */ 344 assert(data_ptr); 345 p = (unsigned char *)data_ptr; 346 347 /* 348 * Integers must be at least 3 bytes: 1 for tag, 1 for length, and 1 349 * for value. The first byte (tag) must be ASN1_INTEGER. 350 */ 351 if ((data_len < 3) || (*p != ASN1_INTEGER)) { 352 /* Invalid ASN.1 integer */ 353 return 1; 354 } 355 p++; 356 357 /* 358 * NV-counters are unsigned integers up to 31 bits. Trailing 359 * padding is not allowed. 360 */ 361 len = (unsigned int)*p; 362 if ((len > 4) || (data_len - 2 != len)) { 363 return 1; 364 } 365 p++; 366 367 /* Check the number is not negative */ 368 if (*p & 0x80) { 369 return 1; 370 } 371 372 /* Convert to unsigned int. This code is for a little-endian CPU */ 373 *cert_nv_ctr = 0; 374 for (i = 0; i < len; i++) { 375 *cert_nv_ctr = (*cert_nv_ctr << 8) | *p++; 376 } 377 378 /* Get the counter from the platform */ 379 rc = plat_get_nv_ctr(param->plat_nv_ctr->cookie, &plat_nv_ctr); 380 if (rc != 0) { 381 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 382 __func__, __LINE__, rc); 383 return rc; 384 } 385 386 if (*cert_nv_ctr < plat_nv_ctr) { 387 /* Invalid NV-counter */ 388 return 1; 389 } else if (*cert_nv_ctr > plat_nv_ctr) { 390 #if PSA_FWU_SUPPORT && IMAGE_BL2 391 is_trial_run = fwu_is_trial_run_state(); 392 #endif /* PSA_FWU_SUPPORT && IMAGE_BL2 */ 393 *need_nv_ctr_upgrade = !is_trial_run; 394 } 395 396 return 0; 397 } 398 399 int plat_set_nv_ctr2(void *cookie, const auth_img_desc_t *img_desc __unused, 400 unsigned int nv_ctr) 401 { 402 return plat_set_nv_ctr(cookie, nv_ctr); 403 } 404 405 /* 406 * Return the parent id in the output parameter '*parent_id' 407 * 408 * Return value: 409 * 0 = Image has parent, 1 = Image has no parent or parent is authenticated 410 */ 411 int auth_mod_get_parent_id(unsigned int img_id, unsigned int *parent_id) 412 { 413 const auth_img_desc_t *img_desc = NULL; 414 415 assert(parent_id != NULL); 416 /* Get the image descriptor */ 417 img_desc = FCONF_GET_PROPERTY(tbbr, cot, img_id); 418 419 /* Check if the image has no parent (ROT) */ 420 if (img_desc->parent == NULL) { 421 *parent_id = 0; 422 return 1; 423 } 424 425 /* Check if the parent has already been authenticated */ 426 if (auth_img_flags[img_desc->parent->img_id] & IMG_FLAG_AUTHENTICATED) { 427 *parent_id = 0; 428 return 1; 429 } 430 431 *parent_id = img_desc->parent->img_id; 432 return 0; 433 } 434 435 /* 436 * Initialize the different modules in the authentication framework 437 */ 438 void auth_mod_init(void) 439 { 440 /* Check we have a valid CoT registered */ 441 assert(cot_desc_ptr != NULL); 442 443 /* Image parser module */ 444 img_parser_init(); 445 } 446 447 /* 448 * Authenticate a certificate/image 449 * 450 * Return: 0 = success, Otherwise = error 451 */ 452 int auth_mod_verify_img(unsigned int img_id, 453 void *img_ptr, 454 unsigned int img_len) 455 { 456 const auth_img_desc_t *img_desc = NULL; 457 const auth_param_type_desc_t *type_desc = NULL; 458 const auth_method_desc_t *auth_method = NULL; 459 void *param_ptr; 460 unsigned int param_len; 461 int rc, i; 462 unsigned int cert_nv_ctr = 0; 463 bool need_nv_ctr_upgrade = false; 464 bool sig_auth_done = false; 465 const auth_method_param_nv_ctr_t *nv_ctr_param = NULL; 466 467 /* Get the image descriptor from the chain of trust */ 468 img_desc = FCONF_GET_PROPERTY(tbbr, cot, img_id); 469 470 /* Ask the parser to check the image integrity */ 471 rc = img_parser_check_integrity(img_desc->img_type, img_ptr, img_len); 472 if (rc != 0) { 473 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 474 __func__, __LINE__, rc); 475 return rc; 476 } 477 478 /* Authenticate the image using the methods indicated in the image 479 * descriptor. */ 480 if (img_desc->img_auth_methods == NULL) 481 return 1; 482 for (i = 0 ; i < AUTH_METHOD_NUM ; i++) { 483 auth_method = &img_desc->img_auth_methods[i]; 484 switch (auth_method->type) { 485 case AUTH_METHOD_NONE: 486 rc = 0; 487 break; 488 case AUTH_METHOD_HASH: 489 rc = auth_hash(&auth_method->param.hash, 490 img_desc, img_ptr, img_len); 491 break; 492 case AUTH_METHOD_SIG: 493 rc = auth_signature(&auth_method->param.sig, 494 img_desc, img_ptr, img_len); 495 sig_auth_done = true; 496 break; 497 case AUTH_METHOD_NV_CTR: 498 nv_ctr_param = &auth_method->param.nv_ctr; 499 rc = auth_nvctr(nv_ctr_param, 500 img_desc, img_ptr, img_len, 501 &cert_nv_ctr, &need_nv_ctr_upgrade); 502 break; 503 default: 504 /* Unknown authentication method */ 505 rc = 1; 506 break; 507 } 508 if (rc != 0) { 509 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 510 __func__, __LINE__, rc); 511 return rc; 512 } 513 } 514 515 /* 516 * Do platform NV counter upgrade only if the certificate gets 517 * authenticated, and platform NV-counter upgrade is needed. 518 */ 519 if (need_nv_ctr_upgrade && sig_auth_done) { 520 rc = plat_set_nv_ctr2(nv_ctr_param->plat_nv_ctr->cookie, 521 img_desc, cert_nv_ctr); 522 if (rc != 0) { 523 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 524 __func__, __LINE__, rc); 525 return rc; 526 } 527 } 528 529 /* Extract the parameters indicated in the image descriptor to 530 * authenticate the children images. */ 531 if (img_desc->authenticated_data != NULL) { 532 for (i = 0 ; i < COT_MAX_VERIFIED_PARAMS ; i++) { 533 if (img_desc->authenticated_data[i].type_desc == NULL) { 534 continue; 535 } 536 537 /* Get the parameter from the image parser module */ 538 rc = img_parser_get_auth_param(img_desc->img_type, 539 img_desc->authenticated_data[i].type_desc, 540 img_ptr, img_len, ¶m_ptr, ¶m_len); 541 if (rc != 0) { 542 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 543 __func__, __LINE__, rc); 544 return rc; 545 } 546 547 /* Check parameter size */ 548 if (param_len > img_desc->authenticated_data[i].data.len) { 549 return 1; 550 } 551 552 /* Copy the parameter for later use */ 553 memcpy((void *)img_desc->authenticated_data[i].data.ptr, 554 (void *)param_ptr, param_len); 555 556 /* 557 * If this is a public key then measure and publicise 558 * it. 559 */ 560 type_desc = img_desc->authenticated_data[i].type_desc; 561 if (type_desc->type == AUTH_PARAM_PUB_KEY) { 562 rc = plat_mboot_measure_key(type_desc->cookie, 563 param_ptr, 564 param_len); 565 if (rc != 0) { 566 VERBOSE("[TBB] %s():%d failed with error code %d.\n", 567 __func__, __LINE__, rc); 568 } 569 } 570 } 571 } 572 573 /* Mark image as authenticated */ 574 auth_img_flags[img_desc->img_id] |= IMG_FLAG_AUTHENTICATED; 575 576 return 0; 577 } 578