blob: 32e12a85d6ea36d4e4501d863da1ecf5be591632 [file] [log] [blame]
Gaurav Shahf67bcaa2010-02-28 19:18:24 -08001/* 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 * Functions for generating and manipulating a verified boot kernel image.
6 */
7
8#include "kernel_image.h"
9
10#include <fcntl.h>
11#include <stdio.h>
12#include <sys/types.h>
13#include <sys/stat.h>
14#include <unistd.h>
15
16#include "file_keys.h"
17#include "padding.h"
Gaurav Shaha82bf262010-03-26 10:38:08 -070018#include "rollback_index.h"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080019#include "rsa_utility.h"
20#include "sha_utility.h"
Gaurav Shahf5564fa2010-03-02 15:40:01 -080021#include "signature_digest.h"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080022#include "utility.h"
23
24/* Macro to determine the size of a field structure in the KernelImage
25 * structure. */
26#define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field))
27
28KernelImage* KernelImageNew(void) {
29 KernelImage* image = (KernelImage*) Malloc(sizeof(KernelImage));
30 if (image) {
31 image->kernel_sign_key = NULL;
32 image->kernel_key_signature = NULL;
33 image->config_signature = NULL;
34 image->kernel_signature = NULL;
35 image->kernel_data = NULL;
36 }
37 return image;
38}
39
40void KernelImageFree(KernelImage* image) {
41 if (image) {
42 Free(image->kernel_sign_key);
43 Free(image->kernel_key_signature);
44 Free(image->config_signature);
45 Free(image->kernel_signature);
46 Free(image->kernel_data);
47 Free(image);
48 }
49}
50
51KernelImage* ReadKernelImage(const char* input_file) {
Gaurav Shah456678b2010-03-10 18:38:45 -080052 uint64_t file_size;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080053 int image_len = 0; /* Total size of the kernel image. */
54 int header_len = 0;
55 int firmware_sign_key_len;
56 int kernel_key_signature_len;
57 int kernel_sign_key_len;
58 int kernel_signature_len;
59 uint8_t* kernel_buf;
Gaurav Shah528a2c12010-03-18 13:10:10 -070060 uint8_t header_checksum[FIELD_LEN(header_checksum)];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080061 MemcpyState st;
62 KernelImage* image = KernelImageNew();
63
64 if (!image)
65 return NULL;
66
67 kernel_buf = BufferFromFile(input_file, &file_size);
68 image_len = file_size;
69
70 st.remaining_len = image_len;
71 st.remaining_buf = kernel_buf;
Gaurav Shahe450be42010-03-29 21:27:08 -070072 st.overrun = 0;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080073
74 /* Read and compare magic bytes. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080075 StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080076
77 if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) {
78 fprintf(stderr, "Wrong Kernel Magic.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -080079 Free(kernel_buf);
80 return NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080081 }
82 StatefulMemcpy(&st, &image->header_version, FIELD_LEN(header_version));
83 StatefulMemcpy(&st, &image->header_len, FIELD_LEN(header_len));
84 StatefulMemcpy(&st, &image->firmware_sign_algorithm,
85 FIELD_LEN(firmware_sign_algorithm));
86 StatefulMemcpy(&st, &image->kernel_sign_algorithm,
87 FIELD_LEN(kernel_sign_algorithm));
88
89 /* Valid Kernel Key signing algorithm. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080090 if (image->firmware_sign_algorithm >= kNumAlgorithms) {
91 Free(kernel_buf);
92 return NULL;
93 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080094
95 /* Valid Kernel Signing Algorithm? */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080096 if (image->kernel_sign_algorithm >= kNumAlgorithms) {
97 Free(kernel_buf);
98 return NULL;
99 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800100
101 /* Compute size of pre-processed RSA public keys and signatures. */
102 firmware_sign_key_len = RSAProcessedKeySize(image->firmware_sign_algorithm);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800103 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800104 kernel_sign_key_len = RSAProcessedKeySize(image->kernel_sign_algorithm);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800105 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800106
107 /* Check whether key header length is correct. */
Gaurav Shah528a2c12010-03-18 13:10:10 -0700108 header_len = GetKernelHeaderLen(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800109 if (header_len != image->header_len) {
110 fprintf(stderr, "Header length mismatch. Got: %d, Expected: %d\n",
111 image->header_len, header_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800112 Free(kernel_buf);
113 return NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800114 }
115
116 /* Read pre-processed public half of the kernel signing key. */
117 StatefulMemcpy(&st, &image->kernel_key_version,
118 FIELD_LEN(kernel_key_version));
119 image->kernel_sign_key = (uint8_t*) Malloc(kernel_sign_key_len);
120 StatefulMemcpy(&st, image->kernel_sign_key, kernel_sign_key_len);
121 StatefulMemcpy(&st, image->header_checksum, FIELD_LEN(header_checksum));
122
Gaurav Shah528a2c12010-03-18 13:10:10 -0700123 /* Check whether the header checksum matches. */
124 CalculateKernelHeaderChecksum(image, header_checksum);
125 if (SafeMemcmp(header_checksum, image->header_checksum,
126 FIELD_LEN(header_checksum))) {
127 fprintf(stderr, "Invalid kernel header checksum!\n");
128 Free(kernel_buf);
129 return NULL;
130 }
131
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800132 /* Read key signature. */
Gaurav Shah80d129b2010-03-03 17:58:43 -0800133 image->kernel_key_signature = (uint8_t*) Malloc(kernel_key_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800134 StatefulMemcpy(&st, image->kernel_key_signature,
Gaurav Shah80d129b2010-03-03 17:58:43 -0800135 kernel_key_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800136
137 /* Read the kernel config. */
138 StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version));
139 StatefulMemcpy(&st, &image->options.version, FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800140 StatefulMemcpy(&st, &image->options.cmd_line, FIELD_LEN(options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800141 StatefulMemcpy(&st, &image->options.kernel_len,
142 FIELD_LEN(options.kernel_len));
143 StatefulMemcpy(&st, &image->options.kernel_load_addr,
144 FIELD_LEN(options.kernel_load_addr));
145 StatefulMemcpy(&st, &image->options.kernel_entry_addr,
146 FIELD_LEN(options.kernel_entry_addr));
147
148 /* Read kernel config signature. */
149 image->config_signature = (uint8_t*) Malloc(kernel_signature_len);
150 StatefulMemcpy(&st, image->config_signature, kernel_signature_len);
151
152 image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len);
153 StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len);
154
155 image->kernel_data = (uint8_t*) Malloc(image->options.kernel_len);
156 StatefulMemcpy(&st, image->kernel_data, image->options.kernel_len);
157
Gaurav Shahe450be42010-03-29 21:27:08 -0700158 if(st.overrun || st.remaining_len != 0) { /* Overrun or underrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800159 Free(kernel_buf);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800160 return NULL;
161 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800162 Free(kernel_buf);
163 return image;
164}
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800165
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800166int GetKernelHeaderLen(const KernelImage* image) {
167 return (FIELD_LEN(header_version) + FIELD_LEN(header_len) +
168 FIELD_LEN(firmware_sign_algorithm) +
169 FIELD_LEN(kernel_sign_algorithm) + FIELD_LEN(kernel_key_version) +
170 RSAProcessedKeySize(image->kernel_sign_algorithm) +
171 FIELD_LEN(header_checksum));
172}
173
Gaurav Shah528a2c12010-03-18 13:10:10 -0700174void CalculateKernelHeaderChecksum(const KernelImage* image,
175 uint8_t* header_checksum) {
176 uint8_t* checksum;
177 DigestContext ctx;
178 DigestInit(&ctx, SHA512_DIGEST_ALGORITHM);
179 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
180 sizeof(image->header_version));
181 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
182 sizeof(image->header_len));
183 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
184 sizeof(image->firmware_sign_algorithm));
185 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
186 sizeof(image->kernel_sign_algorithm));
187 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
188 sizeof(image->kernel_key_version));
189 DigestUpdate(&ctx, image->kernel_sign_key,
190 RSAProcessedKeySize(image->kernel_sign_algorithm));
191 checksum = DigestFinal(&ctx);
192 Memcpy(header_checksum, checksum, FIELD_LEN(header_checksum));
193 Free(checksum);
194 return;
195}
196
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800197uint8_t* GetKernelHeaderBlob(const KernelImage* image) {
198 uint8_t* header_blob = NULL;
199 MemcpyState st;
200
201 header_blob = (uint8_t*) Malloc(GetKernelHeaderLen(image));
202 st.remaining_len = GetKernelHeaderLen(image);
203 st.remaining_buf = header_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700204 st.overrun = 0;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800205
206 StatefulMemcpy_r(&st, &image->header_version, FIELD_LEN(header_version));
207 StatefulMemcpy_r(&st, &image->header_len, FIELD_LEN(header_len));
208 StatefulMemcpy_r(&st, &image->firmware_sign_algorithm,
209 FIELD_LEN(firmware_sign_algorithm));
210 StatefulMemcpy_r(&st, &image->kernel_sign_algorithm,
211 FIELD_LEN(kernel_sign_algorithm));
212 StatefulMemcpy_r(&st, &image->kernel_key_version,
213 FIELD_LEN(kernel_key_version));
214 StatefulMemcpy_r(&st, image->kernel_sign_key,
215 RSAProcessedKeySize(image->kernel_sign_algorithm));
216 StatefulMemcpy_r(&st, &image->header_checksum, FIELD_LEN(header_checksum));
217
Gaurav Shahe450be42010-03-29 21:27:08 -0700218 if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800219 Free(header_blob);
220 return NULL;
221 }
222 return header_blob;
223}
224
Gaurav Shah463be3f2010-03-29 16:13:45 -0700225int GetKernelConfigLen() {
Gaurav Shah4f393862010-03-12 18:13:24 -0800226 return (FIELD_LEN(kernel_version) +
227 FIELD_LEN(options.version) + FIELD_LEN(options.cmd_line) +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800228 FIELD_LEN(options.kernel_len) + FIELD_LEN(options.kernel_load_addr) +
229 FIELD_LEN(options.kernel_entry_addr));
230}
231
232uint8_t* GetKernelConfigBlob(const KernelImage* image) {
233 uint8_t* config_blob = NULL;
234 MemcpyState st;
235
Gaurav Shah463be3f2010-03-29 16:13:45 -0700236 config_blob = (uint8_t*) Malloc(GetKernelConfigLen());
237 st.remaining_len = GetKernelConfigLen();
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800238 st.remaining_buf = config_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700239 st.overrun = 0;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800240
241 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
242 StatefulMemcpy_r(&st, image->options.version, FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800243 StatefulMemcpy_r(&st, image->options.cmd_line, FIELD_LEN(options.cmd_line));
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800244 StatefulMemcpy_r(&st, &image->options.kernel_len,
245 FIELD_LEN(options.kernel_len));
246 StatefulMemcpy_r(&st, &image->options.kernel_load_addr,
247 FIELD_LEN(options.kernel_load_addr));
248 StatefulMemcpy_r(&st, &image->options.kernel_entry_addr,
249 FIELD_LEN(options.kernel_entry_addr));
Gaurav Shahe450be42010-03-29 21:27:08 -0700250 if (st.overrun || st.remaining_len != 0) { /* Overrun or Underrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800251 Free(config_blob);
252 return NULL;
253 }
254 return config_blob;
255}
256
Gaurav Shah13937112010-03-22 17:59:09 -0700257uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800258 int kernel_key_signature_len;
259 int kernel_signature_len;
260 uint8_t* kernel_blob = NULL;
261 uint8_t* header_blob = NULL;
262 uint8_t* config_blob = NULL;
263 MemcpyState st;
264
265 if (!image)
266 return NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800267 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
268 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800269 *blob_len = (FIELD_LEN(magic) +
270 GetKernelHeaderLen(image) +
271 kernel_key_signature_len +
Gaurav Shah463be3f2010-03-29 16:13:45 -0700272 GetKernelConfigLen() +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800273 2 * kernel_signature_len +
274 image->options.kernel_len);
275 kernel_blob = (uint8_t*) Malloc(*blob_len);
276 st.remaining_len = *blob_len;
277 st.remaining_buf = kernel_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700278 st.overrun = 0;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800279
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800280 header_blob = GetKernelHeaderBlob(image);
281 config_blob = GetKernelConfigBlob(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800282
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800283 StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic));
284 StatefulMemcpy_r(&st, header_blob, GetKernelHeaderLen(image));
285 StatefulMemcpy_r(&st, image->kernel_key_signature, kernel_key_signature_len);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700286 StatefulMemcpy_r(&st, config_blob, GetKernelConfigLen());
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800287 StatefulMemcpy_r(&st, image->config_signature, kernel_signature_len);
288 StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len);
289 StatefulMemcpy_r(&st, image->kernel_data, image->options.kernel_len);
290
291 Free(config_blob);
292 Free(header_blob);
293
Gaurav Shahe450be42010-03-29 21:27:08 -0700294 if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800295 Free(kernel_blob);
296 return NULL;
297 }
298 return kernel_blob;
299}
300
301int WriteKernelImage(const char* input_file,
302 const KernelImage* image) {
303 int fd;
304 uint8_t* kernel_blob;
Gaurav Shah13937112010-03-22 17:59:09 -0700305 uint64_t blob_len;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800306
307 if (!image)
308 return 0;
309 if (-1 == (fd = creat(input_file, S_IRWXU))) {
310 fprintf(stderr, "Couldn't open file for writing kernel image: %s\n",
311 input_file);
312 return 0;
313 }
314 kernel_blob = GetKernelBlob(image, &blob_len);
315 if (!kernel_blob) {
316 fprintf(stderr, "Couldn't create kernel blob from KernelImage.\n");
317 return 0;
318 }
319 if (blob_len != write(fd, kernel_blob, blob_len)) {
320 fprintf(stderr, "Couldn't write Kernel Image to file: %s\n",
321 input_file);
322
323 Free(kernel_blob);
324 close(fd);
325 return 0;
326 }
327 Free(kernel_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800328 close(fd);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800329 return 1;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800330}
331
332void PrintKernelImage(const KernelImage* image) {
333 if (!image)
334 return;
335
336 /* Print header. */
Gaurav Shah528a2c12010-03-18 13:10:10 -0700337 printf("Header Version = %d\n"
338 "Header Length = %d\n"
339 "Kernel Key Signature Algorithm = %s\n"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800340 "Kernel Signature Algorithm = %s\n"
341 "Kernel Key Version = %d\n\n",
Gaurav Shah528a2c12010-03-18 13:10:10 -0700342 image->header_version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800343 image->header_len,
Gaurav Shah528a2c12010-03-18 13:10:10 -0700344 algo_strings[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800345 algo_strings[image->kernel_sign_algorithm],
346 image->kernel_key_version);
347 /* TODO(gauravsh): Output hash and key signature here? */
348 /* Print preamble. */
349 printf("Kernel Version = %d\n"
350 "Kernel Config Version = %d.%d\n"
Gaurav Shah528a2c12010-03-18 13:10:10 -0700351 "Kernel Config command line = \"%s\"\n"
Gaurav Shah456678b2010-03-10 18:38:45 -0800352 "kernel Length = %" PRId64 "\n"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800353 "Kernel Load Address = %" PRId64 "\n"
354 "Kernel Entry Address = %" PRId64 "\n\n",
355 image->kernel_version,
356 image->options.version[0], image->options.version[1],
Gaurav Shah4f393862010-03-12 18:13:24 -0800357 image->options.cmd_line,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800358 image->options.kernel_len,
359 image->options.kernel_load_addr,
360 image->options.kernel_entry_addr);
361 /* TODO(gauravsh): Output kernel signature here? */
362}
363
364char* kVerifyKernelErrors[VERIFY_KERNEL_MAX] = {
365 "Success.",
366 "Invalid Image.",
367 "Kernel Key Signature Failed.",
368 "Invalid Kernel Verification Algorithm.",
369 "Config Signature Failed.",
370 "Kernel Signature Failed.",
371 "Wrong Kernel Magic.",
372};
373
374int VerifyKernelHeader(const uint8_t* firmware_key_blob,
375 const uint8_t* header_blob,
376 const int dev_mode,
377 int* firmware_algorithm,
378 int* kernel_algorithm,
379 int* kernel_header_len) {
380 int kernel_sign_key_len;
381 int firmware_sign_key_len;
382 uint16_t header_version, header_len;
383 uint16_t firmware_sign_algorithm, kernel_sign_algorithm;
384 uint8_t* header_checksum = NULL;
385
386 /* Base Offset for the header_checksum field. Actual offset is
387 * this + kernel_sign_key_len. */
388 int base_header_checksum_offset = (FIELD_LEN(header_version) +
389 FIELD_LEN(header_len) +
390 FIELD_LEN(firmware_sign_algorithm) +
391 FIELD_LEN(kernel_sign_algorithm) +
392 FIELD_LEN(kernel_key_version));
393
394 Memcpy(&header_version, header_blob, sizeof(header_version));
395 Memcpy(&header_len, header_blob + FIELD_LEN(header_version),
396 sizeof(header_len));
397 Memcpy(&firmware_sign_algorithm,
398 header_blob + (FIELD_LEN(header_version) +
399 FIELD_LEN(header_len)),
400 sizeof(firmware_sign_algorithm));
401 Memcpy(&kernel_sign_algorithm,
402 header_blob + (FIELD_LEN(header_version) +
403 FIELD_LEN(header_len) +
404 FIELD_LEN(firmware_sign_algorithm)),
405 sizeof(kernel_sign_algorithm));
406
407 /* TODO(gauravsh): Make this return two different error types depending
408 * on whether the firmware or kernel signing algorithm is invalid. */
409 if (firmware_sign_algorithm >= kNumAlgorithms)
410 return VERIFY_KERNEL_INVALID_ALGORITHM;
411 if (kernel_sign_algorithm >= kNumAlgorithms)
412 return VERIFY_KERNEL_INVALID_ALGORITHM;
413
414 *firmware_algorithm = (int) firmware_sign_algorithm;
415 *kernel_algorithm = (int) kernel_sign_algorithm;
416 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
417 firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm);
418
419
420 /* Verify if header len is correct? */
421 if (header_len != (base_header_checksum_offset +
422 kernel_sign_key_len +
423 FIELD_LEN(header_checksum))) {
424 fprintf(stderr, "VerifyKernelHeader: Header length mismatch\n");
425 return VERIFY_KERNEL_INVALID_IMAGE;
426 }
427 *kernel_header_len = (int) header_len;
428
429 /* Verify if the hash of the header is correct. */
430 header_checksum = DigestBuf(header_blob,
431 header_len - FIELD_LEN(header_checksum),
432 SHA512_DIGEST_ALGORITHM);
433 if (SafeMemcmp(header_checksum,
434 header_blob + (base_header_checksum_offset +
435 kernel_sign_key_len),
436 FIELD_LEN(header_checksum))) {
437 Free(header_checksum);
Gaurav Shahccaa90f2010-03-17 20:40:23 -0700438 fprintf(stderr, "VerifyKernelHeader: Invalid header hash\n");
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800439 return VERIFY_KERNEL_INVALID_IMAGE;
440 }
441 Free(header_checksum);
442
443 /* Verify kernel key signature unless we are in dev mode. */
444 if (!dev_mode) {
445 if (!RSAVerifyBinary_f(firmware_key_blob, NULL, /* Key to use */
446 header_blob, /* Data to verify */
447 header_len, /* Length of data */
448 header_blob + header_len, /* Expected Signature */
449 firmware_sign_algorithm))
450 return VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
451 }
452 return 0;
453}
454
455int VerifyKernelConfig(RSAPublicKey* kernel_sign_key,
456 const uint8_t* config_blob,
457 int algorithm,
Gaurav Shahe450be42010-03-29 21:27:08 -0700458 uint64_t* kernel_len) {
459 uint64_t len;
460 int config_len;
461 config_len = GetKernelConfigLen(NULL);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800462 if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use */
463 config_blob, /* Data to verify */
464 config_len, /* Length of data */
465 config_blob + config_len, /* Expected Signature */
466 algorithm))
467 return VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
468
Gaurav Shah4f393862010-03-12 18:13:24 -0800469 Memcpy(&len,
470 config_blob + (FIELD_LEN(kernel_version) + FIELD_LEN(options.version) +
471 FIELD_LEN(options.cmd_line)),
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800472 sizeof(len));
Gaurav Shahe450be42010-03-29 21:27:08 -0700473 *kernel_len = len;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800474 return 0;
475}
476
477int VerifyKernelData(RSAPublicKey* kernel_sign_key,
Gaurav Shah463be3f2010-03-29 16:13:45 -0700478 const uint8_t* kernel_config_start,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800479 const uint8_t* kernel_data_start,
Gaurav Shahe450be42010-03-29 21:27:08 -0700480 uint64_t kernel_len,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800481 int algorithm) {
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800482 int signature_len = siglen_map[algorithm];
Gaurav Shah463be3f2010-03-29 16:13:45 -0700483 uint8_t* digest;
484 DigestContext ctx;
485
486 /* Since the kernel signature is computed over the kernel version, options
487 * and data, which does not form a contiguous region of memory, we calculate
488 * the message digest ourselves. */
489 DigestInit(&ctx, algorithm);
490 DigestUpdate(&ctx, kernel_config_start, GetKernelConfigLen());
491 DigestUpdate(&ctx, kernel_data_start + signature_len, kernel_len);
492 digest = DigestFinal(&ctx);
493 if (!RSAVerifyBinaryWithDigest_f(
494 NULL, kernel_sign_key, /* Key to use. */
495 digest, /* Digest of the data to verify. */
496 kernel_data_start, /* Expected Signature */
497 algorithm)) {
498 Free(digest);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800499 return VERIFY_KERNEL_SIGNATURE_FAILED;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700500 }
501 Free(digest);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800502 return 0;
503}
504
505int VerifyKernel(const uint8_t* firmware_key_blob,
506 const uint8_t* kernel_blob,
507 const int dev_mode) {
508 int error_code;
509 int firmware_sign_algorithm; /* Firmware signing key algorithm. */
510 int kernel_sign_algorithm; /* Kernel Signing key algorithm. */
511 RSAPublicKey* kernel_sign_key;
512 int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len,
Gaurav Shahe450be42010-03-29 21:27:08 -0700513 header_len;
514 uint64_t kernel_len;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800515 const uint8_t* header_ptr; /* Pointer to header. */
516 const uint8_t* kernel_sign_key_ptr; /* Pointer to signing key. */
517 const uint8_t* config_ptr; /* Pointer to kernel config block. */
518 const uint8_t* kernel_ptr; /* Pointer to kernel signature/data. */
519
520 /* Note: All the offset calculations are based on struct FirmwareImage which
521 * is defined in include/firmware_image.h. */
522
523 /* Compare magic bytes. */
524 if (SafeMemcmp(kernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE))
525 return VERIFY_KERNEL_WRONG_MAGIC;
526 header_ptr = kernel_blob + KERNEL_MAGIC_SIZE;
527
528 /* Only continue if header verification succeeds. */
529 if ((error_code = VerifyKernelHeader(firmware_key_blob, header_ptr, dev_mode,
530 &firmware_sign_algorithm,
531 &kernel_sign_algorithm, &header_len))) {
532 fprintf(stderr, "VerifyKernel: Kernel header verification failed.\n");
533 return error_code; /* AKA jump to recovery. */
534 }
535 /* Parse signing key into RSAPublicKey structure since it is required multiple
536 * times. */
537 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
538 kernel_sign_key_ptr = header_ptr + (FIELD_LEN(header_version) +
539 FIELD_LEN(header_len) +
540 FIELD_LEN(firmware_sign_algorithm) +
541 FIELD_LEN(kernel_sign_algorithm) +
542 FIELD_LEN(kernel_key_version));
543 kernel_sign_key = RSAPublicKeyFromBuf(kernel_sign_key_ptr,
544 kernel_sign_key_len);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800545 kernel_signature_len = siglen_map[kernel_sign_algorithm];
546 kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800547
548 /* Only continue if config verification succeeds. */
549 config_ptr = (header_ptr + header_len + kernel_key_signature_len);
550 if ((error_code = VerifyKernelConfig(kernel_sign_key, config_ptr,
551 kernel_sign_algorithm,
Gaurav Shah259de402010-03-12 17:42:03 -0800552 &kernel_len))) {
553 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800554 return error_code; /* AKA jump to recovery. */
Gaurav Shah259de402010-03-12 17:42:03 -0800555 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800556 /* Only continue if kernel data verification succeeds. */
557 kernel_ptr = (config_ptr +
Gaurav Shah463be3f2010-03-29 16:13:45 -0700558 GetKernelConfigLen() + /* Skip config block/signature. */
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800559 kernel_signature_len);
560
Gaurav Shah463be3f2010-03-29 16:13:45 -0700561 if ((error_code = VerifyKernelData(kernel_sign_key, config_ptr, kernel_ptr,
562 kernel_len,
Gaurav Shah259de402010-03-12 17:42:03 -0800563 kernel_sign_algorithm))) {
564 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800565 return error_code; /* AKA jump to recovery. */
Gaurav Shah259de402010-03-12 17:42:03 -0800566 }
567 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800568 return 0; /* Success! */
569}
570
571int VerifyKernelImage(const RSAPublicKey* firmware_key,
572 const KernelImage* image,
573 const int dev_mode) {
Gaurav Shah259de402010-03-12 17:42:03 -0800574 RSAPublicKey* kernel_sign_key = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800575 uint8_t* header_digest = NULL;
576 uint8_t* config_digest = NULL;
577 uint8_t* kernel_digest = NULL;
578 int kernel_sign_key_size;
579 int kernel_signature_size;
580 int error_code = 0;
581 DigestContext ctx;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700582 DigestContext kernel_ctx;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800583 if (!image)
584 return VERIFY_KERNEL_INVALID_IMAGE;
585
586 /* Verify kernel key signature on the key header if we
587 * are not in dev mode.
588 *
589 * TODO(gauravsh): Add additional sanity checks here for:
590 * 1) verifying the header length is correct.
591 * 2) header_checksum is correct.
592 */
593
594 if (image->firmware_sign_algorithm >= kNumAlgorithms)
595 return VERIFY_KERNEL_INVALID_ALGORITHM;
596 if (image->kernel_sign_algorithm >= kNumAlgorithms)
597 return VERIFY_KERNEL_INVALID_ALGORITHM;
598
599 if (!dev_mode) {
600 DigestInit(&ctx, image->firmware_sign_algorithm);
601 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
602 FIELD_LEN(header_version));
603 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
604 FIELD_LEN(header_len));
605 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
606 FIELD_LEN(firmware_sign_algorithm));
607 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
608 FIELD_LEN(kernel_sign_algorithm));
609 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
610 FIELD_LEN(kernel_key_version));
611 DigestUpdate(&ctx, image->kernel_sign_key,
612 RSAProcessedKeySize(image->kernel_sign_algorithm));
613 DigestUpdate(&ctx, image->header_checksum,
614 FIELD_LEN(header_checksum));
615 header_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800616 if (!RSAVerify(firmware_key, image->kernel_key_signature,
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800617 siglen_map[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800618 image->firmware_sign_algorithm,
619 header_digest)) {
620 fprintf(stderr, "VerifyKernelImage(): Key signature check failed.\n");
621 error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
622 goto verify_failure;
623 }
624 }
625
626 /* Get kernel signing key to verify the rest of the kernel. */
627 kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm);
628 kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
629 kernel_sign_key_size);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800630 kernel_signature_size = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800631
632 /* Verify kernel config signature. */
633 DigestInit(&ctx, image->kernel_sign_algorithm);
634 DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
635 FIELD_LEN(kernel_version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800636 DigestUpdate(&ctx, (uint8_t*) image->options.version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800637 FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800638 DigestUpdate(&ctx, (uint8_t*) image->options.cmd_line,
639 FIELD_LEN(options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800640 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_len,
641 FIELD_LEN(options.kernel_len));
642 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_load_addr,
643 FIELD_LEN(options.kernel_load_addr));
644 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_entry_addr,
645 FIELD_LEN(options.kernel_entry_addr));
646 config_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800647 if (!RSAVerify(kernel_sign_key, image->config_signature,
648 kernel_signature_size, image->kernel_sign_algorithm,
649 config_digest)) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800650 error_code = VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
651 goto verify_failure;
652 }
653
Gaurav Shah463be3f2010-03-29 16:13:45 -0700654 /* Verify kernel signature - kernel signature is computed on the contents
655 of kernel version + kernel options + kernel_data. */
656 DigestInit(&kernel_ctx, image->kernel_sign_algorithm);
657 DigestUpdate(&kernel_ctx, (uint8_t*) &image->kernel_version,
658 FIELD_LEN(kernel_version));
659 DigestUpdate(&kernel_ctx, (uint8_t*) image->options.version,
660 FIELD_LEN(options.version));
661 DigestUpdate(&kernel_ctx, (uint8_t*) image->options.cmd_line,
662 FIELD_LEN(options.cmd_line));
663 DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_len,
664 FIELD_LEN(options.kernel_len));
665 DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_load_addr,
666 FIELD_LEN(options.kernel_load_addr));
667 DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_entry_addr,
668 FIELD_LEN(options.kernel_entry_addr));
669 DigestUpdate(&kernel_ctx, image->kernel_data, image->options.kernel_len);
670 kernel_digest = DigestFinal(&kernel_ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800671 if (!RSAVerify(kernel_sign_key, image->kernel_signature,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800672 kernel_signature_size, image->kernel_sign_algorithm,
673 kernel_digest)) {
674 error_code = VERIFY_KERNEL_SIGNATURE_FAILED;
675 goto verify_failure;
676 }
677
678verify_failure:
Gaurav Shah259de402010-03-12 17:42:03 -0800679 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800680 Free(kernel_digest);
681 Free(config_digest);
682 Free(header_digest);
683 return error_code;
684}
685
686const char* VerifyKernelErrorString(int error) {
687 return kVerifyKernelErrors[error];
688}
689
690int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800691 uint8_t* header_blob = NULL;
Gaurav Shah259de402010-03-12 17:42:03 -0800692 uint8_t* signature = NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800693 int signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800694 if (!image || !firmware_key_file)
695 return 0;
696 header_blob = GetKernelHeaderBlob(image);
697 if (!header_blob)
698 return 0;
699 if (!(signature = SignatureBuf(header_blob,
700 GetKernelHeaderLen(image),
701 firmware_key_file,
702 image->firmware_sign_algorithm))) {
703 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800704 return 0;
705 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800706 image->kernel_key_signature = Malloc(signature_len);
707 Memcpy(image->kernel_key_signature, signature, signature_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800708 Free(signature);
709 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800710 return 1;
711}
712
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800713int AddKernelSignature(KernelImage* image,
714 const char* kernel_signing_key_file) {
Gaurav Shah259de402010-03-12 17:42:03 -0800715 uint8_t* config_blob = NULL;
716 uint8_t* config_signature = NULL;
717 uint8_t* kernel_signature = NULL;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700718 uint8_t* kernel_buf;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800719 int signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800720
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800721 config_blob = GetKernelConfigBlob(image);
722 if (!(config_signature = SignatureBuf(config_blob,
Gaurav Shah463be3f2010-03-29 16:13:45 -0700723 GetKernelConfigLen(),
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800724 kernel_signing_key_file,
725 image->kernel_sign_algorithm))) {
726 fprintf(stderr, "Could not compute signature on the kernel config.\n");
727 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800728 return 0;
729 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800730
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800731 image->config_signature = (uint8_t*) Malloc(signature_len);
732 Memcpy(image->config_signature, config_signature, signature_len);
733 Free(config_signature);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700734 /* Kernel signature muse be calculated on the kernel version, options and
735 * kernel data to avoid splicing attacks. */
736 kernel_buf = (uint8_t*) Malloc(GetKernelConfigLen() +
737 image->options.kernel_len);
738 Memcpy(kernel_buf, config_blob, GetKernelConfigLen());
739 Memcpy(kernel_buf + GetKernelConfigLen(), image->kernel_data,
740 image->options.kernel_len);
741 if (!(kernel_signature = SignatureBuf(kernel_buf,
742 GetKernelConfigLen() +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800743 image->options.kernel_len,
744 kernel_signing_key_file,
745 image->kernel_sign_algorithm))) {
Gaurav Shah463be3f2010-03-29 16:13:45 -0700746 Free(config_blob);
747 Free(kernel_buf);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800748 fprintf(stderr, "Could not compute signature on the kernel.\n");
749 return 0;
750 }
751 image->kernel_signature = (uint8_t*) Malloc(signature_len);
752 Memcpy(image->kernel_signature, kernel_signature, signature_len);
753 Free(kernel_signature);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700754 Free(kernel_buf);
755 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800756 return 1;
757}
Gaurav Shaha82bf262010-03-26 10:38:08 -0700758
759uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob) {
760 uint8_t* kernel_ptr;
761 uint16_t kernel_key_version;
762 uint16_t kernel_version;
763 uint16_t firmware_sign_algorithm;
764 uint16_t kernel_sign_algorithm;
765 int kernel_key_signature_len;
766 int kernel_sign_key_len;
767 kernel_ptr = kernel_blob + (FIELD_LEN(magic) +
768 FIELD_LEN(header_version) +
769 FIELD_LEN(header_len));
770 Memcpy(&firmware_sign_algorithm, kernel_ptr, sizeof(firmware_sign_algorithm));
771 kernel_ptr += FIELD_LEN(firmware_sign_algorithm);
772 Memcpy(&kernel_sign_algorithm, kernel_ptr, sizeof(kernel_sign_algorithm));
773 kernel_ptr += FIELD_LEN(kernel_sign_algorithm);
774 Memcpy(&kernel_key_version, kernel_ptr, sizeof(kernel_key_version));
775
776 if (firmware_sign_algorithm >= kNumAlgorithms)
777 return 0;
778 if (kernel_sign_algorithm >= kNumAlgorithms)
779 return 0;
780 kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
781 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
782 kernel_ptr += (FIELD_LEN(kernel_key_version) +
783 kernel_sign_key_len +
784 FIELD_LEN(header_checksum) +
785 kernel_key_signature_len);
786 Memcpy(&kernel_version, kernel_ptr, sizeof(kernel_version));
787 return CombineUint16Pair(kernel_key_version, kernel_version);
788}
789
790void PrintKernelEntry(kernel_entry* entry) {
791 fprintf(stderr, "Boot Priority = %d\n", entry->boot_priority);
792 fprintf(stderr, "Boot Tries Remaining = %d\n", entry->boot_tries_remaining);
793 fprintf(stderr, "Boot Success Flag = %d\n", entry->boot_success_flag);
794}
795
796int VerifyKernelDriver_f(uint8_t* firmware_key_blob,
797 kernel_entry* kernelA,
798 kernel_entry* kernelB,
799 int dev_mode) {
800 int i;
801 /* Contains the logical kernel version (32-bit) which is calculated as
802 * (kernel_key_version << 16 | kernel_version) where
803 * [kernel_key_version], [firmware_version] are both 16-bit.
804 */
805 uint32_t kernelA_lversion, kernelB_lversion;
806 uint32_t min_lversion; /* Minimum of kernel A and kernel B lversion. */
807 uint32_t stored_lversion; /* Stored logical version in the TPM. */
808 kernel_entry* try_kernel[2]; /* Kernel in try order. */
809 int try_kernel_which[2]; /* Which corresponding kernel in the try order */
810 uint32_t try_kernel_lversion[2]; /* Their logical versions. */
811
812 /* [kernel_to_boot] will eventually contain the boot path to follow
813 * and is returned to the caller. Initially, we set it to recovery. If
814 * a valid bootable kernel is found, it will be set to that. */
815 int kernel_to_boot = BOOT_KERNEL_RECOVERY_CONTINUE;
816
817
818 /* The TPM must already have be initialized, so no need to call SetupTPM(). */
819
820 /* We get the key versions by reading directly from the image blobs without
821 * any additional (expensive) sanity checking on the blob since it's faster to
822 * outright reject a kernel with an older kernel key version. A malformed
823 * or corrupted kernel blob will still fail when VerifyKernel() is called
824 * on it.
825 */
826 kernelA_lversion = GetLogicalKernelVersion(kernelA->kernel_blob);
827 kernelB_lversion = GetLogicalKernelVersion(kernelB->kernel_blob);
828 min_lversion = Min(kernelA_lversion, kernelB_lversion);
829 stored_lversion = CombineUint16Pair(GetStoredVersion(KERNEL_KEY_VERSION),
830 GetStoredVersion(KERNEL_VERSION));
831
832 /* TODO(gauravsh): The kernel entries kernelA and kernelB come from the
833 * partition table - verify its signature/checksum before proceeding
834 * further. */
835
836 /* The logic for deciding which kernel to boot from is taken from the
837 * the Chromium OS Drive Map design document.
838 *
839 * We went to consider the kernels in their according to their boot
840 * priority attribute value.
841 */
842
843 if (kernelA->boot_priority >= kernelB->boot_priority) {
844 try_kernel[0] = kernelA;
845 try_kernel_which[0] = BOOT_KERNEL_A_CONTINUE;
846 try_kernel_lversion[0] = kernelA_lversion;
847 try_kernel[1] = kernelB;
848 try_kernel_which[1] = BOOT_KERNEL_B_CONTINUE;
849 try_kernel_lversion[1] = kernelB_lversion;
850 } else {
851 try_kernel[0] = kernelB;
852 try_kernel_which[0] = BOOT_KERNEL_B_CONTINUE;
853 try_kernel_lversion[0] = kernelB_lversion;
854 try_kernel[1] = kernelA;
855 try_kernel_which[1] = BOOT_KERNEL_A_CONTINUE;
856 try_kernel_lversion[1] = kernelA_lversion;
857 }
858
859 /* TODO(gauravsh): Changes to boot_tries_remaining and boot_priority
860 * below should be propagated to partition table. This will be added
861 * once the firmware parition table parsing code is in. */
862 for (i = 0; i < 2; i++) {
863 if ((try_kernel[i]->boot_success_flag ||
864 try_kernel[i]->boot_tries_remaining) &&
865 (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob,
866 try_kernel[i]->kernel_blob,
867 dev_mode))) {
868 if (try_kernel[i]->boot_tries_remaining > 0)
869 try_kernel[i]->boot_tries_remaining--;
870 if (stored_lversion > try_kernel_lversion[i])
871 continue; /* Rollback: I am afraid I can't let you do that Dave. */
872 if (i == 0 && (stored_lversion < try_kernel_lversion[1])) {
873 /* The higher priority kernel is valid and bootable, See if we
874 * need to update the stored version for rollback prevention. */
875 if (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob,
876 try_kernel[1]->kernel_blob,
877 dev_mode)) {
878 WriteStoredVersion(KERNEL_KEY_VERSION,
879 (uint16_t) (min_lversion >> 16));
880 WriteStoredVersion(KERNEL_VERSION,
881 (uint16_t) (min_lversion & 0xFFFF));
882 stored_lversion = min_lversion; /* Update stored version as it's
883 * used later. */
884 }
885 }
886 kernel_to_boot = try_kernel_which[i];
887 break; /* We found a valid kernel. */
888 }
889 try_kernel[i]->boot_priority = 0;
890 } /* for loop. */
891
892 /* Lock Kernel TPM rollback indices from further writes.
893 * TODO(gauravsh): Figure out if these can be combined into one
894 * 32-bit location since we seem to always use them together. This can help
895 * us minimize the number of NVRAM writes/locks (which are limited over flash
896 * memory lifetimes.
897 */
898 LockStoredVersion(KERNEL_KEY_VERSION);
899 LockStoredVersion(KERNEL_VERSION);
900 return kernel_to_boot;
901}