Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(594)

Side by Side Diff: vboot_firmware/lib/vboot_common.c

Issue 2745007: Major refactoring of structures, with unit tests. (Closed) Base URL: ssh://gitrw.chromium.org/vboot_reference.git
Patch Set: Implemented LoadFirmware2() Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 * Common functions between firmware and kernel verified boot.
6 * (Firmware portion)
7 */
8
9 /* TODO: change all 'return 0', 'return 1' into meaningful return codes */
10
11 #include "vboot_common.h"
12 #include "utility.h"
13
14 #include <stdio.h> /* TODO: FOR TESTING */
15
16 char* kVbootErrors[VBOOT_ERROR_MAX] = {
17 "Success.",
18 "Invalid Image.",
19 "Kernel Key Signature Failed.",
20 "Invalid Kernel Verification Algorithm.",
21 "Preamble Signature Failed.",
22 "Kernel Signature Failed.",
23 "Wrong Kernel Magic.",
24 };
25
26
27 uint64_t OffsetOf(const void *base, const void *ptr) {
gauravsh 2010/06/10 14:44:13 since this function assumes 64-bit pointers, would
28 return (uint64_t)(size_t)ptr - (uint64_t)(size_t)base;
29 }
30
31
32 /* Helper functions to get data pointed to by a public key or signature. */
33 uint8_t* GetPublicKeyData(VbPublicKey* key) {
34 return (uint8_t*)key + key->key_offset;
35 }
36
37 const uint8_t* GetPublicKeyDataC(const VbPublicKey* key) {
38 return (const uint8_t*)key + key->key_offset;
39 }
40
41 uint8_t* GetSignatureData(VbSignature* sig) {
42 return (uint8_t*)sig + sig->sig_offset;
43 }
44
45 const uint8_t* GetSignatureDataC(const VbSignature* sig) {
46 return (const uint8_t*)sig + sig->sig_offset;
47 }
48
49
50 /* Helper functions to verify the data pointed to by a subfield is inside
51 * the parent data. Returns 0 if inside, 1 if error. */
52 int VerifyMemberInside(const void* parent, uint64_t parent_size,
53 const void* member, uint64_t member_size,
54 uint64_t member_data_offset,
55 uint64_t member_data_size) {
56 uint64_t end = OffsetOf(parent, member);
57
58 if (end > parent_size)
59 return 1;
60
61 if (end + member_size > parent_size)
62 return 1;
63
64 end += member_data_offset;
65 if (end > parent_size)
66 return 1;
67 if (end + member_data_size > parent_size)
68 return 1;
69
70 return 0;
71 }
72
73
74 int VerifyPublicKeyInside(const void* parent, uint64_t parent_size,
75 const VbPublicKey* key) {
76 return VerifyMemberInside(parent, parent_size,
77 key, sizeof(VbPublicKey),
78 key->key_offset, key->key_size);
79 }
80
81
82 int VerifySignatureInside(const void* parent, uint64_t parent_size,
83 const VbSignature* sig) {
84 return VerifyMemberInside(parent, parent_size,
85 sig, sizeof(VbSignature),
86 sig->sig_offset, sig->sig_size);
87 }
88
89
90 RSAPublicKey* PublicKeyToRSA(const VbPublicKey* key) {
91 RSAPublicKey *rsa;
92
93 if (kNumAlgorithms <= key->algorithm) {
94 debug("Invalid algorithm.\n");
95 return NULL;
96 }
97 if (RSAProcessedKeySize(key->algorithm) != key->key_size) {
98 debug("Wrong key size for algorithm\n");
99 return NULL;
100 }
101
102 rsa = RSAPublicKeyFromBuf(GetPublicKeyDataC(key), key->key_size);
103 if (!rsa)
104 return NULL;
105
106 rsa->algorithm = key->algorithm;
107 return rsa;
108 }
109
110
111 int VerifyData(const uint8_t* data, const VbSignature *sig,
112 const RSAPublicKey* key) {
113
114 if (sig->sig_size != siglen_map[key->algorithm]) {
115 debug("Wrong signature size for algorithm.\n");
116 return 1;
117 }
118
119 if (!RSAVerifyBinary_f(NULL, key, data, sig->data_size,
120 GetSignatureDataC(sig), key->algorithm))
121 return 1;
122
123 return 0;
124 }
125
126
127 int VerifyKeyBlock(const VbKeyBlockHeader* block, uint64_t size,
128 const VbPublicKey *key) {
129
130 const VbSignature* sig;
131
132 /* Sanity checks before attempting signature of data */
133 if (SafeMemcmp(block->magic, KEY_BLOCK_MAGIC, KEY_BLOCK_MAGIC_SIZE)) {
134 debug("Not a valid verified boot key block.\n");
135 return 1;
136 }
137 if (block->header_version_major != KEY_BLOCK_HEADER_VERSION_MAJOR) {
138 debug("Incompatible key block header version.\n");
139 return 1;
140 }
141 if (size < block->key_block_size) {
142 debug("Not enough data for key block.\n");
143 return 1;
144 }
145
146 /* Check signature or hash, depending on whether we have a key. */
147 if (key) {
148 /* Check signature */
149 RSAPublicKey* rsa;
150 int rv;
151
152 sig = &block->key_block_signature;
153
154 if (VerifySignatureInside(block, block->key_block_size, sig)) {
155 debug("Key block signature off end of block\n");
156 return 1;
157 }
158
159 if (!((rsa = PublicKeyToRSA(key)))) {
160 debug("Invalid public key\n");
161 return 1;
162 }
163 rv = VerifyData((const uint8_t*)block, sig, rsa);
164 RSAPublicKeyFree(rsa);
165
166 if (rv)
167 return rv;
168
169 } else {
170 /* Check hash */
171 uint8_t* header_checksum = NULL;
172 int rv;
173
174 sig = &block->key_block_checksum;
175
176 if (VerifySignatureInside(block, block->key_block_size, sig)) {
177 debug("Key block hash off end of block\n");
178 return 1;
179 }
180 if (sig->sig_size != SHA512_DIGEST_SIZE) {
181 debug("Wrong hash size for key block.\n");
182 return 1;
183 }
184
185 header_checksum = DigestBuf((const uint8_t*)block, sig->data_size,
186 SHA512_DIGEST_ALGORITHM);
187 rv = SafeMemcmp(header_checksum, GetSignatureDataC(sig),
188 SHA512_DIGEST_SIZE);
189 Free(header_checksum);
190 if (rv) {
191 debug("Invalid key block hash.\n");
192 return 1;
193 }
194 }
195
196 /* Verify we signed enough data */
197 if (sig->data_size < sizeof(VbKeyBlockHeader)) {
198 debug("Didn't sign enough data\n");
199 return 1;
200 }
201
202 /* Verify data key is inside the block and inside signed data */
203 if (VerifyPublicKeyInside(block, block->key_block_size, &block->data_key)) {
204 debug("Data key off end of key block\n");
205 return 1;
206 }
207 if (VerifyPublicKeyInside(block, sig->data_size, &block->data_key)) {
208 debug("Data key off end of signed data\n");
209 return 1;
210 }
211
212 /* Success */
213 return 0;
214 }
215
216
217 int VerifyFirmwarePreamble2(const VbFirmwarePreambleHeader* preamble,
218 uint64_t size, const RSAPublicKey* key) {
219
220 const VbSignature* sig = &preamble->preamble_signature;
221
222 /* TODO: caller needs to make sure key version is valid */
223
224 /* Sanity checks before attempting signature of data */
225 if (preamble->header_version_major !=
226 FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR) {
227 debug("Incompatible firmware preamble header version.\n");
228 return 1;
229 }
230 if (size < preamble->preamble_size) {
231 debug("Not enough data for preamble.\n");
232 return 1;
233 }
234
235 /* Check signature */
236 if (VerifySignatureInside(preamble, preamble->preamble_size, sig)) {
237 debug("Preamble signature off end of preamble\n");
238 return 1;
239 }
240 if (VerifyData((const uint8_t*)preamble, sig, key)) {
241 debug("Preamble signature validation failed\n");
242 return 1;
243 }
244
245 /* Verify we signed enough data */
246 if (sig->data_size < sizeof(VbFirmwarePreambleHeader)) {
247 debug("Didn't sign enough data\n");
248 return 1;
249 }
250
251 /* Verify body signature is inside the block */
252 if (VerifySignatureInside(preamble, preamble->preamble_size,
253 &preamble->body_signature)) {
254 debug("Firmware body signature off end of preamble\n");
255 return 1;
256 }
257
258 /* Verify kernel subkey is inside the block */
259 if (VerifyPublicKeyInside(preamble, preamble->preamble_size,
260 &preamble->kernel_subkey)) {
261 debug("Kernel subkey off end of preamble\n");
262 return 1;
263 }
264
265 /* Success */
266 return 0;
267 }
268
269
270 int VerifyKernelPreamble2(const VbKernelPreambleHeader* preamble,
271 uint64_t size, const RSAPublicKey* key) {
272
273 const VbSignature* sig = &preamble->preamble_signature;
274
275 /* TODO: caller needs to make sure key version is valid */
276
277 /* Sanity checks before attempting signature of data */
278 if (preamble->header_version_major != KERNEL_PREAMBLE_HEADER_VERSION_MAJOR) {
279 debug("Incompatible kernel preamble header version.\n");
280 return 1;
281 }
282 if (size < preamble->preamble_size) {
283 debug("Not enough data for preamble.\n");
284 return 1;
285 }
286
287 /* Check signature */
288 if (VerifySignatureInside(preamble, preamble->preamble_size, sig)) {
289 debug("Preamble signature off end of preamble\n");
290 return 1;
291 }
292 if (VerifyData((const uint8_t*)preamble, sig, key)) {
293 debug("Preamble signature validation failed\n");
294 return 1;
295 }
296
297 /* Verify we signed enough data */
298 if (sig->data_size < sizeof(VbKernelPreambleHeader)) {
299 debug("Didn't sign enough data\n");
300 return 1;
301 }
302
303 /* Verify body signature is inside the block */
304 if (VerifySignatureInside(preamble, preamble->preamble_size,
305 &preamble->body_signature)) {
306 debug("Kernel body signature off end of preamble\n");
307 return 1;
308 }
309
310 /* Success */
311 return 0;
312 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698