blob: a6b02bcd3700060269bfd4a9da1c2f2ce7e097a5 [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;
Gaurav Shah528a2c12010-03-18 13:10:10 -070059 uint8_t header_checksum[FIELD_LEN(header_checksum)];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080060 MemcpyState st;
61 KernelImage* image = KernelImageNew();
62
63 if (!image)
64 return NULL;
65
66 kernel_buf = BufferFromFile(input_file, &file_size);
67 image_len = file_size;
68
69 st.remaining_len = image_len;
70 st.remaining_buf = kernel_buf;
71
72 /* Read and compare magic bytes. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080073 StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080074
75 if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) {
76 fprintf(stderr, "Wrong Kernel Magic.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -080077 Free(kernel_buf);
78 return NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080079 }
80 StatefulMemcpy(&st, &image->header_version, FIELD_LEN(header_version));
81 StatefulMemcpy(&st, &image->header_len, FIELD_LEN(header_len));
82 StatefulMemcpy(&st, &image->firmware_sign_algorithm,
83 FIELD_LEN(firmware_sign_algorithm));
84 StatefulMemcpy(&st, &image->kernel_sign_algorithm,
85 FIELD_LEN(kernel_sign_algorithm));
86
87 /* Valid Kernel Key signing algorithm. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080088 if (image->firmware_sign_algorithm >= kNumAlgorithms) {
89 Free(kernel_buf);
90 return NULL;
91 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080092
93 /* Valid Kernel Signing Algorithm? */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080094 if (image->kernel_sign_algorithm >= kNumAlgorithms) {
95 Free(kernel_buf);
96 return NULL;
97 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080098
99 /* Compute size of pre-processed RSA public keys and signatures. */
100 firmware_sign_key_len = RSAProcessedKeySize(image->firmware_sign_algorithm);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800101 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800102 kernel_sign_key_len = RSAProcessedKeySize(image->kernel_sign_algorithm);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800103 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800104
105 /* Check whether key header length is correct. */
Gaurav Shah528a2c12010-03-18 13:10:10 -0700106 header_len = GetKernelHeaderLen(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800107 if (header_len != image->header_len) {
108 fprintf(stderr, "Header length mismatch. Got: %d, Expected: %d\n",
109 image->header_len, header_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800110 Free(kernel_buf);
111 return NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800112 }
113
114 /* Read pre-processed public half of the kernel signing key. */
115 StatefulMemcpy(&st, &image->kernel_key_version,
116 FIELD_LEN(kernel_key_version));
117 image->kernel_sign_key = (uint8_t*) Malloc(kernel_sign_key_len);
118 StatefulMemcpy(&st, image->kernel_sign_key, kernel_sign_key_len);
119 StatefulMemcpy(&st, image->header_checksum, FIELD_LEN(header_checksum));
120
Gaurav Shah528a2c12010-03-18 13:10:10 -0700121 /* Check whether the header checksum matches. */
122 CalculateKernelHeaderChecksum(image, header_checksum);
123 if (SafeMemcmp(header_checksum, image->header_checksum,
124 FIELD_LEN(header_checksum))) {
125 fprintf(stderr, "Invalid kernel header checksum!\n");
126 Free(kernel_buf);
127 return NULL;
128 }
129
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800130 /* Read key signature. */
Gaurav Shah80d129b2010-03-03 17:58:43 -0800131 image->kernel_key_signature = (uint8_t*) Malloc(kernel_key_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800132 StatefulMemcpy(&st, image->kernel_key_signature,
Gaurav Shah80d129b2010-03-03 17:58:43 -0800133 kernel_key_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800134
135 /* Read the kernel config. */
136 StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version));
137 StatefulMemcpy(&st, &image->options.version, FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800138 StatefulMemcpy(&st, &image->options.cmd_line, FIELD_LEN(options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800139 StatefulMemcpy(&st, &image->options.kernel_len,
140 FIELD_LEN(options.kernel_len));
141 StatefulMemcpy(&st, &image->options.kernel_load_addr,
142 FIELD_LEN(options.kernel_load_addr));
143 StatefulMemcpy(&st, &image->options.kernel_entry_addr,
144 FIELD_LEN(options.kernel_entry_addr));
145
146 /* Read kernel config signature. */
147 image->config_signature = (uint8_t*) Malloc(kernel_signature_len);
148 StatefulMemcpy(&st, image->config_signature, kernel_signature_len);
149
150 image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len);
151 StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len);
152
153 image->kernel_data = (uint8_t*) Malloc(image->options.kernel_len);
154 StatefulMemcpy(&st, image->kernel_data, image->options.kernel_len);
155
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800156 if(st.remaining_len != 0) { /* Overrun or underrun. */
157 Free(kernel_buf);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800158 return NULL;
159 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800160 Free(kernel_buf);
161 return image;
162}
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800163
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800164int GetKernelHeaderLen(const KernelImage* image) {
165 return (FIELD_LEN(header_version) + FIELD_LEN(header_len) +
166 FIELD_LEN(firmware_sign_algorithm) +
167 FIELD_LEN(kernel_sign_algorithm) + FIELD_LEN(kernel_key_version) +
168 RSAProcessedKeySize(image->kernel_sign_algorithm) +
169 FIELD_LEN(header_checksum));
170}
171
Gaurav Shah528a2c12010-03-18 13:10:10 -0700172void CalculateKernelHeaderChecksum(const KernelImage* image,
173 uint8_t* header_checksum) {
174 uint8_t* checksum;
175 DigestContext ctx;
176 DigestInit(&ctx, SHA512_DIGEST_ALGORITHM);
177 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
178 sizeof(image->header_version));
179 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
180 sizeof(image->header_len));
181 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
182 sizeof(image->firmware_sign_algorithm));
183 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
184 sizeof(image->kernel_sign_algorithm));
185 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
186 sizeof(image->kernel_key_version));
187 DigestUpdate(&ctx, image->kernel_sign_key,
188 RSAProcessedKeySize(image->kernel_sign_algorithm));
189 checksum = DigestFinal(&ctx);
190 Memcpy(header_checksum, checksum, FIELD_LEN(header_checksum));
191 Free(checksum);
192 return;
193}
194
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800195uint8_t* GetKernelHeaderBlob(const KernelImage* image) {
196 uint8_t* header_blob = NULL;
197 MemcpyState st;
198
199 header_blob = (uint8_t*) Malloc(GetKernelHeaderLen(image));
200 st.remaining_len = GetKernelHeaderLen(image);
201 st.remaining_buf = header_blob;
202
203 StatefulMemcpy_r(&st, &image->header_version, FIELD_LEN(header_version));
204 StatefulMemcpy_r(&st, &image->header_len, FIELD_LEN(header_len));
205 StatefulMemcpy_r(&st, &image->firmware_sign_algorithm,
206 FIELD_LEN(firmware_sign_algorithm));
207 StatefulMemcpy_r(&st, &image->kernel_sign_algorithm,
208 FIELD_LEN(kernel_sign_algorithm));
209 StatefulMemcpy_r(&st, &image->kernel_key_version,
210 FIELD_LEN(kernel_key_version));
211 StatefulMemcpy_r(&st, image->kernel_sign_key,
212 RSAProcessedKeySize(image->kernel_sign_algorithm));
213 StatefulMemcpy_r(&st, &image->header_checksum, FIELD_LEN(header_checksum));
214
215 if (st.remaining_len != 0) { /* Underrun or Overrun. */
216 Free(header_blob);
217 return NULL;
218 }
219 return header_blob;
220}
221
222int GetKernelConfigLen(const KernelImage* image) {
Gaurav Shah4f393862010-03-12 18:13:24 -0800223 return (FIELD_LEN(kernel_version) +
224 FIELD_LEN(options.version) + FIELD_LEN(options.cmd_line) +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800225 FIELD_LEN(options.kernel_len) + FIELD_LEN(options.kernel_load_addr) +
226 FIELD_LEN(options.kernel_entry_addr));
227}
228
229uint8_t* GetKernelConfigBlob(const KernelImage* image) {
230 uint8_t* config_blob = NULL;
231 MemcpyState st;
232
233 config_blob = (uint8_t*) Malloc(GetKernelConfigLen(image));
234 st.remaining_len = GetKernelConfigLen(image);
235 st.remaining_buf = config_blob;
236
237 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
238 StatefulMemcpy_r(&st, image->options.version, FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800239 StatefulMemcpy_r(&st, image->options.cmd_line, FIELD_LEN(options.cmd_line));
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800240 StatefulMemcpy_r(&st, &image->options.kernel_len,
241 FIELD_LEN(options.kernel_len));
242 StatefulMemcpy_r(&st, &image->options.kernel_load_addr,
243 FIELD_LEN(options.kernel_load_addr));
244 StatefulMemcpy_r(&st, &image->options.kernel_entry_addr,
245 FIELD_LEN(options.kernel_entry_addr));
246 if (st.remaining_len != 0) { /* Overrun or Underrun. */
247 Free(config_blob);
248 return NULL;
249 }
250 return config_blob;
251}
252
253uint8_t* GetKernelBlob(const KernelImage* image, int* blob_len) {
254 int kernel_key_signature_len;
255 int kernel_signature_len;
256 uint8_t* kernel_blob = NULL;
257 uint8_t* header_blob = NULL;
258 uint8_t* config_blob = NULL;
259 MemcpyState st;
260
261 if (!image)
262 return NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800263 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
264 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800265 *blob_len = (FIELD_LEN(magic) +
266 GetKernelHeaderLen(image) +
267 kernel_key_signature_len +
268 GetKernelConfigLen(image) +
269 2 * kernel_signature_len +
270 image->options.kernel_len);
271 kernel_blob = (uint8_t*) Malloc(*blob_len);
272 st.remaining_len = *blob_len;
273 st.remaining_buf = kernel_blob;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800274
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800275 header_blob = GetKernelHeaderBlob(image);
276 config_blob = GetKernelConfigBlob(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800277
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800278 StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic));
279 StatefulMemcpy_r(&st, header_blob, GetKernelHeaderLen(image));
280 StatefulMemcpy_r(&st, image->kernel_key_signature, kernel_key_signature_len);
281 StatefulMemcpy_r(&st, config_blob, GetKernelConfigLen(image));
282 StatefulMemcpy_r(&st, image->config_signature, kernel_signature_len);
283 StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len);
284 StatefulMemcpy_r(&st, image->kernel_data, image->options.kernel_len);
285
286 Free(config_blob);
287 Free(header_blob);
288
289 if (st.remaining_len != 0) { /* Underrun or Overrun. */
290 Free(kernel_blob);
291 return NULL;
292 }
293 return kernel_blob;
294}
295
296int WriteKernelImage(const char* input_file,
297 const KernelImage* image) {
298 int fd;
299 uint8_t* kernel_blob;
300 int blob_len;
301
302 if (!image)
303 return 0;
304 if (-1 == (fd = creat(input_file, S_IRWXU))) {
305 fprintf(stderr, "Couldn't open file for writing kernel image: %s\n",
306 input_file);
307 return 0;
308 }
309 kernel_blob = GetKernelBlob(image, &blob_len);
310 if (!kernel_blob) {
311 fprintf(stderr, "Couldn't create kernel blob from KernelImage.\n");
312 return 0;
313 }
314 if (blob_len != write(fd, kernel_blob, blob_len)) {
315 fprintf(stderr, "Couldn't write Kernel Image to file: %s\n",
316 input_file);
317
318 Free(kernel_blob);
319 close(fd);
320 return 0;
321 }
322 Free(kernel_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800323 close(fd);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800324 return 1;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800325}
326
327void PrintKernelImage(const KernelImage* image) {
328 if (!image)
329 return;
330
331 /* Print header. */
Gaurav Shah528a2c12010-03-18 13:10:10 -0700332 printf("Header Version = %d\n"
333 "Header Length = %d\n"
334 "Kernel Key Signature Algorithm = %s\n"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800335 "Kernel Signature Algorithm = %s\n"
336 "Kernel Key Version = %d\n\n",
Gaurav Shah528a2c12010-03-18 13:10:10 -0700337 image->header_version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800338 image->header_len,
Gaurav Shah528a2c12010-03-18 13:10:10 -0700339 algo_strings[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800340 algo_strings[image->kernel_sign_algorithm],
341 image->kernel_key_version);
342 /* TODO(gauravsh): Output hash and key signature here? */
343 /* Print preamble. */
344 printf("Kernel Version = %d\n"
345 "Kernel Config Version = %d.%d\n"
Gaurav Shah528a2c12010-03-18 13:10:10 -0700346 "Kernel Config command line = \"%s\"\n"
Gaurav Shah456678b2010-03-10 18:38:45 -0800347 "kernel Length = %" PRId64 "\n"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800348 "Kernel Load Address = %" PRId64 "\n"
349 "Kernel Entry Address = %" PRId64 "\n\n",
350 image->kernel_version,
351 image->options.version[0], image->options.version[1],
Gaurav Shah4f393862010-03-12 18:13:24 -0800352 image->options.cmd_line,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800353 image->options.kernel_len,
354 image->options.kernel_load_addr,
355 image->options.kernel_entry_addr);
356 /* TODO(gauravsh): Output kernel signature here? */
357}
358
359char* kVerifyKernelErrors[VERIFY_KERNEL_MAX] = {
360 "Success.",
361 "Invalid Image.",
362 "Kernel Key Signature Failed.",
363 "Invalid Kernel Verification Algorithm.",
364 "Config Signature Failed.",
365 "Kernel Signature Failed.",
366 "Wrong Kernel Magic.",
367};
368
369int VerifyKernelHeader(const uint8_t* firmware_key_blob,
370 const uint8_t* header_blob,
371 const int dev_mode,
372 int* firmware_algorithm,
373 int* kernel_algorithm,
374 int* kernel_header_len) {
375 int kernel_sign_key_len;
376 int firmware_sign_key_len;
377 uint16_t header_version, header_len;
378 uint16_t firmware_sign_algorithm, kernel_sign_algorithm;
379 uint8_t* header_checksum = NULL;
380
381 /* Base Offset for the header_checksum field. Actual offset is
382 * this + kernel_sign_key_len. */
383 int base_header_checksum_offset = (FIELD_LEN(header_version) +
384 FIELD_LEN(header_len) +
385 FIELD_LEN(firmware_sign_algorithm) +
386 FIELD_LEN(kernel_sign_algorithm) +
387 FIELD_LEN(kernel_key_version));
388
389 Memcpy(&header_version, header_blob, sizeof(header_version));
390 Memcpy(&header_len, header_blob + FIELD_LEN(header_version),
391 sizeof(header_len));
392 Memcpy(&firmware_sign_algorithm,
393 header_blob + (FIELD_LEN(header_version) +
394 FIELD_LEN(header_len)),
395 sizeof(firmware_sign_algorithm));
396 Memcpy(&kernel_sign_algorithm,
397 header_blob + (FIELD_LEN(header_version) +
398 FIELD_LEN(header_len) +
399 FIELD_LEN(firmware_sign_algorithm)),
400 sizeof(kernel_sign_algorithm));
401
402 /* TODO(gauravsh): Make this return two different error types depending
403 * on whether the firmware or kernel signing algorithm is invalid. */
404 if (firmware_sign_algorithm >= kNumAlgorithms)
405 return VERIFY_KERNEL_INVALID_ALGORITHM;
406 if (kernel_sign_algorithm >= kNumAlgorithms)
407 return VERIFY_KERNEL_INVALID_ALGORITHM;
408
409 *firmware_algorithm = (int) firmware_sign_algorithm;
410 *kernel_algorithm = (int) kernel_sign_algorithm;
411 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
412 firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm);
413
414
415 /* Verify if header len is correct? */
416 if (header_len != (base_header_checksum_offset +
417 kernel_sign_key_len +
418 FIELD_LEN(header_checksum))) {
419 fprintf(stderr, "VerifyKernelHeader: Header length mismatch\n");
420 return VERIFY_KERNEL_INVALID_IMAGE;
421 }
422 *kernel_header_len = (int) header_len;
423
424 /* Verify if the hash of the header is correct. */
425 header_checksum = DigestBuf(header_blob,
426 header_len - FIELD_LEN(header_checksum),
427 SHA512_DIGEST_ALGORITHM);
428 if (SafeMemcmp(header_checksum,
429 header_blob + (base_header_checksum_offset +
430 kernel_sign_key_len),
431 FIELD_LEN(header_checksum))) {
432 Free(header_checksum);
Gaurav Shahccaa90f2010-03-17 20:40:23 -0700433 fprintf(stderr, "VerifyKernelHeader: Invalid header hash\n");
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800434 return VERIFY_KERNEL_INVALID_IMAGE;
435 }
436 Free(header_checksum);
437
438 /* Verify kernel key signature unless we are in dev mode. */
439 if (!dev_mode) {
440 if (!RSAVerifyBinary_f(firmware_key_blob, NULL, /* Key to use */
441 header_blob, /* Data to verify */
442 header_len, /* Length of data */
443 header_blob + header_len, /* Expected Signature */
444 firmware_sign_algorithm))
445 return VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
446 }
447 return 0;
448}
449
450int VerifyKernelConfig(RSAPublicKey* kernel_sign_key,
451 const uint8_t* config_blob,
452 int algorithm,
453 int* kernel_len) {
454 uint32_t len, config_len;
Gaurav Shah4f393862010-03-12 18:13:24 -0800455 config_len = GetKernelConfigLen(NULL);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800456 if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use */
457 config_blob, /* Data to verify */
458 config_len, /* Length of data */
459 config_blob + config_len, /* Expected Signature */
460 algorithm))
461 return VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
462
Gaurav Shah4f393862010-03-12 18:13:24 -0800463 Memcpy(&len,
464 config_blob + (FIELD_LEN(kernel_version) + FIELD_LEN(options.version) +
465 FIELD_LEN(options.cmd_line)),
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800466 sizeof(len));
467 *kernel_len = (int) len;
468 return 0;
469}
470
471int VerifyKernelData(RSAPublicKey* kernel_sign_key,
472 const uint8_t* kernel_data_start,
473 int kernel_len,
474 int algorithm) {
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800475 int signature_len = siglen_map[algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800476 if (!RSAVerifyBinary_f(NULL, kernel_sign_key, /* Key to use. */
477 kernel_data_start + signature_len, /* Data to
478 * verify */
479 kernel_len, /* Length of data. */
480 kernel_data_start, /* Expected Signature */
481 algorithm))
482 return VERIFY_KERNEL_SIGNATURE_FAILED;
483 return 0;
484}
485
486int VerifyKernel(const uint8_t* firmware_key_blob,
487 const uint8_t* kernel_blob,
488 const int dev_mode) {
489 int error_code;
490 int firmware_sign_algorithm; /* Firmware signing key algorithm. */
491 int kernel_sign_algorithm; /* Kernel Signing key algorithm. */
492 RSAPublicKey* kernel_sign_key;
493 int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len,
494 header_len, kernel_len;
495 const uint8_t* header_ptr; /* Pointer to header. */
496 const uint8_t* kernel_sign_key_ptr; /* Pointer to signing key. */
497 const uint8_t* config_ptr; /* Pointer to kernel config block. */
498 const uint8_t* kernel_ptr; /* Pointer to kernel signature/data. */
499
500 /* Note: All the offset calculations are based on struct FirmwareImage which
501 * is defined in include/firmware_image.h. */
502
503 /* Compare magic bytes. */
504 if (SafeMemcmp(kernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE))
505 return VERIFY_KERNEL_WRONG_MAGIC;
506 header_ptr = kernel_blob + KERNEL_MAGIC_SIZE;
507
508 /* Only continue if header verification succeeds. */
509 if ((error_code = VerifyKernelHeader(firmware_key_blob, header_ptr, dev_mode,
510 &firmware_sign_algorithm,
511 &kernel_sign_algorithm, &header_len))) {
512 fprintf(stderr, "VerifyKernel: Kernel header verification failed.\n");
513 return error_code; /* AKA jump to recovery. */
514 }
515 /* Parse signing key into RSAPublicKey structure since it is required multiple
516 * times. */
517 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
518 kernel_sign_key_ptr = header_ptr + (FIELD_LEN(header_version) +
519 FIELD_LEN(header_len) +
520 FIELD_LEN(firmware_sign_algorithm) +
521 FIELD_LEN(kernel_sign_algorithm) +
522 FIELD_LEN(kernel_key_version));
523 kernel_sign_key = RSAPublicKeyFromBuf(kernel_sign_key_ptr,
524 kernel_sign_key_len);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800525 kernel_signature_len = siglen_map[kernel_sign_algorithm];
526 kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800527
528 /* Only continue if config verification succeeds. */
529 config_ptr = (header_ptr + header_len + kernel_key_signature_len);
530 if ((error_code = VerifyKernelConfig(kernel_sign_key, config_ptr,
531 kernel_sign_algorithm,
Gaurav Shah259de402010-03-12 17:42:03 -0800532 &kernel_len))) {
533 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800534 return error_code; /* AKA jump to recovery. */
Gaurav Shah259de402010-03-12 17:42:03 -0800535 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800536 /* Only continue if kernel data verification succeeds. */
537 kernel_ptr = (config_ptr +
Gaurav Shah4f393862010-03-12 18:13:24 -0800538 GetKernelConfigLen(NULL) + /* Skip config block/signature. */
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800539 kernel_signature_len);
540
541 if ((error_code = VerifyKernelData(kernel_sign_key, kernel_ptr, kernel_len,
Gaurav Shah259de402010-03-12 17:42:03 -0800542 kernel_sign_algorithm))) {
543 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800544 return error_code; /* AKA jump to recovery. */
Gaurav Shah259de402010-03-12 17:42:03 -0800545 }
546 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800547 return 0; /* Success! */
548}
549
550int VerifyKernelImage(const RSAPublicKey* firmware_key,
551 const KernelImage* image,
552 const int dev_mode) {
Gaurav Shah259de402010-03-12 17:42:03 -0800553 RSAPublicKey* kernel_sign_key = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800554 uint8_t* header_digest = NULL;
555 uint8_t* config_digest = NULL;
556 uint8_t* kernel_digest = NULL;
557 int kernel_sign_key_size;
558 int kernel_signature_size;
559 int error_code = 0;
560 DigestContext ctx;
561
562 if (!image)
563 return VERIFY_KERNEL_INVALID_IMAGE;
564
565 /* Verify kernel key signature on the key header if we
566 * are not in dev mode.
567 *
568 * TODO(gauravsh): Add additional sanity checks here for:
569 * 1) verifying the header length is correct.
570 * 2) header_checksum is correct.
571 */
572
573 if (image->firmware_sign_algorithm >= kNumAlgorithms)
574 return VERIFY_KERNEL_INVALID_ALGORITHM;
575 if (image->kernel_sign_algorithm >= kNumAlgorithms)
576 return VERIFY_KERNEL_INVALID_ALGORITHM;
577
578 if (!dev_mode) {
579 DigestInit(&ctx, image->firmware_sign_algorithm);
580 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
581 FIELD_LEN(header_version));
582 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
583 FIELD_LEN(header_len));
584 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
585 FIELD_LEN(firmware_sign_algorithm));
586 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
587 FIELD_LEN(kernel_sign_algorithm));
588 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
589 FIELD_LEN(kernel_key_version));
590 DigestUpdate(&ctx, image->kernel_sign_key,
591 RSAProcessedKeySize(image->kernel_sign_algorithm));
592 DigestUpdate(&ctx, image->header_checksum,
593 FIELD_LEN(header_checksum));
594 header_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800595 if (!RSAVerify(firmware_key, image->kernel_key_signature,
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800596 siglen_map[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800597 image->firmware_sign_algorithm,
598 header_digest)) {
599 fprintf(stderr, "VerifyKernelImage(): Key signature check failed.\n");
600 error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
601 goto verify_failure;
602 }
603 }
604
605 /* Get kernel signing key to verify the rest of the kernel. */
606 kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm);
607 kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
608 kernel_sign_key_size);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800609 kernel_signature_size = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800610
611 /* Verify kernel config signature. */
612 DigestInit(&ctx, image->kernel_sign_algorithm);
613 DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
614 FIELD_LEN(kernel_version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800615 DigestUpdate(&ctx, (uint8_t*) image->options.version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800616 FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800617 DigestUpdate(&ctx, (uint8_t*) image->options.cmd_line,
618 FIELD_LEN(options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800619 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_len,
620 FIELD_LEN(options.kernel_len));
621 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_load_addr,
622 FIELD_LEN(options.kernel_load_addr));
623 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_entry_addr,
624 FIELD_LEN(options.kernel_entry_addr));
625 config_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800626 if (!RSAVerify(kernel_sign_key, image->config_signature,
627 kernel_signature_size, image->kernel_sign_algorithm,
628 config_digest)) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800629 error_code = VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
630 goto verify_failure;
631 }
632
633 /* Verify firmware signature. */
634 kernel_digest = DigestBuf(image->kernel_data,
635 image->options.kernel_len,
636 image->kernel_sign_algorithm);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800637 if (!RSAVerify(kernel_sign_key, image->kernel_signature,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800638 kernel_signature_size, image->kernel_sign_algorithm,
639 kernel_digest)) {
640 error_code = VERIFY_KERNEL_SIGNATURE_FAILED;
641 goto verify_failure;
642 }
643
644verify_failure:
Gaurav Shah259de402010-03-12 17:42:03 -0800645 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800646 Free(kernel_digest);
647 Free(config_digest);
648 Free(header_digest);
649 return error_code;
650}
651
652const char* VerifyKernelErrorString(int error) {
653 return kVerifyKernelErrors[error];
654}
655
656int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800657 uint8_t* header_blob = NULL;
Gaurav Shah259de402010-03-12 17:42:03 -0800658 uint8_t* signature = NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800659 int signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800660 if (!image || !firmware_key_file)
661 return 0;
662 header_blob = GetKernelHeaderBlob(image);
663 if (!header_blob)
664 return 0;
665 if (!(signature = SignatureBuf(header_blob,
666 GetKernelHeaderLen(image),
667 firmware_key_file,
668 image->firmware_sign_algorithm))) {
669 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800670 return 0;
671 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800672 image->kernel_key_signature = Malloc(signature_len);
673 Memcpy(image->kernel_key_signature, signature, signature_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800674 Free(signature);
675 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800676 return 1;
677}
678
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800679int AddKernelSignature(KernelImage* image,
680 const char* kernel_signing_key_file) {
Gaurav Shah259de402010-03-12 17:42:03 -0800681 uint8_t* config_blob = NULL;
682 uint8_t* config_signature = NULL;
683 uint8_t* kernel_signature = NULL;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800684 int signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800685
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800686 config_blob = GetKernelConfigBlob(image);
687 if (!(config_signature = SignatureBuf(config_blob,
688 GetKernelConfigLen(image),
689 kernel_signing_key_file,
690 image->kernel_sign_algorithm))) {
691 fprintf(stderr, "Could not compute signature on the kernel config.\n");
692 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800693 return 0;
694 }
Gaurav Shah259de402010-03-12 17:42:03 -0800695 Free(config_blob);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800696
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800697 image->config_signature = (uint8_t*) Malloc(signature_len);
698 Memcpy(image->config_signature, config_signature, signature_len);
699 Free(config_signature);
700
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800701 if (!(kernel_signature = SignatureBuf(image->kernel_data,
702 image->options.kernel_len,
703 kernel_signing_key_file,
704 image->kernel_sign_algorithm))) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800705 fprintf(stderr, "Could not compute signature on the kernel.\n");
706 return 0;
707 }
708 image->kernel_signature = (uint8_t*) Malloc(signature_len);
709 Memcpy(image->kernel_signature, kernel_signature, signature_len);
710 Free(kernel_signature);
711 return 1;
712}