blob: a1b943f83a556fecd489bdf24dca60eb24e582e9 [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);
407 return VERIFY_KERNEL_INVALID_IMAGE;
408 }
409 Free(header_checksum);
410
411 /* Verify kernel key signature unless we are in dev mode. */
412 if (!dev_mode) {
413 if (!RSAVerifyBinary_f(firmware_key_blob, NULL, /* Key to use */
414 header_blob, /* Data to verify */
415 header_len, /* Length of data */
416 header_blob + header_len, /* Expected Signature */
417 firmware_sign_algorithm))
418 return VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
419 }
420 return 0;
421}
422
423int VerifyKernelConfig(RSAPublicKey* kernel_sign_key,
424 const uint8_t* config_blob,
425 int algorithm,
426 int* kernel_len) {
427 uint32_t len, config_len;
Gaurav Shah4f393862010-03-12 18:13:24 -0800428 config_len = GetKernelConfigLen(NULL);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800429 if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use */
430 config_blob, /* Data to verify */
431 config_len, /* Length of data */
432 config_blob + config_len, /* Expected Signature */
433 algorithm))
434 return VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
435
Gaurav Shah4f393862010-03-12 18:13:24 -0800436 Memcpy(&len,
437 config_blob + (FIELD_LEN(kernel_version) + FIELD_LEN(options.version) +
438 FIELD_LEN(options.cmd_line)),
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800439 sizeof(len));
440 *kernel_len = (int) len;
441 return 0;
442}
443
444int VerifyKernelData(RSAPublicKey* kernel_sign_key,
445 const uint8_t* kernel_data_start,
446 int kernel_len,
447 int algorithm) {
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800448 int signature_len = siglen_map[algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800449 if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use. */
450 kernel_data_start + signature_len, /* Data to
451 * verify */
452 kernel_len, /* Length of data. */
453 kernel_data_start, /* Expected Signature */
454 algorithm))
455 return VERIFY_KERNEL_SIGNATURE_FAILED;
456 return 0;
457}
458
459int VerifyKernel(const uint8_t* firmware_key_blob,
460 const uint8_t* kernel_blob,
461 const int dev_mode) {
462 int error_code;
463 int firmware_sign_algorithm; /* Firmware signing key algorithm. */
464 int kernel_sign_algorithm; /* Kernel Signing key algorithm. */
465 RSAPublicKey* kernel_sign_key;
466 int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len,
467 header_len, kernel_len;
468 const uint8_t* header_ptr; /* Pointer to header. */
469 const uint8_t* kernel_sign_key_ptr; /* Pointer to signing key. */
470 const uint8_t* config_ptr; /* Pointer to kernel config block. */
471 const uint8_t* kernel_ptr; /* Pointer to kernel signature/data. */
472
473 /* Note: All the offset calculations are based on struct FirmwareImage which
474 * is defined in include/firmware_image.h. */
475
476 /* Compare magic bytes. */
477 if (SafeMemcmp(kernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE))
478 return VERIFY_KERNEL_WRONG_MAGIC;
479 header_ptr = kernel_blob + KERNEL_MAGIC_SIZE;
480
481 /* Only continue if header verification succeeds. */
482 if ((error_code = VerifyKernelHeader(firmware_key_blob, header_ptr, dev_mode,
483 &firmware_sign_algorithm,
484 &kernel_sign_algorithm, &header_len))) {
485 fprintf(stderr, "VerifyKernel: Kernel header verification failed.\n");
486 return error_code; /* AKA jump to recovery. */
487 }
488 /* Parse signing key into RSAPublicKey structure since it is required multiple
489 * times. */
490 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
491 kernel_sign_key_ptr = header_ptr + (FIELD_LEN(header_version) +
492 FIELD_LEN(header_len) +
493 FIELD_LEN(firmware_sign_algorithm) +
494 FIELD_LEN(kernel_sign_algorithm) +
495 FIELD_LEN(kernel_key_version));
496 kernel_sign_key = RSAPublicKeyFromBuf(kernel_sign_key_ptr,
497 kernel_sign_key_len);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800498 kernel_signature_len = siglen_map[kernel_sign_algorithm];
499 kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800500
501 /* Only continue if config verification succeeds. */
502 config_ptr = (header_ptr + header_len + kernel_key_signature_len);
503 if ((error_code = VerifyKernelConfig(kernel_sign_key, config_ptr,
504 kernel_sign_algorithm,
Gaurav Shah259de402010-03-12 17:42:03 -0800505 &kernel_len))) {
506 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800507 return error_code; /* AKA jump to recovery. */
Gaurav Shah259de402010-03-12 17:42:03 -0800508 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800509 /* Only continue if kernel data verification succeeds. */
510 kernel_ptr = (config_ptr +
Gaurav Shah4f393862010-03-12 18:13:24 -0800511 GetKernelConfigLen(NULL) + /* Skip config block/signature. */
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800512 kernel_signature_len);
513
514 if ((error_code = VerifyKernelData(kernel_sign_key, kernel_ptr, kernel_len,
Gaurav Shah259de402010-03-12 17:42:03 -0800515 kernel_sign_algorithm))) {
516 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800517 return error_code; /* AKA jump to recovery. */
Gaurav Shah259de402010-03-12 17:42:03 -0800518 }
519 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800520 return 0; /* Success! */
521}
522
523int VerifyKernelImage(const RSAPublicKey* firmware_key,
524 const KernelImage* image,
525 const int dev_mode) {
Gaurav Shah259de402010-03-12 17:42:03 -0800526 RSAPublicKey* kernel_sign_key = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800527 uint8_t* header_digest = NULL;
528 uint8_t* config_digest = NULL;
529 uint8_t* kernel_digest = NULL;
530 int kernel_sign_key_size;
531 int kernel_signature_size;
532 int error_code = 0;
533 DigestContext ctx;
534
535 if (!image)
536 return VERIFY_KERNEL_INVALID_IMAGE;
537
538 /* Verify kernel key signature on the key header if we
539 * are not in dev mode.
540 *
541 * TODO(gauravsh): Add additional sanity checks here for:
542 * 1) verifying the header length is correct.
543 * 2) header_checksum is correct.
544 */
545
546 if (image->firmware_sign_algorithm >= kNumAlgorithms)
547 return VERIFY_KERNEL_INVALID_ALGORITHM;
548 if (image->kernel_sign_algorithm >= kNumAlgorithms)
549 return VERIFY_KERNEL_INVALID_ALGORITHM;
550
551 if (!dev_mode) {
552 DigestInit(&ctx, image->firmware_sign_algorithm);
553 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
554 FIELD_LEN(header_version));
555 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
556 FIELD_LEN(header_len));
557 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
558 FIELD_LEN(firmware_sign_algorithm));
559 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
560 FIELD_LEN(kernel_sign_algorithm));
561 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
562 FIELD_LEN(kernel_key_version));
563 DigestUpdate(&ctx, image->kernel_sign_key,
564 RSAProcessedKeySize(image->kernel_sign_algorithm));
565 DigestUpdate(&ctx, image->header_checksum,
566 FIELD_LEN(header_checksum));
567 header_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800568 if (!RSAVerify(firmware_key, image->kernel_key_signature,
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800569 siglen_map[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800570 image->firmware_sign_algorithm,
571 header_digest)) {
572 fprintf(stderr, "VerifyKernelImage(): Key signature check failed.\n");
573 error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
574 goto verify_failure;
575 }
576 }
577
578 /* Get kernel signing key to verify the rest of the kernel. */
579 kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm);
580 kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
581 kernel_sign_key_size);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800582 kernel_signature_size = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800583
584 /* Verify kernel config signature. */
585 DigestInit(&ctx, image->kernel_sign_algorithm);
586 DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
587 FIELD_LEN(kernel_version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800588 DigestUpdate(&ctx, (uint8_t*) image->options.version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800589 FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800590 DigestUpdate(&ctx, (uint8_t*) image->options.cmd_line,
591 FIELD_LEN(options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800592 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_len,
593 FIELD_LEN(options.kernel_len));
594 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_load_addr,
595 FIELD_LEN(options.kernel_load_addr));
596 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_entry_addr,
597 FIELD_LEN(options.kernel_entry_addr));
598 config_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800599 if (!RSAVerify(kernel_sign_key, image->config_signature,
600 kernel_signature_size, image->kernel_sign_algorithm,
601 config_digest)) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800602 error_code = VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
603 goto verify_failure;
604 }
605
606 /* Verify firmware signature. */
607 kernel_digest = DigestBuf(image->kernel_data,
608 image->options.kernel_len,
609 image->kernel_sign_algorithm);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800610 if (!RSAVerify(kernel_sign_key, image->kernel_signature,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800611 kernel_signature_size, image->kernel_sign_algorithm,
612 kernel_digest)) {
613 error_code = VERIFY_KERNEL_SIGNATURE_FAILED;
614 goto verify_failure;
615 }
616
617verify_failure:
Gaurav Shah259de402010-03-12 17:42:03 -0800618 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800619 Free(kernel_digest);
620 Free(config_digest);
621 Free(header_digest);
622 return error_code;
623}
624
625const char* VerifyKernelErrorString(int error) {
626 return kVerifyKernelErrors[error];
627}
628
629int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800630 uint8_t* header_blob = NULL;
Gaurav Shah259de402010-03-12 17:42:03 -0800631 uint8_t* signature = NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800632 int signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800633 if (!image || !firmware_key_file)
634 return 0;
635 header_blob = GetKernelHeaderBlob(image);
636 if (!header_blob)
637 return 0;
638 if (!(signature = SignatureBuf(header_blob,
639 GetKernelHeaderLen(image),
640 firmware_key_file,
641 image->firmware_sign_algorithm))) {
642 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800643 return 0;
644 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800645 image->kernel_key_signature = Malloc(signature_len);
646 Memcpy(image->kernel_key_signature, signature, signature_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800647 Free(signature);
648 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800649 return 1;
650}
651
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800652int AddKernelSignature(KernelImage* image,
653 const char* kernel_signing_key_file) {
Gaurav Shah259de402010-03-12 17:42:03 -0800654 uint8_t* config_blob = NULL;
655 uint8_t* config_signature = NULL;
656 uint8_t* kernel_signature = NULL;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800657 int signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800658
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800659 config_blob = GetKernelConfigBlob(image);
660 if (!(config_signature = SignatureBuf(config_blob,
661 GetKernelConfigLen(image),
662 kernel_signing_key_file,
663 image->kernel_sign_algorithm))) {
664 fprintf(stderr, "Could not compute signature on the kernel config.\n");
665 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800666 return 0;
667 }
Gaurav Shah259de402010-03-12 17:42:03 -0800668 Free(config_blob);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800669
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800670 image->config_signature = (uint8_t*) Malloc(signature_len);
671 Memcpy(image->config_signature, config_signature, signature_len);
672 Free(config_signature);
673
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800674 if (!(kernel_signature = SignatureBuf(image->kernel_data,
675 image->options.kernel_len,
676 kernel_signing_key_file,
677 image->kernel_sign_algorithm))) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800678 fprintf(stderr, "Could not compute signature on the kernel.\n");
679 return 0;
680 }
681 image->kernel_signature = (uint8_t*) Malloc(signature_len);
682 Memcpy(image->kernel_signature, kernel_signature, signature_len);
683 Free(kernel_signature);
684 return 1;
685}