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 |