blob: e66ce384febfc7fe4f2ac21a5fe3783946423928 [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
17#include "file_keys.h"
David Garcia21c3f7f2010-03-31 09:04:15 -070018#include "padding.h"
Gaurav Shaha82bf262010-03-26 10:38:08 -070019#include "rollback_index.h"
David Garcia21c3f7f2010-03-31 09:04:15 -070020#include "rsa_utility.h"
21#include "sha_utility.h"
Gaurav Shahf5564fa2010-03-02 15:40:01 -080022#include "signature_digest.h"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080023#include "utility.h"
24
25/* Macro to determine the size of a field structure in the KernelImage
26 * structure. */
27#define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field))
28
29KernelImage* KernelImageNew(void) {
30 KernelImage* image = (KernelImage*) Malloc(sizeof(KernelImage));
31 if (image) {
32 image->kernel_sign_key = NULL;
33 image->kernel_key_signature = NULL;
34 image->config_signature = NULL;
35 image->kernel_signature = NULL;
36 image->kernel_data = NULL;
37 }
38 return image;
39}
40
41void KernelImageFree(KernelImage* image) {
42 if (image) {
43 Free(image->kernel_sign_key);
44 Free(image->kernel_key_signature);
45 Free(image->config_signature);
46 Free(image->kernel_signature);
47 Free(image->kernel_data);
48 Free(image);
49 }
50}
51
52KernelImage* ReadKernelImage(const char* input_file) {
Gaurav Shah456678b2010-03-10 18:38:45 -080053 uint64_t file_size;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080054 int image_len = 0; /* Total size of the kernel image. */
55 int header_len = 0;
56 int firmware_sign_key_len;
57 int kernel_key_signature_len;
58 int kernel_sign_key_len;
59 int kernel_signature_len;
60 uint8_t* kernel_buf;
Gaurav Shah528a2c12010-03-18 13:10:10 -070061 uint8_t header_checksum[FIELD_LEN(header_checksum)];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080062 MemcpyState st;
63 KernelImage* image = KernelImageNew();
64
65 if (!image)
66 return NULL;
67
68 kernel_buf = BufferFromFile(input_file, &file_size);
69 image_len = file_size;
70
71 st.remaining_len = image_len;
72 st.remaining_buf = kernel_buf;
Gaurav Shahe450be42010-03-29 21:27:08 -070073 st.overrun = 0;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080074
75 /* Read and compare magic bytes. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080076 StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080077
78 if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -070079 debug("Wrong Kernel Magic.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -080080 Free(kernel_buf);
81 return NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080082 }
83 StatefulMemcpy(&st, &image->header_version, FIELD_LEN(header_version));
84 StatefulMemcpy(&st, &image->header_len, FIELD_LEN(header_len));
85 StatefulMemcpy(&st, &image->firmware_sign_algorithm,
86 FIELD_LEN(firmware_sign_algorithm));
87 StatefulMemcpy(&st, &image->kernel_sign_algorithm,
88 FIELD_LEN(kernel_sign_algorithm));
89
90 /* Valid Kernel Key signing algorithm. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080091 if (image->firmware_sign_algorithm >= kNumAlgorithms) {
92 Free(kernel_buf);
93 return NULL;
94 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080095
96 /* Valid Kernel Signing Algorithm? */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080097 if (image->kernel_sign_algorithm >= kNumAlgorithms) {
98 Free(kernel_buf);
99 return NULL;
100 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800101
102 /* Compute size of pre-processed RSA public keys and signatures. */
103 firmware_sign_key_len = RSAProcessedKeySize(image->firmware_sign_algorithm);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800104 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800105 kernel_sign_key_len = RSAProcessedKeySize(image->kernel_sign_algorithm);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800106 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800107
108 /* Check whether key header length is correct. */
Gaurav Shah528a2c12010-03-18 13:10:10 -0700109 header_len = GetKernelHeaderLen(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800110 if (header_len != image->header_len) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700111 debug("Header length mismatch. Got: %d, Expected: %d\n",
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800112 image->header_len, header_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800113 Free(kernel_buf);
114 return NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800115 }
116
117 /* Read pre-processed public half of the kernel signing key. */
118 StatefulMemcpy(&st, &image->kernel_key_version,
119 FIELD_LEN(kernel_key_version));
120 image->kernel_sign_key = (uint8_t*) Malloc(kernel_sign_key_len);
121 StatefulMemcpy(&st, image->kernel_sign_key, kernel_sign_key_len);
122 StatefulMemcpy(&st, image->header_checksum, FIELD_LEN(header_checksum));
123
Gaurav Shah528a2c12010-03-18 13:10:10 -0700124 /* Check whether the header checksum matches. */
125 CalculateKernelHeaderChecksum(image, header_checksum);
126 if (SafeMemcmp(header_checksum, image->header_checksum,
127 FIELD_LEN(header_checksum))) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700128 debug("Invalid kernel header checksum!\n");
Gaurav Shah528a2c12010-03-18 13:10:10 -0700129 Free(kernel_buf);
130 return NULL;
131 }
132
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800133 /* Read key signature. */
Gaurav Shah80d129b2010-03-03 17:58:43 -0800134 image->kernel_key_signature = (uint8_t*) Malloc(kernel_key_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800135 StatefulMemcpy(&st, image->kernel_key_signature,
Gaurav Shah80d129b2010-03-03 17:58:43 -0800136 kernel_key_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800137
138 /* Read the kernel config. */
139 StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version));
140 StatefulMemcpy(&st, &image->options.version, FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800141 StatefulMemcpy(&st, &image->options.cmd_line, FIELD_LEN(options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800142 StatefulMemcpy(&st, &image->options.kernel_len,
143 FIELD_LEN(options.kernel_len));
144 StatefulMemcpy(&st, &image->options.kernel_load_addr,
145 FIELD_LEN(options.kernel_load_addr));
146 StatefulMemcpy(&st, &image->options.kernel_entry_addr,
147 FIELD_LEN(options.kernel_entry_addr));
148
149 /* Read kernel config signature. */
150 image->config_signature = (uint8_t*) Malloc(kernel_signature_len);
151 StatefulMemcpy(&st, image->config_signature, kernel_signature_len);
152
153 image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len);
154 StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len);
155
156 image->kernel_data = (uint8_t*) Malloc(image->options.kernel_len);
157 StatefulMemcpy(&st, image->kernel_data, image->options.kernel_len);
158
Gaurav Shahe450be42010-03-29 21:27:08 -0700159 if(st.overrun || st.remaining_len != 0) { /* Overrun or underrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800160 Free(kernel_buf);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800161 return NULL;
162 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800163 Free(kernel_buf);
164 return image;
165}
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800166
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800167int GetKernelHeaderLen(const KernelImage* image) {
168 return (FIELD_LEN(header_version) + FIELD_LEN(header_len) +
169 FIELD_LEN(firmware_sign_algorithm) +
170 FIELD_LEN(kernel_sign_algorithm) + FIELD_LEN(kernel_key_version) +
171 RSAProcessedKeySize(image->kernel_sign_algorithm) +
172 FIELD_LEN(header_checksum));
173}
174
Gaurav Shah528a2c12010-03-18 13:10:10 -0700175void CalculateKernelHeaderChecksum(const KernelImage* image,
176 uint8_t* header_checksum) {
177 uint8_t* checksum;
178 DigestContext ctx;
179 DigestInit(&ctx, SHA512_DIGEST_ALGORITHM);
180 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
181 sizeof(image->header_version));
182 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
183 sizeof(image->header_len));
184 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
185 sizeof(image->firmware_sign_algorithm));
186 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
187 sizeof(image->kernel_sign_algorithm));
188 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
189 sizeof(image->kernel_key_version));
190 DigestUpdate(&ctx, image->kernel_sign_key,
191 RSAProcessedKeySize(image->kernel_sign_algorithm));
192 checksum = DigestFinal(&ctx);
193 Memcpy(header_checksum, checksum, FIELD_LEN(header_checksum));
194 Free(checksum);
195 return;
196}
197
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800198uint8_t* GetKernelHeaderBlob(const KernelImage* image) {
199 uint8_t* header_blob = NULL;
200 MemcpyState st;
201
202 header_blob = (uint8_t*) Malloc(GetKernelHeaderLen(image));
203 st.remaining_len = GetKernelHeaderLen(image);
204 st.remaining_buf = header_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700205 st.overrun = 0;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800206
207 StatefulMemcpy_r(&st, &image->header_version, FIELD_LEN(header_version));
208 StatefulMemcpy_r(&st, &image->header_len, FIELD_LEN(header_len));
209 StatefulMemcpy_r(&st, &image->firmware_sign_algorithm,
210 FIELD_LEN(firmware_sign_algorithm));
211 StatefulMemcpy_r(&st, &image->kernel_sign_algorithm,
212 FIELD_LEN(kernel_sign_algorithm));
213 StatefulMemcpy_r(&st, &image->kernel_key_version,
214 FIELD_LEN(kernel_key_version));
215 StatefulMemcpy_r(&st, image->kernel_sign_key,
216 RSAProcessedKeySize(image->kernel_sign_algorithm));
217 StatefulMemcpy_r(&st, &image->header_checksum, FIELD_LEN(header_checksum));
218
Gaurav Shahe450be42010-03-29 21:27:08 -0700219 if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800220 Free(header_blob);
221 return NULL;
222 }
223 return header_blob;
224}
225
Gaurav Shah463be3f2010-03-29 16:13:45 -0700226int GetKernelConfigLen() {
Gaurav Shah4f393862010-03-12 18:13:24 -0800227 return (FIELD_LEN(kernel_version) +
228 FIELD_LEN(options.version) + FIELD_LEN(options.cmd_line) +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800229 FIELD_LEN(options.kernel_len) + FIELD_LEN(options.kernel_load_addr) +
230 FIELD_LEN(options.kernel_entry_addr));
231}
232
233uint8_t* GetKernelConfigBlob(const KernelImage* image) {
234 uint8_t* config_blob = NULL;
235 MemcpyState st;
236
Gaurav Shah463be3f2010-03-29 16:13:45 -0700237 config_blob = (uint8_t*) Malloc(GetKernelConfigLen());
238 st.remaining_len = GetKernelConfigLen();
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800239 st.remaining_buf = config_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700240 st.overrun = 0;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800241
242 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
243 StatefulMemcpy_r(&st, image->options.version, FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800244 StatefulMemcpy_r(&st, image->options.cmd_line, FIELD_LEN(options.cmd_line));
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800245 StatefulMemcpy_r(&st, &image->options.kernel_len,
246 FIELD_LEN(options.kernel_len));
247 StatefulMemcpy_r(&st, &image->options.kernel_load_addr,
248 FIELD_LEN(options.kernel_load_addr));
249 StatefulMemcpy_r(&st, &image->options.kernel_entry_addr,
250 FIELD_LEN(options.kernel_entry_addr));
Gaurav Shahe450be42010-03-29 21:27:08 -0700251 if (st.overrun || st.remaining_len != 0) { /* Overrun or Underrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800252 Free(config_blob);
253 return NULL;
254 }
255 return config_blob;
256}
257
Gaurav Shah13937112010-03-22 17:59:09 -0700258uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800259 int kernel_key_signature_len;
260 int kernel_signature_len;
261 uint8_t* kernel_blob = NULL;
262 uint8_t* header_blob = NULL;
263 uint8_t* config_blob = NULL;
264 MemcpyState st;
265
266 if (!image)
267 return NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800268 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
269 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800270 *blob_len = (FIELD_LEN(magic) +
271 GetKernelHeaderLen(image) +
272 kernel_key_signature_len +
Gaurav Shah463be3f2010-03-29 16:13:45 -0700273 GetKernelConfigLen() +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800274 2 * kernel_signature_len +
275 image->options.kernel_len);
276 kernel_blob = (uint8_t*) Malloc(*blob_len);
277 st.remaining_len = *blob_len;
278 st.remaining_buf = kernel_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700279 st.overrun = 0;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800280
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800281 header_blob = GetKernelHeaderBlob(image);
282 config_blob = GetKernelConfigBlob(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800283
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800284 StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic));
285 StatefulMemcpy_r(&st, header_blob, GetKernelHeaderLen(image));
286 StatefulMemcpy_r(&st, image->kernel_key_signature, kernel_key_signature_len);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700287 StatefulMemcpy_r(&st, config_blob, GetKernelConfigLen());
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800288 StatefulMemcpy_r(&st, image->config_signature, kernel_signature_len);
289 StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len);
290 StatefulMemcpy_r(&st, image->kernel_data, image->options.kernel_len);
291
292 Free(config_blob);
293 Free(header_blob);
294
Gaurav Shahe450be42010-03-29 21:27:08 -0700295 if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800296 Free(kernel_blob);
297 return NULL;
298 }
299 return kernel_blob;
300}
301
302int WriteKernelImage(const char* input_file,
303 const KernelImage* image) {
304 int fd;
305 uint8_t* kernel_blob;
Gaurav Shah13937112010-03-22 17:59:09 -0700306 uint64_t blob_len;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800307
308 if (!image)
309 return 0;
310 if (-1 == (fd = creat(input_file, S_IRWXU))) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700311 debug("Couldn't open file for writing kernel image: %s\n",
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800312 input_file);
313 return 0;
314 }
315 kernel_blob = GetKernelBlob(image, &blob_len);
316 if (!kernel_blob) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700317 debug("Couldn't create kernel blob from KernelImage.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800318 return 0;
319 }
320 if (blob_len != write(fd, kernel_blob, blob_len)) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700321 debug("Couldn't write Kernel Image to file: %s\n",
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800322 input_file);
323
324 Free(kernel_blob);
325 close(fd);
326 return 0;
327 }
328 Free(kernel_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800329 close(fd);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800330 return 1;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800331}
332
333void PrintKernelImage(const KernelImage* image) {
334 if (!image)
335 return;
336
337 /* Print header. */
Gaurav Shah528a2c12010-03-18 13:10:10 -0700338 printf("Header Version = %d\n"
339 "Header Length = %d\n"
340 "Kernel Key Signature Algorithm = %s\n"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800341 "Kernel Signature Algorithm = %s\n"
342 "Kernel Key Version = %d\n\n",
Gaurav Shah528a2c12010-03-18 13:10:10 -0700343 image->header_version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800344 image->header_len,
Gaurav Shah528a2c12010-03-18 13:10:10 -0700345 algo_strings[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800346 algo_strings[image->kernel_sign_algorithm],
347 image->kernel_key_version);
348 /* TODO(gauravsh): Output hash and key signature here? */
349 /* Print preamble. */
350 printf("Kernel Version = %d\n"
351 "Kernel Config Version = %d.%d\n"
Gaurav Shah528a2c12010-03-18 13:10:10 -0700352 "Kernel Config command line = \"%s\"\n"
Gaurav Shah456678b2010-03-10 18:38:45 -0800353 "kernel Length = %" PRId64 "\n"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800354 "Kernel Load Address = %" PRId64 "\n"
355 "Kernel Entry Address = %" PRId64 "\n\n",
356 image->kernel_version,
357 image->options.version[0], image->options.version[1],
Gaurav Shah4f393862010-03-12 18:13:24 -0800358 image->options.cmd_line,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800359 image->options.kernel_len,
360 image->options.kernel_load_addr,
361 image->options.kernel_entry_addr);
362 /* TODO(gauravsh): Output kernel signature here? */
363}
364
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800365
366int VerifyKernelImage(const RSAPublicKey* firmware_key,
367 const KernelImage* image,
368 const int dev_mode) {
Gaurav Shah259de402010-03-12 17:42:03 -0800369 RSAPublicKey* kernel_sign_key = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800370 uint8_t* header_digest = NULL;
371 uint8_t* config_digest = NULL;
372 uint8_t* kernel_digest = NULL;
373 int kernel_sign_key_size;
374 int kernel_signature_size;
375 int error_code = 0;
376 DigestContext ctx;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700377 DigestContext kernel_ctx;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800378 if (!image)
379 return VERIFY_KERNEL_INVALID_IMAGE;
380
381 /* Verify kernel key signature on the key header if we
382 * are not in dev mode.
383 *
384 * TODO(gauravsh): Add additional sanity checks here for:
385 * 1) verifying the header length is correct.
386 * 2) header_checksum is correct.
387 */
388
389 if (image->firmware_sign_algorithm >= kNumAlgorithms)
390 return VERIFY_KERNEL_INVALID_ALGORITHM;
391 if (image->kernel_sign_algorithm >= kNumAlgorithms)
392 return VERIFY_KERNEL_INVALID_ALGORITHM;
393
394 if (!dev_mode) {
395 DigestInit(&ctx, image->firmware_sign_algorithm);
396 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
397 FIELD_LEN(header_version));
398 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
399 FIELD_LEN(header_len));
400 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
401 FIELD_LEN(firmware_sign_algorithm));
402 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
403 FIELD_LEN(kernel_sign_algorithm));
404 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
405 FIELD_LEN(kernel_key_version));
406 DigestUpdate(&ctx, image->kernel_sign_key,
407 RSAProcessedKeySize(image->kernel_sign_algorithm));
408 DigestUpdate(&ctx, image->header_checksum,
409 FIELD_LEN(header_checksum));
410 header_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800411 if (!RSAVerify(firmware_key, image->kernel_key_signature,
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800412 siglen_map[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800413 image->firmware_sign_algorithm,
414 header_digest)) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700415 debug("VerifyKernelImage(): Key signature check failed.\n");
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800416 error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
417 goto verify_failure;
418 }
419 }
420
421 /* Get kernel signing key to verify the rest of the kernel. */
422 kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm);
423 kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
424 kernel_sign_key_size);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800425 kernel_signature_size = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800426
427 /* Verify kernel config signature. */
428 DigestInit(&ctx, image->kernel_sign_algorithm);
429 DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
430 FIELD_LEN(kernel_version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800431 DigestUpdate(&ctx, (uint8_t*) image->options.version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800432 FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800433 DigestUpdate(&ctx, (uint8_t*) image->options.cmd_line,
434 FIELD_LEN(options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800435 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_len,
436 FIELD_LEN(options.kernel_len));
437 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_load_addr,
438 FIELD_LEN(options.kernel_load_addr));
439 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_entry_addr,
440 FIELD_LEN(options.kernel_entry_addr));
441 config_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800442 if (!RSAVerify(kernel_sign_key, image->config_signature,
443 kernel_signature_size, image->kernel_sign_algorithm,
444 config_digest)) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800445 error_code = VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
446 goto verify_failure;
447 }
448
Gaurav Shah463be3f2010-03-29 16:13:45 -0700449 /* Verify kernel signature - kernel signature is computed on the contents
450 of kernel version + kernel options + kernel_data. */
451 DigestInit(&kernel_ctx, image->kernel_sign_algorithm);
452 DigestUpdate(&kernel_ctx, (uint8_t*) &image->kernel_version,
453 FIELD_LEN(kernel_version));
454 DigestUpdate(&kernel_ctx, (uint8_t*) image->options.version,
455 FIELD_LEN(options.version));
456 DigestUpdate(&kernel_ctx, (uint8_t*) image->options.cmd_line,
457 FIELD_LEN(options.cmd_line));
458 DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_len,
459 FIELD_LEN(options.kernel_len));
460 DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_load_addr,
461 FIELD_LEN(options.kernel_load_addr));
462 DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_entry_addr,
463 FIELD_LEN(options.kernel_entry_addr));
464 DigestUpdate(&kernel_ctx, image->kernel_data, image->options.kernel_len);
465 kernel_digest = DigestFinal(&kernel_ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800466 if (!RSAVerify(kernel_sign_key, image->kernel_signature,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800467 kernel_signature_size, image->kernel_sign_algorithm,
468 kernel_digest)) {
469 error_code = VERIFY_KERNEL_SIGNATURE_FAILED;
470 goto verify_failure;
471 }
472
473verify_failure:
Gaurav Shah259de402010-03-12 17:42:03 -0800474 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800475 Free(kernel_digest);
476 Free(config_digest);
477 Free(header_digest);
478 return error_code;
479}
480
481const char* VerifyKernelErrorString(int error) {
482 return kVerifyKernelErrors[error];
483}
484
485int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800486 uint8_t* header_blob = NULL;
Gaurav Shah259de402010-03-12 17:42:03 -0800487 uint8_t* signature = NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800488 int signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800489 if (!image || !firmware_key_file)
490 return 0;
491 header_blob = GetKernelHeaderBlob(image);
492 if (!header_blob)
493 return 0;
494 if (!(signature = SignatureBuf(header_blob,
495 GetKernelHeaderLen(image),
496 firmware_key_file,
497 image->firmware_sign_algorithm))) {
498 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800499 return 0;
500 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800501 image->kernel_key_signature = Malloc(signature_len);
502 Memcpy(image->kernel_key_signature, signature, signature_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800503 Free(signature);
504 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800505 return 1;
506}
507
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800508int AddKernelSignature(KernelImage* image,
509 const char* kernel_signing_key_file) {
Gaurav Shah259de402010-03-12 17:42:03 -0800510 uint8_t* config_blob = NULL;
511 uint8_t* config_signature = NULL;
512 uint8_t* kernel_signature = NULL;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700513 uint8_t* kernel_buf;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800514 int signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800515
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800516 config_blob = GetKernelConfigBlob(image);
517 if (!(config_signature = SignatureBuf(config_blob,
Gaurav Shah463be3f2010-03-29 16:13:45 -0700518 GetKernelConfigLen(),
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800519 kernel_signing_key_file,
520 image->kernel_sign_algorithm))) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700521 debug("Could not compute signature on the kernel config.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800522 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800523 return 0;
524 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800525
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800526 image->config_signature = (uint8_t*) Malloc(signature_len);
527 Memcpy(image->config_signature, config_signature, signature_len);
528 Free(config_signature);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700529 /* Kernel signature muse be calculated on the kernel version, options and
530 * kernel data to avoid splicing attacks. */
531 kernel_buf = (uint8_t*) Malloc(GetKernelConfigLen() +
532 image->options.kernel_len);
533 Memcpy(kernel_buf, config_blob, GetKernelConfigLen());
534 Memcpy(kernel_buf + GetKernelConfigLen(), image->kernel_data,
535 image->options.kernel_len);
536 if (!(kernel_signature = SignatureBuf(kernel_buf,
537 GetKernelConfigLen() +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800538 image->options.kernel_len,
539 kernel_signing_key_file,
540 image->kernel_sign_algorithm))) {
Gaurav Shah463be3f2010-03-29 16:13:45 -0700541 Free(config_blob);
542 Free(kernel_buf);
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700543 debug("Could not compute signature on the kernel.\n");
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800544 return 0;
545 }
546 image->kernel_signature = (uint8_t*) Malloc(signature_len);
547 Memcpy(image->kernel_signature, kernel_signature, signature_len);
548 Free(kernel_signature);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700549 Free(kernel_buf);
550 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800551 return 1;
552}
Gaurav Shaha82bf262010-03-26 10:38:08 -0700553
Gaurav Shaha82bf262010-03-26 10:38:08 -0700554void PrintKernelEntry(kernel_entry* entry) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700555 debug("Boot Priority = %d\n", entry->boot_priority);
556 debug("Boot Tries Remaining = %d\n", entry->boot_tries_remaining);
557 debug("Boot Success Flag = %d\n", entry->boot_success_flag);
Gaurav Shaha82bf262010-03-26 10:38:08 -0700558}