blob: 8201137a4f32fb2c53c48c4bc38eb36bd7ef8b81 [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,
Gaurav Shah259de402010-03-12 17:42:03 -0800503 &kernel_len))) {
504 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800505 return error_code; /* AKA jump to recovery. */
Gaurav Shah259de402010-03-12 17:42:03 -0800506 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800507 /* Only continue if kernel data verification succeeds. */
508 kernel_ptr = (config_ptr +
509 FIELD_LEN(kernel_version) +
510 FIELD_LEN(options.version) +
511 FIELD_LEN(options.kernel_len) +
512 FIELD_LEN(options.kernel_entry_addr) +
513 FIELD_LEN(options.kernel_load_addr) +
514 kernel_signature_len);
515
516 if ((error_code = VerifyKernelData(kernel_sign_key, kernel_ptr, kernel_len,
Gaurav Shah259de402010-03-12 17:42:03 -0800517 kernel_sign_algorithm))) {
518 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800519 return error_code; /* AKA jump to recovery. */
Gaurav Shah259de402010-03-12 17:42:03 -0800520 }
521 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800522 return 0; /* Success! */
523}
524
525int VerifyKernelImage(const RSAPublicKey* firmware_key,
526 const KernelImage* image,
527 const int dev_mode) {
Gaurav Shah259de402010-03-12 17:42:03 -0800528 RSAPublicKey* kernel_sign_key = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800529 uint8_t* header_digest = NULL;
530 uint8_t* config_digest = NULL;
531 uint8_t* kernel_digest = NULL;
532 int kernel_sign_key_size;
533 int kernel_signature_size;
534 int error_code = 0;
535 DigestContext ctx;
536
537 if (!image)
538 return VERIFY_KERNEL_INVALID_IMAGE;
539
540 /* Verify kernel key signature on the key header if we
541 * are not in dev mode.
542 *
543 * TODO(gauravsh): Add additional sanity checks here for:
544 * 1) verifying the header length is correct.
545 * 2) header_checksum is correct.
546 */
547
548 if (image->firmware_sign_algorithm >= kNumAlgorithms)
549 return VERIFY_KERNEL_INVALID_ALGORITHM;
550 if (image->kernel_sign_algorithm >= kNumAlgorithms)
551 return VERIFY_KERNEL_INVALID_ALGORITHM;
552
553 if (!dev_mode) {
554 DigestInit(&ctx, image->firmware_sign_algorithm);
555 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
556 FIELD_LEN(header_version));
557 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
558 FIELD_LEN(header_len));
559 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
560 FIELD_LEN(firmware_sign_algorithm));
561 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
562 FIELD_LEN(kernel_sign_algorithm));
563 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
564 FIELD_LEN(kernel_key_version));
565 DigestUpdate(&ctx, image->kernel_sign_key,
566 RSAProcessedKeySize(image->kernel_sign_algorithm));
567 DigestUpdate(&ctx, image->header_checksum,
568 FIELD_LEN(header_checksum));
569 header_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800570 if (!RSAVerify(firmware_key, image->kernel_key_signature,
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800571 siglen_map[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800572 image->firmware_sign_algorithm,
573 header_digest)) {
574 fprintf(stderr, "VerifyKernelImage(): Key signature check failed.\n");
575 error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
576 goto verify_failure;
577 }
578 }
579
580 /* Get kernel signing key to verify the rest of the kernel. */
581 kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm);
582 kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
583 kernel_sign_key_size);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800584 kernel_signature_size = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800585
586 /* Verify kernel config signature. */
587 DigestInit(&ctx, image->kernel_sign_algorithm);
588 DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
589 FIELD_LEN(kernel_version));
590 DigestUpdate(&ctx, (uint8_t*) &image->options.version,
591 FIELD_LEN(options.version));
592 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}