blob: fc71f35bc0ad972f476ff4f1418ff3930fcb6007 [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 Shahbf7615b2010-05-26 10:26:00 -070032 image->preamble_signature = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080033 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);
Gaurav Shahbf7615b2010-05-26 10:26:00 -070043 Free(image->preamble_signature);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080044 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;
Gaurav Shahe450be42010-03-29 21:27:08 -070071 st.overrun = 0;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080072
73 /* Read and compare magic bytes. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080074 StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080075
76 if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -070077 debug("Wrong Kernel Magic.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -080078 Free(kernel_buf);
79 return NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080080 }
81 StatefulMemcpy(&st, &image->header_version, FIELD_LEN(header_version));
82 StatefulMemcpy(&st, &image->header_len, FIELD_LEN(header_len));
83 StatefulMemcpy(&st, &image->firmware_sign_algorithm,
84 FIELD_LEN(firmware_sign_algorithm));
85 StatefulMemcpy(&st, &image->kernel_sign_algorithm,
86 FIELD_LEN(kernel_sign_algorithm));
87
88 /* Valid Kernel Key signing algorithm. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080089 if (image->firmware_sign_algorithm >= kNumAlgorithms) {
90 Free(kernel_buf);
91 return NULL;
92 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080093
94 /* Valid Kernel Signing Algorithm? */
Gaurav Shahf5564fa2010-03-02 15:40:01 -080095 if (image->kernel_sign_algorithm >= kNumAlgorithms) {
96 Free(kernel_buf);
97 return NULL;
98 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -080099
100 /* Compute size of pre-processed RSA public keys and signatures. */
101 firmware_sign_key_len = RSAProcessedKeySize(image->firmware_sign_algorithm);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800102 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800103 kernel_sign_key_len = RSAProcessedKeySize(image->kernel_sign_algorithm);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800104 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800105
106 /* Check whether key header length is correct. */
Gaurav Shah528a2c12010-03-18 13:10:10 -0700107 header_len = GetKernelHeaderLen(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800108 if (header_len != image->header_len) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700109 debug("Header length mismatch. Got: %d, Expected: %d\n",
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800110 image->header_len, header_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800111 Free(kernel_buf);
112 return NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800113 }
114
115 /* Read pre-processed public half of the kernel signing key. */
116 StatefulMemcpy(&st, &image->kernel_key_version,
117 FIELD_LEN(kernel_key_version));
118 image->kernel_sign_key = (uint8_t*) Malloc(kernel_sign_key_len);
119 StatefulMemcpy(&st, image->kernel_sign_key, kernel_sign_key_len);
120 StatefulMemcpy(&st, image->header_checksum, FIELD_LEN(header_checksum));
121
Gaurav Shah528a2c12010-03-18 13:10:10 -0700122 /* Check whether the header checksum matches. */
123 CalculateKernelHeaderChecksum(image, header_checksum);
124 if (SafeMemcmp(header_checksum, image->header_checksum,
125 FIELD_LEN(header_checksum))) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700126 debug("Invalid kernel header checksum!\n");
Gaurav Shah528a2c12010-03-18 13:10:10 -0700127 Free(kernel_buf);
128 return NULL;
129 }
130
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800131 /* Read key signature. */
Gaurav Shah80d129b2010-03-03 17:58:43 -0800132 image->kernel_key_signature = (uint8_t*) Malloc(kernel_key_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800133 StatefulMemcpy(&st, image->kernel_key_signature,
Gaurav Shah80d129b2010-03-03 17:58:43 -0800134 kernel_key_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800135
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700136 /* Read the kernel preamble. */
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800137 StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version));
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700138 StatefulMemcpy(&st, &image->kernel_len, FIELD_LEN(kernel_len));
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700139 StatefulMemcpy(&st, &image->bootloader_offset, FIELD_LEN(bootloader_offset));
140 StatefulMemcpy(&st, &image->bootloader_size, FIELD_LEN(bootloader_size));
141 StatefulMemcpy(&st, &image->padded_header_size,
142 FIELD_LEN(padded_header_size));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800143
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700144 /* Read config and kernel signatures. */
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700145 image->preamble_signature = (uint8_t*) Malloc(kernel_signature_len);
146 StatefulMemcpy(&st, image->preamble_signature, kernel_signature_len);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800147 image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len);
148 StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len);
149
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700150 /* Read kernel image data. */
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700151 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 Shahbf7615b2010-05-26 10:26:00 -0700221uint8_t* GetKernelPreambleBlob(const KernelImage* image) {
222 uint8_t* preamble_blob = NULL;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800223 MemcpyState st;
224
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700225 preamble_blob = (uint8_t*) Malloc(GetKernelPreambleLen());
226 st.remaining_len = GetKernelPreambleLen();
227 st.remaining_buf = preamble_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700228 st.overrun = 0;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800229
230 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700231 StatefulMemcpy_r(&st, &image->kernel_len, FIELD_LEN(kernel_len));
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700232 StatefulMemcpy_r(&st, &image->bootloader_offset, FIELD_LEN(bootloader_offset));
233 StatefulMemcpy_r(&st, &image->bootloader_size, FIELD_LEN(bootloader_size));
234 StatefulMemcpy_r(&st, &image->padded_header_size,
235 FIELD_LEN(padded_header_size));
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700236
Gaurav Shahe450be42010-03-29 21:27:08 -0700237 if (st.overrun || st.remaining_len != 0) { /* Overrun or Underrun. */
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700238 Free(preamble_blob);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800239 return NULL;
240 }
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700241 return preamble_blob;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800242}
243
Gaurav Shah13937112010-03-22 17:59:09 -0700244uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800245 int kernel_key_signature_len;
246 int kernel_signature_len;
247 uint8_t* kernel_blob = NULL;
248 uint8_t* header_blob = NULL;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800249 MemcpyState st;
250
251 if (!image)
252 return NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800253 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
254 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800255 *blob_len = (FIELD_LEN(magic) +
256 GetKernelHeaderLen(image) +
257 kernel_key_signature_len +
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700258 GetKernelPreambleLen() +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800259 2 * kernel_signature_len +
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700260 image->kernel_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800261 kernel_blob = (uint8_t*) Malloc(*blob_len);
262 st.remaining_len = *blob_len;
263 st.remaining_buf = kernel_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700264 st.overrun = 0;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800265
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800266 header_blob = GetKernelHeaderBlob(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800267
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800268 StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic));
269 StatefulMemcpy_r(&st, header_blob, GetKernelHeaderLen(image));
270 StatefulMemcpy_r(&st, image->kernel_key_signature, kernel_key_signature_len);
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700271 /* Copy over kernel preamble blob (including signatures.) */
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700272 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
273 StatefulMemcpy_r(&st, &image->kernel_len, FIELD_LEN(kernel_len));
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700274 StatefulMemcpy_r(&st, &image->bootloader_offset,
275 FIELD_LEN(bootloader_offset));
276 StatefulMemcpy_r(&st, &image->bootloader_size, FIELD_LEN(bootloader_size));
277 StatefulMemcpy_r(&st, &image->padded_header_size,
278 FIELD_LEN(padded_header_size));
279 StatefulMemcpy_r(&st, image->preamble_signature, kernel_signature_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800280 StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len);
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700281 StatefulMemcpy_r(&st, image->kernel_data, image->kernel_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800282
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800283 Free(header_blob);
284
Gaurav Shahe450be42010-03-29 21:27:08 -0700285 if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800286 Free(kernel_blob);
287 return NULL;
288 }
289 return kernel_blob;
290}
291
292int WriteKernelImage(const char* input_file,
Gaurav Shah2480a182010-04-26 11:41:53 -0700293 const KernelImage* image,
294 int is_only_vblock) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800295 int fd;
Gaurav Shah2480a182010-04-26 11:41:53 -0700296 int success = 1;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800297 uint8_t* kernel_blob;
Gaurav Shah13937112010-03-22 17:59:09 -0700298 uint64_t blob_len;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800299
300 if (!image)
301 return 0;
302 if (-1 == (fd = creat(input_file, S_IRWXU))) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700303 debug("Couldn't open file for writing kernel image: %s\n",
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800304 input_file);
305 return 0;
306 }
307 kernel_blob = GetKernelBlob(image, &blob_len);
308 if (!kernel_blob) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700309 debug("Couldn't create kernel blob from KernelImage.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800310 return 0;
311 }
Gaurav Shah2480a182010-04-26 11:41:53 -0700312 if (!is_only_vblock) {
313 if (blob_len != write(fd, kernel_blob, blob_len)) {
314 debug("Couldn't write Kernel Image to file: %s\n",
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800315 input_file);
Gaurav Shah2480a182010-04-26 11:41:53 -0700316 success = 0;
317 }
318 } else {
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700319 /* Exclude kernel_data. */
320 int vblock_len = blob_len - (image->kernel_len);
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 Shahbf7615b2010-05-26 10:26:00 -0700350 "kernel Length = %" PRId64 "\n"
351 "Bootloader Offset = %" PRId64 "\n"
352 "Bootloader Size = %" PRId64 "\n"
353 "Padded Header Size = %" PRId64 "\n",
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800354 image->kernel_version,
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700355 image->kernel_len,
356 image->bootloader_offset,
357 image->bootloader_size,
358 image->padded_header_size);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800359 /* TODO(gauravsh): Output kernel signature here? */
360}
361
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800362
363int VerifyKernelImage(const RSAPublicKey* firmware_key,
364 const KernelImage* image,
365 const int dev_mode) {
Gaurav Shah259de402010-03-12 17:42:03 -0800366 RSAPublicKey* kernel_sign_key = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800367 uint8_t* header_digest = NULL;
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700368 uint8_t* preamble_digest = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800369 uint8_t* kernel_digest = NULL;
370 int kernel_sign_key_size;
371 int kernel_signature_size;
372 int error_code = 0;
373 DigestContext ctx;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700374 DigestContext kernel_ctx;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800375 if (!image)
376 return VERIFY_KERNEL_INVALID_IMAGE;
377
378 /* Verify kernel key signature on the key header if we
379 * are not in dev mode.
380 *
381 * TODO(gauravsh): Add additional sanity checks here for:
382 * 1) verifying the header length is correct.
383 * 2) header_checksum is correct.
384 */
385
386 if (image->firmware_sign_algorithm >= kNumAlgorithms)
387 return VERIFY_KERNEL_INVALID_ALGORITHM;
388 if (image->kernel_sign_algorithm >= kNumAlgorithms)
389 return VERIFY_KERNEL_INVALID_ALGORITHM;
390
391 if (!dev_mode) {
392 DigestInit(&ctx, image->firmware_sign_algorithm);
393 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
394 FIELD_LEN(header_version));
395 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
396 FIELD_LEN(header_len));
397 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
398 FIELD_LEN(firmware_sign_algorithm));
399 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
400 FIELD_LEN(kernel_sign_algorithm));
401 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
402 FIELD_LEN(kernel_key_version));
403 DigestUpdate(&ctx, image->kernel_sign_key,
404 RSAProcessedKeySize(image->kernel_sign_algorithm));
405 DigestUpdate(&ctx, image->header_checksum,
406 FIELD_LEN(header_checksum));
407 header_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800408 if (!RSAVerify(firmware_key, image->kernel_key_signature,
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800409 siglen_map[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800410 image->firmware_sign_algorithm,
411 header_digest)) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700412 debug("VerifyKernelImage(): Key signature check failed.\n");
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800413 error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
414 goto verify_failure;
415 }
416 }
417
418 /* Get kernel signing key to verify the rest of the kernel. */
419 kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm);
420 kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
421 kernel_sign_key_size);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800422 kernel_signature_size = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800423
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700424 /* Verify kernel preamble signature. */
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800425 DigestInit(&ctx, image->kernel_sign_algorithm);
426 DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
427 FIELD_LEN(kernel_version));
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700428 DigestUpdate(&ctx, (uint8_t*) &image->kernel_len,
429 FIELD_LEN(kernel_len));
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700430 DigestUpdate(&ctx, (uint8_t*) &image->bootloader_offset,
431 FIELD_LEN(bootloader_offset));
432 DigestUpdate(&ctx, (uint8_t*) &image->bootloader_size,
433 FIELD_LEN(bootloader_size));
434 DigestUpdate(&ctx, (uint8_t*) &image->padded_header_size,
435 FIELD_LEN(padded_header_size));
436 preamble_digest = DigestFinal(&ctx);
437 if (!RSAVerify(kernel_sign_key, image->preamble_signature,
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800438 kernel_signature_size, image->kernel_sign_algorithm,
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700439 preamble_digest)) {
440 error_code = VERIFY_KERNEL_PREAMBLE_SIGNATURE_FAILED;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800441 goto verify_failure;
442 }
443
Gaurav Shah463be3f2010-03-29 16:13:45 -0700444 /* Verify kernel signature - kernel signature is computed on the contents
445 of kernel version + kernel options + kernel_data. */
446 DigestInit(&kernel_ctx, image->kernel_sign_algorithm);
447 DigestUpdate(&kernel_ctx, (uint8_t*) &image->kernel_version,
448 FIELD_LEN(kernel_version));
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700449 DigestUpdate(&kernel_ctx, (uint8_t*) &image->kernel_len,
450 FIELD_LEN(kernel_len));
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700451 DigestUpdate(&kernel_ctx, (uint8_t*) &image->bootloader_offset,
452 FIELD_LEN(bootloader_offset));
453 DigestUpdate(&kernel_ctx, (uint8_t*) &image->bootloader_size,
454 FIELD_LEN(bootloader_size));
455 DigestUpdate(&kernel_ctx, (uint8_t*) &image->padded_header_size,
456 FIELD_LEN(padded_header_size));
457 DigestUpdate(&kernel_ctx, (uint8_t*) image->kernel_data,
458 image->kernel_len);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700459 kernel_digest = DigestFinal(&kernel_ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800460 if (!RSAVerify(kernel_sign_key, image->kernel_signature,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800461 kernel_signature_size, image->kernel_sign_algorithm,
462 kernel_digest)) {
463 error_code = VERIFY_KERNEL_SIGNATURE_FAILED;
464 goto verify_failure;
465 }
466
467verify_failure:
Gaurav Shah259de402010-03-12 17:42:03 -0800468 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800469 Free(kernel_digest);
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700470 Free(preamble_digest);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800471 Free(header_digest);
472 return error_code;
473}
474
475const char* VerifyKernelErrorString(int error) {
476 return kVerifyKernelErrors[error];
477}
478
479int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800480 uint8_t* header_blob = NULL;
Gaurav Shah259de402010-03-12 17:42:03 -0800481 uint8_t* signature = NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800482 int signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800483 if (!image || !firmware_key_file)
484 return 0;
485 header_blob = GetKernelHeaderBlob(image);
486 if (!header_blob)
487 return 0;
488 if (!(signature = SignatureBuf(header_blob,
489 GetKernelHeaderLen(image),
490 firmware_key_file,
491 image->firmware_sign_algorithm))) {
492 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800493 return 0;
494 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800495 image->kernel_key_signature = Malloc(signature_len);
496 Memcpy(image->kernel_key_signature, signature, signature_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800497 Free(signature);
498 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800499 return 1;
500}
501
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800502int AddKernelSignature(KernelImage* image,
503 const char* kernel_signing_key_file) {
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700504 uint8_t* preamble_blob = NULL;
505 uint8_t* preamble_signature = NULL;
Gaurav Shah259de402010-03-12 17:42:03 -0800506 uint8_t* kernel_signature = NULL;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700507 uint8_t* kernel_buf;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800508 int signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800509
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700510 preamble_blob = GetKernelPreambleBlob(image);
511 if (!(preamble_signature = SignatureBuf(preamble_blob,
512 GetKernelPreambleLen(),
513 kernel_signing_key_file,
514 image->kernel_sign_algorithm))) {
515 debug("Could not compute signature on the kernel preamble.\n");
516 Free(preamble_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800517 return 0;
518 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800519
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700520 image->preamble_signature = (uint8_t*) Malloc(signature_len);
521 Memcpy(image->preamble_signature, preamble_signature, signature_len);
522 Free(preamble_signature);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700523 /* Kernel signature muse be calculated on the kernel version, options and
524 * kernel data to avoid splicing attacks. */
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700525 kernel_buf = (uint8_t*) Malloc(GetKernelPreambleLen() +
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700526 image->kernel_len);
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700527 Memcpy(kernel_buf, preamble_blob, GetKernelPreambleLen());
528 Memcpy(kernel_buf + GetKernelPreambleLen(), image->kernel_data,
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700529 image->kernel_len);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700530 if (!(kernel_signature = SignatureBuf(kernel_buf,
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700531 GetKernelPreambleLen() +
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700532 image->kernel_len,
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800533 kernel_signing_key_file,
534 image->kernel_sign_algorithm))) {
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700535 Free(preamble_blob);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700536 Free(kernel_buf);
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700537 debug("Could not compute signature on the kernel.\n");
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800538 return 0;
539 }
540 image->kernel_signature = (uint8_t*) Malloc(signature_len);
541 Memcpy(image->kernel_signature, kernel_signature, signature_len);
542 Free(kernel_signature);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700543 Free(kernel_buf);
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700544 Free(preamble_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800545 return 1;
546}
Gaurav Shaha82bf262010-03-26 10:38:08 -0700547
Gaurav Shaha82bf262010-03-26 10:38:08 -0700548void PrintKernelEntry(kernel_entry* entry) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700549 debug("Boot Priority = %d\n", entry->boot_priority);
550 debug("Boot Tries Remaining = %d\n", entry->boot_tries_remaining);
551 debug("Boot Success Flag = %d\n", entry->boot_success_flag);
Gaurav Shaha82bf262010-03-26 10:38:08 -0700552}