blob: 6833ef64bd96019883455b0453f057142383a006 [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 Shahbd52fc72010-04-29 15:30:25 -070032 Memset(image->kernel_config,
33 0,
34 sizeof(image->kernel_config));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080035 image->config_signature = NULL;
36 image->kernel_signature = NULL;
37 image->kernel_data = NULL;
38 }
39 return image;
40}
41
42void KernelImageFree(KernelImage* image) {
43 if (image) {
44 Free(image->kernel_sign_key);
45 Free(image->kernel_key_signature);
46 Free(image->config_signature);
47 Free(image->kernel_signature);
48 Free(image->kernel_data);
49 Free(image);
50 }
51}
52
53KernelImage* ReadKernelImage(const char* input_file) {
Gaurav Shah456678b2010-03-10 18:38:45 -080054 uint64_t file_size;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080055 int image_len = 0; /* Total size of the kernel image. */
56 int header_len = 0;
57 int firmware_sign_key_len;
58 int kernel_key_signature_len;
59 int kernel_sign_key_len;
60 int kernel_signature_len;
61 uint8_t* kernel_buf;
Gaurav Shah528a2c12010-03-18 13:10:10 -070062 uint8_t header_checksum[FIELD_LEN(header_checksum)];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080063 MemcpyState st;
64 KernelImage* image = KernelImageNew();
65
66 if (!image)
67 return NULL;
68
69 kernel_buf = BufferFromFile(input_file, &file_size);
70 image_len = file_size;
71
72 st.remaining_len = image_len;
73 st.remaining_buf = kernel_buf;
Gaurav Shahe450be42010-03-29 21:27:08 -070074 st.overrun = 0;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080075
76 /* Read and compare magic bytes. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080077 StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080078
79 if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -070080 debug("Wrong Kernel Magic.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -080081 Free(kernel_buf);
82 return NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080083 }
84 StatefulMemcpy(&st, &image->header_version, FIELD_LEN(header_version));
85 StatefulMemcpy(&st, &image->header_len, FIELD_LEN(header_len));
86 StatefulMemcpy(&st, &image->firmware_sign_algorithm,
87 FIELD_LEN(firmware_sign_algorithm));
88 StatefulMemcpy(&st, &image->kernel_sign_algorithm,
89 FIELD_LEN(kernel_sign_algorithm));
90
91 /* Valid Kernel Key signing algorithm. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080092 if (image->firmware_sign_algorithm >= kNumAlgorithms) {
93 Free(kernel_buf);
94 return NULL;
95 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080096
97 /* Valid Kernel Signing Algorithm? */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080098 if (image->kernel_sign_algorithm >= kNumAlgorithms) {
99 Free(kernel_buf);
100 return NULL;
101 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800102
103 /* Compute size of pre-processed RSA public keys and signatures. */
104 firmware_sign_key_len = RSAProcessedKeySize(image->firmware_sign_algorithm);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800105 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800106 kernel_sign_key_len = RSAProcessedKeySize(image->kernel_sign_algorithm);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800107 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800108
109 /* Check whether key header length is correct. */
Gaurav Shah528a2c12010-03-18 13:10:10 -0700110 header_len = GetKernelHeaderLen(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800111 if (header_len != image->header_len) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700112 debug("Header length mismatch. Got: %d, Expected: %d\n",
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800113 image->header_len, header_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800114 Free(kernel_buf);
115 return NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800116 }
117
118 /* Read pre-processed public half of the kernel signing key. */
119 StatefulMemcpy(&st, &image->kernel_key_version,
120 FIELD_LEN(kernel_key_version));
121 image->kernel_sign_key = (uint8_t*) Malloc(kernel_sign_key_len);
122 StatefulMemcpy(&st, image->kernel_sign_key, kernel_sign_key_len);
123 StatefulMemcpy(&st, image->header_checksum, FIELD_LEN(header_checksum));
124
Gaurav Shah528a2c12010-03-18 13:10:10 -0700125 /* Check whether the header checksum matches. */
126 CalculateKernelHeaderChecksum(image, header_checksum);
127 if (SafeMemcmp(header_checksum, image->header_checksum,
128 FIELD_LEN(header_checksum))) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700129 debug("Invalid kernel header checksum!\n");
Gaurav Shah528a2c12010-03-18 13:10:10 -0700130 Free(kernel_buf);
131 return NULL;
132 }
133
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800134 /* Read key signature. */
Gaurav Shah80d129b2010-03-03 17:58:43 -0800135 image->kernel_key_signature = (uint8_t*) Malloc(kernel_key_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800136 StatefulMemcpy(&st, image->kernel_key_signature,
Gaurav Shah80d129b2010-03-03 17:58:43 -0800137 kernel_key_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800138
139 /* Read the kernel config. */
140 StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version));
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700141 StatefulMemcpy(&st, &image->kernel_len, FIELD_LEN(kernel_len));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800142
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700143 /* Read config and kernel signatures. */
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800144 image->config_signature = (uint8_t*) Malloc(kernel_signature_len);
145 StatefulMemcpy(&st, image->config_signature, kernel_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800146 image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len);
147 StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len);
148
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700149 /* Read kernel config command line and kernel image data. */
150 StatefulMemcpy(&st, image->kernel_config, FIELD_LEN(kernel_config));
151 image->kernel_data = (uint8_t*) Malloc(image->kernel_len);
152 StatefulMemcpy(&st, image->kernel_data, image->kernel_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800153
Gaurav Shahe450be42010-03-29 21:27:08 -0700154 if(st.overrun || st.remaining_len != 0) { /* Overrun or underrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800155 Free(kernel_buf);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800156 return NULL;
157 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800158 Free(kernel_buf);
159 return image;
160}
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800161
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800162int GetKernelHeaderLen(const KernelImage* image) {
163 return (FIELD_LEN(header_version) + FIELD_LEN(header_len) +
164 FIELD_LEN(firmware_sign_algorithm) +
165 FIELD_LEN(kernel_sign_algorithm) + FIELD_LEN(kernel_key_version) +
166 RSAProcessedKeySize(image->kernel_sign_algorithm) +
167 FIELD_LEN(header_checksum));
168}
169
Gaurav Shah528a2c12010-03-18 13:10:10 -0700170void CalculateKernelHeaderChecksum(const KernelImage* image,
171 uint8_t* header_checksum) {
172 uint8_t* checksum;
173 DigestContext ctx;
174 DigestInit(&ctx, SHA512_DIGEST_ALGORITHM);
175 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
176 sizeof(image->header_version));
177 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
178 sizeof(image->header_len));
179 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
180 sizeof(image->firmware_sign_algorithm));
181 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
182 sizeof(image->kernel_sign_algorithm));
183 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
184 sizeof(image->kernel_key_version));
185 DigestUpdate(&ctx, image->kernel_sign_key,
186 RSAProcessedKeySize(image->kernel_sign_algorithm));
187 checksum = DigestFinal(&ctx);
188 Memcpy(header_checksum, checksum, FIELD_LEN(header_checksum));
189 Free(checksum);
190 return;
191}
192
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800193uint8_t* GetKernelHeaderBlob(const KernelImage* image) {
194 uint8_t* header_blob = NULL;
195 MemcpyState st;
196
197 header_blob = (uint8_t*) Malloc(GetKernelHeaderLen(image));
198 st.remaining_len = GetKernelHeaderLen(image);
199 st.remaining_buf = header_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700200 st.overrun = 0;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800201
202 StatefulMemcpy_r(&st, &image->header_version, FIELD_LEN(header_version));
203 StatefulMemcpy_r(&st, &image->header_len, FIELD_LEN(header_len));
204 StatefulMemcpy_r(&st, &image->firmware_sign_algorithm,
205 FIELD_LEN(firmware_sign_algorithm));
206 StatefulMemcpy_r(&st, &image->kernel_sign_algorithm,
207 FIELD_LEN(kernel_sign_algorithm));
208 StatefulMemcpy_r(&st, &image->kernel_key_version,
209 FIELD_LEN(kernel_key_version));
210 StatefulMemcpy_r(&st, image->kernel_sign_key,
211 RSAProcessedKeySize(image->kernel_sign_algorithm));
212 StatefulMemcpy_r(&st, &image->header_checksum, FIELD_LEN(header_checksum));
213
Gaurav Shahe450be42010-03-29 21:27:08 -0700214 if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800215 Free(header_blob);
216 return NULL;
217 }
218 return header_blob;
219}
220
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700221int GetKernelConfigLen(const KernelImage* image) {
Gaurav Shah4f393862010-03-12 18:13:24 -0800222 return (FIELD_LEN(kernel_version) +
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700223 FIELD_LEN(kernel_len) +
224 FIELD_LEN(kernel_config));
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800225}
226
227uint8_t* GetKernelConfigBlob(const KernelImage* image) {
228 uint8_t* config_blob = NULL;
229 MemcpyState st;
230
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700231 config_blob = (uint8_t*) Malloc(GetKernelConfigLen(image));
232 st.remaining_len = GetKernelConfigLen(image);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800233 st.remaining_buf = config_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700234 st.overrun = 0;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800235
236 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700237 StatefulMemcpy_r(&st, &image->kernel_len, FIELD_LEN(kernel_len));
238 StatefulMemcpy_r(&st, image->kernel_config, FIELD_LEN(kernel_config));
239
Gaurav Shahe450be42010-03-29 21:27:08 -0700240 if (st.overrun || st.remaining_len != 0) { /* Overrun or Underrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800241 Free(config_blob);
242 return NULL;
243 }
244 return config_blob;
245}
246
Gaurav Shah13937112010-03-22 17:59:09 -0700247uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800248 int kernel_key_signature_len;
249 int kernel_signature_len;
250 uint8_t* kernel_blob = NULL;
251 uint8_t* header_blob = NULL;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800252 MemcpyState st;
253
254 if (!image)
255 return NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800256 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
257 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800258 *blob_len = (FIELD_LEN(magic) +
259 GetKernelHeaderLen(image) +
260 kernel_key_signature_len +
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700261 GetKernelConfigLen(image) +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800262 2 * kernel_signature_len +
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700263 image->kernel_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800264 kernel_blob = (uint8_t*) Malloc(*blob_len);
265 st.remaining_len = *blob_len;
266 st.remaining_buf = kernel_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700267 st.overrun = 0;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800268
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800269 header_blob = GetKernelHeaderBlob(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800270
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800271 StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic));
272 StatefulMemcpy_r(&st, header_blob, GetKernelHeaderLen(image));
273 StatefulMemcpy_r(&st, image->kernel_key_signature, kernel_key_signature_len);
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700274 /* Copy over kernel config blob (including signatures.) */
275 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
276 StatefulMemcpy_r(&st, &image->kernel_len, FIELD_LEN(kernel_len));
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800277 StatefulMemcpy_r(&st, image->config_signature, kernel_signature_len);
278 StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len);
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700279 StatefulMemcpy_r(&st, image->kernel_config, FIELD_LEN(kernel_config));
280 StatefulMemcpy_r(&st, image->kernel_data, image->kernel_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800281
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800282 Free(header_blob);
283
Gaurav Shahe450be42010-03-29 21:27:08 -0700284 if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800285 Free(kernel_blob);
286 return NULL;
287 }
288 return kernel_blob;
289}
290
291int WriteKernelImage(const char* input_file,
Gaurav Shah2480a182010-04-26 11:41:53 -0700292 const KernelImage* image,
293 int is_only_vblock) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800294 int fd;
Gaurav Shah2480a182010-04-26 11:41:53 -0700295 int success = 1;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800296 uint8_t* kernel_blob;
Gaurav Shah13937112010-03-22 17:59:09 -0700297 uint64_t blob_len;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800298
299 if (!image)
300 return 0;
301 if (-1 == (fd = creat(input_file, S_IRWXU))) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700302 debug("Couldn't open file for writing kernel image: %s\n",
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800303 input_file);
304 return 0;
305 }
306 kernel_blob = GetKernelBlob(image, &blob_len);
307 if (!kernel_blob) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700308 debug("Couldn't create kernel blob from KernelImage.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800309 return 0;
310 }
Gaurav Shah2480a182010-04-26 11:41:53 -0700311 if (!is_only_vblock) {
312 if (blob_len != write(fd, kernel_blob, blob_len)) {
313 debug("Couldn't write Kernel Image to file: %s\n",
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800314 input_file);
Gaurav Shah2480a182010-04-26 11:41:53 -0700315 success = 0;
316 }
317 } else {
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700318 /* Exclude kernel_config and kernel_data. */
319 int vblock_len = blob_len - (image->kernel_len +
320 sizeof(image->kernel_config));
Gaurav Shah2480a182010-04-26 11:41:53 -0700321 if (vblock_len != write(fd, kernel_blob, vblock_len)) {
322 debug("Couldn't write Kernel Image Verification block to file: %s\n",
323 input_file);
324 success = 0;
325 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800326 }
327 Free(kernel_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800328 close(fd);
Gaurav Shah2480a182010-04-26 11:41:53 -0700329 return success;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800330}
331
332void PrintKernelImage(const KernelImage* image) {
333 if (!image)
334 return;
335
336 /* Print header. */
Gaurav Shah528a2c12010-03-18 13:10:10 -0700337 printf("Header Version = %d\n"
338 "Header Length = %d\n"
339 "Kernel Key Signature Algorithm = %s\n"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800340 "Kernel Signature Algorithm = %s\n"
341 "Kernel Key Version = %d\n\n",
Gaurav Shah528a2c12010-03-18 13:10:10 -0700342 image->header_version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800343 image->header_len,
Gaurav Shah528a2c12010-03-18 13:10:10 -0700344 algo_strings[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800345 algo_strings[image->kernel_sign_algorithm],
346 image->kernel_key_version);
347 /* TODO(gauravsh): Output hash and key signature here? */
348 /* Print preamble. */
349 printf("Kernel Version = %d\n"
Gaurav Shah528a2c12010-03-18 13:10:10 -0700350 "Kernel Config command line = \"%s\"\n"
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700351 "kernel Length = %" PRId64 "\n",
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800352 image->kernel_version,
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700353 image->kernel_config,
354 image->kernel_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800355 /* TODO(gauravsh): Output kernel signature here? */
356}
357
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800358
359int VerifyKernelImage(const RSAPublicKey* firmware_key,
360 const KernelImage* image,
361 const int dev_mode) {
Gaurav Shah259de402010-03-12 17:42:03 -0800362 RSAPublicKey* kernel_sign_key = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800363 uint8_t* header_digest = NULL;
364 uint8_t* config_digest = NULL;
365 uint8_t* kernel_digest = NULL;
366 int kernel_sign_key_size;
367 int kernel_signature_size;
368 int error_code = 0;
369 DigestContext ctx;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700370 DigestContext kernel_ctx;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800371 if (!image)
372 return VERIFY_KERNEL_INVALID_IMAGE;
373
374 /* Verify kernel key signature on the key header if we
375 * are not in dev mode.
376 *
377 * TODO(gauravsh): Add additional sanity checks here for:
378 * 1) verifying the header length is correct.
379 * 2) header_checksum is correct.
380 */
381
382 if (image->firmware_sign_algorithm >= kNumAlgorithms)
383 return VERIFY_KERNEL_INVALID_ALGORITHM;
384 if (image->kernel_sign_algorithm >= kNumAlgorithms)
385 return VERIFY_KERNEL_INVALID_ALGORITHM;
386
387 if (!dev_mode) {
388 DigestInit(&ctx, image->firmware_sign_algorithm);
389 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
390 FIELD_LEN(header_version));
391 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
392 FIELD_LEN(header_len));
393 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
394 FIELD_LEN(firmware_sign_algorithm));
395 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
396 FIELD_LEN(kernel_sign_algorithm));
397 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
398 FIELD_LEN(kernel_key_version));
399 DigestUpdate(&ctx, image->kernel_sign_key,
400 RSAProcessedKeySize(image->kernel_sign_algorithm));
401 DigestUpdate(&ctx, image->header_checksum,
402 FIELD_LEN(header_checksum));
403 header_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800404 if (!RSAVerify(firmware_key, image->kernel_key_signature,
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800405 siglen_map[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800406 image->firmware_sign_algorithm,
407 header_digest)) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700408 debug("VerifyKernelImage(): Key signature check failed.\n");
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800409 error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
410 goto verify_failure;
411 }
412 }
413
414 /* Get kernel signing key to verify the rest of the kernel. */
415 kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm);
416 kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
417 kernel_sign_key_size);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800418 kernel_signature_size = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800419
420 /* Verify kernel config signature. */
421 DigestInit(&ctx, image->kernel_sign_algorithm);
422 DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
423 FIELD_LEN(kernel_version));
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700424 DigestUpdate(&ctx, (uint8_t*) &image->kernel_len,
425 FIELD_LEN(kernel_len));
426 DigestUpdate(&ctx, (uint8_t*) image->kernel_config,
427 FIELD_LEN(kernel_config));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800428 config_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800429 if (!RSAVerify(kernel_sign_key, image->config_signature,
430 kernel_signature_size, image->kernel_sign_algorithm,
431 config_digest)) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800432 error_code = VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
433 goto verify_failure;
434 }
435
Gaurav Shah463be3f2010-03-29 16:13:45 -0700436 /* Verify kernel signature - kernel signature is computed on the contents
437 of kernel version + kernel options + kernel_data. */
438 DigestInit(&kernel_ctx, image->kernel_sign_algorithm);
439 DigestUpdate(&kernel_ctx, (uint8_t*) &image->kernel_version,
440 FIELD_LEN(kernel_version));
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700441 DigestUpdate(&kernel_ctx, (uint8_t*) &image->kernel_len,
442 FIELD_LEN(kernel_len));
443 DigestUpdate(&kernel_ctx, (uint8_t*) image->kernel_config,
444 FIELD_LEN(kernel_config));
445 DigestUpdate(&kernel_ctx, image->kernel_data, image->kernel_len);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700446 kernel_digest = DigestFinal(&kernel_ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800447 if (!RSAVerify(kernel_sign_key, image->kernel_signature,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800448 kernel_signature_size, image->kernel_sign_algorithm,
449 kernel_digest)) {
450 error_code = VERIFY_KERNEL_SIGNATURE_FAILED;
451 goto verify_failure;
452 }
453
454verify_failure:
Gaurav Shah259de402010-03-12 17:42:03 -0800455 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800456 Free(kernel_digest);
457 Free(config_digest);
458 Free(header_digest);
459 return error_code;
460}
461
462const char* VerifyKernelErrorString(int error) {
463 return kVerifyKernelErrors[error];
464}
465
466int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800467 uint8_t* header_blob = NULL;
Gaurav Shah259de402010-03-12 17:42:03 -0800468 uint8_t* signature = NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800469 int signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800470 if (!image || !firmware_key_file)
471 return 0;
472 header_blob = GetKernelHeaderBlob(image);
473 if (!header_blob)
474 return 0;
475 if (!(signature = SignatureBuf(header_blob,
476 GetKernelHeaderLen(image),
477 firmware_key_file,
478 image->firmware_sign_algorithm))) {
479 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800480 return 0;
481 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800482 image->kernel_key_signature = Malloc(signature_len);
483 Memcpy(image->kernel_key_signature, signature, signature_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800484 Free(signature);
485 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800486 return 1;
487}
488
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800489int AddKernelSignature(KernelImage* image,
490 const char* kernel_signing_key_file) {
Gaurav Shah259de402010-03-12 17:42:03 -0800491 uint8_t* config_blob = NULL;
492 uint8_t* config_signature = NULL;
493 uint8_t* kernel_signature = NULL;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700494 uint8_t* kernel_buf;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800495 int signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800496
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800497 config_blob = GetKernelConfigBlob(image);
498 if (!(config_signature = SignatureBuf(config_blob,
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700499 GetKernelConfigLen(image),
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800500 kernel_signing_key_file,
501 image->kernel_sign_algorithm))) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700502 debug("Could not compute signature on the kernel config.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800503 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800504 return 0;
505 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800506
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800507 image->config_signature = (uint8_t*) Malloc(signature_len);
508 Memcpy(image->config_signature, config_signature, signature_len);
509 Free(config_signature);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700510 /* Kernel signature muse be calculated on the kernel version, options and
511 * kernel data to avoid splicing attacks. */
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700512 kernel_buf = (uint8_t*) Malloc(GetKernelConfigLen(image) +
513 image->kernel_len);
514 Memcpy(kernel_buf, config_blob, GetKernelConfigLen(image));
515 Memcpy(kernel_buf + GetKernelConfigLen(image), image->kernel_data,
516 image->kernel_len);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700517 if (!(kernel_signature = SignatureBuf(kernel_buf,
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700518 GetKernelConfigLen(image) +
519 image->kernel_len,
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800520 kernel_signing_key_file,
521 image->kernel_sign_algorithm))) {
Gaurav Shah463be3f2010-03-29 16:13:45 -0700522 Free(config_blob);
523 Free(kernel_buf);
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700524 debug("Could not compute signature on the kernel.\n");
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800525 return 0;
526 }
527 image->kernel_signature = (uint8_t*) Malloc(signature_len);
528 Memcpy(image->kernel_signature, kernel_signature, signature_len);
529 Free(kernel_signature);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700530 Free(kernel_buf);
531 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800532 return 1;
533}
Gaurav Shaha82bf262010-03-26 10:38:08 -0700534
Gaurav Shaha82bf262010-03-26 10:38:08 -0700535void PrintKernelEntry(kernel_entry* entry) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700536 debug("Boot Priority = %d\n", entry->boot_priority);
537 debug("Boot Tries Remaining = %d\n", entry->boot_tries_remaining);
538 debug("Boot Success Flag = %d\n", entry->boot_success_flag);
Gaurav Shaha82bf262010-03-26 10:38:08 -0700539}