blob: f92a9f84e334a3fba8461bca5af8727a4474d3a8 [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;
72
73 /* Read and compare magic bytes. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080074 StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080075
76 if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) {
77 fprintf(stderr, "Wrong Kernel Magic.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -080078 Free(kernel_buf);
79 return NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080080 }
81 StatefulMemcpy(&st, &image->header_version, FIELD_LEN(header_version));
82 StatefulMemcpy(&st, &image->header_len, FIELD_LEN(header_len));
83 StatefulMemcpy(&st, &image->firmware_sign_algorithm,
84 FIELD_LEN(firmware_sign_algorithm));
85 StatefulMemcpy(&st, &image->kernel_sign_algorithm,
86 FIELD_LEN(kernel_sign_algorithm));
87
88 /* Valid Kernel Key signing algorithm. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080089 if (image->firmware_sign_algorithm >= kNumAlgorithms) {
90 Free(kernel_buf);
91 return NULL;
92 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080093
94 /* Valid Kernel Signing Algorithm? */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080095 if (image->kernel_sign_algorithm >= kNumAlgorithms) {
96 Free(kernel_buf);
97 return NULL;
98 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080099
100 /* Compute size of pre-processed RSA public keys and signatures. */
101 firmware_sign_key_len = RSAProcessedKeySize(image->firmware_sign_algorithm);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800102 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800103 kernel_sign_key_len = RSAProcessedKeySize(image->kernel_sign_algorithm);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800104 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800105
106 /* Check whether key header length is correct. */
Gaurav Shah528a2c12010-03-18 13:10:10 -0700107 header_len = GetKernelHeaderLen(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800108 if (header_len != image->header_len) {
109 fprintf(stderr, "Header length mismatch. Got: %d, Expected: %d\n",
110 image->header_len, header_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800111 Free(kernel_buf);
112 return NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800113 }
114
115 /* Read pre-processed public half of the kernel signing key. */
116 StatefulMemcpy(&st, &image->kernel_key_version,
117 FIELD_LEN(kernel_key_version));
118 image->kernel_sign_key = (uint8_t*) Malloc(kernel_sign_key_len);
119 StatefulMemcpy(&st, image->kernel_sign_key, kernel_sign_key_len);
120 StatefulMemcpy(&st, image->header_checksum, FIELD_LEN(header_checksum));
121
Gaurav Shah528a2c12010-03-18 13:10:10 -0700122 /* Check whether the header checksum matches. */
123 CalculateKernelHeaderChecksum(image, header_checksum);
124 if (SafeMemcmp(header_checksum, image->header_checksum,
125 FIELD_LEN(header_checksum))) {
126 fprintf(stderr, "Invalid kernel header checksum!\n");
127 Free(kernel_buf);
128 return NULL;
129 }
130
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800131 /* Read key signature. */
Gaurav Shah80d129b2010-03-03 17:58:43 -0800132 image->kernel_key_signature = (uint8_t*) Malloc(kernel_key_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800133 StatefulMemcpy(&st, image->kernel_key_signature,
Gaurav Shah80d129b2010-03-03 17:58:43 -0800134 kernel_key_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800135
136 /* Read the kernel config. */
137 StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version));
138 StatefulMemcpy(&st, &image->options.version, FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800139 StatefulMemcpy(&st, &image->options.cmd_line, FIELD_LEN(options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800140 StatefulMemcpy(&st, &image->options.kernel_len,
141 FIELD_LEN(options.kernel_len));
142 StatefulMemcpy(&st, &image->options.kernel_load_addr,
143 FIELD_LEN(options.kernel_load_addr));
144 StatefulMemcpy(&st, &image->options.kernel_entry_addr,
145 FIELD_LEN(options.kernel_entry_addr));
146
147 /* Read kernel config signature. */
148 image->config_signature = (uint8_t*) Malloc(kernel_signature_len);
149 StatefulMemcpy(&st, image->config_signature, kernel_signature_len);
150
151 image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len);
152 StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len);
153
154 image->kernel_data = (uint8_t*) Malloc(image->options.kernel_len);
155 StatefulMemcpy(&st, image->kernel_data, image->options.kernel_len);
156
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800157 if(st.remaining_len != 0) { /* Overrun or underrun. */
158 Free(kernel_buf);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800159 return NULL;
160 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800161 Free(kernel_buf);
162 return image;
163}
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800164
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800165int GetKernelHeaderLen(const KernelImage* image) {
166 return (FIELD_LEN(header_version) + FIELD_LEN(header_len) +
167 FIELD_LEN(firmware_sign_algorithm) +
168 FIELD_LEN(kernel_sign_algorithm) + FIELD_LEN(kernel_key_version) +
169 RSAProcessedKeySize(image->kernel_sign_algorithm) +
170 FIELD_LEN(header_checksum));
171}
172
Gaurav Shah528a2c12010-03-18 13:10:10 -0700173void CalculateKernelHeaderChecksum(const KernelImage* image,
174 uint8_t* header_checksum) {
175 uint8_t* checksum;
176 DigestContext ctx;
177 DigestInit(&ctx, SHA512_DIGEST_ALGORITHM);
178 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
179 sizeof(image->header_version));
180 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
181 sizeof(image->header_len));
182 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
183 sizeof(image->firmware_sign_algorithm));
184 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
185 sizeof(image->kernel_sign_algorithm));
186 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
187 sizeof(image->kernel_key_version));
188 DigestUpdate(&ctx, image->kernel_sign_key,
189 RSAProcessedKeySize(image->kernel_sign_algorithm));
190 checksum = DigestFinal(&ctx);
191 Memcpy(header_checksum, checksum, FIELD_LEN(header_checksum));
192 Free(checksum);
193 return;
194}
195
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800196uint8_t* GetKernelHeaderBlob(const KernelImage* image) {
197 uint8_t* header_blob = NULL;
198 MemcpyState st;
199
200 header_blob = (uint8_t*) Malloc(GetKernelHeaderLen(image));
201 st.remaining_len = GetKernelHeaderLen(image);
202 st.remaining_buf = header_blob;
203
204 StatefulMemcpy_r(&st, &image->header_version, FIELD_LEN(header_version));
205 StatefulMemcpy_r(&st, &image->header_len, FIELD_LEN(header_len));
206 StatefulMemcpy_r(&st, &image->firmware_sign_algorithm,
207 FIELD_LEN(firmware_sign_algorithm));
208 StatefulMemcpy_r(&st, &image->kernel_sign_algorithm,
209 FIELD_LEN(kernel_sign_algorithm));
210 StatefulMemcpy_r(&st, &image->kernel_key_version,
211 FIELD_LEN(kernel_key_version));
212 StatefulMemcpy_r(&st, image->kernel_sign_key,
213 RSAProcessedKeySize(image->kernel_sign_algorithm));
214 StatefulMemcpy_r(&st, &image->header_checksum, FIELD_LEN(header_checksum));
215
216 if (st.remaining_len != 0) { /* Underrun or Overrun. */
217 Free(header_blob);
218 return NULL;
219 }
220 return header_blob;
221}
222
Gaurav Shah463be3f2010-03-29 16:13:45 -0700223int GetKernelConfigLen() {
Gaurav Shah4f393862010-03-12 18:13:24 -0800224 return (FIELD_LEN(kernel_version) +
225 FIELD_LEN(options.version) + FIELD_LEN(options.cmd_line) +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800226 FIELD_LEN(options.kernel_len) + FIELD_LEN(options.kernel_load_addr) +
227 FIELD_LEN(options.kernel_entry_addr));
228}
229
230uint8_t* GetKernelConfigBlob(const KernelImage* image) {
231 uint8_t* config_blob = NULL;
232 MemcpyState st;
233
Gaurav Shah463be3f2010-03-29 16:13:45 -0700234 config_blob = (uint8_t*) Malloc(GetKernelConfigLen());
235 st.remaining_len = GetKernelConfigLen();
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800236 st.remaining_buf = config_blob;
237
238 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
239 StatefulMemcpy_r(&st, image->options.version, FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800240 StatefulMemcpy_r(&st, image->options.cmd_line, FIELD_LEN(options.cmd_line));
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800241 StatefulMemcpy_r(&st, &image->options.kernel_len,
242 FIELD_LEN(options.kernel_len));
243 StatefulMemcpy_r(&st, &image->options.kernel_load_addr,
244 FIELD_LEN(options.kernel_load_addr));
245 StatefulMemcpy_r(&st, &image->options.kernel_entry_addr,
246 FIELD_LEN(options.kernel_entry_addr));
247 if (st.remaining_len != 0) { /* Overrun or Underrun. */
248 Free(config_blob);
249 return NULL;
250 }
251 return config_blob;
252}
253
Gaurav Shah13937112010-03-22 17:59:09 -0700254uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800255 int kernel_key_signature_len;
256 int kernel_signature_len;
257 uint8_t* kernel_blob = NULL;
258 uint8_t* header_blob = NULL;
259 uint8_t* config_blob = NULL;
260 MemcpyState st;
261
262 if (!image)
263 return NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800264 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
265 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800266 *blob_len = (FIELD_LEN(magic) +
267 GetKernelHeaderLen(image) +
268 kernel_key_signature_len +
Gaurav Shah463be3f2010-03-29 16:13:45 -0700269 GetKernelConfigLen() +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800270 2 * kernel_signature_len +
271 image->options.kernel_len);
272 kernel_blob = (uint8_t*) Malloc(*blob_len);
273 st.remaining_len = *blob_len;
274 st.remaining_buf = kernel_blob;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800275
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800276 header_blob = GetKernelHeaderBlob(image);
277 config_blob = GetKernelConfigBlob(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800278
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800279 StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic));
280 StatefulMemcpy_r(&st, header_blob, GetKernelHeaderLen(image));
281 StatefulMemcpy_r(&st, image->kernel_key_signature, kernel_key_signature_len);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700282 StatefulMemcpy_r(&st, config_blob, GetKernelConfigLen());
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800283 StatefulMemcpy_r(&st, image->config_signature, kernel_signature_len);
284 StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len);
285 StatefulMemcpy_r(&st, image->kernel_data, image->options.kernel_len);
286
287 Free(config_blob);
288 Free(header_blob);
289
290 if (st.remaining_len != 0) { /* Underrun or Overrun. */
291 Free(kernel_blob);
292 return NULL;
293 }
294 return kernel_blob;
295}
296
297int WriteKernelImage(const char* input_file,
298 const KernelImage* image) {
299 int fd;
300 uint8_t* kernel_blob;
Gaurav Shah13937112010-03-22 17:59:09 -0700301 uint64_t blob_len;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800302
303 if (!image)
304 return 0;
305 if (-1 == (fd = creat(input_file, S_IRWXU))) {
306 fprintf(stderr, "Couldn't open file for writing kernel image: %s\n",
307 input_file);
308 return 0;
309 }
310 kernel_blob = GetKernelBlob(image, &blob_len);
311 if (!kernel_blob) {
312 fprintf(stderr, "Couldn't create kernel blob from KernelImage.\n");
313 return 0;
314 }
315 if (blob_len != write(fd, kernel_blob, blob_len)) {
316 fprintf(stderr, "Couldn't write Kernel Image to file: %s\n",
317 input_file);
318
319 Free(kernel_blob);
320 close(fd);
321 return 0;
322 }
323 Free(kernel_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800324 close(fd);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800325 return 1;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800326}
327
328void PrintKernelImage(const KernelImage* image) {
329 if (!image)
330 return;
331
332 /* Print header. */
Gaurav Shah528a2c12010-03-18 13:10:10 -0700333 printf("Header Version = %d\n"
334 "Header Length = %d\n"
335 "Kernel Key Signature Algorithm = %s\n"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800336 "Kernel Signature Algorithm = %s\n"
337 "Kernel Key Version = %d\n\n",
Gaurav Shah528a2c12010-03-18 13:10:10 -0700338 image->header_version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800339 image->header_len,
Gaurav Shah528a2c12010-03-18 13:10:10 -0700340 algo_strings[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800341 algo_strings[image->kernel_sign_algorithm],
342 image->kernel_key_version);
343 /* TODO(gauravsh): Output hash and key signature here? */
344 /* Print preamble. */
345 printf("Kernel Version = %d\n"
346 "Kernel Config Version = %d.%d\n"
Gaurav Shah528a2c12010-03-18 13:10:10 -0700347 "Kernel Config command line = \"%s\"\n"
Gaurav Shah456678b2010-03-10 18:38:45 -0800348 "kernel Length = %" PRId64 "\n"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800349 "Kernel Load Address = %" PRId64 "\n"
350 "Kernel Entry Address = %" PRId64 "\n\n",
351 image->kernel_version,
352 image->options.version[0], image->options.version[1],
Gaurav Shah4f393862010-03-12 18:13:24 -0800353 image->options.cmd_line,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800354 image->options.kernel_len,
355 image->options.kernel_load_addr,
356 image->options.kernel_entry_addr);
357 /* TODO(gauravsh): Output kernel signature here? */
358}
359
360char* kVerifyKernelErrors[VERIFY_KERNEL_MAX] = {
361 "Success.",
362 "Invalid Image.",
363 "Kernel Key Signature Failed.",
364 "Invalid Kernel Verification Algorithm.",
365 "Config Signature Failed.",
366 "Kernel Signature Failed.",
367 "Wrong Kernel Magic.",
368};
369
370int VerifyKernelHeader(const uint8_t* firmware_key_blob,
371 const uint8_t* header_blob,
372 const int dev_mode,
373 int* firmware_algorithm,
374 int* kernel_algorithm,
375 int* kernel_header_len) {
376 int kernel_sign_key_len;
377 int firmware_sign_key_len;
378 uint16_t header_version, header_len;
379 uint16_t firmware_sign_algorithm, kernel_sign_algorithm;
380 uint8_t* header_checksum = NULL;
381
382 /* Base Offset for the header_checksum field. Actual offset is
383 * this + kernel_sign_key_len. */
384 int base_header_checksum_offset = (FIELD_LEN(header_version) +
385 FIELD_LEN(header_len) +
386 FIELD_LEN(firmware_sign_algorithm) +
387 FIELD_LEN(kernel_sign_algorithm) +
388 FIELD_LEN(kernel_key_version));
389
390 Memcpy(&header_version, header_blob, sizeof(header_version));
391 Memcpy(&header_len, header_blob + FIELD_LEN(header_version),
392 sizeof(header_len));
393 Memcpy(&firmware_sign_algorithm,
394 header_blob + (FIELD_LEN(header_version) +
395 FIELD_LEN(header_len)),
396 sizeof(firmware_sign_algorithm));
397 Memcpy(&kernel_sign_algorithm,
398 header_blob + (FIELD_LEN(header_version) +
399 FIELD_LEN(header_len) +
400 FIELD_LEN(firmware_sign_algorithm)),
401 sizeof(kernel_sign_algorithm));
402
403 /* TODO(gauravsh): Make this return two different error types depending
404 * on whether the firmware or kernel signing algorithm is invalid. */
405 if (firmware_sign_algorithm >= kNumAlgorithms)
406 return VERIFY_KERNEL_INVALID_ALGORITHM;
407 if (kernel_sign_algorithm >= kNumAlgorithms)
408 return VERIFY_KERNEL_INVALID_ALGORITHM;
409
410 *firmware_algorithm = (int) firmware_sign_algorithm;
411 *kernel_algorithm = (int) kernel_sign_algorithm;
412 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
413 firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm);
414
415
416 /* Verify if header len is correct? */
417 if (header_len != (base_header_checksum_offset +
418 kernel_sign_key_len +
419 FIELD_LEN(header_checksum))) {
420 fprintf(stderr, "VerifyKernelHeader: Header length mismatch\n");
421 return VERIFY_KERNEL_INVALID_IMAGE;
422 }
423 *kernel_header_len = (int) header_len;
424
425 /* Verify if the hash of the header is correct. */
426 header_checksum = DigestBuf(header_blob,
427 header_len - FIELD_LEN(header_checksum),
428 SHA512_DIGEST_ALGORITHM);
429 if (SafeMemcmp(header_checksum,
430 header_blob + (base_header_checksum_offset +
431 kernel_sign_key_len),
432 FIELD_LEN(header_checksum))) {
433 Free(header_checksum);
Gaurav Shahccaa90f2010-03-17 20:40:23 -0700434 fprintf(stderr, "VerifyKernelHeader: Invalid header hash\n");
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800435 return VERIFY_KERNEL_INVALID_IMAGE;
436 }
437 Free(header_checksum);
438
439 /* Verify kernel key signature unless we are in dev mode. */
440 if (!dev_mode) {
441 if (!RSAVerifyBinary_f(firmware_key_blob, NULL, /* Key to use */
442 header_blob, /* Data to verify */
443 header_len, /* Length of data */
444 header_blob + header_len, /* Expected Signature */
445 firmware_sign_algorithm))
446 return VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
447 }
448 return 0;
449}
450
451int VerifyKernelConfig(RSAPublicKey* kernel_sign_key,
452 const uint8_t* config_blob,
453 int algorithm,
454 int* kernel_len) {
455 uint32_t len, config_len;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700456 config_len = GetKernelConfigLen();
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800457 if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use */
458 config_blob, /* Data to verify */
459 config_len, /* Length of data */
460 config_blob + config_len, /* Expected Signature */
461 algorithm))
462 return VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
463
Gaurav Shah4f393862010-03-12 18:13:24 -0800464 Memcpy(&len,
465 config_blob + (FIELD_LEN(kernel_version) + FIELD_LEN(options.version) +
466 FIELD_LEN(options.cmd_line)),
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800467 sizeof(len));
468 *kernel_len = (int) len;
469 return 0;
470}
471
472int VerifyKernelData(RSAPublicKey* kernel_sign_key,
Gaurav Shah463be3f2010-03-29 16:13:45 -0700473 const uint8_t* kernel_config_start,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800474 const uint8_t* kernel_data_start,
475 int kernel_len,
476 int algorithm) {
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800477 int signature_len = siglen_map[algorithm];
Gaurav Shah463be3f2010-03-29 16:13:45 -0700478 uint8_t* digest;
479 DigestContext ctx;
480
481 /* Since the kernel signature is computed over the kernel version, options
482 * and data, which does not form a contiguous region of memory, we calculate
483 * the message digest ourselves. */
484 DigestInit(&ctx, algorithm);
485 DigestUpdate(&ctx, kernel_config_start, GetKernelConfigLen());
486 DigestUpdate(&ctx, kernel_data_start + signature_len, kernel_len);
487 digest = DigestFinal(&ctx);
488 if (!RSAVerifyBinaryWithDigest_f(
489 NULL, kernel_sign_key, /* Key to use. */
490 digest, /* Digest of the data to verify. */
491 kernel_data_start, /* Expected Signature */
492 algorithm)) {
493 Free(digest);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800494 return VERIFY_KERNEL_SIGNATURE_FAILED;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700495 }
496 Free(digest);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800497 return 0;
498}
499
500int VerifyKernel(const uint8_t* firmware_key_blob,
501 const uint8_t* kernel_blob,
502 const int dev_mode) {
503 int error_code;
504 int firmware_sign_algorithm; /* Firmware signing key algorithm. */
505 int kernel_sign_algorithm; /* Kernel Signing key algorithm. */
506 RSAPublicKey* kernel_sign_key;
507 int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len,
508 header_len, kernel_len;
509 const uint8_t* header_ptr; /* Pointer to header. */
510 const uint8_t* kernel_sign_key_ptr; /* Pointer to signing key. */
511 const uint8_t* config_ptr; /* Pointer to kernel config block. */
512 const uint8_t* kernel_ptr; /* Pointer to kernel signature/data. */
513
514 /* Note: All the offset calculations are based on struct FirmwareImage which
515 * is defined in include/firmware_image.h. */
516
517 /* Compare magic bytes. */
518 if (SafeMemcmp(kernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE))
519 return VERIFY_KERNEL_WRONG_MAGIC;
520 header_ptr = kernel_blob + KERNEL_MAGIC_SIZE;
521
522 /* Only continue if header verification succeeds. */
523 if ((error_code = VerifyKernelHeader(firmware_key_blob, header_ptr, dev_mode,
524 &firmware_sign_algorithm,
525 &kernel_sign_algorithm, &header_len))) {
526 fprintf(stderr, "VerifyKernel: Kernel header verification failed.\n");
527 return error_code; /* AKA jump to recovery. */
528 }
529 /* Parse signing key into RSAPublicKey structure since it is required multiple
530 * times. */
531 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
532 kernel_sign_key_ptr = header_ptr + (FIELD_LEN(header_version) +
533 FIELD_LEN(header_len) +
534 FIELD_LEN(firmware_sign_algorithm) +
535 FIELD_LEN(kernel_sign_algorithm) +
536 FIELD_LEN(kernel_key_version));
537 kernel_sign_key = RSAPublicKeyFromBuf(kernel_sign_key_ptr,
538 kernel_sign_key_len);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800539 kernel_signature_len = siglen_map[kernel_sign_algorithm];
540 kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800541
542 /* Only continue if config verification succeeds. */
543 config_ptr = (header_ptr + header_len + kernel_key_signature_len);
544 if ((error_code = VerifyKernelConfig(kernel_sign_key, config_ptr,
545 kernel_sign_algorithm,
Gaurav Shah259de402010-03-12 17:42:03 -0800546 &kernel_len))) {
547 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800548 return error_code; /* AKA jump to recovery. */
Gaurav Shah259de402010-03-12 17:42:03 -0800549 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800550 /* Only continue if kernel data verification succeeds. */
551 kernel_ptr = (config_ptr +
Gaurav Shah463be3f2010-03-29 16:13:45 -0700552 GetKernelConfigLen() + /* Skip config block/signature. */
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800553 kernel_signature_len);
554
Gaurav Shah463be3f2010-03-29 16:13:45 -0700555 if ((error_code = VerifyKernelData(kernel_sign_key, config_ptr, kernel_ptr,
556 kernel_len,
Gaurav Shah259de402010-03-12 17:42:03 -0800557 kernel_sign_algorithm))) {
558 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800559 return error_code; /* AKA jump to recovery. */
Gaurav Shah259de402010-03-12 17:42:03 -0800560 }
561 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800562 return 0; /* Success! */
563}
564
565int VerifyKernelImage(const RSAPublicKey* firmware_key,
566 const KernelImage* image,
567 const int dev_mode) {
Gaurav Shah259de402010-03-12 17:42:03 -0800568 RSAPublicKey* kernel_sign_key = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800569 uint8_t* header_digest = NULL;
570 uint8_t* config_digest = NULL;
571 uint8_t* kernel_digest = NULL;
572 int kernel_sign_key_size;
573 int kernel_signature_size;
574 int error_code = 0;
575 DigestContext ctx;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700576 DigestContext kernel_ctx;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800577 if (!image)
578 return VERIFY_KERNEL_INVALID_IMAGE;
579
580 /* Verify kernel key signature on the key header if we
581 * are not in dev mode.
582 *
583 * TODO(gauravsh): Add additional sanity checks here for:
584 * 1) verifying the header length is correct.
585 * 2) header_checksum is correct.
586 */
587
588 if (image->firmware_sign_algorithm >= kNumAlgorithms)
589 return VERIFY_KERNEL_INVALID_ALGORITHM;
590 if (image->kernel_sign_algorithm >= kNumAlgorithms)
591 return VERIFY_KERNEL_INVALID_ALGORITHM;
592
593 if (!dev_mode) {
594 DigestInit(&ctx, image->firmware_sign_algorithm);
595 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
596 FIELD_LEN(header_version));
597 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
598 FIELD_LEN(header_len));
599 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
600 FIELD_LEN(firmware_sign_algorithm));
601 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
602 FIELD_LEN(kernel_sign_algorithm));
603 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
604 FIELD_LEN(kernel_key_version));
605 DigestUpdate(&ctx, image->kernel_sign_key,
606 RSAProcessedKeySize(image->kernel_sign_algorithm));
607 DigestUpdate(&ctx, image->header_checksum,
608 FIELD_LEN(header_checksum));
609 header_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800610 if (!RSAVerify(firmware_key, image->kernel_key_signature,
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800611 siglen_map[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800612 image->firmware_sign_algorithm,
613 header_digest)) {
614 fprintf(stderr, "VerifyKernelImage(): Key signature check failed.\n");
615 error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
616 goto verify_failure;
617 }
618 }
619
620 /* Get kernel signing key to verify the rest of the kernel. */
621 kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm);
622 kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
623 kernel_sign_key_size);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800624 kernel_signature_size = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800625
626 /* Verify kernel config signature. */
627 DigestInit(&ctx, image->kernel_sign_algorithm);
628 DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
629 FIELD_LEN(kernel_version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800630 DigestUpdate(&ctx, (uint8_t*) image->options.version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800631 FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800632 DigestUpdate(&ctx, (uint8_t*) image->options.cmd_line,
633 FIELD_LEN(options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800634 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_len,
635 FIELD_LEN(options.kernel_len));
636 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_load_addr,
637 FIELD_LEN(options.kernel_load_addr));
638 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_entry_addr,
639 FIELD_LEN(options.kernel_entry_addr));
640 config_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800641 if (!RSAVerify(kernel_sign_key, image->config_signature,
642 kernel_signature_size, image->kernel_sign_algorithm,
643 config_digest)) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800644 error_code = VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
645 goto verify_failure;
646 }
647
Gaurav Shah463be3f2010-03-29 16:13:45 -0700648 /* Verify kernel signature - kernel signature is computed on the contents
649 of kernel version + kernel options + kernel_data. */
650 DigestInit(&kernel_ctx, image->kernel_sign_algorithm);
651 DigestUpdate(&kernel_ctx, (uint8_t*) &image->kernel_version,
652 FIELD_LEN(kernel_version));
653 DigestUpdate(&kernel_ctx, (uint8_t*) image->options.version,
654 FIELD_LEN(options.version));
655 DigestUpdate(&kernel_ctx, (uint8_t*) image->options.cmd_line,
656 FIELD_LEN(options.cmd_line));
657 DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_len,
658 FIELD_LEN(options.kernel_len));
659 DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_load_addr,
660 FIELD_LEN(options.kernel_load_addr));
661 DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_entry_addr,
662 FIELD_LEN(options.kernel_entry_addr));
663 DigestUpdate(&kernel_ctx, image->kernel_data, image->options.kernel_len);
664 kernel_digest = DigestFinal(&kernel_ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800665 if (!RSAVerify(kernel_sign_key, image->kernel_signature,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800666 kernel_signature_size, image->kernel_sign_algorithm,
667 kernel_digest)) {
668 error_code = VERIFY_KERNEL_SIGNATURE_FAILED;
669 goto verify_failure;
670 }
671
672verify_failure:
Gaurav Shah259de402010-03-12 17:42:03 -0800673 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800674 Free(kernel_digest);
675 Free(config_digest);
676 Free(header_digest);
677 return error_code;
678}
679
680const char* VerifyKernelErrorString(int error) {
681 return kVerifyKernelErrors[error];
682}
683
684int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800685 uint8_t* header_blob = NULL;
Gaurav Shah259de402010-03-12 17:42:03 -0800686 uint8_t* signature = NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800687 int signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800688 if (!image || !firmware_key_file)
689 return 0;
690 header_blob = GetKernelHeaderBlob(image);
691 if (!header_blob)
692 return 0;
693 if (!(signature = SignatureBuf(header_blob,
694 GetKernelHeaderLen(image),
695 firmware_key_file,
696 image->firmware_sign_algorithm))) {
697 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800698 return 0;
699 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800700 image->kernel_key_signature = Malloc(signature_len);
701 Memcpy(image->kernel_key_signature, signature, signature_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800702 Free(signature);
703 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800704 return 1;
705}
706
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800707int AddKernelSignature(KernelImage* image,
708 const char* kernel_signing_key_file) {
Gaurav Shah259de402010-03-12 17:42:03 -0800709 uint8_t* config_blob = NULL;
710 uint8_t* config_signature = NULL;
711 uint8_t* kernel_signature = NULL;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700712 uint8_t* kernel_buf;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800713 int signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800714
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800715 config_blob = GetKernelConfigBlob(image);
716 if (!(config_signature = SignatureBuf(config_blob,
Gaurav Shah463be3f2010-03-29 16:13:45 -0700717 GetKernelConfigLen(),
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800718 kernel_signing_key_file,
719 image->kernel_sign_algorithm))) {
720 fprintf(stderr, "Could not compute signature on the kernel config.\n");
721 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800722 return 0;
723 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800724
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800725 image->config_signature = (uint8_t*) Malloc(signature_len);
726 Memcpy(image->config_signature, config_signature, signature_len);
727 Free(config_signature);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700728 /* Kernel signature muse be calculated on the kernel version, options and
729 * kernel data to avoid splicing attacks. */
730 kernel_buf = (uint8_t*) Malloc(GetKernelConfigLen() +
731 image->options.kernel_len);
732 Memcpy(kernel_buf, config_blob, GetKernelConfigLen());
733 Memcpy(kernel_buf + GetKernelConfigLen(), image->kernel_data,
734 image->options.kernel_len);
735 if (!(kernel_signature = SignatureBuf(kernel_buf,
736 GetKernelConfigLen() +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800737 image->options.kernel_len,
738 kernel_signing_key_file,
739 image->kernel_sign_algorithm))) {
Gaurav Shah463be3f2010-03-29 16:13:45 -0700740 Free(config_blob);
741 Free(kernel_buf);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800742 fprintf(stderr, "Could not compute signature on the kernel.\n");
743 return 0;
744 }
745 image->kernel_signature = (uint8_t*) Malloc(signature_len);
746 Memcpy(image->kernel_signature, kernel_signature, signature_len);
747 Free(kernel_signature);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700748 Free(kernel_buf);
749 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800750 return 1;
751}
Gaurav Shaha82bf262010-03-26 10:38:08 -0700752
753uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob) {
754 uint8_t* kernel_ptr;
755 uint16_t kernel_key_version;
756 uint16_t kernel_version;
757 uint16_t firmware_sign_algorithm;
758 uint16_t kernel_sign_algorithm;
759 int kernel_key_signature_len;
760 int kernel_sign_key_len;
761 kernel_ptr = kernel_blob + (FIELD_LEN(magic) +
762 FIELD_LEN(header_version) +
763 FIELD_LEN(header_len));
764 Memcpy(&firmware_sign_algorithm, kernel_ptr, sizeof(firmware_sign_algorithm));
765 kernel_ptr += FIELD_LEN(firmware_sign_algorithm);
766 Memcpy(&kernel_sign_algorithm, kernel_ptr, sizeof(kernel_sign_algorithm));
767 kernel_ptr += FIELD_LEN(kernel_sign_algorithm);
768 Memcpy(&kernel_key_version, kernel_ptr, sizeof(kernel_key_version));
769
770 if (firmware_sign_algorithm >= kNumAlgorithms)
771 return 0;
772 if (kernel_sign_algorithm >= kNumAlgorithms)
773 return 0;
774 kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
775 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
776 kernel_ptr += (FIELD_LEN(kernel_key_version) +
777 kernel_sign_key_len +
778 FIELD_LEN(header_checksum) +
779 kernel_key_signature_len);
780 Memcpy(&kernel_version, kernel_ptr, sizeof(kernel_version));
781 return CombineUint16Pair(kernel_key_version, kernel_version);
782}
783
784void PrintKernelEntry(kernel_entry* entry) {
785 fprintf(stderr, "Boot Priority = %d\n", entry->boot_priority);
786 fprintf(stderr, "Boot Tries Remaining = %d\n", entry->boot_tries_remaining);
787 fprintf(stderr, "Boot Success Flag = %d\n", entry->boot_success_flag);
788}
789
790int VerifyKernelDriver_f(uint8_t* firmware_key_blob,
791 kernel_entry* kernelA,
792 kernel_entry* kernelB,
793 int dev_mode) {
794 int i;
795 /* Contains the logical kernel version (32-bit) which is calculated as
796 * (kernel_key_version << 16 | kernel_version) where
797 * [kernel_key_version], [firmware_version] are both 16-bit.
798 */
799 uint32_t kernelA_lversion, kernelB_lversion;
800 uint32_t min_lversion; /* Minimum of kernel A and kernel B lversion. */
801 uint32_t stored_lversion; /* Stored logical version in the TPM. */
802 kernel_entry* try_kernel[2]; /* Kernel in try order. */
803 int try_kernel_which[2]; /* Which corresponding kernel in the try order */
804 uint32_t try_kernel_lversion[2]; /* Their logical versions. */
805
806 /* [kernel_to_boot] will eventually contain the boot path to follow
807 * and is returned to the caller. Initially, we set it to recovery. If
808 * a valid bootable kernel is found, it will be set to that. */
809 int kernel_to_boot = BOOT_KERNEL_RECOVERY_CONTINUE;
810
811
812 /* The TPM must already have be initialized, so no need to call SetupTPM(). */
813
814 /* We get the key versions by reading directly from the image blobs without
815 * any additional (expensive) sanity checking on the blob since it's faster to
816 * outright reject a kernel with an older kernel key version. A malformed
817 * or corrupted kernel blob will still fail when VerifyKernel() is called
818 * on it.
819 */
820 kernelA_lversion = GetLogicalKernelVersion(kernelA->kernel_blob);
821 kernelB_lversion = GetLogicalKernelVersion(kernelB->kernel_blob);
822 min_lversion = Min(kernelA_lversion, kernelB_lversion);
823 stored_lversion = CombineUint16Pair(GetStoredVersion(KERNEL_KEY_VERSION),
824 GetStoredVersion(KERNEL_VERSION));
825
826 /* TODO(gauravsh): The kernel entries kernelA and kernelB come from the
827 * partition table - verify its signature/checksum before proceeding
828 * further. */
829
830 /* The logic for deciding which kernel to boot from is taken from the
831 * the Chromium OS Drive Map design document.
832 *
833 * We went to consider the kernels in their according to their boot
834 * priority attribute value.
835 */
836
837 if (kernelA->boot_priority >= kernelB->boot_priority) {
838 try_kernel[0] = kernelA;
839 try_kernel_which[0] = BOOT_KERNEL_A_CONTINUE;
840 try_kernel_lversion[0] = kernelA_lversion;
841 try_kernel[1] = kernelB;
842 try_kernel_which[1] = BOOT_KERNEL_B_CONTINUE;
843 try_kernel_lversion[1] = kernelB_lversion;
844 } else {
845 try_kernel[0] = kernelB;
846 try_kernel_which[0] = BOOT_KERNEL_B_CONTINUE;
847 try_kernel_lversion[0] = kernelB_lversion;
848 try_kernel[1] = kernelA;
849 try_kernel_which[1] = BOOT_KERNEL_A_CONTINUE;
850 try_kernel_lversion[1] = kernelA_lversion;
851 }
852
853 /* TODO(gauravsh): Changes to boot_tries_remaining and boot_priority
854 * below should be propagated to partition table. This will be added
855 * once the firmware parition table parsing code is in. */
856 for (i = 0; i < 2; i++) {
857 if ((try_kernel[i]->boot_success_flag ||
858 try_kernel[i]->boot_tries_remaining) &&
859 (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob,
860 try_kernel[i]->kernel_blob,
861 dev_mode))) {
862 if (try_kernel[i]->boot_tries_remaining > 0)
863 try_kernel[i]->boot_tries_remaining--;
864 if (stored_lversion > try_kernel_lversion[i])
865 continue; /* Rollback: I am afraid I can't let you do that Dave. */
866 if (i == 0 && (stored_lversion < try_kernel_lversion[1])) {
867 /* The higher priority kernel is valid and bootable, See if we
868 * need to update the stored version for rollback prevention. */
869 if (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob,
870 try_kernel[1]->kernel_blob,
871 dev_mode)) {
872 WriteStoredVersion(KERNEL_KEY_VERSION,
873 (uint16_t) (min_lversion >> 16));
874 WriteStoredVersion(KERNEL_VERSION,
875 (uint16_t) (min_lversion & 0xFFFF));
876 stored_lversion = min_lversion; /* Update stored version as it's
877 * used later. */
878 }
879 }
880 kernel_to_boot = try_kernel_which[i];
881 break; /* We found a valid kernel. */
882 }
883 try_kernel[i]->boot_priority = 0;
884 } /* for loop. */
885
886 /* Lock Kernel TPM rollback indices from further writes.
887 * TODO(gauravsh): Figure out if these can be combined into one
888 * 32-bit location since we seem to always use them together. This can help
889 * us minimize the number of NVRAM writes/locks (which are limited over flash
890 * memory lifetimes.
891 */
892 LockStoredVersion(KERNEL_KEY_VERSION);
893 LockStoredVersion(KERNEL_VERSION);
894 return kernel_to_boot;
895}