blob: 893f49a13cef68b9afa7c308ccfdbf751a7a33c4 [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) {
Gaurav Shah456678b2010-03-10 18:38:45 -080051 uint64_t file_size;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080052 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. */
Gaurav Shah80d129b2010-03-03 17:58:43 -0800128 image->kernel_key_signature = (uint8_t*) Malloc(kernel_key_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800129 StatefulMemcpy(&st, image->kernel_key_signature,
Gaurav Shah80d129b2010-03-03 17:58:43 -0800130 kernel_key_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800131
132 /* Read the kernel config. */
133 StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version));
134 StatefulMemcpy(&st, &image->options.version, FIELD_LEN(options.version));
135 StatefulMemcpy(&st, &image->options.kernel_len,
136 FIELD_LEN(options.kernel_len));
137 StatefulMemcpy(&st, &image->options.kernel_load_addr,
138 FIELD_LEN(options.kernel_load_addr));
139 StatefulMemcpy(&st, &image->options.kernel_entry_addr,
140 FIELD_LEN(options.kernel_entry_addr));
141
142 /* Read kernel config signature. */
143 image->config_signature = (uint8_t*) Malloc(kernel_signature_len);
144 StatefulMemcpy(&st, image->config_signature, kernel_signature_len);
145
146 image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len);
147 StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len);
148
149 image->kernel_data = (uint8_t*) Malloc(image->options.kernel_len);
150 StatefulMemcpy(&st, image->kernel_data, image->options.kernel_len);
151
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800152 if(st.remaining_len != 0) { /* Overrun or underrun. */
153 Free(kernel_buf);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800154 return NULL;
155 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800156 Free(kernel_buf);
157 return image;
158}
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800159
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800160int GetKernelHeaderLen(const KernelImage* image) {
161 return (FIELD_LEN(header_version) + FIELD_LEN(header_len) +
162 FIELD_LEN(firmware_sign_algorithm) +
163 FIELD_LEN(kernel_sign_algorithm) + FIELD_LEN(kernel_key_version) +
164 RSAProcessedKeySize(image->kernel_sign_algorithm) +
165 FIELD_LEN(header_checksum));
166}
167
168uint8_t* GetKernelHeaderBlob(const KernelImage* image) {
169 uint8_t* header_blob = NULL;
170 MemcpyState st;
171
172 header_blob = (uint8_t*) Malloc(GetKernelHeaderLen(image));
173 st.remaining_len = GetKernelHeaderLen(image);
174 st.remaining_buf = header_blob;
175
176 StatefulMemcpy_r(&st, &image->header_version, FIELD_LEN(header_version));
177 StatefulMemcpy_r(&st, &image->header_len, FIELD_LEN(header_len));
178 StatefulMemcpy_r(&st, &image->firmware_sign_algorithm,
179 FIELD_LEN(firmware_sign_algorithm));
180 StatefulMemcpy_r(&st, &image->kernel_sign_algorithm,
181 FIELD_LEN(kernel_sign_algorithm));
182 StatefulMemcpy_r(&st, &image->kernel_key_version,
183 FIELD_LEN(kernel_key_version));
184 StatefulMemcpy_r(&st, image->kernel_sign_key,
185 RSAProcessedKeySize(image->kernel_sign_algorithm));
186 StatefulMemcpy_r(&st, &image->header_checksum, FIELD_LEN(header_checksum));
187
188 if (st.remaining_len != 0) { /* Underrun or Overrun. */
189 Free(header_blob);
190 return NULL;
191 }
192 return header_blob;
193}
194
195int GetKernelConfigLen(const KernelImage* image) {
196 return (FIELD_LEN(kernel_version) + FIELD_LEN(options.version) +
197 FIELD_LEN(options.kernel_len) + FIELD_LEN(options.kernel_load_addr) +
198 FIELD_LEN(options.kernel_entry_addr));
199}
200
201uint8_t* GetKernelConfigBlob(const KernelImage* image) {
202 uint8_t* config_blob = NULL;
203 MemcpyState st;
204
205 config_blob = (uint8_t*) Malloc(GetKernelConfigLen(image));
206 st.remaining_len = GetKernelConfigLen(image);
207 st.remaining_buf = config_blob;
208
209 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
210 StatefulMemcpy_r(&st, image->options.version, FIELD_LEN(options.version));
211 StatefulMemcpy_r(&st, &image->options.kernel_len,
212 FIELD_LEN(options.kernel_len));
213 StatefulMemcpy_r(&st, &image->options.kernel_load_addr,
214 FIELD_LEN(options.kernel_load_addr));
215 StatefulMemcpy_r(&st, &image->options.kernel_entry_addr,
216 FIELD_LEN(options.kernel_entry_addr));
217 if (st.remaining_len != 0) { /* Overrun or Underrun. */
218 Free(config_blob);
219 return NULL;
220 }
221 return config_blob;
222}
223
224uint8_t* GetKernelBlob(const KernelImage* image, int* blob_len) {
225 int kernel_key_signature_len;
226 int kernel_signature_len;
227 uint8_t* kernel_blob = NULL;
228 uint8_t* header_blob = NULL;
229 uint8_t* config_blob = NULL;
230 MemcpyState st;
231
232 if (!image)
233 return NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800234 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
235 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800236 *blob_len = (FIELD_LEN(magic) +
237 GetKernelHeaderLen(image) +
238 kernel_key_signature_len +
239 GetKernelConfigLen(image) +
240 2 * kernel_signature_len +
241 image->options.kernel_len);
242 kernel_blob = (uint8_t*) Malloc(*blob_len);
243 st.remaining_len = *blob_len;
244 st.remaining_buf = kernel_blob;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800245
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800246 header_blob = GetKernelHeaderBlob(image);
247 config_blob = GetKernelConfigBlob(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800248
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800249 StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic));
250 StatefulMemcpy_r(&st, header_blob, GetKernelHeaderLen(image));
251 StatefulMemcpy_r(&st, image->kernel_key_signature, kernel_key_signature_len);
252 StatefulMemcpy_r(&st, config_blob, GetKernelConfigLen(image));
253 StatefulMemcpy_r(&st, image->config_signature, kernel_signature_len);
254 StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len);
255 StatefulMemcpy_r(&st, image->kernel_data, image->options.kernel_len);
256
257 Free(config_blob);
258 Free(header_blob);
259
260 if (st.remaining_len != 0) { /* Underrun or Overrun. */
261 Free(kernel_blob);
262 return NULL;
263 }
264 return kernel_blob;
265}
266
267int WriteKernelImage(const char* input_file,
268 const KernelImage* image) {
269 int fd;
270 uint8_t* kernel_blob;
271 int blob_len;
272
273 if (!image)
274 return 0;
275 if (-1 == (fd = creat(input_file, S_IRWXU))) {
276 fprintf(stderr, "Couldn't open file for writing kernel image: %s\n",
277 input_file);
278 return 0;
279 }
280 kernel_blob = GetKernelBlob(image, &blob_len);
281 if (!kernel_blob) {
282 fprintf(stderr, "Couldn't create kernel blob from KernelImage.\n");
283 return 0;
284 }
285 if (blob_len != write(fd, kernel_blob, blob_len)) {
286 fprintf(stderr, "Couldn't write Kernel Image to file: %s\n",
287 input_file);
288
289 Free(kernel_blob);
290 close(fd);
291 return 0;
292 }
293 Free(kernel_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800294 close(fd);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800295 return 1;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800296}
297
298void PrintKernelImage(const KernelImage* image) {
299 if (!image)
300 return;
301
302 /* Print header. */
303 printf("Header Length = %d\n"
304 "Firmware Signing key algorithm id = %d\n"
305 "Kernel Signing key algorithm id = %d\n"
306 "Kernel Signature Algorithm = %s\n"
307 "Kernel Key Version = %d\n\n",
308 image->header_len,
309 image->firmware_sign_algorithm,
310 image->kernel_sign_algorithm,
311 algo_strings[image->kernel_sign_algorithm],
312 image->kernel_key_version);
313 /* TODO(gauravsh): Output hash and key signature here? */
314 /* Print preamble. */
315 printf("Kernel Version = %d\n"
316 "Kernel Config Version = %d.%d\n"
Gaurav Shah456678b2010-03-10 18:38:45 -0800317 "kernel Length = %" PRId64 "\n"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800318 "Kernel Load Address = %" PRId64 "\n"
319 "Kernel Entry Address = %" PRId64 "\n\n",
320 image->kernel_version,
321 image->options.version[0], image->options.version[1],
322 image->options.kernel_len,
323 image->options.kernel_load_addr,
324 image->options.kernel_entry_addr);
325 /* TODO(gauravsh): Output kernel signature here? */
326}
327
328char* kVerifyKernelErrors[VERIFY_KERNEL_MAX] = {
329 "Success.",
330 "Invalid Image.",
331 "Kernel Key Signature Failed.",
332 "Invalid Kernel Verification Algorithm.",
333 "Config Signature Failed.",
334 "Kernel Signature Failed.",
335 "Wrong Kernel Magic.",
336};
337
338int VerifyKernelHeader(const uint8_t* firmware_key_blob,
339 const uint8_t* header_blob,
340 const int dev_mode,
341 int* firmware_algorithm,
342 int* kernel_algorithm,
343 int* kernel_header_len) {
344 int kernel_sign_key_len;
345 int firmware_sign_key_len;
346 uint16_t header_version, header_len;
347 uint16_t firmware_sign_algorithm, kernel_sign_algorithm;
348 uint8_t* header_checksum = NULL;
349
350 /* Base Offset for the header_checksum field. Actual offset is
351 * this + kernel_sign_key_len. */
352 int base_header_checksum_offset = (FIELD_LEN(header_version) +
353 FIELD_LEN(header_len) +
354 FIELD_LEN(firmware_sign_algorithm) +
355 FIELD_LEN(kernel_sign_algorithm) +
356 FIELD_LEN(kernel_key_version));
357
358 Memcpy(&header_version, header_blob, sizeof(header_version));
359 Memcpy(&header_len, header_blob + FIELD_LEN(header_version),
360 sizeof(header_len));
361 Memcpy(&firmware_sign_algorithm,
362 header_blob + (FIELD_LEN(header_version) +
363 FIELD_LEN(header_len)),
364 sizeof(firmware_sign_algorithm));
365 Memcpy(&kernel_sign_algorithm,
366 header_blob + (FIELD_LEN(header_version) +
367 FIELD_LEN(header_len) +
368 FIELD_LEN(firmware_sign_algorithm)),
369 sizeof(kernel_sign_algorithm));
370
371 /* TODO(gauravsh): Make this return two different error types depending
372 * on whether the firmware or kernel signing algorithm is invalid. */
373 if (firmware_sign_algorithm >= kNumAlgorithms)
374 return VERIFY_KERNEL_INVALID_ALGORITHM;
375 if (kernel_sign_algorithm >= kNumAlgorithms)
376 return VERIFY_KERNEL_INVALID_ALGORITHM;
377
378 *firmware_algorithm = (int) firmware_sign_algorithm;
379 *kernel_algorithm = (int) kernel_sign_algorithm;
380 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
381 firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm);
382
383
384 /* Verify if header len is correct? */
385 if (header_len != (base_header_checksum_offset +
386 kernel_sign_key_len +
387 FIELD_LEN(header_checksum))) {
388 fprintf(stderr, "VerifyKernelHeader: Header length mismatch\n");
389 return VERIFY_KERNEL_INVALID_IMAGE;
390 }
391 *kernel_header_len = (int) header_len;
392
393 /* Verify if the hash of the header is correct. */
394 header_checksum = DigestBuf(header_blob,
395 header_len - FIELD_LEN(header_checksum),
396 SHA512_DIGEST_ALGORITHM);
397 if (SafeMemcmp(header_checksum,
398 header_blob + (base_header_checksum_offset +
399 kernel_sign_key_len),
400 FIELD_LEN(header_checksum))) {
401 Free(header_checksum);
402 return VERIFY_KERNEL_INVALID_IMAGE;
403 }
404 Free(header_checksum);
405
406 /* Verify kernel key signature unless we are in dev mode. */
407 if (!dev_mode) {
408 if (!RSAVerifyBinary_f(firmware_key_blob, NULL, /* Key to use */
409 header_blob, /* Data to verify */
410 header_len, /* Length of data */
411 header_blob + header_len, /* Expected Signature */
412 firmware_sign_algorithm))
413 return VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
414 }
415 return 0;
416}
417
418int VerifyKernelConfig(RSAPublicKey* kernel_sign_key,
419 const uint8_t* config_blob,
420 int algorithm,
421 int* kernel_len) {
422 uint32_t len, config_len;
423 config_len = (FIELD_LEN(kernel_version) +
424 FIELD_LEN(options.version)+
425 FIELD_LEN(options.kernel_len) +
426 FIELD_LEN(options.kernel_load_addr) +
427 FIELD_LEN(options.kernel_entry_addr));
428 if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use */
429 config_blob, /* Data to verify */
430 config_len, /* Length of data */
431 config_blob + config_len, /* Expected Signature */
432 algorithm))
433 return VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
434
435 Memcpy(&len, config_blob + (FIELD_LEN(kernel_version)+
436 FIELD_LEN(options.version)),
437 sizeof(len));
438 *kernel_len = (int) len;
439 return 0;
440}
441
442int VerifyKernelData(RSAPublicKey* kernel_sign_key,
443 const uint8_t* kernel_data_start,
444 int kernel_len,
445 int algorithm) {
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800446 int signature_len = siglen_map[algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800447 if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use. */
448 kernel_data_start + signature_len, /* Data to
449 * verify */
450 kernel_len, /* Length of data. */
451 kernel_data_start, /* Expected Signature */
452 algorithm))
453 return VERIFY_KERNEL_SIGNATURE_FAILED;
454 return 0;
455}
456
457int VerifyKernel(const uint8_t* firmware_key_blob,
458 const uint8_t* kernel_blob,
459 const int dev_mode) {
460 int error_code;
461 int firmware_sign_algorithm; /* Firmware signing key algorithm. */
462 int kernel_sign_algorithm; /* Kernel Signing key algorithm. */
463 RSAPublicKey* kernel_sign_key;
464 int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len,
465 header_len, kernel_len;
466 const uint8_t* header_ptr; /* Pointer to header. */
467 const uint8_t* kernel_sign_key_ptr; /* Pointer to signing key. */
468 const uint8_t* config_ptr; /* Pointer to kernel config block. */
469 const uint8_t* kernel_ptr; /* Pointer to kernel signature/data. */
470
471 /* Note: All the offset calculations are based on struct FirmwareImage which
472 * is defined in include/firmware_image.h. */
473
474 /* Compare magic bytes. */
475 if (SafeMemcmp(kernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE))
476 return VERIFY_KERNEL_WRONG_MAGIC;
477 header_ptr = kernel_blob + KERNEL_MAGIC_SIZE;
478
479 /* Only continue if header verification succeeds. */
480 if ((error_code = VerifyKernelHeader(firmware_key_blob, header_ptr, dev_mode,
481 &firmware_sign_algorithm,
482 &kernel_sign_algorithm, &header_len))) {
483 fprintf(stderr, "VerifyKernel: Kernel header verification failed.\n");
484 return error_code; /* AKA jump to recovery. */
485 }
486 /* Parse signing key into RSAPublicKey structure since it is required multiple
487 * times. */
488 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
489 kernel_sign_key_ptr = header_ptr + (FIELD_LEN(header_version) +
490 FIELD_LEN(header_len) +
491 FIELD_LEN(firmware_sign_algorithm) +
492 FIELD_LEN(kernel_sign_algorithm) +
493 FIELD_LEN(kernel_key_version));
494 kernel_sign_key = RSAPublicKeyFromBuf(kernel_sign_key_ptr,
495 kernel_sign_key_len);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800496 kernel_signature_len = siglen_map[kernel_sign_algorithm];
497 kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800498
499 /* Only continue if config verification succeeds. */
500 config_ptr = (header_ptr + header_len + kernel_key_signature_len);
501 if ((error_code = VerifyKernelConfig(kernel_sign_key, config_ptr,
502 kernel_sign_algorithm,
503 &kernel_len)))
504 return error_code; /* AKA jump to recovery. */
505 /* Only continue if kernel data verification succeeds. */
506 kernel_ptr = (config_ptr +
507 FIELD_LEN(kernel_version) +
508 FIELD_LEN(options.version) +
509 FIELD_LEN(options.kernel_len) +
510 FIELD_LEN(options.kernel_entry_addr) +
511 FIELD_LEN(options.kernel_load_addr) +
512 kernel_signature_len);
513
514 if ((error_code = VerifyKernelData(kernel_sign_key, kernel_ptr, kernel_len,
515 kernel_sign_algorithm)))
516 return error_code; /* AKA jump to recovery. */
517 return 0; /* Success! */
518}
519
520int VerifyKernelImage(const RSAPublicKey* firmware_key,
521 const KernelImage* image,
522 const int dev_mode) {
523 RSAPublicKey* kernel_sign_key;
524 uint8_t* header_digest = NULL;
525 uint8_t* config_digest = NULL;
526 uint8_t* kernel_digest = NULL;
527 int kernel_sign_key_size;
528 int kernel_signature_size;
529 int error_code = 0;
530 DigestContext ctx;
531
532 if (!image)
533 return VERIFY_KERNEL_INVALID_IMAGE;
534
535 /* Verify kernel key signature on the key header if we
536 * are not in dev mode.
537 *
538 * TODO(gauravsh): Add additional sanity checks here for:
539 * 1) verifying the header length is correct.
540 * 2) header_checksum is correct.
541 */
542
543 if (image->firmware_sign_algorithm >= kNumAlgorithms)
544 return VERIFY_KERNEL_INVALID_ALGORITHM;
545 if (image->kernel_sign_algorithm >= kNumAlgorithms)
546 return VERIFY_KERNEL_INVALID_ALGORITHM;
547
548 if (!dev_mode) {
549 DigestInit(&ctx, image->firmware_sign_algorithm);
550 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
551 FIELD_LEN(header_version));
552 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
553 FIELD_LEN(header_len));
554 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
555 FIELD_LEN(firmware_sign_algorithm));
556 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
557 FIELD_LEN(kernel_sign_algorithm));
558 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
559 FIELD_LEN(kernel_key_version));
560 DigestUpdate(&ctx, image->kernel_sign_key,
561 RSAProcessedKeySize(image->kernel_sign_algorithm));
562 DigestUpdate(&ctx, image->header_checksum,
563 FIELD_LEN(header_checksum));
564 header_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800565 if (!RSAVerify(firmware_key, image->kernel_key_signature,
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800566 siglen_map[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800567 image->firmware_sign_algorithm,
568 header_digest)) {
569 fprintf(stderr, "VerifyKernelImage(): Key signature check failed.\n");
570 error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
571 goto verify_failure;
572 }
573 }
574
575 /* Get kernel signing key to verify the rest of the kernel. */
576 kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm);
577 kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
578 kernel_sign_key_size);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800579 kernel_signature_size = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800580
581 /* Verify kernel config signature. */
582 DigestInit(&ctx, image->kernel_sign_algorithm);
583 DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
584 FIELD_LEN(kernel_version));
585 DigestUpdate(&ctx, (uint8_t*) &image->options.version,
586 FIELD_LEN(options.version));
587 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_len,
588 FIELD_LEN(options.kernel_len));
589 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_load_addr,
590 FIELD_LEN(options.kernel_load_addr));
591 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_entry_addr,
592 FIELD_LEN(options.kernel_entry_addr));
593 config_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800594 if (!RSAVerify(kernel_sign_key, image->config_signature,
595 kernel_signature_size, image->kernel_sign_algorithm,
596 config_digest)) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800597 error_code = VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
598 goto verify_failure;
599 }
600
601 /* Verify firmware signature. */
602 kernel_digest = DigestBuf(image->kernel_data,
603 image->options.kernel_len,
604 image->kernel_sign_algorithm);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800605 if (!RSAVerify(kernel_sign_key, image->kernel_signature,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800606 kernel_signature_size, image->kernel_sign_algorithm,
607 kernel_digest)) {
608 error_code = VERIFY_KERNEL_SIGNATURE_FAILED;
609 goto verify_failure;
610 }
611
612verify_failure:
613 Free(kernel_digest);
614 Free(config_digest);
615 Free(header_digest);
616 return error_code;
617}
618
619const char* VerifyKernelErrorString(int error) {
620 return kVerifyKernelErrors[error];
621}
622
623int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800624 uint8_t* header_blob = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800625 uint8_t* signature;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800626 int signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800627 if (!image || !firmware_key_file)
628 return 0;
629 header_blob = GetKernelHeaderBlob(image);
630 if (!header_blob)
631 return 0;
632 if (!(signature = SignatureBuf(header_blob,
633 GetKernelHeaderLen(image),
634 firmware_key_file,
635 image->firmware_sign_algorithm))) {
636 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800637 return 0;
638 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800639 image->kernel_key_signature = Malloc(signature_len);
640 Memcpy(image->kernel_key_signature, signature, signature_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800641 Free(signature);
642 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800643 return 1;
644}
645
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800646int AddKernelSignature(KernelImage* image,
647 const char* kernel_signing_key_file) {
648 uint8_t* config_blob;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800649 uint8_t* config_signature;
650 uint8_t* kernel_signature;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800651 int signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800652
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800653 config_blob = GetKernelConfigBlob(image);
654 if (!(config_signature = SignatureBuf(config_blob,
655 GetKernelConfigLen(image),
656 kernel_signing_key_file,
657 image->kernel_sign_algorithm))) {
658 fprintf(stderr, "Could not compute signature on the kernel config.\n");
659 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800660 return 0;
661 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800662
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800663 image->config_signature = (uint8_t*) Malloc(signature_len);
664 Memcpy(image->config_signature, config_signature, signature_len);
665 Free(config_signature);
666
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800667 if (!(kernel_signature = SignatureBuf(image->kernel_data,
668 image->options.kernel_len,
669 kernel_signing_key_file,
670 image->kernel_sign_algorithm))) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800671 fprintf(stderr, "Could not compute signature on the kernel.\n");
672 return 0;
673 }
674 image->kernel_signature = (uint8_t*) Malloc(signature_len);
675 Memcpy(image->kernel_signature, kernel_signature, signature_len);
676 Free(kernel_signature);
677 return 1;
678}