blob: 06b340b4c709737205919c205fa552bc14d79bbf [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"
18#include "rsa_utility.h"
19#include "sha_utility.h"
Gaurav Shahf5564fa2010-03-02 15:40:01 -080020#include "signature_digest.h"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080021#include "utility.h"
22
23/* Macro to determine the size of a field structure in the KernelImage
24 * structure. */
25#define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field))
26
27KernelImage* KernelImageNew(void) {
28 KernelImage* image = (KernelImage*) Malloc(sizeof(KernelImage));
29 if (image) {
30 image->kernel_sign_key = NULL;
31 image->kernel_key_signature = NULL;
32 image->config_signature = NULL;
33 image->kernel_signature = NULL;
34 image->kernel_data = NULL;
35 }
36 return image;
37}
38
39void KernelImageFree(KernelImage* image) {
40 if (image) {
41 Free(image->kernel_sign_key);
42 Free(image->kernel_key_signature);
43 Free(image->config_signature);
44 Free(image->kernel_signature);
45 Free(image->kernel_data);
46 Free(image);
47 }
48}
49
50KernelImage* ReadKernelImage(const char* input_file) {
51 uint32_t file_size;
52 int image_len = 0; /* Total size of the kernel image. */
53 int header_len = 0;
54 int firmware_sign_key_len;
55 int kernel_key_signature_len;
56 int kernel_sign_key_len;
57 int kernel_signature_len;
58 uint8_t* kernel_buf;
59 MemcpyState st;
60 KernelImage* image = KernelImageNew();
61
62 if (!image)
63 return NULL;
64
65 kernel_buf = BufferFromFile(input_file, &file_size);
66 image_len = file_size;
67
68 st.remaining_len = image_len;
69 st.remaining_buf = kernel_buf;
70
71 /* Read and compare magic bytes. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080072 StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080073
74 if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) {
75 fprintf(stderr, "Wrong Kernel Magic.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -080076 Free(kernel_buf);
77 return NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080078 }
79 StatefulMemcpy(&st, &image->header_version, FIELD_LEN(header_version));
80 StatefulMemcpy(&st, &image->header_len, FIELD_LEN(header_len));
81 StatefulMemcpy(&st, &image->firmware_sign_algorithm,
82 FIELD_LEN(firmware_sign_algorithm));
83 StatefulMemcpy(&st, &image->kernel_sign_algorithm,
84 FIELD_LEN(kernel_sign_algorithm));
85
86 /* Valid Kernel Key signing algorithm. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080087 if (image->firmware_sign_algorithm >= kNumAlgorithms) {
88 Free(kernel_buf);
89 return NULL;
90 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080091
92 /* Valid Kernel Signing Algorithm? */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080093 if (image->kernel_sign_algorithm >= kNumAlgorithms) {
94 Free(kernel_buf);
95 return NULL;
96 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080097
98 /* Compute size of pre-processed RSA public keys and signatures. */
99 firmware_sign_key_len = RSAProcessedKeySize(image->firmware_sign_algorithm);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800100 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800101 kernel_sign_key_len = RSAProcessedKeySize(image->kernel_sign_algorithm);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800102 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800103
104 /* Check whether key header length is correct. */
105 header_len = (FIELD_LEN(header_version) +
106 FIELD_LEN(header_len) +
107 FIELD_LEN(firmware_sign_algorithm) +
108 FIELD_LEN(kernel_sign_algorithm) +
109 FIELD_LEN(kernel_key_version) +
110 kernel_sign_key_len +
111 FIELD_LEN(header_checksum));
112
113 if (header_len != image->header_len) {
114 fprintf(stderr, "Header length mismatch. Got: %d, Expected: %d\n",
115 image->header_len, header_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800116 Free(kernel_buf);
117 return NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800118 }
119
120 /* Read pre-processed public half of the kernel signing key. */
121 StatefulMemcpy(&st, &image->kernel_key_version,
122 FIELD_LEN(kernel_key_version));
123 image->kernel_sign_key = (uint8_t*) Malloc(kernel_sign_key_len);
124 StatefulMemcpy(&st, image->kernel_sign_key, kernel_sign_key_len);
125 StatefulMemcpy(&st, image->header_checksum, FIELD_LEN(header_checksum));
126
127 /* Read key signature. */
128 StatefulMemcpy(&st, image->kernel_key_signature,
129 FIELD_LEN(kernel_key_signature));
130
131 /* Read the kernel config. */
132 StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version));
133 StatefulMemcpy(&st, &image->options.version, FIELD_LEN(options.version));
134 StatefulMemcpy(&st, &image->options.kernel_len,
135 FIELD_LEN(options.kernel_len));
136 StatefulMemcpy(&st, &image->options.kernel_load_addr,
137 FIELD_LEN(options.kernel_load_addr));
138 StatefulMemcpy(&st, &image->options.kernel_entry_addr,
139 FIELD_LEN(options.kernel_entry_addr));
140
141 /* Read kernel config signature. */
142 image->config_signature = (uint8_t*) Malloc(kernel_signature_len);
143 StatefulMemcpy(&st, image->config_signature, kernel_signature_len);
144
145 image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len);
146 StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len);
147
148 image->kernel_data = (uint8_t*) Malloc(image->options.kernel_len);
149 StatefulMemcpy(&st, image->kernel_data, image->options.kernel_len);
150
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800151 if(st.remaining_len != 0) { /* Overrun or underrun. */
152 Free(kernel_buf);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800153 return NULL;
154 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800155 Free(kernel_buf);
156 return image;
157}
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800158
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800159int GetKernelHeaderLen(const KernelImage* image) {
160 return (FIELD_LEN(header_version) + FIELD_LEN(header_len) +
161 FIELD_LEN(firmware_sign_algorithm) +
162 FIELD_LEN(kernel_sign_algorithm) + FIELD_LEN(kernel_key_version) +
163 RSAProcessedKeySize(image->kernel_sign_algorithm) +
164 FIELD_LEN(header_checksum));
165}
166
167uint8_t* GetKernelHeaderBlob(const KernelImage* image) {
168 uint8_t* header_blob = NULL;
169 MemcpyState st;
170
171 header_blob = (uint8_t*) Malloc(GetKernelHeaderLen(image));
172 st.remaining_len = GetKernelHeaderLen(image);
173 st.remaining_buf = header_blob;
174
175 StatefulMemcpy_r(&st, &image->header_version, FIELD_LEN(header_version));
176 StatefulMemcpy_r(&st, &image->header_len, FIELD_LEN(header_len));
177 StatefulMemcpy_r(&st, &image->firmware_sign_algorithm,
178 FIELD_LEN(firmware_sign_algorithm));
179 StatefulMemcpy_r(&st, &image->kernel_sign_algorithm,
180 FIELD_LEN(kernel_sign_algorithm));
181 StatefulMemcpy_r(&st, &image->kernel_key_version,
182 FIELD_LEN(kernel_key_version));
183 StatefulMemcpy_r(&st, image->kernel_sign_key,
184 RSAProcessedKeySize(image->kernel_sign_algorithm));
185 StatefulMemcpy_r(&st, &image->header_checksum, FIELD_LEN(header_checksum));
186
187 if (st.remaining_len != 0) { /* Underrun or Overrun. */
188 Free(header_blob);
189 return NULL;
190 }
191 return header_blob;
192}
193
194int GetKernelConfigLen(const KernelImage* image) {
195 return (FIELD_LEN(kernel_version) + FIELD_LEN(options.version) +
196 FIELD_LEN(options.kernel_len) + FIELD_LEN(options.kernel_load_addr) +
197 FIELD_LEN(options.kernel_entry_addr));
198}
199
200uint8_t* GetKernelConfigBlob(const KernelImage* image) {
201 uint8_t* config_blob = NULL;
202 MemcpyState st;
203
204 config_blob = (uint8_t*) Malloc(GetKernelConfigLen(image));
205 st.remaining_len = GetKernelConfigLen(image);
206 st.remaining_buf = config_blob;
207
208 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
209 StatefulMemcpy_r(&st, image->options.version, FIELD_LEN(options.version));
210 StatefulMemcpy_r(&st, &image->options.kernel_len,
211 FIELD_LEN(options.kernel_len));
212 StatefulMemcpy_r(&st, &image->options.kernel_load_addr,
213 FIELD_LEN(options.kernel_load_addr));
214 StatefulMemcpy_r(&st, &image->options.kernel_entry_addr,
215 FIELD_LEN(options.kernel_entry_addr));
216 if (st.remaining_len != 0) { /* Overrun or Underrun. */
217 Free(config_blob);
218 return NULL;
219 }
220 return config_blob;
221}
222
223uint8_t* GetKernelBlob(const KernelImage* image, int* blob_len) {
224 int kernel_key_signature_len;
225 int kernel_signature_len;
226 uint8_t* kernel_blob = NULL;
227 uint8_t* header_blob = NULL;
228 uint8_t* config_blob = NULL;
229 MemcpyState st;
230
231 if (!image)
232 return NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800233 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
234 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800235 *blob_len = (FIELD_LEN(magic) +
236 GetKernelHeaderLen(image) +
237 kernel_key_signature_len +
238 GetKernelConfigLen(image) +
239 2 * kernel_signature_len +
240 image->options.kernel_len);
241 kernel_blob = (uint8_t*) Malloc(*blob_len);
242 st.remaining_len = *blob_len;
243 st.remaining_buf = kernel_blob;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800244
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800245 header_blob = GetKernelHeaderBlob(image);
246 config_blob = GetKernelConfigBlob(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800247
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800248 StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic));
249 StatefulMemcpy_r(&st, header_blob, GetKernelHeaderLen(image));
250 StatefulMemcpy_r(&st, image->kernel_key_signature, kernel_key_signature_len);
251 StatefulMemcpy_r(&st, config_blob, GetKernelConfigLen(image));
252 StatefulMemcpy_r(&st, image->config_signature, kernel_signature_len);
253 StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len);
254 StatefulMemcpy_r(&st, image->kernel_data, image->options.kernel_len);
255
256 Free(config_blob);
257 Free(header_blob);
258
259 if (st.remaining_len != 0) { /* Underrun or Overrun. */
260 Free(kernel_blob);
261 return NULL;
262 }
263 return kernel_blob;
264}
265
266int WriteKernelImage(const char* input_file,
267 const KernelImage* image) {
268 int fd;
269 uint8_t* kernel_blob;
270 int blob_len;
271
272 if (!image)
273 return 0;
274 if (-1 == (fd = creat(input_file, S_IRWXU))) {
275 fprintf(stderr, "Couldn't open file for writing kernel image: %s\n",
276 input_file);
277 return 0;
278 }
279 kernel_blob = GetKernelBlob(image, &blob_len);
280 if (!kernel_blob) {
281 fprintf(stderr, "Couldn't create kernel blob from KernelImage.\n");
282 return 0;
283 }
284 if (blob_len != write(fd, kernel_blob, blob_len)) {
285 fprintf(stderr, "Couldn't write Kernel Image to file: %s\n",
286 input_file);
287
288 Free(kernel_blob);
289 close(fd);
290 return 0;
291 }
292 Free(kernel_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800293 close(fd);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800294 return 1;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800295}
296
297void PrintKernelImage(const KernelImage* image) {
298 if (!image)
299 return;
300
301 /* Print header. */
302 printf("Header Length = %d\n"
303 "Firmware Signing key algorithm id = %d\n"
304 "Kernel Signing key algorithm id = %d\n"
305 "Kernel Signature Algorithm = %s\n"
306 "Kernel Key Version = %d\n\n",
307 image->header_len,
308 image->firmware_sign_algorithm,
309 image->kernel_sign_algorithm,
310 algo_strings[image->kernel_sign_algorithm],
311 image->kernel_key_version);
312 /* TODO(gauravsh): Output hash and key signature here? */
313 /* Print preamble. */
314 printf("Kernel Version = %d\n"
315 "Kernel Config Version = %d.%d\n"
316 "kernel Length = %d\n"
317 "Kernel Load Address = %" PRId64 "\n"
318 "Kernel Entry Address = %" PRId64 "\n\n",
319 image->kernel_version,
320 image->options.version[0], image->options.version[1],
321 image->options.kernel_len,
322 image->options.kernel_load_addr,
323 image->options.kernel_entry_addr);
324 /* TODO(gauravsh): Output kernel signature here? */
325}
326
327char* kVerifyKernelErrors[VERIFY_KERNEL_MAX] = {
328 "Success.",
329 "Invalid Image.",
330 "Kernel Key Signature Failed.",
331 "Invalid Kernel Verification Algorithm.",
332 "Config Signature Failed.",
333 "Kernel Signature Failed.",
334 "Wrong Kernel Magic.",
335};
336
337int VerifyKernelHeader(const uint8_t* firmware_key_blob,
338 const uint8_t* header_blob,
339 const int dev_mode,
340 int* firmware_algorithm,
341 int* kernel_algorithm,
342 int* kernel_header_len) {
343 int kernel_sign_key_len;
344 int firmware_sign_key_len;
345 uint16_t header_version, header_len;
346 uint16_t firmware_sign_algorithm, kernel_sign_algorithm;
347 uint8_t* header_checksum = NULL;
348
349 /* Base Offset for the header_checksum field. Actual offset is
350 * this + kernel_sign_key_len. */
351 int base_header_checksum_offset = (FIELD_LEN(header_version) +
352 FIELD_LEN(header_len) +
353 FIELD_LEN(firmware_sign_algorithm) +
354 FIELD_LEN(kernel_sign_algorithm) +
355 FIELD_LEN(kernel_key_version));
356
357 Memcpy(&header_version, header_blob, sizeof(header_version));
358 Memcpy(&header_len, header_blob + FIELD_LEN(header_version),
359 sizeof(header_len));
360 Memcpy(&firmware_sign_algorithm,
361 header_blob + (FIELD_LEN(header_version) +
362 FIELD_LEN(header_len)),
363 sizeof(firmware_sign_algorithm));
364 Memcpy(&kernel_sign_algorithm,
365 header_blob + (FIELD_LEN(header_version) +
366 FIELD_LEN(header_len) +
367 FIELD_LEN(firmware_sign_algorithm)),
368 sizeof(kernel_sign_algorithm));
369
370 /* TODO(gauravsh): Make this return two different error types depending
371 * on whether the firmware or kernel signing algorithm is invalid. */
372 if (firmware_sign_algorithm >= kNumAlgorithms)
373 return VERIFY_KERNEL_INVALID_ALGORITHM;
374 if (kernel_sign_algorithm >= kNumAlgorithms)
375 return VERIFY_KERNEL_INVALID_ALGORITHM;
376
377 *firmware_algorithm = (int) firmware_sign_algorithm;
378 *kernel_algorithm = (int) kernel_sign_algorithm;
379 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
380 firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm);
381
382
383 /* Verify if header len is correct? */
384 if (header_len != (base_header_checksum_offset +
385 kernel_sign_key_len +
386 FIELD_LEN(header_checksum))) {
387 fprintf(stderr, "VerifyKernelHeader: Header length mismatch\n");
388 return VERIFY_KERNEL_INVALID_IMAGE;
389 }
390 *kernel_header_len = (int) header_len;
391
392 /* Verify if the hash of the header is correct. */
393 header_checksum = DigestBuf(header_blob,
394 header_len - FIELD_LEN(header_checksum),
395 SHA512_DIGEST_ALGORITHM);
396 if (SafeMemcmp(header_checksum,
397 header_blob + (base_header_checksum_offset +
398 kernel_sign_key_len),
399 FIELD_LEN(header_checksum))) {
400 Free(header_checksum);
401 return VERIFY_KERNEL_INVALID_IMAGE;
402 }
403 Free(header_checksum);
404
405 /* Verify kernel key signature unless we are in dev mode. */
406 if (!dev_mode) {
407 if (!RSAVerifyBinary_f(firmware_key_blob, NULL, /* Key to use */
408 header_blob, /* Data to verify */
409 header_len, /* Length of data */
410 header_blob + header_len, /* Expected Signature */
411 firmware_sign_algorithm))
412 return VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
413 }
414 return 0;
415}
416
417int VerifyKernelConfig(RSAPublicKey* kernel_sign_key,
418 const uint8_t* config_blob,
419 int algorithm,
420 int* kernel_len) {
421 uint32_t len, config_len;
422 config_len = (FIELD_LEN(kernel_version) +
423 FIELD_LEN(options.version)+
424 FIELD_LEN(options.kernel_len) +
425 FIELD_LEN(options.kernel_load_addr) +
426 FIELD_LEN(options.kernel_entry_addr));
427 if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use */
428 config_blob, /* Data to verify */
429 config_len, /* Length of data */
430 config_blob + config_len, /* Expected Signature */
431 algorithm))
432 return VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
433
434 Memcpy(&len, config_blob + (FIELD_LEN(kernel_version)+
435 FIELD_LEN(options.version)),
436 sizeof(len));
437 *kernel_len = (int) len;
438 return 0;
439}
440
441int VerifyKernelData(RSAPublicKey* kernel_sign_key,
442 const uint8_t* kernel_data_start,
443 int kernel_len,
444 int algorithm) {
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800445 int signature_len = siglen_map[algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800446 if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use. */
447 kernel_data_start + signature_len, /* Data to
448 * verify */
449 kernel_len, /* Length of data. */
450 kernel_data_start, /* Expected Signature */
451 algorithm))
452 return VERIFY_KERNEL_SIGNATURE_FAILED;
453 return 0;
454}
455
456int VerifyKernel(const uint8_t* firmware_key_blob,
457 const uint8_t* kernel_blob,
458 const int dev_mode) {
459 int error_code;
460 int firmware_sign_algorithm; /* Firmware signing key algorithm. */
461 int kernel_sign_algorithm; /* Kernel Signing key algorithm. */
462 RSAPublicKey* kernel_sign_key;
463 int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len,
464 header_len, kernel_len;
465 const uint8_t* header_ptr; /* Pointer to header. */
466 const uint8_t* kernel_sign_key_ptr; /* Pointer to signing key. */
467 const uint8_t* config_ptr; /* Pointer to kernel config block. */
468 const uint8_t* kernel_ptr; /* Pointer to kernel signature/data. */
469
470 /* Note: All the offset calculations are based on struct FirmwareImage which
471 * is defined in include/firmware_image.h. */
472
473 /* Compare magic bytes. */
474 if (SafeMemcmp(kernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE))
475 return VERIFY_KERNEL_WRONG_MAGIC;
476 header_ptr = kernel_blob + KERNEL_MAGIC_SIZE;
477
478 /* Only continue if header verification succeeds. */
479 if ((error_code = VerifyKernelHeader(firmware_key_blob, header_ptr, dev_mode,
480 &firmware_sign_algorithm,
481 &kernel_sign_algorithm, &header_len))) {
482 fprintf(stderr, "VerifyKernel: Kernel header verification failed.\n");
483 return error_code; /* AKA jump to recovery. */
484 }
485 /* Parse signing key into RSAPublicKey structure since it is required multiple
486 * times. */
487 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
488 kernel_sign_key_ptr = header_ptr + (FIELD_LEN(header_version) +
489 FIELD_LEN(header_len) +
490 FIELD_LEN(firmware_sign_algorithm) +
491 FIELD_LEN(kernel_sign_algorithm) +
492 FIELD_LEN(kernel_key_version));
493 kernel_sign_key = RSAPublicKeyFromBuf(kernel_sign_key_ptr,
494 kernel_sign_key_len);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800495 kernel_signature_len = siglen_map[kernel_sign_algorithm];
496 kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800497
498 /* Only continue if config verification succeeds. */
499 config_ptr = (header_ptr + header_len + kernel_key_signature_len);
500 if ((error_code = VerifyKernelConfig(kernel_sign_key, config_ptr,
501 kernel_sign_algorithm,
502 &kernel_len)))
503 return error_code; /* AKA jump to recovery. */
504 /* Only continue if kernel data verification succeeds. */
505 kernel_ptr = (config_ptr +
506 FIELD_LEN(kernel_version) +
507 FIELD_LEN(options.version) +
508 FIELD_LEN(options.kernel_len) +
509 FIELD_LEN(options.kernel_entry_addr) +
510 FIELD_LEN(options.kernel_load_addr) +
511 kernel_signature_len);
512
513 if ((error_code = VerifyKernelData(kernel_sign_key, kernel_ptr, kernel_len,
514 kernel_sign_algorithm)))
515 return error_code; /* AKA jump to recovery. */
516 return 0; /* Success! */
517}
518
519int VerifyKernelImage(const RSAPublicKey* firmware_key,
520 const KernelImage* image,
521 const int dev_mode) {
522 RSAPublicKey* kernel_sign_key;
523 uint8_t* header_digest = NULL;
524 uint8_t* config_digest = NULL;
525 uint8_t* kernel_digest = NULL;
526 int kernel_sign_key_size;
527 int kernel_signature_size;
528 int error_code = 0;
529 DigestContext ctx;
530
531 if (!image)
532 return VERIFY_KERNEL_INVALID_IMAGE;
533
534 /* Verify kernel key signature on the key header if we
535 * are not in dev mode.
536 *
537 * TODO(gauravsh): Add additional sanity checks here for:
538 * 1) verifying the header length is correct.
539 * 2) header_checksum is correct.
540 */
541
542 if (image->firmware_sign_algorithm >= kNumAlgorithms)
543 return VERIFY_KERNEL_INVALID_ALGORITHM;
544 if (image->kernel_sign_algorithm >= kNumAlgorithms)
545 return VERIFY_KERNEL_INVALID_ALGORITHM;
546
547 if (!dev_mode) {
548 DigestInit(&ctx, image->firmware_sign_algorithm);
549 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
550 FIELD_LEN(header_version));
551 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
552 FIELD_LEN(header_len));
553 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
554 FIELD_LEN(firmware_sign_algorithm));
555 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
556 FIELD_LEN(kernel_sign_algorithm));
557 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
558 FIELD_LEN(kernel_key_version));
559 DigestUpdate(&ctx, image->kernel_sign_key,
560 RSAProcessedKeySize(image->kernel_sign_algorithm));
561 DigestUpdate(&ctx, image->header_checksum,
562 FIELD_LEN(header_checksum));
563 header_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800564 if (!RSAVerify(firmware_key, image->kernel_key_signature,
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800565 siglen_map[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800566 image->firmware_sign_algorithm,
567 header_digest)) {
568 fprintf(stderr, "VerifyKernelImage(): Key signature check failed.\n");
569 error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
570 goto verify_failure;
571 }
572 }
573
574 /* Get kernel signing key to verify the rest of the kernel. */
575 kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm);
576 kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
577 kernel_sign_key_size);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800578 kernel_signature_size = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800579
580 /* Verify kernel config signature. */
581 DigestInit(&ctx, image->kernel_sign_algorithm);
582 DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
583 FIELD_LEN(kernel_version));
584 DigestUpdate(&ctx, (uint8_t*) &image->options.version,
585 FIELD_LEN(options.version));
586 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_len,
587 FIELD_LEN(options.kernel_len));
588 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_load_addr,
589 FIELD_LEN(options.kernel_load_addr));
590 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_entry_addr,
591 FIELD_LEN(options.kernel_entry_addr));
592 config_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800593 if (!RSAVerify(kernel_sign_key, image->config_signature,
594 kernel_signature_size, image->kernel_sign_algorithm,
595 config_digest)) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800596 error_code = VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
597 goto verify_failure;
598 }
599
600 /* Verify firmware signature. */
601 kernel_digest = DigestBuf(image->kernel_data,
602 image->options.kernel_len,
603 image->kernel_sign_algorithm);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800604 if (!RSAVerify(kernel_sign_key, image->kernel_signature,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800605 kernel_signature_size, image->kernel_sign_algorithm,
606 kernel_digest)) {
607 error_code = VERIFY_KERNEL_SIGNATURE_FAILED;
608 goto verify_failure;
609 }
610
611verify_failure:
612 Free(kernel_digest);
613 Free(config_digest);
614 Free(header_digest);
615 return error_code;
616}
617
618const char* VerifyKernelErrorString(int error) {
619 return kVerifyKernelErrors[error];
620}
621
622int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800623 uint8_t* header_blob = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800624 uint8_t* signature;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800625 int signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800626 if (!image || !firmware_key_file)
627 return 0;
628 header_blob = GetKernelHeaderBlob(image);
629 if (!header_blob)
630 return 0;
631 if (!(signature = SignatureBuf(header_blob,
632 GetKernelHeaderLen(image),
633 firmware_key_file,
634 image->firmware_sign_algorithm))) {
635 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800636 return 0;
637 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800638 image->kernel_key_signature = Malloc(signature_len);
639 Memcpy(image->kernel_key_signature, signature, signature_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800640 Free(signature);
641 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800642 return 1;
643}
644
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800645int AddKernelSignature(KernelImage* image,
646 const char* kernel_signing_key_file) {
647 uint8_t* config_blob;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800648 uint8_t* config_signature;
649 uint8_t* kernel_signature;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800650 int signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800651
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800652 config_blob = GetKernelConfigBlob(image);
653 if (!(config_signature = SignatureBuf(config_blob,
654 GetKernelConfigLen(image),
655 kernel_signing_key_file,
656 image->kernel_sign_algorithm))) {
657 fprintf(stderr, "Could not compute signature on the kernel config.\n");
658 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800659 return 0;
660 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800661
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800662 image->config_signature = (uint8_t*) Malloc(signature_len);
663 Memcpy(image->config_signature, config_signature, signature_len);
664 Free(config_signature);
665
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800666 if (!(kernel_signature = SignatureBuf(image->kernel_data,
667 image->options.kernel_len,
668 kernel_signing_key_file,
669 image->kernel_sign_algorithm))) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800670 fprintf(stderr, "Could not compute signature on the kernel.\n");
671 return 0;
672 }
673 image->kernel_signature = (uint8_t*) Malloc(signature_len);
674 Memcpy(image->kernel_signature, kernel_signature, signature_len);
675 Free(kernel_signature);
676 return 1;
677}