OLD | NEW |
---|---|
(Empty) | |
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 | |
3 * found in the LICENSE file. | |
4 * | |
5 * High-level firmware API for loading and verifying rewritable firmware. | |
6 * (Firmware portion) | |
7 */ | |
8 | |
9 #include "vboot_firmware.h" | |
10 | |
11 #include "load_firmware_fw.h" | |
12 #include "rollback_index.h" | |
13 #include "utility.h" | |
14 #include "vboot_common.h" | |
15 | |
16 | |
17 void UpdateFirmwareBodyHash2(uint8_t* data, uint64_t size) { | |
18 /* TODO: actually update the hash. */ | |
19 } | |
20 | |
21 | |
22 int LoadFirmware2(LoadFirmwareParams* params) { | |
23 | |
24 VbPublicKey* root_key = (VbPublicKey*)params->firmware_root_key_blob; | |
25 | |
26 uint16_t tpm_key_version = 0; | |
27 uint16_t tpm_fw_version = 0; | |
28 uint64_t lowest_key_version = 0xFFFF; | |
29 uint64_t lowest_fw_version = 0xFFFF; | |
30 int good_index = -1; | |
31 int index; | |
32 | |
33 /* Clear output params in case we fail */ | |
34 params->firmware_index = 0; | |
35 params->kernel_sign_key_blob = NULL; | |
36 params->kernel_sign_key_size = 0; | |
37 | |
38 /* Must have a root key */ | |
39 if (!root_key) | |
40 return LOAD_FIRMWARE_RECOVERY; | |
41 | |
42 /* Initialize the TPM and read rollback indices. */ | |
43 if (0 != SetupTPM() ) | |
44 return LOAD_FIRMWARE_RECOVERY; | |
45 if (0 != GetStoredVersions(FIRMWARE_VERSIONS, | |
46 &tpm_key_version, &tpm_fw_version)) | |
47 return LOAD_FIRMWARE_RECOVERY; | |
48 | |
49 /* Loop over indices */ | |
50 for (index = 0; index < 2; index++) { | |
51 VbKeyBlockHeader* key_block; | |
52 uint64_t vblock_size; | |
53 VbFirmwarePreambleHeader* preamble; | |
54 RSAPublicKey* data_key; | |
55 uint64_t key_version; | |
56 uint8_t* body_data; | |
57 uint64_t body_size; | |
58 | |
59 /* Verify the key block */ | |
60 if (index) { | |
gauravsh
2010/06/10 14:44:13
nit/suggestion: since this is not a boolean check,
| |
61 key_block = (VbKeyBlockHeader*)params->verification_block_1; | |
62 vblock_size = params->verification_size_1; | |
63 } else { | |
64 key_block = (VbKeyBlockHeader*)params->verification_block_0; | |
65 vblock_size = params->verification_size_0; | |
66 } | |
67 if ((0 != VerifyKeyBlock(key_block, vblock_size, root_key))) | |
68 continue; | |
69 | |
70 /* Check for rollback of key version. */ | |
71 key_version = key_block->data_key.key_version; | |
72 if (key_version < tpm_key_version) | |
73 continue; | |
74 | |
75 /* Get the key for preamble/data verification from the key block. */ | |
76 data_key = PublicKeyToRSA(&key_block->data_key); | |
77 if (!data_key) | |
78 continue; | |
79 | |
80 /* Verify the preamble, which follows the key block. */ | |
81 preamble = (VbFirmwarePreambleHeader*)((uint8_t*)key_block + | |
82 key_block->key_block_size); | |
83 if ((0 != VerifyFirmwarePreamble2(preamble, | |
84 vblock_size - key_block->key_block_size, | |
85 data_key))) { | |
86 RSAPublicKeyFree(data_key); | |
87 continue; | |
88 } | |
89 | |
90 /* Check for rollback of firmware version. */ | |
91 if (key_version == tpm_key_version && | |
92 preamble->firmware_version < tpm_fw_version) { | |
93 RSAPublicKeyFree(data_key); | |
94 continue; | |
95 } | |
96 | |
97 /* Check for lowest key version from a valid header. */ | |
98 if (lowest_key_version > key_version) { | |
99 lowest_key_version = key_version; | |
100 lowest_fw_version = preamble->firmware_version; | |
101 } | |
102 else if (lowest_key_version == key_version && | |
103 lowest_fw_version > preamble->firmware_version) { | |
104 lowest_fw_version = preamble->firmware_version; | |
105 } | |
106 | |
107 /* If we already have good firmware, no need to read another one; | |
108 * we only needed to look at the versions to check for | |
109 * rollback. */ | |
110 if (-1 != good_index) | |
111 continue; | |
112 | |
113 /* Read the firmware data */ | |
114 /* TODO: should set up hash for UpdateFirmwareBodyHash(). */ | |
115 body_data = GetFirmwareBody(index, &body_size); | |
116 if (!body_data || (body_size != preamble->body_signature.data_size)) { | |
117 RSAPublicKeyFree(data_key); | |
118 continue; | |
119 } | |
120 | |
121 /* Verify firmware data */ | |
122 /* TODO: should use hash from UpdateFirmwareBodyHash() rather than | |
123 * recalculating it in VerifyData(). */ | |
124 if (0 != VerifyData(body_data, &preamble->body_signature, data_key)) { | |
125 RSAPublicKeyFree(data_key); | |
126 continue; | |
127 } | |
128 | |
129 /* Done with the data key, so can free it now */ | |
130 RSAPublicKeyFree(data_key); | |
131 | |
132 /* If we're still here, the firmware is valid. */ | |
133 /* Save the first good firmware we find; that's the one we'll boot */ | |
134 if (-1 == good_index) { | |
135 good_index = index; | |
136 params->firmware_index = index; | |
137 params->kernel_sign_key_blob = &preamble->kernel_subkey; | |
138 params->kernel_sign_key_size = (preamble->kernel_subkey.key_offset + | |
139 preamble->kernel_subkey.key_size); | |
140 | |
141 /* If the good firmware's key version is the same as the tpm, | |
142 * then the TPM doesn't need updating; we can stop now. | |
143 * Otherwise, we'll check all the other headers to see if they | |
144 * contain a newer key. */ | |
145 if (key_version == tpm_key_version && | |
146 preamble->firmware_version == tpm_fw_version) | |
147 break; | |
148 } | |
149 } | |
150 | |
151 /* Handle finding good firmware */ | |
152 if (good_index >= 0) { | |
153 | |
154 /* Update TPM if necessary */ | |
155 if ((lowest_key_version > tpm_key_version) || | |
156 (lowest_key_version == tpm_key_version && | |
157 lowest_fw_version > tpm_fw_version)) { | |
158 if (0 != WriteStoredVersions(FIRMWARE_VERSIONS, | |
159 lowest_key_version, | |
160 lowest_fw_version)) | |
161 return LOAD_FIRMWARE_RECOVERY; | |
162 } | |
163 | |
164 /* Lock Firmware TPM rollback indices from further writes. In | |
165 * this design, this is done by setting the globalLock bit, which | |
166 * is cleared only by TPM_Init at reboot. */ | |
167 if (0 != LockFirmwareVersions()) | |
168 return LOAD_FIRMWARE_RECOVERY; | |
169 } | |
170 | |
171 /* If we're still here, no good firmware, so go to recovery mode. */ | |
172 return LOAD_FIRMWARE_RECOVERY; | |
173 } | |
OLD | NEW |