| OLD | NEW |
| 1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 * Use of this source code is governed by a BSD-style license that can be | 2 * Use of this source code is governed by a BSD-style license that can be |
| 3 * found in the LICENSE file. | 3 * found in the LICENSE file. |
| 4 * | 4 * |
| 5 * Functions for verifying a verified boot kernel image. | 5 * Functions for verifying a verified boot kernel image. |
| 6 * (Firmware portion) | 6 * (Firmware portion) |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 #include "kernel_image_fw.h" | 9 #include "kernel_image_fw.h" |
| 10 | 10 |
| (...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 374 | 374 |
| 375 kernel_key_signature_len = siglen_map[firmware_sign_algorithm]; | 375 kernel_key_signature_len = siglen_map[firmware_sign_algorithm]; |
| 376 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm); | 376 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm); |
| 377 kernel_ptr += (FIELD_LEN(kernel_key_version) + | 377 kernel_ptr += (FIELD_LEN(kernel_key_version) + |
| 378 kernel_sign_key_len + | 378 kernel_sign_key_len + |
| 379 FIELD_LEN(header_checksum) + | 379 FIELD_LEN(header_checksum) + |
| 380 kernel_key_signature_len); | 380 kernel_key_signature_len); |
| 381 Memcpy(&kernel_version, kernel_ptr, sizeof(kernel_version)); | 381 Memcpy(&kernel_version, kernel_ptr, sizeof(kernel_version)); |
| 382 return CombineUint16Pair(kernel_key_version, kernel_version); | 382 return CombineUint16Pair(kernel_key_version, kernel_version); |
| 383 } | 383 } |
| 384 | |
| 385 int VerifyKernelDriver_f(uint8_t* firmware_key_blob, | |
| 386 kernel_entry* kernelA, | |
| 387 kernel_entry* kernelB, | |
| 388 int dev_mode) { | |
| 389 int i; | |
| 390 /* Contains the logical kernel version (32-bit) which is calculated as | |
| 391 * (kernel_key_version << 16 | kernel_version) where | |
| 392 * [kernel_key_version], [firmware_version] are both 16-bit. | |
| 393 */ | |
| 394 uint32_t kernelA_lversion, kernelB_lversion; | |
| 395 uint32_t min_lversion; /* Minimum of kernel A and kernel B lversion. */ | |
| 396 uint32_t stored_lversion; /* Stored logical version in the TPM. */ | |
| 397 kernel_entry* try_kernel[2]; /* Kernel in try order. */ | |
| 398 int try_kernel_which[2]; /* Which corresponding kernel in the try order */ | |
| 399 uint32_t try_kernel_lversion[2]; /* Their logical versions. */ | |
| 400 uint16_t kernel_version, kernel_key_version; /* Temporary variables */ | |
| 401 | |
| 402 /* [kernel_to_boot] will eventually contain the boot path to follow | |
| 403 * and is returned to the caller. Initially, we set it to recovery. If | |
| 404 * a valid bootable kernel is found, it will be set to that. */ | |
| 405 int kernel_to_boot = BOOT_KERNEL_RECOVERY_CONTINUE; | |
| 406 | |
| 407 | |
| 408 /* The TPM must already have be initialized, so no need to call SetupTPM(). */ | |
| 409 | |
| 410 /* We get the key versions by reading directly from the image blobs without | |
| 411 * any additional (expensive) sanity checking on the blob since it's faster to | |
| 412 * outright reject a kernel with an older kernel key version. A malformed | |
| 413 * or corrupted kernel blob will still fail when VerifyKernel() is called | |
| 414 * on it. | |
| 415 */ | |
| 416 kernelA_lversion = GetLogicalKernelVersion(kernelA->kernel_blob); | |
| 417 kernelB_lversion = GetLogicalKernelVersion(kernelB->kernel_blob); | |
| 418 min_lversion = Min(kernelA_lversion, kernelB_lversion); | |
| 419 GetStoredVersions(KERNEL_VERSIONS, &kernel_key_version, &kernel_version); | |
| 420 stored_lversion = CombineUint16Pair(kernel_key_version, kernel_version); | |
| 421 | |
| 422 /* TODO(gauravsh): The kernel entries kernelA and kernelB come from the | |
| 423 * partition table - verify its signature/checksum before proceeding | |
| 424 * further. */ | |
| 425 | |
| 426 /* The logic for deciding which kernel to boot from is taken from the | |
| 427 * the Chromium OS Drive Map design document. | |
| 428 * | |
| 429 * We went to consider the kernels in their according to their boot | |
| 430 * priority attribute value. | |
| 431 */ | |
| 432 | |
| 433 if (kernelA->boot_priority >= kernelB->boot_priority) { | |
| 434 try_kernel[0] = kernelA; | |
| 435 try_kernel_which[0] = BOOT_KERNEL_A_CONTINUE; | |
| 436 try_kernel_lversion[0] = kernelA_lversion; | |
| 437 try_kernel[1] = kernelB; | |
| 438 try_kernel_which[1] = BOOT_KERNEL_B_CONTINUE; | |
| 439 try_kernel_lversion[1] = kernelB_lversion; | |
| 440 } else { | |
| 441 try_kernel[0] = kernelB; | |
| 442 try_kernel_which[0] = BOOT_KERNEL_B_CONTINUE; | |
| 443 try_kernel_lversion[0] = kernelB_lversion; | |
| 444 try_kernel[1] = kernelA; | |
| 445 try_kernel_which[1] = BOOT_KERNEL_A_CONTINUE; | |
| 446 try_kernel_lversion[1] = kernelA_lversion; | |
| 447 } | |
| 448 | |
| 449 /* TODO(gauravsh): Changes to boot_tries_remaining and boot_priority | |
| 450 * below should be propagated to partition table. This will be added | |
| 451 * once the firmware parition table parsing code is in. */ | |
| 452 for (i = 0; i < 2; i++) { | |
| 453 if ((try_kernel[i]->boot_success_flag || | |
| 454 try_kernel[i]->boot_tries_remaining) && | |
| 455 (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob, | |
| 456 try_kernel[i]->kernel_blob, | |
| 457 dev_mode))) { | |
| 458 if (try_kernel[i]->boot_tries_remaining > 0) | |
| 459 try_kernel[i]->boot_tries_remaining--; | |
| 460 if (stored_lversion > try_kernel_lversion[i]) | |
| 461 continue; /* Rollback: I am afraid I can't let you do that Dave. */ | |
| 462 if (i == 0 && (stored_lversion < try_kernel_lversion[1])) { | |
| 463 /* The higher priority kernel is valid and bootable, See if we | |
| 464 * need to update the stored version for rollback prevention. */ | |
| 465 if (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob, | |
| 466 try_kernel[1]->kernel_blob, | |
| 467 dev_mode)) { | |
| 468 WriteStoredVersions(KERNEL_VERSIONS, | |
| 469 (uint16_t) (min_lversion >> 16), | |
| 470 (uint16_t) (min_lversion & 0xFFFF)); | |
| 471 stored_lversion = min_lversion; /* Update stored version as it's | |
| 472 * used later. */ | |
| 473 } | |
| 474 } | |
| 475 kernel_to_boot = try_kernel_which[i]; | |
| 476 break; /* We found a valid kernel. */ | |
| 477 } | |
| 478 try_kernel[i]->boot_priority = 0; | |
| 479 } /* for loop. */ | |
| 480 | |
| 481 /* Lock Kernel TPM rollback indices from further writes. In this design, | |
| 482 * this is tied to locking physical presence---so (software) physical | |
| 483 * presence cannot be asserted after this point. This is a big side effect, | |
| 484 * so we want to make it clear in the function name. | |
| 485 * TODO(gauravsh): figure out better abstractions. | |
| 486 */ | |
| 487 LockKernelVersionsByLockingPP(); | |
| 488 return kernel_to_boot; | |
| 489 } | |
| OLD | NEW |