blob: e63529162ecc630ac3a9a13b9903900f61014eb4 [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
223int GetKernelConfigLen(const KernelImage* image) {
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
234 config_blob = (uint8_t*) Malloc(GetKernelConfigLen(image));
235 st.remaining_len = GetKernelConfigLen(image);
236 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 +
269 GetKernelConfigLen(image) +
270 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);
282 StatefulMemcpy_r(&st, config_blob, GetKernelConfigLen(image));
283 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 Shah4f393862010-03-12 18:13:24 -0800456 config_len = GetKernelConfigLen(NULL);
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,
473 const uint8_t* kernel_data_start,
474 int kernel_len,
475 int algorithm) {
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800476 int signature_len = siglen_map[algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800477 if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use. */
478 kernel_data_start + signature_len, /* Data to
479 * verify */
480 kernel_len, /* Length of data. */
481 kernel_data_start, /* Expected Signature */
482 algorithm))
483 return VERIFY_KERNEL_SIGNATURE_FAILED;
484 return 0;
485}
486
487int VerifyKernel(const uint8_t* firmware_key_blob,
488 const uint8_t* kernel_blob,
489 const int dev_mode) {
490 int error_code;
491 int firmware_sign_algorithm; /* Firmware signing key algorithm. */
492 int kernel_sign_algorithm; /* Kernel Signing key algorithm. */
493 RSAPublicKey* kernel_sign_key;
494 int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len,
495 header_len, kernel_len;
496 const uint8_t* header_ptr; /* Pointer to header. */
497 const uint8_t* kernel_sign_key_ptr; /* Pointer to signing key. */
498 const uint8_t* config_ptr; /* Pointer to kernel config block. */
499 const uint8_t* kernel_ptr; /* Pointer to kernel signature/data. */
500
501 /* Note: All the offset calculations are based on struct FirmwareImage which
502 * is defined in include/firmware_image.h. */
503
504 /* Compare magic bytes. */
505 if (SafeMemcmp(kernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE))
506 return VERIFY_KERNEL_WRONG_MAGIC;
507 header_ptr = kernel_blob + KERNEL_MAGIC_SIZE;
508
509 /* Only continue if header verification succeeds. */
510 if ((error_code = VerifyKernelHeader(firmware_key_blob, header_ptr, dev_mode,
511 &firmware_sign_algorithm,
512 &kernel_sign_algorithm, &header_len))) {
513 fprintf(stderr, "VerifyKernel: Kernel header verification failed.\n");
514 return error_code; /* AKA jump to recovery. */
515 }
516 /* Parse signing key into RSAPublicKey structure since it is required multiple
517 * times. */
518 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
519 kernel_sign_key_ptr = header_ptr + (FIELD_LEN(header_version) +
520 FIELD_LEN(header_len) +
521 FIELD_LEN(firmware_sign_algorithm) +
522 FIELD_LEN(kernel_sign_algorithm) +
523 FIELD_LEN(kernel_key_version));
524 kernel_sign_key = RSAPublicKeyFromBuf(kernel_sign_key_ptr,
525 kernel_sign_key_len);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800526 kernel_signature_len = siglen_map[kernel_sign_algorithm];
527 kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800528
529 /* Only continue if config verification succeeds. */
530 config_ptr = (header_ptr + header_len + kernel_key_signature_len);
531 if ((error_code = VerifyKernelConfig(kernel_sign_key, config_ptr,
532 kernel_sign_algorithm,
Gaurav Shah259de402010-03-12 17:42:03 -0800533 &kernel_len))) {
534 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800535 return error_code; /* AKA jump to recovery. */
Gaurav Shah259de402010-03-12 17:42:03 -0800536 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800537 /* Only continue if kernel data verification succeeds. */
538 kernel_ptr = (config_ptr +
Gaurav Shah4f393862010-03-12 18:13:24 -0800539 GetKernelConfigLen(NULL) + /* Skip config block/signature. */
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800540 kernel_signature_len);
541
542 if ((error_code = VerifyKernelData(kernel_sign_key, kernel_ptr, kernel_len,
Gaurav Shah259de402010-03-12 17:42:03 -0800543 kernel_sign_algorithm))) {
544 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800545 return error_code; /* AKA jump to recovery. */
Gaurav Shah259de402010-03-12 17:42:03 -0800546 }
547 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800548 return 0; /* Success! */
549}
550
551int VerifyKernelImage(const RSAPublicKey* firmware_key,
552 const KernelImage* image,
553 const int dev_mode) {
Gaurav Shah259de402010-03-12 17:42:03 -0800554 RSAPublicKey* kernel_sign_key = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800555 uint8_t* header_digest = NULL;
556 uint8_t* config_digest = NULL;
557 uint8_t* kernel_digest = NULL;
558 int kernel_sign_key_size;
559 int kernel_signature_size;
560 int error_code = 0;
561 DigestContext ctx;
562
563 if (!image)
564 return VERIFY_KERNEL_INVALID_IMAGE;
565
566 /* Verify kernel key signature on the key header if we
567 * are not in dev mode.
568 *
569 * TODO(gauravsh): Add additional sanity checks here for:
570 * 1) verifying the header length is correct.
571 * 2) header_checksum is correct.
572 */
573
574 if (image->firmware_sign_algorithm >= kNumAlgorithms)
575 return VERIFY_KERNEL_INVALID_ALGORITHM;
576 if (image->kernel_sign_algorithm >= kNumAlgorithms)
577 return VERIFY_KERNEL_INVALID_ALGORITHM;
578
579 if (!dev_mode) {
580 DigestInit(&ctx, image->firmware_sign_algorithm);
581 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
582 FIELD_LEN(header_version));
583 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
584 FIELD_LEN(header_len));
585 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
586 FIELD_LEN(firmware_sign_algorithm));
587 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
588 FIELD_LEN(kernel_sign_algorithm));
589 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
590 FIELD_LEN(kernel_key_version));
591 DigestUpdate(&ctx, image->kernel_sign_key,
592 RSAProcessedKeySize(image->kernel_sign_algorithm));
593 DigestUpdate(&ctx, image->header_checksum,
594 FIELD_LEN(header_checksum));
595 header_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800596 if (!RSAVerify(firmware_key, image->kernel_key_signature,
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800597 siglen_map[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800598 image->firmware_sign_algorithm,
599 header_digest)) {
600 fprintf(stderr, "VerifyKernelImage(): Key signature check failed.\n");
601 error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
602 goto verify_failure;
603 }
604 }
605
606 /* Get kernel signing key to verify the rest of the kernel. */
607 kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm);
608 kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
609 kernel_sign_key_size);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800610 kernel_signature_size = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800611
612 /* Verify kernel config signature. */
613 DigestInit(&ctx, image->kernel_sign_algorithm);
614 DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
615 FIELD_LEN(kernel_version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800616 DigestUpdate(&ctx, (uint8_t*) image->options.version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800617 FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800618 DigestUpdate(&ctx, (uint8_t*) image->options.cmd_line,
619 FIELD_LEN(options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800620 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_len,
621 FIELD_LEN(options.kernel_len));
622 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_load_addr,
623 FIELD_LEN(options.kernel_load_addr));
624 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_entry_addr,
625 FIELD_LEN(options.kernel_entry_addr));
626 config_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800627 if (!RSAVerify(kernel_sign_key, image->config_signature,
628 kernel_signature_size, image->kernel_sign_algorithm,
629 config_digest)) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800630 error_code = VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
631 goto verify_failure;
632 }
633
634 /* Verify firmware signature. */
635 kernel_digest = DigestBuf(image->kernel_data,
636 image->options.kernel_len,
637 image->kernel_sign_algorithm);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800638 if (!RSAVerify(kernel_sign_key, image->kernel_signature,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800639 kernel_signature_size, image->kernel_sign_algorithm,
640 kernel_digest)) {
641 error_code = VERIFY_KERNEL_SIGNATURE_FAILED;
642 goto verify_failure;
643 }
644
645verify_failure:
Gaurav Shah259de402010-03-12 17:42:03 -0800646 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800647 Free(kernel_digest);
648 Free(config_digest);
649 Free(header_digest);
650 return error_code;
651}
652
653const char* VerifyKernelErrorString(int error) {
654 return kVerifyKernelErrors[error];
655}
656
657int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800658 uint8_t* header_blob = NULL;
Gaurav Shah259de402010-03-12 17:42:03 -0800659 uint8_t* signature = NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800660 int signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800661 if (!image || !firmware_key_file)
662 return 0;
663 header_blob = GetKernelHeaderBlob(image);
664 if (!header_blob)
665 return 0;
666 if (!(signature = SignatureBuf(header_blob,
667 GetKernelHeaderLen(image),
668 firmware_key_file,
669 image->firmware_sign_algorithm))) {
670 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800671 return 0;
672 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800673 image->kernel_key_signature = Malloc(signature_len);
674 Memcpy(image->kernel_key_signature, signature, signature_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800675 Free(signature);
676 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800677 return 1;
678}
679
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800680int AddKernelSignature(KernelImage* image,
681 const char* kernel_signing_key_file) {
Gaurav Shah259de402010-03-12 17:42:03 -0800682 uint8_t* config_blob = NULL;
683 uint8_t* config_signature = NULL;
684 uint8_t* kernel_signature = NULL;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800685 int signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800686
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800687 config_blob = GetKernelConfigBlob(image);
688 if (!(config_signature = SignatureBuf(config_blob,
689 GetKernelConfigLen(image),
690 kernel_signing_key_file,
691 image->kernel_sign_algorithm))) {
692 fprintf(stderr, "Could not compute signature on the kernel config.\n");
693 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800694 return 0;
695 }
Gaurav Shah259de402010-03-12 17:42:03 -0800696 Free(config_blob);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800697
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800698 image->config_signature = (uint8_t*) Malloc(signature_len);
699 Memcpy(image->config_signature, config_signature, signature_len);
700 Free(config_signature);
701
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800702 if (!(kernel_signature = SignatureBuf(image->kernel_data,
703 image->options.kernel_len,
704 kernel_signing_key_file,
705 image->kernel_sign_algorithm))) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800706 fprintf(stderr, "Could not compute signature on the kernel.\n");
707 return 0;
708 }
709 image->kernel_signature = (uint8_t*) Malloc(signature_len);
710 Memcpy(image->kernel_signature, kernel_signature, signature_len);
711 Free(kernel_signature);
712 return 1;
713}
Gaurav Shaha82bf262010-03-26 10:38:08 -0700714
715uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob) {
716 uint8_t* kernel_ptr;
717 uint16_t kernel_key_version;
718 uint16_t kernel_version;
719 uint16_t firmware_sign_algorithm;
720 uint16_t kernel_sign_algorithm;
721 int kernel_key_signature_len;
722 int kernel_sign_key_len;
723 kernel_ptr = kernel_blob + (FIELD_LEN(magic) +
724 FIELD_LEN(header_version) +
725 FIELD_LEN(header_len));
726 Memcpy(&firmware_sign_algorithm, kernel_ptr, sizeof(firmware_sign_algorithm));
727 kernel_ptr += FIELD_LEN(firmware_sign_algorithm);
728 Memcpy(&kernel_sign_algorithm, kernel_ptr, sizeof(kernel_sign_algorithm));
729 kernel_ptr += FIELD_LEN(kernel_sign_algorithm);
730 Memcpy(&kernel_key_version, kernel_ptr, sizeof(kernel_key_version));
731
732 if (firmware_sign_algorithm >= kNumAlgorithms)
733 return 0;
734 if (kernel_sign_algorithm >= kNumAlgorithms)
735 return 0;
736 kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
737 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
738 kernel_ptr += (FIELD_LEN(kernel_key_version) +
739 kernel_sign_key_len +
740 FIELD_LEN(header_checksum) +
741 kernel_key_signature_len);
742 Memcpy(&kernel_version, kernel_ptr, sizeof(kernel_version));
743 return CombineUint16Pair(kernel_key_version, kernel_version);
744}
745
746void PrintKernelEntry(kernel_entry* entry) {
747 fprintf(stderr, "Boot Priority = %d\n", entry->boot_priority);
748 fprintf(stderr, "Boot Tries Remaining = %d\n", entry->boot_tries_remaining);
749 fprintf(stderr, "Boot Success Flag = %d\n", entry->boot_success_flag);
750}
751
752int VerifyKernelDriver_f(uint8_t* firmware_key_blob,
753 kernel_entry* kernelA,
754 kernel_entry* kernelB,
755 int dev_mode) {
756 int i;
757 /* Contains the logical kernel version (32-bit) which is calculated as
758 * (kernel_key_version << 16 | kernel_version) where
759 * [kernel_key_version], [firmware_version] are both 16-bit.
760 */
761 uint32_t kernelA_lversion, kernelB_lversion;
762 uint32_t min_lversion; /* Minimum of kernel A and kernel B lversion. */
763 uint32_t stored_lversion; /* Stored logical version in the TPM. */
764 kernel_entry* try_kernel[2]; /* Kernel in try order. */
765 int try_kernel_which[2]; /* Which corresponding kernel in the try order */
766 uint32_t try_kernel_lversion[2]; /* Their logical versions. */
767
768 /* [kernel_to_boot] will eventually contain the boot path to follow
769 * and is returned to the caller. Initially, we set it to recovery. If
770 * a valid bootable kernel is found, it will be set to that. */
771 int kernel_to_boot = BOOT_KERNEL_RECOVERY_CONTINUE;
772
773
774 /* The TPM must already have be initialized, so no need to call SetupTPM(). */
775
776 /* We get the key versions by reading directly from the image blobs without
777 * any additional (expensive) sanity checking on the blob since it's faster to
778 * outright reject a kernel with an older kernel key version. A malformed
779 * or corrupted kernel blob will still fail when VerifyKernel() is called
780 * on it.
781 */
782 kernelA_lversion = GetLogicalKernelVersion(kernelA->kernel_blob);
783 kernelB_lversion = GetLogicalKernelVersion(kernelB->kernel_blob);
784 min_lversion = Min(kernelA_lversion, kernelB_lversion);
785 stored_lversion = CombineUint16Pair(GetStoredVersion(KERNEL_KEY_VERSION),
786 GetStoredVersion(KERNEL_VERSION));
787
788 /* TODO(gauravsh): The kernel entries kernelA and kernelB come from the
789 * partition table - verify its signature/checksum before proceeding
790 * further. */
791
792 /* The logic for deciding which kernel to boot from is taken from the
793 * the Chromium OS Drive Map design document.
794 *
795 * We went to consider the kernels in their according to their boot
796 * priority attribute value.
797 */
798
799 if (kernelA->boot_priority >= kernelB->boot_priority) {
800 try_kernel[0] = kernelA;
801 try_kernel_which[0] = BOOT_KERNEL_A_CONTINUE;
802 try_kernel_lversion[0] = kernelA_lversion;
803 try_kernel[1] = kernelB;
804 try_kernel_which[1] = BOOT_KERNEL_B_CONTINUE;
805 try_kernel_lversion[1] = kernelB_lversion;
806 } else {
807 try_kernel[0] = kernelB;
808 try_kernel_which[0] = BOOT_KERNEL_B_CONTINUE;
809 try_kernel_lversion[0] = kernelB_lversion;
810 try_kernel[1] = kernelA;
811 try_kernel_which[1] = BOOT_KERNEL_A_CONTINUE;
812 try_kernel_lversion[1] = kernelA_lversion;
813 }
814
815 /* TODO(gauravsh): Changes to boot_tries_remaining and boot_priority
816 * below should be propagated to partition table. This will be added
817 * once the firmware parition table parsing code is in. */
818 for (i = 0; i < 2; i++) {
819 if ((try_kernel[i]->boot_success_flag ||
820 try_kernel[i]->boot_tries_remaining) &&
821 (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob,
822 try_kernel[i]->kernel_blob,
823 dev_mode))) {
824 if (try_kernel[i]->boot_tries_remaining > 0)
825 try_kernel[i]->boot_tries_remaining--;
826 if (stored_lversion > try_kernel_lversion[i])
827 continue; /* Rollback: I am afraid I can't let you do that Dave. */
828 if (i == 0 && (stored_lversion < try_kernel_lversion[1])) {
829 /* The higher priority kernel is valid and bootable, See if we
830 * need to update the stored version for rollback prevention. */
831 if (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob,
832 try_kernel[1]->kernel_blob,
833 dev_mode)) {
834 WriteStoredVersion(KERNEL_KEY_VERSION,
835 (uint16_t) (min_lversion >> 16));
836 WriteStoredVersion(KERNEL_VERSION,
837 (uint16_t) (min_lversion & 0xFFFF));
838 stored_lversion = min_lversion; /* Update stored version as it's
839 * used later. */
840 }
841 }
842 kernel_to_boot = try_kernel_which[i];
843 break; /* We found a valid kernel. */
844 }
845 try_kernel[i]->boot_priority = 0;
846 } /* for loop. */
847
848 /* Lock Kernel TPM rollback indices from further writes.
849 * TODO(gauravsh): Figure out if these can be combined into one
850 * 32-bit location since we seem to always use them together. This can help
851 * us minimize the number of NVRAM writes/locks (which are limited over flash
852 * memory lifetimes.
853 */
854 LockStoredVersion(KERNEL_KEY_VERSION);
855 LockStoredVersion(KERNEL_VERSION);
856 return kernel_to_boot;
857}