blob: 81aa06fdaead884cd6b515b60d7edd393136b593 [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));
Gaurav Shah4f393862010-03-12 18:13:24 -0800135 StatefulMemcpy(&st, &image->options.cmd_line, FIELD_LEN(options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800136 StatefulMemcpy(&st, &image->options.kernel_len,
137 FIELD_LEN(options.kernel_len));
138 StatefulMemcpy(&st, &image->options.kernel_load_addr,
139 FIELD_LEN(options.kernel_load_addr));
140 StatefulMemcpy(&st, &image->options.kernel_entry_addr,
141 FIELD_LEN(options.kernel_entry_addr));
142
143 /* Read kernel config signature. */
144 image->config_signature = (uint8_t*) Malloc(kernel_signature_len);
145 StatefulMemcpy(&st, image->config_signature, kernel_signature_len);
146
147 image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len);
148 StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len);
149
150 image->kernel_data = (uint8_t*) Malloc(image->options.kernel_len);
151 StatefulMemcpy(&st, image->kernel_data, image->options.kernel_len);
152
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800153 if(st.remaining_len != 0) { /* Overrun or underrun. */
154 Free(kernel_buf);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800155 return NULL;
156 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800157 Free(kernel_buf);
158 return image;
159}
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800160
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800161int GetKernelHeaderLen(const KernelImage* image) {
162 return (FIELD_LEN(header_version) + FIELD_LEN(header_len) +
163 FIELD_LEN(firmware_sign_algorithm) +
164 FIELD_LEN(kernel_sign_algorithm) + FIELD_LEN(kernel_key_version) +
165 RSAProcessedKeySize(image->kernel_sign_algorithm) +
166 FIELD_LEN(header_checksum));
167}
168
169uint8_t* GetKernelHeaderBlob(const KernelImage* image) {
170 uint8_t* header_blob = NULL;
171 MemcpyState st;
172
173 header_blob = (uint8_t*) Malloc(GetKernelHeaderLen(image));
174 st.remaining_len = GetKernelHeaderLen(image);
175 st.remaining_buf = header_blob;
176
177 StatefulMemcpy_r(&st, &image->header_version, FIELD_LEN(header_version));
178 StatefulMemcpy_r(&st, &image->header_len, FIELD_LEN(header_len));
179 StatefulMemcpy_r(&st, &image->firmware_sign_algorithm,
180 FIELD_LEN(firmware_sign_algorithm));
181 StatefulMemcpy_r(&st, &image->kernel_sign_algorithm,
182 FIELD_LEN(kernel_sign_algorithm));
183 StatefulMemcpy_r(&st, &image->kernel_key_version,
184 FIELD_LEN(kernel_key_version));
185 StatefulMemcpy_r(&st, image->kernel_sign_key,
186 RSAProcessedKeySize(image->kernel_sign_algorithm));
187 StatefulMemcpy_r(&st, &image->header_checksum, FIELD_LEN(header_checksum));
188
189 if (st.remaining_len != 0) { /* Underrun or Overrun. */
190 Free(header_blob);
191 return NULL;
192 }
193 return header_blob;
194}
195
196int GetKernelConfigLen(const KernelImage* image) {
Gaurav Shah4f393862010-03-12 18:13:24 -0800197 return (FIELD_LEN(kernel_version) +
198 FIELD_LEN(options.version) + FIELD_LEN(options.cmd_line) +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800199 FIELD_LEN(options.kernel_len) + FIELD_LEN(options.kernel_load_addr) +
200 FIELD_LEN(options.kernel_entry_addr));
201}
202
203uint8_t* GetKernelConfigBlob(const KernelImage* image) {
204 uint8_t* config_blob = NULL;
205 MemcpyState st;
206
207 config_blob = (uint8_t*) Malloc(GetKernelConfigLen(image));
208 st.remaining_len = GetKernelConfigLen(image);
209 st.remaining_buf = config_blob;
210
211 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
212 StatefulMemcpy_r(&st, image->options.version, FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800213 StatefulMemcpy_r(&st, image->options.cmd_line, FIELD_LEN(options.cmd_line));
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800214 StatefulMemcpy_r(&st, &image->options.kernel_len,
215 FIELD_LEN(options.kernel_len));
216 StatefulMemcpy_r(&st, &image->options.kernel_load_addr,
217 FIELD_LEN(options.kernel_load_addr));
218 StatefulMemcpy_r(&st, &image->options.kernel_entry_addr,
219 FIELD_LEN(options.kernel_entry_addr));
220 if (st.remaining_len != 0) { /* Overrun or Underrun. */
221 Free(config_blob);
222 return NULL;
223 }
224 return config_blob;
225}
226
227uint8_t* GetKernelBlob(const KernelImage* image, int* blob_len) {
228 int kernel_key_signature_len;
229 int kernel_signature_len;
230 uint8_t* kernel_blob = NULL;
231 uint8_t* header_blob = NULL;
232 uint8_t* config_blob = NULL;
233 MemcpyState st;
234
235 if (!image)
236 return NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800237 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
238 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800239 *blob_len = (FIELD_LEN(magic) +
240 GetKernelHeaderLen(image) +
241 kernel_key_signature_len +
242 GetKernelConfigLen(image) +
243 2 * kernel_signature_len +
244 image->options.kernel_len);
245 kernel_blob = (uint8_t*) Malloc(*blob_len);
246 st.remaining_len = *blob_len;
247 st.remaining_buf = kernel_blob;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800248
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800249 header_blob = GetKernelHeaderBlob(image);
250 config_blob = GetKernelConfigBlob(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800251
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800252 StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic));
253 StatefulMemcpy_r(&st, header_blob, GetKernelHeaderLen(image));
254 StatefulMemcpy_r(&st, image->kernel_key_signature, kernel_key_signature_len);
255 StatefulMemcpy_r(&st, config_blob, GetKernelConfigLen(image));
256 StatefulMemcpy_r(&st, image->config_signature, kernel_signature_len);
257 StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len);
258 StatefulMemcpy_r(&st, image->kernel_data, image->options.kernel_len);
259
260 Free(config_blob);
261 Free(header_blob);
262
263 if (st.remaining_len != 0) { /* Underrun or Overrun. */
264 Free(kernel_blob);
265 return NULL;
266 }
267 return kernel_blob;
268}
269
270int WriteKernelImage(const char* input_file,
271 const KernelImage* image) {
272 int fd;
273 uint8_t* kernel_blob;
274 int blob_len;
275
276 if (!image)
277 return 0;
278 if (-1 == (fd = creat(input_file, S_IRWXU))) {
279 fprintf(stderr, "Couldn't open file for writing kernel image: %s\n",
280 input_file);
281 return 0;
282 }
283 kernel_blob = GetKernelBlob(image, &blob_len);
284 if (!kernel_blob) {
285 fprintf(stderr, "Couldn't create kernel blob from KernelImage.\n");
286 return 0;
287 }
288 if (blob_len != write(fd, kernel_blob, blob_len)) {
289 fprintf(stderr, "Couldn't write Kernel Image to file: %s\n",
290 input_file);
291
292 Free(kernel_blob);
293 close(fd);
294 return 0;
295 }
296 Free(kernel_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800297 close(fd);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800298 return 1;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800299}
300
301void PrintKernelImage(const KernelImage* image) {
302 if (!image)
303 return;
304
305 /* Print header. */
306 printf("Header Length = %d\n"
307 "Firmware Signing key algorithm id = %d\n"
308 "Kernel Signing key algorithm id = %d\n"
309 "Kernel Signature Algorithm = %s\n"
310 "Kernel Key Version = %d\n\n",
311 image->header_len,
312 image->firmware_sign_algorithm,
313 image->kernel_sign_algorithm,
314 algo_strings[image->kernel_sign_algorithm],
315 image->kernel_key_version);
316 /* TODO(gauravsh): Output hash and key signature here? */
317 /* Print preamble. */
318 printf("Kernel Version = %d\n"
319 "Kernel Config Version = %d.%d\n"
Gaurav Shah4f393862010-03-12 18:13:24 -0800320 "Kernel Config command line = %s\n"
Gaurav Shah456678b2010-03-10 18:38:45 -0800321 "kernel Length = %" PRId64 "\n"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800322 "Kernel Load Address = %" PRId64 "\n"
323 "Kernel Entry Address = %" PRId64 "\n\n",
324 image->kernel_version,
325 image->options.version[0], image->options.version[1],
Gaurav Shah4f393862010-03-12 18:13:24 -0800326 image->options.cmd_line,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800327 image->options.kernel_len,
328 image->options.kernel_load_addr,
329 image->options.kernel_entry_addr);
330 /* TODO(gauravsh): Output kernel signature here? */
331}
332
333char* kVerifyKernelErrors[VERIFY_KERNEL_MAX] = {
334 "Success.",
335 "Invalid Image.",
336 "Kernel Key Signature Failed.",
337 "Invalid Kernel Verification Algorithm.",
338 "Config Signature Failed.",
339 "Kernel Signature Failed.",
340 "Wrong Kernel Magic.",
341};
342
343int VerifyKernelHeader(const uint8_t* firmware_key_blob,
344 const uint8_t* header_blob,
345 const int dev_mode,
346 int* firmware_algorithm,
347 int* kernel_algorithm,
348 int* kernel_header_len) {
349 int kernel_sign_key_len;
350 int firmware_sign_key_len;
351 uint16_t header_version, header_len;
352 uint16_t firmware_sign_algorithm, kernel_sign_algorithm;
353 uint8_t* header_checksum = NULL;
354
355 /* Base Offset for the header_checksum field. Actual offset is
356 * this + kernel_sign_key_len. */
357 int base_header_checksum_offset = (FIELD_LEN(header_version) +
358 FIELD_LEN(header_len) +
359 FIELD_LEN(firmware_sign_algorithm) +
360 FIELD_LEN(kernel_sign_algorithm) +
361 FIELD_LEN(kernel_key_version));
362
363 Memcpy(&header_version, header_blob, sizeof(header_version));
364 Memcpy(&header_len, header_blob + FIELD_LEN(header_version),
365 sizeof(header_len));
366 Memcpy(&firmware_sign_algorithm,
367 header_blob + (FIELD_LEN(header_version) +
368 FIELD_LEN(header_len)),
369 sizeof(firmware_sign_algorithm));
370 Memcpy(&kernel_sign_algorithm,
371 header_blob + (FIELD_LEN(header_version) +
372 FIELD_LEN(header_len) +
373 FIELD_LEN(firmware_sign_algorithm)),
374 sizeof(kernel_sign_algorithm));
375
376 /* TODO(gauravsh): Make this return two different error types depending
377 * on whether the firmware or kernel signing algorithm is invalid. */
378 if (firmware_sign_algorithm >= kNumAlgorithms)
379 return VERIFY_KERNEL_INVALID_ALGORITHM;
380 if (kernel_sign_algorithm >= kNumAlgorithms)
381 return VERIFY_KERNEL_INVALID_ALGORITHM;
382
383 *firmware_algorithm = (int) firmware_sign_algorithm;
384 *kernel_algorithm = (int) kernel_sign_algorithm;
385 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
386 firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm);
387
388
389 /* Verify if header len is correct? */
390 if (header_len != (base_header_checksum_offset +
391 kernel_sign_key_len +
392 FIELD_LEN(header_checksum))) {
393 fprintf(stderr, "VerifyKernelHeader: Header length mismatch\n");
394 return VERIFY_KERNEL_INVALID_IMAGE;
395 }
396 *kernel_header_len = (int) header_len;
397
398 /* Verify if the hash of the header is correct. */
399 header_checksum = DigestBuf(header_blob,
400 header_len - FIELD_LEN(header_checksum),
401 SHA512_DIGEST_ALGORITHM);
402 if (SafeMemcmp(header_checksum,
403 header_blob + (base_header_checksum_offset +
404 kernel_sign_key_len),
405 FIELD_LEN(header_checksum))) {
406 Free(header_checksum);
Gaurav Shahccaa90f2010-03-17 20:40:23 -0700407 fprintf(stderr, "VerifyKernelHeader: Invalid header hash\n");
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800408 return VERIFY_KERNEL_INVALID_IMAGE;
409 }
410 Free(header_checksum);
411
412 /* Verify kernel key signature unless we are in dev mode. */
413 if (!dev_mode) {
414 if (!RSAVerifyBinary_f(firmware_key_blob, NULL, /* Key to use */
415 header_blob, /* Data to verify */
416 header_len, /* Length of data */
417 header_blob + header_len, /* Expected Signature */
418 firmware_sign_algorithm))
419 return VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
420 }
421 return 0;
422}
423
424int VerifyKernelConfig(RSAPublicKey* kernel_sign_key,
425 const uint8_t* config_blob,
426 int algorithm,
427 int* kernel_len) {
428 uint32_t len, config_len;
Gaurav Shah4f393862010-03-12 18:13:24 -0800429 config_len = GetKernelConfigLen(NULL);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800430 if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use */
431 config_blob, /* Data to verify */
432 config_len, /* Length of data */
433 config_blob + config_len, /* Expected Signature */
434 algorithm))
435 return VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
436
Gaurav Shah4f393862010-03-12 18:13:24 -0800437 Memcpy(&len,
438 config_blob + (FIELD_LEN(kernel_version) + FIELD_LEN(options.version) +
439 FIELD_LEN(options.cmd_line)),
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800440 sizeof(len));
441 *kernel_len = (int) len;
442 return 0;
443}
444
445int VerifyKernelData(RSAPublicKey* kernel_sign_key,
446 const uint8_t* kernel_data_start,
447 int kernel_len,
448 int algorithm) {
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800449 int signature_len = siglen_map[algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800450 if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use. */
451 kernel_data_start + signature_len, /* Data to
452 * verify */
453 kernel_len, /* Length of data. */
454 kernel_data_start, /* Expected Signature */
455 algorithm))
456 return VERIFY_KERNEL_SIGNATURE_FAILED;
457 return 0;
458}
459
460int VerifyKernel(const uint8_t* firmware_key_blob,
461 const uint8_t* kernel_blob,
462 const int dev_mode) {
463 int error_code;
464 int firmware_sign_algorithm; /* Firmware signing key algorithm. */
465 int kernel_sign_algorithm; /* Kernel Signing key algorithm. */
466 RSAPublicKey* kernel_sign_key;
467 int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len,
468 header_len, kernel_len;
469 const uint8_t* header_ptr; /* Pointer to header. */
470 const uint8_t* kernel_sign_key_ptr; /* Pointer to signing key. */
471 const uint8_t* config_ptr; /* Pointer to kernel config block. */
472 const uint8_t* kernel_ptr; /* Pointer to kernel signature/data. */
473
474 /* Note: All the offset calculations are based on struct FirmwareImage which
475 * is defined in include/firmware_image.h. */
476
477 /* Compare magic bytes. */
478 if (SafeMemcmp(kernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE))
479 return VERIFY_KERNEL_WRONG_MAGIC;
480 header_ptr = kernel_blob + KERNEL_MAGIC_SIZE;
481
482 /* Only continue if header verification succeeds. */
483 if ((error_code = VerifyKernelHeader(firmware_key_blob, header_ptr, dev_mode,
484 &firmware_sign_algorithm,
485 &kernel_sign_algorithm, &header_len))) {
486 fprintf(stderr, "VerifyKernel: Kernel header verification failed.\n");
487 return error_code; /* AKA jump to recovery. */
488 }
489 /* Parse signing key into RSAPublicKey structure since it is required multiple
490 * times. */
491 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
492 kernel_sign_key_ptr = header_ptr + (FIELD_LEN(header_version) +
493 FIELD_LEN(header_len) +
494 FIELD_LEN(firmware_sign_algorithm) +
495 FIELD_LEN(kernel_sign_algorithm) +
496 FIELD_LEN(kernel_key_version));
497 kernel_sign_key = RSAPublicKeyFromBuf(kernel_sign_key_ptr,
498 kernel_sign_key_len);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800499 kernel_signature_len = siglen_map[kernel_sign_algorithm];
500 kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800501
502 /* Only continue if config verification succeeds. */
503 config_ptr = (header_ptr + header_len + kernel_key_signature_len);
504 if ((error_code = VerifyKernelConfig(kernel_sign_key, config_ptr,
505 kernel_sign_algorithm,
Gaurav Shah259de402010-03-12 17:42:03 -0800506 &kernel_len))) {
507 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800508 return error_code; /* AKA jump to recovery. */
Gaurav Shah259de402010-03-12 17:42:03 -0800509 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800510 /* Only continue if kernel data verification succeeds. */
511 kernel_ptr = (config_ptr +
Gaurav Shah4f393862010-03-12 18:13:24 -0800512 GetKernelConfigLen(NULL) + /* Skip config block/signature. */
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800513 kernel_signature_len);
514
515 if ((error_code = VerifyKernelData(kernel_sign_key, kernel_ptr, kernel_len,
Gaurav Shah259de402010-03-12 17:42:03 -0800516 kernel_sign_algorithm))) {
517 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800518 return error_code; /* AKA jump to recovery. */
Gaurav Shah259de402010-03-12 17:42:03 -0800519 }
520 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800521 return 0; /* Success! */
522}
523
524int VerifyKernelImage(const RSAPublicKey* firmware_key,
525 const KernelImage* image,
526 const int dev_mode) {
Gaurav Shah259de402010-03-12 17:42:03 -0800527 RSAPublicKey* kernel_sign_key = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800528 uint8_t* header_digest = NULL;
529 uint8_t* config_digest = NULL;
530 uint8_t* kernel_digest = NULL;
531 int kernel_sign_key_size;
532 int kernel_signature_size;
533 int error_code = 0;
534 DigestContext ctx;
535
536 if (!image)
537 return VERIFY_KERNEL_INVALID_IMAGE;
538
539 /* Verify kernel key signature on the key header if we
540 * are not in dev mode.
541 *
542 * TODO(gauravsh): Add additional sanity checks here for:
543 * 1) verifying the header length is correct.
544 * 2) header_checksum is correct.
545 */
546
547 if (image->firmware_sign_algorithm >= kNumAlgorithms)
548 return VERIFY_KERNEL_INVALID_ALGORITHM;
549 if (image->kernel_sign_algorithm >= kNumAlgorithms)
550 return VERIFY_KERNEL_INVALID_ALGORITHM;
551
552 if (!dev_mode) {
553 DigestInit(&ctx, image->firmware_sign_algorithm);
554 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
555 FIELD_LEN(header_version));
556 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
557 FIELD_LEN(header_len));
558 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
559 FIELD_LEN(firmware_sign_algorithm));
560 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
561 FIELD_LEN(kernel_sign_algorithm));
562 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
563 FIELD_LEN(kernel_key_version));
564 DigestUpdate(&ctx, image->kernel_sign_key,
565 RSAProcessedKeySize(image->kernel_sign_algorithm));
566 DigestUpdate(&ctx, image->header_checksum,
567 FIELD_LEN(header_checksum));
568 header_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800569 if (!RSAVerify(firmware_key, image->kernel_key_signature,
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800570 siglen_map[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800571 image->firmware_sign_algorithm,
572 header_digest)) {
573 fprintf(stderr, "VerifyKernelImage(): Key signature check failed.\n");
574 error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
575 goto verify_failure;
576 }
577 }
578
579 /* Get kernel signing key to verify the rest of the kernel. */
580 kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm);
581 kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
582 kernel_sign_key_size);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800583 kernel_signature_size = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800584
585 /* Verify kernel config signature. */
586 DigestInit(&ctx, image->kernel_sign_algorithm);
587 DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
588 FIELD_LEN(kernel_version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800589 DigestUpdate(&ctx, (uint8_t*) image->options.version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800590 FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800591 DigestUpdate(&ctx, (uint8_t*) image->options.cmd_line,
592 FIELD_LEN(options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800593 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_len,
594 FIELD_LEN(options.kernel_len));
595 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_load_addr,
596 FIELD_LEN(options.kernel_load_addr));
597 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_entry_addr,
598 FIELD_LEN(options.kernel_entry_addr));
599 config_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800600 if (!RSAVerify(kernel_sign_key, image->config_signature,
601 kernel_signature_size, image->kernel_sign_algorithm,
602 config_digest)) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800603 error_code = VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
604 goto verify_failure;
605 }
606
607 /* Verify firmware signature. */
608 kernel_digest = DigestBuf(image->kernel_data,
609 image->options.kernel_len,
610 image->kernel_sign_algorithm);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800611 if (!RSAVerify(kernel_sign_key, image->kernel_signature,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800612 kernel_signature_size, image->kernel_sign_algorithm,
613 kernel_digest)) {
614 error_code = VERIFY_KERNEL_SIGNATURE_FAILED;
615 goto verify_failure;
616 }
617
618verify_failure:
Gaurav Shah259de402010-03-12 17:42:03 -0800619 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800620 Free(kernel_digest);
621 Free(config_digest);
622 Free(header_digest);
623 return error_code;
624}
625
626const char* VerifyKernelErrorString(int error) {
627 return kVerifyKernelErrors[error];
628}
629
630int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800631 uint8_t* header_blob = NULL;
Gaurav Shah259de402010-03-12 17:42:03 -0800632 uint8_t* signature = NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800633 int signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800634 if (!image || !firmware_key_file)
635 return 0;
636 header_blob = GetKernelHeaderBlob(image);
637 if (!header_blob)
638 return 0;
639 if (!(signature = SignatureBuf(header_blob,
640 GetKernelHeaderLen(image),
641 firmware_key_file,
642 image->firmware_sign_algorithm))) {
643 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800644 return 0;
645 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800646 image->kernel_key_signature = Malloc(signature_len);
647 Memcpy(image->kernel_key_signature, signature, signature_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800648 Free(signature);
649 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800650 return 1;
651}
652
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800653int AddKernelSignature(KernelImage* image,
654 const char* kernel_signing_key_file) {
Gaurav Shah259de402010-03-12 17:42:03 -0800655 uint8_t* config_blob = NULL;
656 uint8_t* config_signature = NULL;
657 uint8_t* kernel_signature = NULL;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800658 int signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800659
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800660 config_blob = GetKernelConfigBlob(image);
661 if (!(config_signature = SignatureBuf(config_blob,
662 GetKernelConfigLen(image),
663 kernel_signing_key_file,
664 image->kernel_sign_algorithm))) {
665 fprintf(stderr, "Could not compute signature on the kernel config.\n");
666 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800667 return 0;
668 }
Gaurav Shah259de402010-03-12 17:42:03 -0800669 Free(config_blob);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800670
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800671 image->config_signature = (uint8_t*) Malloc(signature_len);
672 Memcpy(image->config_signature, config_signature, signature_len);
673 Free(config_signature);
674
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800675 if (!(kernel_signature = SignatureBuf(image->kernel_data,
676 image->options.kernel_len,
677 kernel_signing_key_file,
678 image->kernel_sign_algorithm))) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800679 fprintf(stderr, "Could not compute signature on the kernel.\n");
680 return 0;
681 }
682 image->kernel_signature = (uint8_t*) Malloc(signature_len);
683 Memcpy(image->kernel_signature, kernel_signature, signature_len);
684 Free(kernel_signature);
685 return 1;
686}