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 generating and manipulating a verified boot kernel image. | 5 * Functions for generating and manipulating a verified boot kernel image. |
6 */ | 6 */ |
7 | 7 |
8 #include "kernel_image.h" | 8 #include "kernel_image.h" |
9 | 9 |
10 #include <fcntl.h> | 10 #include <fcntl.h> |
11 #include <stdio.h> | 11 #include <stdio.h> |
12 #include <sys/types.h> | 12 #include <sys/types.h> |
13 #include <sys/stat.h> | 13 #include <sys/stat.h> |
14 #include <unistd.h> | 14 #include <unistd.h> |
15 | 15 |
16 #include "file_keys.h" | 16 #include "file_keys.h" |
17 #include "padding.h" | 17 #include "padding.h" |
| 18 #include "rollback_index.h" |
18 #include "rsa_utility.h" | 19 #include "rsa_utility.h" |
19 #include "sha_utility.h" | 20 #include "sha_utility.h" |
20 #include "signature_digest.h" | 21 #include "signature_digest.h" |
21 #include "utility.h" | 22 #include "utility.h" |
22 | 23 |
23 /* Macro to determine the size of a field structure in the KernelImage | 24 /* Macro to determine the size of a field structure in the KernelImage |
24 * structure. */ | 25 * structure. */ |
25 #define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field)) | 26 #define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field)) |
26 | 27 |
27 KernelImage* KernelImageNew(void) { | 28 KernelImage* KernelImageNew(void) { |
(...skipping 675 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
703 kernel_signing_key_file, | 704 kernel_signing_key_file, |
704 image->kernel_sign_algorithm))) { | 705 image->kernel_sign_algorithm))) { |
705 fprintf(stderr, "Could not compute signature on the kernel.\n"); | 706 fprintf(stderr, "Could not compute signature on the kernel.\n"); |
706 return 0; | 707 return 0; |
707 } | 708 } |
708 image->kernel_signature = (uint8_t*) Malloc(signature_len); | 709 image->kernel_signature = (uint8_t*) Malloc(signature_len); |
709 Memcpy(image->kernel_signature, kernel_signature, signature_len); | 710 Memcpy(image->kernel_signature, kernel_signature, signature_len); |
710 Free(kernel_signature); | 711 Free(kernel_signature); |
711 return 1; | 712 return 1; |
712 } | 713 } |
| 714 |
| 715 uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob) { |
| 716 uint8_t* kernel_ptr; |
| 717 uint16_t kernel_key_version; |
| 718 uint16_t kernel_version; |
| 719 uint16_t firmware_sign_algorithm; |
| 720 uint16_t kernel_sign_algorithm; |
| 721 int kernel_key_signature_len; |
| 722 int kernel_sign_key_len; |
| 723 kernel_ptr = kernel_blob + (FIELD_LEN(magic) + |
| 724 FIELD_LEN(header_version) + |
| 725 FIELD_LEN(header_len)); |
| 726 Memcpy(&firmware_sign_algorithm, kernel_ptr, sizeof(firmware_sign_algorithm)); |
| 727 kernel_ptr += FIELD_LEN(firmware_sign_algorithm); |
| 728 Memcpy(&kernel_sign_algorithm, kernel_ptr, sizeof(kernel_sign_algorithm)); |
| 729 kernel_ptr += FIELD_LEN(kernel_sign_algorithm); |
| 730 Memcpy(&kernel_key_version, kernel_ptr, sizeof(kernel_key_version)); |
| 731 |
| 732 if (firmware_sign_algorithm >= kNumAlgorithms) |
| 733 return 0; |
| 734 if (kernel_sign_algorithm >= kNumAlgorithms) |
| 735 return 0; |
| 736 kernel_key_signature_len = siglen_map[firmware_sign_algorithm]; |
| 737 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm); |
| 738 kernel_ptr += (FIELD_LEN(kernel_key_version) + |
| 739 kernel_sign_key_len + |
| 740 FIELD_LEN(header_checksum) + |
| 741 kernel_key_signature_len); |
| 742 Memcpy(&kernel_version, kernel_ptr, sizeof(kernel_version)); |
| 743 return CombineUint16Pair(kernel_key_version, kernel_version); |
| 744 } |
| 745 |
| 746 void PrintKernelEntry(kernel_entry* entry) { |
| 747 fprintf(stderr, "Boot Priority = %d\n", entry->boot_priority); |
| 748 fprintf(stderr, "Boot Tries Remaining = %d\n", entry->boot_tries_remaining); |
| 749 fprintf(stderr, "Boot Success Flag = %d\n", entry->boot_success_flag); |
| 750 } |
| 751 |
| 752 int VerifyKernelDriver_f(uint8_t* firmware_key_blob, |
| 753 kernel_entry* kernelA, |
| 754 kernel_entry* kernelB, |
| 755 int dev_mode) { |
| 756 int i; |
| 757 /* Contains the logical kernel version (32-bit) which is calculated as |
| 758 * (kernel_key_version << 16 | kernel_version) where |
| 759 * [kernel_key_version], [firmware_version] are both 16-bit. |
| 760 */ |
| 761 uint32_t kernelA_lversion, kernelB_lversion; |
| 762 uint32_t min_lversion; /* Minimum of kernel A and kernel B lversion. */ |
| 763 uint32_t stored_lversion; /* Stored logical version in the TPM. */ |
| 764 kernel_entry* try_kernel[2]; /* Kernel in try order. */ |
| 765 int try_kernel_which[2]; /* Which corresponding kernel in the try order */ |
| 766 uint32_t try_kernel_lversion[2]; /* Their logical versions. */ |
| 767 |
| 768 /* [kernel_to_boot] will eventually contain the boot path to follow |
| 769 * and is returned to the caller. Initially, we set it to recovery. If |
| 770 * a valid bootable kernel is found, it will be set to that. */ |
| 771 int kernel_to_boot = BOOT_KERNEL_RECOVERY_CONTINUE; |
| 772 |
| 773 |
| 774 /* The TPM must already have be initialized, so no need to call SetupTPM(). */ |
| 775 |
| 776 /* We get the key versions by reading directly from the image blobs without |
| 777 * any additional (expensive) sanity checking on the blob since it's faster to |
| 778 * outright reject a kernel with an older kernel key version. A malformed |
| 779 * or corrupted kernel blob will still fail when VerifyKernel() is called |
| 780 * on it. |
| 781 */ |
| 782 kernelA_lversion = GetLogicalKernelVersion(kernelA->kernel_blob); |
| 783 kernelB_lversion = GetLogicalKernelVersion(kernelB->kernel_blob); |
| 784 min_lversion = Min(kernelA_lversion, kernelB_lversion); |
| 785 stored_lversion = CombineUint16Pair(GetStoredVersion(KERNEL_KEY_VERSION), |
| 786 GetStoredVersion(KERNEL_VERSION)); |
| 787 |
| 788 /* TODO(gauravsh): The kernel entries kernelA and kernelB come from the |
| 789 * partition table - verify its signature/checksum before proceeding |
| 790 * further. */ |
| 791 |
| 792 /* The logic for deciding which kernel to boot from is taken from the |
| 793 * the Chromium OS Drive Map design document. |
| 794 * |
| 795 * We went to consider the kernels in their according to their boot |
| 796 * priority attribute value. |
| 797 */ |
| 798 |
| 799 if (kernelA->boot_priority >= kernelB->boot_priority) { |
| 800 try_kernel[0] = kernelA; |
| 801 try_kernel_which[0] = BOOT_KERNEL_A_CONTINUE; |
| 802 try_kernel_lversion[0] = kernelA_lversion; |
| 803 try_kernel[1] = kernelB; |
| 804 try_kernel_which[1] = BOOT_KERNEL_B_CONTINUE; |
| 805 try_kernel_lversion[1] = kernelB_lversion; |
| 806 } else { |
| 807 try_kernel[0] = kernelB; |
| 808 try_kernel_which[0] = BOOT_KERNEL_B_CONTINUE; |
| 809 try_kernel_lversion[0] = kernelB_lversion; |
| 810 try_kernel[1] = kernelA; |
| 811 try_kernel_which[1] = BOOT_KERNEL_A_CONTINUE; |
| 812 try_kernel_lversion[1] = kernelA_lversion; |
| 813 } |
| 814 |
| 815 /* TODO(gauravsh): Changes to boot_tries_remaining and boot_priority |
| 816 * below should be propagated to partition table. This will be added |
| 817 * once the firmware parition table parsing code is in. */ |
| 818 for (i = 0; i < 2; i++) { |
| 819 if ((try_kernel[i]->boot_success_flag || |
| 820 try_kernel[i]->boot_tries_remaining) && |
| 821 (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob, |
| 822 try_kernel[i]->kernel_blob, |
| 823 dev_mode))) { |
| 824 if (try_kernel[i]->boot_tries_remaining > 0) |
| 825 try_kernel[i]->boot_tries_remaining--; |
| 826 if (stored_lversion > try_kernel_lversion[i]) |
| 827 continue; /* Rollback: I am afraid I can't let you do that Dave. */ |
| 828 if (i == 0 && (stored_lversion < try_kernel_lversion[1])) { |
| 829 /* The higher priority kernel is valid and bootable, See if we |
| 830 * need to update the stored version for rollback prevention. */ |
| 831 if (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob, |
| 832 try_kernel[1]->kernel_blob, |
| 833 dev_mode)) { |
| 834 WriteStoredVersion(KERNEL_KEY_VERSION, |
| 835 (uint16_t) (min_lversion >> 16)); |
| 836 WriteStoredVersion(KERNEL_VERSION, |
| 837 (uint16_t) (min_lversion & 0xFFFF)); |
| 838 stored_lversion = min_lversion; /* Update stored version as it's |
| 839 * used later. */ |
| 840 } |
| 841 } |
| 842 kernel_to_boot = try_kernel_which[i]; |
| 843 break; /* We found a valid kernel. */ |
| 844 } |
| 845 try_kernel[i]->boot_priority = 0; |
| 846 } /* for loop. */ |
| 847 |
| 848 /* Lock Kernel TPM rollback indices from further writes. |
| 849 * TODO(gauravsh): Figure out if these can be combined into one |
| 850 * 32-bit location since we seem to always use them together. This can help |
| 851 * us minimize the number of NVRAM writes/locks (which are limited over flash |
| 852 * memory lifetimes. |
| 853 */ |
| 854 LockStoredVersion(KERNEL_KEY_VERSION); |
| 855 LockStoredVersion(KERNEL_VERSION); |
| 856 return kernel_to_boot; |
| 857 } |
OLD | NEW |