blob: cc184673692bb2a61773a304474c50ccd9efca3c [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.
Gaurav Shahed9c96a2010-03-30 18:56:07 -07006 * (Userland portion)
Gaurav Shahf67bcaa2010-02-28 19:18:24 -08007 */
8
9#include "kernel_image.h"
10
11#include <fcntl.h>
12#include <stdio.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <unistd.h>
16
Gaurav Shah5411c7a2010-03-31 10:56:49 -070017#include "cryptolib.h"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080018#include "file_keys.h"
Gaurav Shaha82bf262010-03-26 10:38:08 -070019#include "rollback_index.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;
Gaurav Shah2480a182010-04-26 11:41:53 -070032 Memset(image->options.cmd_line, 0, sizeof(image->options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080033 image->config_signature = NULL;
34 image->kernel_signature = NULL;
35 image->kernel_data = NULL;
36 }
37 return image;
38}
39
40void KernelImageFree(KernelImage* image) {
41 if (image) {
42 Free(image->kernel_sign_key);
43 Free(image->kernel_key_signature);
44 Free(image->config_signature);
45 Free(image->kernel_signature);
46 Free(image->kernel_data);
47 Free(image);
48 }
49}
50
51KernelImage* ReadKernelImage(const char* input_file) {
Gaurav Shah456678b2010-03-10 18:38:45 -080052 uint64_t file_size;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080053 int image_len = 0; /* Total size of the kernel image. */
54 int header_len = 0;
55 int firmware_sign_key_len;
56 int kernel_key_signature_len;
57 int kernel_sign_key_len;
58 int kernel_signature_len;
59 uint8_t* kernel_buf;
Gaurav Shah528a2c12010-03-18 13:10:10 -070060 uint8_t header_checksum[FIELD_LEN(header_checksum)];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080061 MemcpyState st;
62 KernelImage* image = KernelImageNew();
63
64 if (!image)
65 return NULL;
66
67 kernel_buf = BufferFromFile(input_file, &file_size);
68 image_len = file_size;
69
70 st.remaining_len = image_len;
71 st.remaining_buf = kernel_buf;
Gaurav Shahe450be42010-03-29 21:27:08 -070072 st.overrun = 0;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080073
74 /* Read and compare magic bytes. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080075 StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080076
77 if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -070078 debug("Wrong Kernel Magic.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -080079 Free(kernel_buf);
80 return NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080081 }
82 StatefulMemcpy(&st, &image->header_version, FIELD_LEN(header_version));
83 StatefulMemcpy(&st, &image->header_len, FIELD_LEN(header_len));
84 StatefulMemcpy(&st, &image->firmware_sign_algorithm,
85 FIELD_LEN(firmware_sign_algorithm));
86 StatefulMemcpy(&st, &image->kernel_sign_algorithm,
87 FIELD_LEN(kernel_sign_algorithm));
88
89 /* Valid Kernel Key signing algorithm. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080090 if (image->firmware_sign_algorithm >= kNumAlgorithms) {
91 Free(kernel_buf);
92 return NULL;
93 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080094
95 /* Valid Kernel Signing Algorithm? */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080096 if (image->kernel_sign_algorithm >= kNumAlgorithms) {
97 Free(kernel_buf);
98 return NULL;
99 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800100
101 /* Compute size of pre-processed RSA public keys and signatures. */
102 firmware_sign_key_len = RSAProcessedKeySize(image->firmware_sign_algorithm);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800103 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800104 kernel_sign_key_len = RSAProcessedKeySize(image->kernel_sign_algorithm);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800105 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800106
107 /* Check whether key header length is correct. */
Gaurav Shah528a2c12010-03-18 13:10:10 -0700108 header_len = GetKernelHeaderLen(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800109 if (header_len != image->header_len) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700110 debug("Header length mismatch. Got: %d, Expected: %d\n",
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800111 image->header_len, header_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800112 Free(kernel_buf);
113 return NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800114 }
115
116 /* Read pre-processed public half of the kernel signing key. */
117 StatefulMemcpy(&st, &image->kernel_key_version,
118 FIELD_LEN(kernel_key_version));
119 image->kernel_sign_key = (uint8_t*) Malloc(kernel_sign_key_len);
120 StatefulMemcpy(&st, image->kernel_sign_key, kernel_sign_key_len);
121 StatefulMemcpy(&st, image->header_checksum, FIELD_LEN(header_checksum));
122
Gaurav Shah528a2c12010-03-18 13:10:10 -0700123 /* Check whether the header checksum matches. */
124 CalculateKernelHeaderChecksum(image, header_checksum);
125 if (SafeMemcmp(header_checksum, image->header_checksum,
126 FIELD_LEN(header_checksum))) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700127 debug("Invalid kernel header checksum!\n");
Gaurav Shah528a2c12010-03-18 13:10:10 -0700128 Free(kernel_buf);
129 return NULL;
130 }
131
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800132 /* Read key signature. */
Gaurav Shah80d129b2010-03-03 17:58:43 -0800133 image->kernel_key_signature = (uint8_t*) Malloc(kernel_key_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800134 StatefulMemcpy(&st, image->kernel_key_signature,
Gaurav Shah80d129b2010-03-03 17:58:43 -0800135 kernel_key_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800136
137 /* Read the kernel config. */
138 StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version));
139 StatefulMemcpy(&st, &image->options.version, FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800140 StatefulMemcpy(&st, &image->options.cmd_line, FIELD_LEN(options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800141 StatefulMemcpy(&st, &image->options.kernel_len,
142 FIELD_LEN(options.kernel_len));
143 StatefulMemcpy(&st, &image->options.kernel_load_addr,
144 FIELD_LEN(options.kernel_load_addr));
145 StatefulMemcpy(&st, &image->options.kernel_entry_addr,
146 FIELD_LEN(options.kernel_entry_addr));
147
148 /* Read kernel config signature. */
149 image->config_signature = (uint8_t*) Malloc(kernel_signature_len);
150 StatefulMemcpy(&st, image->config_signature, kernel_signature_len);
151
152 image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len);
153 StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len);
154
155 image->kernel_data = (uint8_t*) Malloc(image->options.kernel_len);
156 StatefulMemcpy(&st, image->kernel_data, image->options.kernel_len);
157
Gaurav Shahe450be42010-03-29 21:27:08 -0700158 if(st.overrun || st.remaining_len != 0) { /* Overrun or underrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800159 Free(kernel_buf);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800160 return NULL;
161 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800162 Free(kernel_buf);
163 return image;
164}
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800165
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800166int GetKernelHeaderLen(const KernelImage* image) {
167 return (FIELD_LEN(header_version) + FIELD_LEN(header_len) +
168 FIELD_LEN(firmware_sign_algorithm) +
169 FIELD_LEN(kernel_sign_algorithm) + FIELD_LEN(kernel_key_version) +
170 RSAProcessedKeySize(image->kernel_sign_algorithm) +
171 FIELD_LEN(header_checksum));
172}
173
Gaurav Shah528a2c12010-03-18 13:10:10 -0700174void CalculateKernelHeaderChecksum(const KernelImage* image,
175 uint8_t* header_checksum) {
176 uint8_t* checksum;
177 DigestContext ctx;
178 DigestInit(&ctx, SHA512_DIGEST_ALGORITHM);
179 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
180 sizeof(image->header_version));
181 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
182 sizeof(image->header_len));
183 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
184 sizeof(image->firmware_sign_algorithm));
185 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
186 sizeof(image->kernel_sign_algorithm));
187 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
188 sizeof(image->kernel_key_version));
189 DigestUpdate(&ctx, image->kernel_sign_key,
190 RSAProcessedKeySize(image->kernel_sign_algorithm));
191 checksum = DigestFinal(&ctx);
192 Memcpy(header_checksum, checksum, FIELD_LEN(header_checksum));
193 Free(checksum);
194 return;
195}
196
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800197uint8_t* GetKernelHeaderBlob(const KernelImage* image) {
198 uint8_t* header_blob = NULL;
199 MemcpyState st;
200
201 header_blob = (uint8_t*) Malloc(GetKernelHeaderLen(image));
202 st.remaining_len = GetKernelHeaderLen(image);
203 st.remaining_buf = header_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700204 st.overrun = 0;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800205
206 StatefulMemcpy_r(&st, &image->header_version, FIELD_LEN(header_version));
207 StatefulMemcpy_r(&st, &image->header_len, FIELD_LEN(header_len));
208 StatefulMemcpy_r(&st, &image->firmware_sign_algorithm,
209 FIELD_LEN(firmware_sign_algorithm));
210 StatefulMemcpy_r(&st, &image->kernel_sign_algorithm,
211 FIELD_LEN(kernel_sign_algorithm));
212 StatefulMemcpy_r(&st, &image->kernel_key_version,
213 FIELD_LEN(kernel_key_version));
214 StatefulMemcpy_r(&st, image->kernel_sign_key,
215 RSAProcessedKeySize(image->kernel_sign_algorithm));
216 StatefulMemcpy_r(&st, &image->header_checksum, FIELD_LEN(header_checksum));
217
Gaurav Shahe450be42010-03-29 21:27:08 -0700218 if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800219 Free(header_blob);
220 return NULL;
221 }
222 return header_blob;
223}
224
Gaurav Shah463be3f2010-03-29 16:13:45 -0700225int GetKernelConfigLen() {
Gaurav Shah4f393862010-03-12 18:13:24 -0800226 return (FIELD_LEN(kernel_version) +
227 FIELD_LEN(options.version) + FIELD_LEN(options.cmd_line) +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800228 FIELD_LEN(options.kernel_len) + FIELD_LEN(options.kernel_load_addr) +
229 FIELD_LEN(options.kernel_entry_addr));
230}
231
232uint8_t* GetKernelConfigBlob(const KernelImage* image) {
233 uint8_t* config_blob = NULL;
234 MemcpyState st;
235
Gaurav Shah463be3f2010-03-29 16:13:45 -0700236 config_blob = (uint8_t*) Malloc(GetKernelConfigLen());
237 st.remaining_len = GetKernelConfigLen();
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800238 st.remaining_buf = config_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700239 st.overrun = 0;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800240
241 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
242 StatefulMemcpy_r(&st, image->options.version, FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800243 StatefulMemcpy_r(&st, image->options.cmd_line, FIELD_LEN(options.cmd_line));
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800244 StatefulMemcpy_r(&st, &image->options.kernel_len,
245 FIELD_LEN(options.kernel_len));
246 StatefulMemcpy_r(&st, &image->options.kernel_load_addr,
247 FIELD_LEN(options.kernel_load_addr));
248 StatefulMemcpy_r(&st, &image->options.kernel_entry_addr,
249 FIELD_LEN(options.kernel_entry_addr));
Gaurav Shahe450be42010-03-29 21:27:08 -0700250 if (st.overrun || st.remaining_len != 0) { /* Overrun or Underrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800251 Free(config_blob);
252 return NULL;
253 }
254 return config_blob;
255}
256
Gaurav Shah13937112010-03-22 17:59:09 -0700257uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800258 int kernel_key_signature_len;
259 int kernel_signature_len;
260 uint8_t* kernel_blob = NULL;
261 uint8_t* header_blob = NULL;
262 uint8_t* config_blob = NULL;
263 MemcpyState st;
264
265 if (!image)
266 return NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800267 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
268 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800269 *blob_len = (FIELD_LEN(magic) +
270 GetKernelHeaderLen(image) +
271 kernel_key_signature_len +
Gaurav Shah463be3f2010-03-29 16:13:45 -0700272 GetKernelConfigLen() +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800273 2 * kernel_signature_len +
274 image->options.kernel_len);
275 kernel_blob = (uint8_t*) Malloc(*blob_len);
276 st.remaining_len = *blob_len;
277 st.remaining_buf = kernel_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700278 st.overrun = 0;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800279
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800280 header_blob = GetKernelHeaderBlob(image);
281 config_blob = GetKernelConfigBlob(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800282
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800283 StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic));
284 StatefulMemcpy_r(&st, header_blob, GetKernelHeaderLen(image));
285 StatefulMemcpy_r(&st, image->kernel_key_signature, kernel_key_signature_len);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700286 StatefulMemcpy_r(&st, config_blob, GetKernelConfigLen());
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800287 StatefulMemcpy_r(&st, image->config_signature, kernel_signature_len);
288 StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len);
289 StatefulMemcpy_r(&st, image->kernel_data, image->options.kernel_len);
290
291 Free(config_blob);
292 Free(header_blob);
293
Gaurav Shahe450be42010-03-29 21:27:08 -0700294 if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800295 Free(kernel_blob);
296 return NULL;
297 }
298 return kernel_blob;
299}
300
301int WriteKernelImage(const char* input_file,
Gaurav Shah2480a182010-04-26 11:41:53 -0700302 const KernelImage* image,
303 int is_only_vblock) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800304 int fd;
Gaurav Shah2480a182010-04-26 11:41:53 -0700305 int success = 1;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800306 uint8_t* kernel_blob;
Gaurav Shah13937112010-03-22 17:59:09 -0700307 uint64_t blob_len;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800308
309 if (!image)
310 return 0;
311 if (-1 == (fd = creat(input_file, S_IRWXU))) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700312 debug("Couldn't open file for writing kernel image: %s\n",
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800313 input_file);
314 return 0;
315 }
316 kernel_blob = GetKernelBlob(image, &blob_len);
317 if (!kernel_blob) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700318 debug("Couldn't create kernel blob from KernelImage.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800319 return 0;
320 }
Gaurav Shah2480a182010-04-26 11:41:53 -0700321 if (!is_only_vblock) {
322 if (blob_len != write(fd, kernel_blob, blob_len)) {
323 debug("Couldn't write Kernel Image to file: %s\n",
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800324 input_file);
Gaurav Shah2480a182010-04-26 11:41:53 -0700325 success = 0;
326 }
327 } else {
328 /* Exclude the kernel_data. */
329 int vblock_len = blob_len - image->options.kernel_len;
330 if (vblock_len != write(fd, kernel_blob, vblock_len)) {
331 debug("Couldn't write Kernel Image Verification block to file: %s\n",
332 input_file);
333 success = 0;
334 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800335 }
336 Free(kernel_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800337 close(fd);
Gaurav Shah2480a182010-04-26 11:41:53 -0700338 return success;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800339}
340
341void PrintKernelImage(const KernelImage* image) {
342 if (!image)
343 return;
344
345 /* Print header. */
Gaurav Shah528a2c12010-03-18 13:10:10 -0700346 printf("Header Version = %d\n"
347 "Header Length = %d\n"
348 "Kernel Key Signature Algorithm = %s\n"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800349 "Kernel Signature Algorithm = %s\n"
350 "Kernel Key Version = %d\n\n",
Gaurav Shah528a2c12010-03-18 13:10:10 -0700351 image->header_version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800352 image->header_len,
Gaurav Shah528a2c12010-03-18 13:10:10 -0700353 algo_strings[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800354 algo_strings[image->kernel_sign_algorithm],
355 image->kernel_key_version);
356 /* TODO(gauravsh): Output hash and key signature here? */
357 /* Print preamble. */
358 printf("Kernel Version = %d\n"
359 "Kernel Config Version = %d.%d\n"
Gaurav Shah528a2c12010-03-18 13:10:10 -0700360 "Kernel Config command line = \"%s\"\n"
Gaurav Shah456678b2010-03-10 18:38:45 -0800361 "kernel Length = %" PRId64 "\n"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800362 "Kernel Load Address = %" PRId64 "\n"
363 "Kernel Entry Address = %" PRId64 "\n\n",
364 image->kernel_version,
365 image->options.version[0], image->options.version[1],
Gaurav Shah4f393862010-03-12 18:13:24 -0800366 image->options.cmd_line,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800367 image->options.kernel_len,
368 image->options.kernel_load_addr,
369 image->options.kernel_entry_addr);
370 /* TODO(gauravsh): Output kernel signature here? */
371}
372
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800373
374int VerifyKernelImage(const RSAPublicKey* firmware_key,
375 const KernelImage* image,
376 const int dev_mode) {
Gaurav Shah259de402010-03-12 17:42:03 -0800377 RSAPublicKey* kernel_sign_key = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800378 uint8_t* header_digest = NULL;
379 uint8_t* config_digest = NULL;
380 uint8_t* kernel_digest = NULL;
381 int kernel_sign_key_size;
382 int kernel_signature_size;
383 int error_code = 0;
384 DigestContext ctx;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700385 DigestContext kernel_ctx;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800386 if (!image)
387 return VERIFY_KERNEL_INVALID_IMAGE;
388
389 /* Verify kernel key signature on the key header if we
390 * are not in dev mode.
391 *
392 * TODO(gauravsh): Add additional sanity checks here for:
393 * 1) verifying the header length is correct.
394 * 2) header_checksum is correct.
395 */
396
397 if (image->firmware_sign_algorithm >= kNumAlgorithms)
398 return VERIFY_KERNEL_INVALID_ALGORITHM;
399 if (image->kernel_sign_algorithm >= kNumAlgorithms)
400 return VERIFY_KERNEL_INVALID_ALGORITHM;
401
402 if (!dev_mode) {
403 DigestInit(&ctx, image->firmware_sign_algorithm);
404 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
405 FIELD_LEN(header_version));
406 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
407 FIELD_LEN(header_len));
408 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
409 FIELD_LEN(firmware_sign_algorithm));
410 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
411 FIELD_LEN(kernel_sign_algorithm));
412 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
413 FIELD_LEN(kernel_key_version));
414 DigestUpdate(&ctx, image->kernel_sign_key,
415 RSAProcessedKeySize(image->kernel_sign_algorithm));
416 DigestUpdate(&ctx, image->header_checksum,
417 FIELD_LEN(header_checksum));
418 header_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800419 if (!RSAVerify(firmware_key, image->kernel_key_signature,
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800420 siglen_map[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800421 image->firmware_sign_algorithm,
422 header_digest)) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700423 debug("VerifyKernelImage(): Key signature check failed.\n");
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800424 error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
425 goto verify_failure;
426 }
427 }
428
429 /* Get kernel signing key to verify the rest of the kernel. */
430 kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm);
431 kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
432 kernel_sign_key_size);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800433 kernel_signature_size = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800434
435 /* Verify kernel config signature. */
436 DigestInit(&ctx, image->kernel_sign_algorithm);
437 DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
438 FIELD_LEN(kernel_version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800439 DigestUpdate(&ctx, (uint8_t*) image->options.version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800440 FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800441 DigestUpdate(&ctx, (uint8_t*) image->options.cmd_line,
442 FIELD_LEN(options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800443 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_len,
444 FIELD_LEN(options.kernel_len));
445 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_load_addr,
446 FIELD_LEN(options.kernel_load_addr));
447 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_entry_addr,
448 FIELD_LEN(options.kernel_entry_addr));
449 config_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800450 if (!RSAVerify(kernel_sign_key, image->config_signature,
451 kernel_signature_size, image->kernel_sign_algorithm,
452 config_digest)) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800453 error_code = VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
454 goto verify_failure;
455 }
456
Gaurav Shah463be3f2010-03-29 16:13:45 -0700457 /* Verify kernel signature - kernel signature is computed on the contents
458 of kernel version + kernel options + kernel_data. */
459 DigestInit(&kernel_ctx, image->kernel_sign_algorithm);
460 DigestUpdate(&kernel_ctx, (uint8_t*) &image->kernel_version,
461 FIELD_LEN(kernel_version));
462 DigestUpdate(&kernel_ctx, (uint8_t*) image->options.version,
463 FIELD_LEN(options.version));
464 DigestUpdate(&kernel_ctx, (uint8_t*) image->options.cmd_line,
465 FIELD_LEN(options.cmd_line));
466 DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_len,
467 FIELD_LEN(options.kernel_len));
468 DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_load_addr,
469 FIELD_LEN(options.kernel_load_addr));
470 DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_entry_addr,
471 FIELD_LEN(options.kernel_entry_addr));
472 DigestUpdate(&kernel_ctx, image->kernel_data, image->options.kernel_len);
473 kernel_digest = DigestFinal(&kernel_ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800474 if (!RSAVerify(kernel_sign_key, image->kernel_signature,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800475 kernel_signature_size, image->kernel_sign_algorithm,
476 kernel_digest)) {
477 error_code = VERIFY_KERNEL_SIGNATURE_FAILED;
478 goto verify_failure;
479 }
480
481verify_failure:
Gaurav Shah259de402010-03-12 17:42:03 -0800482 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800483 Free(kernel_digest);
484 Free(config_digest);
485 Free(header_digest);
486 return error_code;
487}
488
489const char* VerifyKernelErrorString(int error) {
490 return kVerifyKernelErrors[error];
491}
492
493int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800494 uint8_t* header_blob = NULL;
Gaurav Shah259de402010-03-12 17:42:03 -0800495 uint8_t* signature = NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800496 int signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800497 if (!image || !firmware_key_file)
498 return 0;
499 header_blob = GetKernelHeaderBlob(image);
500 if (!header_blob)
501 return 0;
502 if (!(signature = SignatureBuf(header_blob,
503 GetKernelHeaderLen(image),
504 firmware_key_file,
505 image->firmware_sign_algorithm))) {
506 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800507 return 0;
508 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800509 image->kernel_key_signature = Malloc(signature_len);
510 Memcpy(image->kernel_key_signature, signature, signature_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800511 Free(signature);
512 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800513 return 1;
514}
515
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800516int AddKernelSignature(KernelImage* image,
517 const char* kernel_signing_key_file) {
Gaurav Shah259de402010-03-12 17:42:03 -0800518 uint8_t* config_blob = NULL;
519 uint8_t* config_signature = NULL;
520 uint8_t* kernel_signature = NULL;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700521 uint8_t* kernel_buf;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800522 int signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800523
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800524 config_blob = GetKernelConfigBlob(image);
525 if (!(config_signature = SignatureBuf(config_blob,
Gaurav Shah463be3f2010-03-29 16:13:45 -0700526 GetKernelConfigLen(),
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800527 kernel_signing_key_file,
528 image->kernel_sign_algorithm))) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700529 debug("Could not compute signature on the kernel config.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800530 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800531 return 0;
532 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800533
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800534 image->config_signature = (uint8_t*) Malloc(signature_len);
535 Memcpy(image->config_signature, config_signature, signature_len);
536 Free(config_signature);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700537 /* Kernel signature muse be calculated on the kernel version, options and
538 * kernel data to avoid splicing attacks. */
539 kernel_buf = (uint8_t*) Malloc(GetKernelConfigLen() +
540 image->options.kernel_len);
541 Memcpy(kernel_buf, config_blob, GetKernelConfigLen());
542 Memcpy(kernel_buf + GetKernelConfigLen(), image->kernel_data,
543 image->options.kernel_len);
544 if (!(kernel_signature = SignatureBuf(kernel_buf,
545 GetKernelConfigLen() +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800546 image->options.kernel_len,
547 kernel_signing_key_file,
548 image->kernel_sign_algorithm))) {
Gaurav Shah463be3f2010-03-29 16:13:45 -0700549 Free(config_blob);
550 Free(kernel_buf);
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700551 debug("Could not compute signature on the kernel.\n");
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800552 return 0;
553 }
554 image->kernel_signature = (uint8_t*) Malloc(signature_len);
555 Memcpy(image->kernel_signature, kernel_signature, signature_len);
556 Free(kernel_signature);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700557 Free(kernel_buf);
558 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800559 return 1;
560}
Gaurav Shaha82bf262010-03-26 10:38:08 -0700561
Gaurav Shaha82bf262010-03-26 10:38:08 -0700562void PrintKernelEntry(kernel_entry* entry) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700563 debug("Boot Priority = %d\n", entry->boot_priority);
564 debug("Boot Tries Remaining = %d\n", entry->boot_tries_remaining);
565 debug("Boot Success Flag = %d\n", entry->boot_success_flag);
Gaurav Shaha82bf262010-03-26 10:38:08 -0700566}