blob: 5eeb784f679599b12eba5d2b92099f1466e7c29a [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 Shahbcd8f4a2010-05-26 13:19:00 -0700225 preamble_blob = (uint8_t*) Malloc(
226 GetKernelPreambleLen(image->kernel_sign_algorithm));
227 st.remaining_len = GetKernelPreambleLen(image->kernel_sign_algorithm);
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700228 st.remaining_buf = preamble_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700229 st.overrun = 0;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800230
231 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700232 StatefulMemcpy_r(&st, &image->kernel_len, FIELD_LEN(kernel_len));
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700233 StatefulMemcpy_r(&st, &image->bootloader_offset, FIELD_LEN(bootloader_offset));
234 StatefulMemcpy_r(&st, &image->bootloader_size, FIELD_LEN(bootloader_size));
235 StatefulMemcpy_r(&st, &image->padded_header_size,
236 FIELD_LEN(padded_header_size));
Gaurav Shahbcd8f4a2010-05-26 13:19:00 -0700237 StatefulMemcpy_r(&st, image->kernel_signature,
238 siglen_map[image->kernel_sign_algorithm]);
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700239
Gaurav Shahe450be42010-03-29 21:27:08 -0700240 if (st.overrun || st.remaining_len != 0) { /* Overrun or Underrun. */
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700241 Free(preamble_blob);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800242 return NULL;
243 }
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700244 return preamble_blob;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800245}
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 Shahbcd8f4a2010-05-26 13:19:00 -0700261 GetKernelPreambleLen(image->kernel_sign_algorithm) +
262 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 Shahbf7615b2010-05-26 10:26:00 -0700274 /* Copy over kernel preamble blob (including signatures.) */
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700275 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
276 StatefulMemcpy_r(&st, &image->kernel_len, FIELD_LEN(kernel_len));
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700277 StatefulMemcpy_r(&st, &image->bootloader_offset,
278 FIELD_LEN(bootloader_offset));
279 StatefulMemcpy_r(&st, &image->bootloader_size, FIELD_LEN(bootloader_size));
280 StatefulMemcpy_r(&st, &image->padded_header_size,
281 FIELD_LEN(padded_header_size));
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800282 StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len);
Gaurav Shahbcd8f4a2010-05-26 13:19:00 -0700283 StatefulMemcpy_r(&st, image->preamble_signature, kernel_signature_len);
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700284 StatefulMemcpy_r(&st, image->kernel_data, image->kernel_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800285
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800286 Free(header_blob);
287
Gaurav Shahe450be42010-03-29 21:27:08 -0700288 if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */
Gaurav Shahbcd8f4a2010-05-26 13:19:00 -0700289 debug("GetKernelBlob() failed.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800290 Free(kernel_blob);
291 return NULL;
292 }
293 return kernel_blob;
294}
295
296int WriteKernelImage(const char* input_file,
Gaurav Shah2480a182010-04-26 11:41:53 -0700297 const KernelImage* image,
298 int is_only_vblock) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800299 int fd;
Gaurav Shah2480a182010-04-26 11:41:53 -0700300 int success = 1;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800301 uint8_t* kernel_blob;
Gaurav Shah13937112010-03-22 17:59:09 -0700302 uint64_t blob_len;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800303
304 if (!image)
305 return 0;
306 if (-1 == (fd = creat(input_file, S_IRWXU))) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700307 debug("Couldn't open file for writing kernel image: %s\n",
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800308 input_file);
309 return 0;
310 }
311 kernel_blob = GetKernelBlob(image, &blob_len);
312 if (!kernel_blob) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700313 debug("Couldn't create kernel blob from KernelImage.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800314 return 0;
315 }
Gaurav Shah2480a182010-04-26 11:41:53 -0700316 if (!is_only_vblock) {
317 if (blob_len != write(fd, kernel_blob, blob_len)) {
318 debug("Couldn't write Kernel Image to file: %s\n",
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800319 input_file);
Gaurav Shah2480a182010-04-26 11:41:53 -0700320 success = 0;
321 }
322 } else {
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700323 /* Exclude kernel_data. */
324 int vblock_len = blob_len - (image->kernel_len);
Gaurav Shah2480a182010-04-26 11:41:53 -0700325 if (vblock_len != write(fd, kernel_blob, vblock_len)) {
326 debug("Couldn't write Kernel Image Verification block to file: %s\n",
327 input_file);
328 success = 0;
329 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800330 }
331 Free(kernel_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800332 close(fd);
Gaurav Shah2480a182010-04-26 11:41:53 -0700333 return success;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800334}
335
336void PrintKernelImage(const KernelImage* image) {
337 if (!image)
338 return;
339
340 /* Print header. */
Gaurav Shah528a2c12010-03-18 13:10:10 -0700341 printf("Header Version = %d\n"
342 "Header Length = %d\n"
343 "Kernel Key Signature Algorithm = %s\n"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800344 "Kernel Signature Algorithm = %s\n"
345 "Kernel Key Version = %d\n\n",
Gaurav Shah528a2c12010-03-18 13:10:10 -0700346 image->header_version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800347 image->header_len,
Gaurav Shah528a2c12010-03-18 13:10:10 -0700348 algo_strings[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800349 algo_strings[image->kernel_sign_algorithm],
350 image->kernel_key_version);
351 /* TODO(gauravsh): Output hash and key signature here? */
352 /* Print preamble. */
353 printf("Kernel Version = %d\n"
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700354 "kernel Length = %" PRId64 "\n"
355 "Bootloader Offset = %" PRId64 "\n"
356 "Bootloader Size = %" PRId64 "\n"
357 "Padded Header Size = %" PRId64 "\n",
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800358 image->kernel_version,
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700359 image->kernel_len,
360 image->bootloader_offset,
361 image->bootloader_size,
362 image->padded_header_size);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800363 /* TODO(gauravsh): Output kernel signature here? */
364}
365
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800366
367int VerifyKernelImage(const RSAPublicKey* firmware_key,
368 const KernelImage* image,
369 const int dev_mode) {
Gaurav Shah259de402010-03-12 17:42:03 -0800370 RSAPublicKey* kernel_sign_key = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800371 uint8_t* header_digest = NULL;
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700372 uint8_t* preamble_digest = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800373 uint8_t* kernel_digest = NULL;
374 int kernel_sign_key_size;
375 int kernel_signature_size;
376 int error_code = 0;
377 DigestContext 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
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700427 /* Verify kernel preamble signature. */
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800428 DigestInit(&ctx, image->kernel_sign_algorithm);
429 DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
430 FIELD_LEN(kernel_version));
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700431 DigestUpdate(&ctx, (uint8_t*) &image->kernel_len,
432 FIELD_LEN(kernel_len));
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700433 DigestUpdate(&ctx, (uint8_t*) &image->bootloader_offset,
434 FIELD_LEN(bootloader_offset));
435 DigestUpdate(&ctx, (uint8_t*) &image->bootloader_size,
436 FIELD_LEN(bootloader_size));
437 DigestUpdate(&ctx, (uint8_t*) &image->padded_header_size,
438 FIELD_LEN(padded_header_size));
Gaurav Shahbcd8f4a2010-05-26 13:19:00 -0700439 DigestUpdate(&ctx, (uint8_t*) image->kernel_signature,
440 kernel_signature_size);
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700441 preamble_digest = DigestFinal(&ctx);
442 if (!RSAVerify(kernel_sign_key, image->preamble_signature,
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800443 kernel_signature_size, image->kernel_sign_algorithm,
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700444 preamble_digest)) {
445 error_code = VERIFY_KERNEL_PREAMBLE_SIGNATURE_FAILED;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800446 goto verify_failure;
447 }
448
Gaurav Shah463be3f2010-03-29 16:13:45 -0700449 /* Verify kernel signature - kernel signature is computed on the contents
Gaurav Shahbcd8f4a2010-05-26 13:19:00 -0700450 * of kernel_data.
451 * Association between the kernel_data and preamble is maintained by making
452 * the kernel signature a part of the preamble and verifying it as part
453 * of preamble signature checking. */
454
455 kernel_digest = DigestBuf(image->kernel_data,
456 image->kernel_len,
457 image->kernel_sign_algorithm);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800458 if (!RSAVerify(kernel_sign_key, image->kernel_signature,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800459 kernel_signature_size, image->kernel_sign_algorithm,
460 kernel_digest)) {
461 error_code = VERIFY_KERNEL_SIGNATURE_FAILED;
462 goto verify_failure;
463 }
464
465verify_failure:
Gaurav Shah259de402010-03-12 17:42:03 -0800466 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800467 Free(kernel_digest);
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700468 Free(preamble_digest);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800469 Free(header_digest);
470 return error_code;
471}
472
473const char* VerifyKernelErrorString(int error) {
474 return kVerifyKernelErrors[error];
475}
476
477int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800478 uint8_t* header_blob = NULL;
Gaurav Shah259de402010-03-12 17:42:03 -0800479 uint8_t* signature = NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800480 int signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800481 if (!image || !firmware_key_file)
482 return 0;
483 header_blob = GetKernelHeaderBlob(image);
484 if (!header_blob)
485 return 0;
486 if (!(signature = SignatureBuf(header_blob,
487 GetKernelHeaderLen(image),
488 firmware_key_file,
489 image->firmware_sign_algorithm))) {
490 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800491 return 0;
492 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800493 image->kernel_key_signature = Malloc(signature_len);
494 Memcpy(image->kernel_key_signature, signature, signature_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800495 Free(signature);
496 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800497 return 1;
498}
499
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800500int AddKernelSignature(KernelImage* image,
501 const char* kernel_signing_key_file) {
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700502 uint8_t* preamble_blob = NULL;
503 uint8_t* preamble_signature = NULL;
Gaurav Shah259de402010-03-12 17:42:03 -0800504 uint8_t* kernel_signature = NULL;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700505 uint8_t* kernel_buf;
Gaurav Shahbcd8f4a2010-05-26 13:19:00 -0700506 int algorithm = image->kernel_sign_algorithm;
507 int signature_len = siglen_map[algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800508
Gaurav Shahbcd8f4a2010-05-26 13:19:00 -0700509 /* Kernel signature must be calculated first as its used for computing the
510 * preamble signature. */
511 kernel_buf = (uint8_t*) Malloc(image->kernel_len);
512 Memcpy(kernel_buf, image->kernel_data, image->kernel_len);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700513 if (!(kernel_signature = SignatureBuf(kernel_buf,
Gaurav Shahbd52fc72010-04-29 15:30:25 -0700514 image->kernel_len,
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800515 kernel_signing_key_file,
Gaurav Shahbcd8f4a2010-05-26 13:19:00 -0700516 algorithm))) {
Gaurav Shahbf7615b2010-05-26 10:26:00 -0700517 Free(preamble_blob);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700518 Free(kernel_buf);
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700519 debug("Could not compute signature on the kernel.\n");
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800520 return 0;
521 }
522 image->kernel_signature = (uint8_t*) Malloc(signature_len);
523 Memcpy(image->kernel_signature, kernel_signature, signature_len);
Gaurav Shahbcd8f4a2010-05-26 13:19:00 -0700524
525
526 preamble_blob = GetKernelPreambleBlob(image);
527 if (!(preamble_signature = SignatureBuf(preamble_blob,
528 GetKernelPreambleLen(algorithm),
529 kernel_signing_key_file,
530 algorithm))) {
531 debug("Could not compute signature on the kernel preamble.\n");
532 Free(preamble_blob);
533 return 0;
534 }
535 image->preamble_signature = (uint8_t*) Malloc(signature_len);
536 Memcpy(image->preamble_signature, preamble_signature, signature_len);
537
538 Free(preamble_signature);
539 Free(preamble_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800540 Free(kernel_signature);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700541 Free(kernel_buf);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800542 return 1;
543}
Gaurav Shaha82bf262010-03-26 10:38:08 -0700544
Gaurav Shaha82bf262010-03-26 10:38:08 -0700545void PrintKernelEntry(kernel_entry* entry) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700546 debug("Boot Priority = %d\n", entry->boot_priority);
547 debug("Boot Tries Remaining = %d\n", entry->boot_tries_remaining);
548 debug("Boot Success Flag = %d\n", entry->boot_success_flag);
Gaurav Shaha82bf262010-03-26 10:38:08 -0700549}