blob: 8c8c09221113c57f4e7a6ada39b222635bc392ea [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 Shahd46c3472010-03-30 23:08:10 -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;
32 image->config_signature = NULL;
33 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);
43 Free(image->config_signature);
44 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
136 /* Read the kernel config. */
137 StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version));
138 StatefulMemcpy(&st, &image->options.version, FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800139 StatefulMemcpy(&st, &image->options.cmd_line, FIELD_LEN(options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800140 StatefulMemcpy(&st, &image->options.kernel_len,
141 FIELD_LEN(options.kernel_len));
142 StatefulMemcpy(&st, &image->options.kernel_load_addr,
143 FIELD_LEN(options.kernel_load_addr));
144 StatefulMemcpy(&st, &image->options.kernel_entry_addr,
145 FIELD_LEN(options.kernel_entry_addr));
146
147 /* Read kernel config signature. */
148 image->config_signature = (uint8_t*) Malloc(kernel_signature_len);
149 StatefulMemcpy(&st, image->config_signature, kernel_signature_len);
150
151 image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len);
152 StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len);
153
154 image->kernel_data = (uint8_t*) Malloc(image->options.kernel_len);
155 StatefulMemcpy(&st, image->kernel_data, image->options.kernel_len);
156
Gaurav Shahe450be42010-03-29 21:27:08 -0700157 if(st.overrun || st.remaining_len != 0) { /* Overrun or underrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800158 Free(kernel_buf);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800159 return NULL;
160 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800161 Free(kernel_buf);
162 return image;
163}
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800164
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800165int GetKernelHeaderLen(const KernelImage* image) {
166 return (FIELD_LEN(header_version) + FIELD_LEN(header_len) +
167 FIELD_LEN(firmware_sign_algorithm) +
168 FIELD_LEN(kernel_sign_algorithm) + FIELD_LEN(kernel_key_version) +
169 RSAProcessedKeySize(image->kernel_sign_algorithm) +
170 FIELD_LEN(header_checksum));
171}
172
Gaurav Shah528a2c12010-03-18 13:10:10 -0700173void CalculateKernelHeaderChecksum(const KernelImage* image,
174 uint8_t* header_checksum) {
175 uint8_t* checksum;
176 DigestContext ctx;
177 DigestInit(&ctx, SHA512_DIGEST_ALGORITHM);
178 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
179 sizeof(image->header_version));
180 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
181 sizeof(image->header_len));
182 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
183 sizeof(image->firmware_sign_algorithm));
184 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
185 sizeof(image->kernel_sign_algorithm));
186 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
187 sizeof(image->kernel_key_version));
188 DigestUpdate(&ctx, image->kernel_sign_key,
189 RSAProcessedKeySize(image->kernel_sign_algorithm));
190 checksum = DigestFinal(&ctx);
191 Memcpy(header_checksum, checksum, FIELD_LEN(header_checksum));
192 Free(checksum);
193 return;
194}
195
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800196uint8_t* GetKernelHeaderBlob(const KernelImage* image) {
197 uint8_t* header_blob = NULL;
198 MemcpyState st;
199
200 header_blob = (uint8_t*) Malloc(GetKernelHeaderLen(image));
201 st.remaining_len = GetKernelHeaderLen(image);
202 st.remaining_buf = header_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700203 st.overrun = 0;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800204
205 StatefulMemcpy_r(&st, &image->header_version, FIELD_LEN(header_version));
206 StatefulMemcpy_r(&st, &image->header_len, FIELD_LEN(header_len));
207 StatefulMemcpy_r(&st, &image->firmware_sign_algorithm,
208 FIELD_LEN(firmware_sign_algorithm));
209 StatefulMemcpy_r(&st, &image->kernel_sign_algorithm,
210 FIELD_LEN(kernel_sign_algorithm));
211 StatefulMemcpy_r(&st, &image->kernel_key_version,
212 FIELD_LEN(kernel_key_version));
213 StatefulMemcpy_r(&st, image->kernel_sign_key,
214 RSAProcessedKeySize(image->kernel_sign_algorithm));
215 StatefulMemcpy_r(&st, &image->header_checksum, FIELD_LEN(header_checksum));
216
Gaurav Shahe450be42010-03-29 21:27:08 -0700217 if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800218 Free(header_blob);
219 return NULL;
220 }
221 return header_blob;
222}
223
Gaurav Shah463be3f2010-03-29 16:13:45 -0700224int GetKernelConfigLen() {
Gaurav Shah4f393862010-03-12 18:13:24 -0800225 return (FIELD_LEN(kernel_version) +
226 FIELD_LEN(options.version) + FIELD_LEN(options.cmd_line) +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800227 FIELD_LEN(options.kernel_len) + FIELD_LEN(options.kernel_load_addr) +
228 FIELD_LEN(options.kernel_entry_addr));
229}
230
231uint8_t* GetKernelConfigBlob(const KernelImage* image) {
232 uint8_t* config_blob = NULL;
233 MemcpyState st;
234
Gaurav Shah463be3f2010-03-29 16:13:45 -0700235 config_blob = (uint8_t*) Malloc(GetKernelConfigLen());
236 st.remaining_len = GetKernelConfigLen();
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800237 st.remaining_buf = config_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700238 st.overrun = 0;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800239
240 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version));
241 StatefulMemcpy_r(&st, image->options.version, FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800242 StatefulMemcpy_r(&st, image->options.cmd_line, FIELD_LEN(options.cmd_line));
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800243 StatefulMemcpy_r(&st, &image->options.kernel_len,
244 FIELD_LEN(options.kernel_len));
245 StatefulMemcpy_r(&st, &image->options.kernel_load_addr,
246 FIELD_LEN(options.kernel_load_addr));
247 StatefulMemcpy_r(&st, &image->options.kernel_entry_addr,
248 FIELD_LEN(options.kernel_entry_addr));
Gaurav Shahe450be42010-03-29 21:27:08 -0700249 if (st.overrun || st.remaining_len != 0) { /* Overrun or Underrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800250 Free(config_blob);
251 return NULL;
252 }
253 return config_blob;
254}
255
Gaurav Shah13937112010-03-22 17:59:09 -0700256uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800257 int kernel_key_signature_len;
258 int kernel_signature_len;
259 uint8_t* kernel_blob = NULL;
260 uint8_t* header_blob = NULL;
261 uint8_t* config_blob = NULL;
262 MemcpyState st;
263
264 if (!image)
265 return NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800266 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
267 kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800268 *blob_len = (FIELD_LEN(magic) +
269 GetKernelHeaderLen(image) +
270 kernel_key_signature_len +
Gaurav Shah463be3f2010-03-29 16:13:45 -0700271 GetKernelConfigLen() +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800272 2 * kernel_signature_len +
273 image->options.kernel_len);
274 kernel_blob = (uint8_t*) Malloc(*blob_len);
275 st.remaining_len = *blob_len;
276 st.remaining_buf = kernel_blob;
Gaurav Shahe450be42010-03-29 21:27:08 -0700277 st.overrun = 0;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800278
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800279 header_blob = GetKernelHeaderBlob(image);
280 config_blob = GetKernelConfigBlob(image);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800281
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800282 StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic));
283 StatefulMemcpy_r(&st, header_blob, GetKernelHeaderLen(image));
284 StatefulMemcpy_r(&st, image->kernel_key_signature, kernel_key_signature_len);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700285 StatefulMemcpy_r(&st, config_blob, GetKernelConfigLen());
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800286 StatefulMemcpy_r(&st, image->config_signature, kernel_signature_len);
287 StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len);
288 StatefulMemcpy_r(&st, image->kernel_data, image->options.kernel_len);
289
290 Free(config_blob);
291 Free(header_blob);
292
Gaurav Shahe450be42010-03-29 21:27:08 -0700293 if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800294 Free(kernel_blob);
295 return NULL;
296 }
297 return kernel_blob;
298}
299
300int WriteKernelImage(const char* input_file,
301 const KernelImage* image) {
302 int fd;
303 uint8_t* kernel_blob;
Gaurav Shah13937112010-03-22 17:59:09 -0700304 uint64_t blob_len;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800305
306 if (!image)
307 return 0;
308 if (-1 == (fd = creat(input_file, S_IRWXU))) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700309 debug("Couldn't open file for writing kernel image: %s\n",
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800310 input_file);
311 return 0;
312 }
313 kernel_blob = GetKernelBlob(image, &blob_len);
314 if (!kernel_blob) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700315 debug("Couldn't create kernel blob from KernelImage.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800316 return 0;
317 }
318 if (blob_len != write(fd, kernel_blob, blob_len)) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700319 debug("Couldn't write Kernel Image to file: %s\n",
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800320 input_file);
321
322 Free(kernel_blob);
323 close(fd);
324 return 0;
325 }
326 Free(kernel_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800327 close(fd);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800328 return 1;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800329}
330
331void PrintKernelImage(const KernelImage* image) {
332 if (!image)
333 return;
334
335 /* Print header. */
Gaurav Shah528a2c12010-03-18 13:10:10 -0700336 printf("Header Version = %d\n"
337 "Header Length = %d\n"
338 "Kernel Key Signature Algorithm = %s\n"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800339 "Kernel Signature Algorithm = %s\n"
340 "Kernel Key Version = %d\n\n",
Gaurav Shah528a2c12010-03-18 13:10:10 -0700341 image->header_version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800342 image->header_len,
Gaurav Shah528a2c12010-03-18 13:10:10 -0700343 algo_strings[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800344 algo_strings[image->kernel_sign_algorithm],
345 image->kernel_key_version);
346 /* TODO(gauravsh): Output hash and key signature here? */
347 /* Print preamble. */
348 printf("Kernel Version = %d\n"
349 "Kernel Config Version = %d.%d\n"
Gaurav Shah528a2c12010-03-18 13:10:10 -0700350 "Kernel Config command line = \"%s\"\n"
Gaurav Shah456678b2010-03-10 18:38:45 -0800351 "kernel Length = %" PRId64 "\n"
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800352 "Kernel Load Address = %" PRId64 "\n"
353 "Kernel Entry Address = %" PRId64 "\n\n",
354 image->kernel_version,
355 image->options.version[0], image->options.version[1],
Gaurav Shah4f393862010-03-12 18:13:24 -0800356 image->options.cmd_line,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800357 image->options.kernel_len,
358 image->options.kernel_load_addr,
359 image->options.kernel_entry_addr);
360 /* TODO(gauravsh): Output kernel signature here? */
361}
362
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800363
364int VerifyKernelImage(const RSAPublicKey* firmware_key,
365 const KernelImage* image,
366 const int dev_mode) {
Gaurav Shah259de402010-03-12 17:42:03 -0800367 RSAPublicKey* kernel_sign_key = NULL;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800368 uint8_t* header_digest = NULL;
369 uint8_t* config_digest = NULL;
370 uint8_t* kernel_digest = NULL;
371 int kernel_sign_key_size;
372 int kernel_signature_size;
373 int error_code = 0;
374 DigestContext ctx;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700375 DigestContext kernel_ctx;
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800376 if (!image)
377 return VERIFY_KERNEL_INVALID_IMAGE;
378
379 /* Verify kernel key signature on the key header if we
380 * are not in dev mode.
381 *
382 * TODO(gauravsh): Add additional sanity checks here for:
383 * 1) verifying the header length is correct.
384 * 2) header_checksum is correct.
385 */
386
387 if (image->firmware_sign_algorithm >= kNumAlgorithms)
388 return VERIFY_KERNEL_INVALID_ALGORITHM;
389 if (image->kernel_sign_algorithm >= kNumAlgorithms)
390 return VERIFY_KERNEL_INVALID_ALGORITHM;
391
392 if (!dev_mode) {
393 DigestInit(&ctx, image->firmware_sign_algorithm);
394 DigestUpdate(&ctx, (uint8_t*) &image->header_version,
395 FIELD_LEN(header_version));
396 DigestUpdate(&ctx, (uint8_t*) &image->header_len,
397 FIELD_LEN(header_len));
398 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm,
399 FIELD_LEN(firmware_sign_algorithm));
400 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm,
401 FIELD_LEN(kernel_sign_algorithm));
402 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version,
403 FIELD_LEN(kernel_key_version));
404 DigestUpdate(&ctx, image->kernel_sign_key,
405 RSAProcessedKeySize(image->kernel_sign_algorithm));
406 DigestUpdate(&ctx, image->header_checksum,
407 FIELD_LEN(header_checksum));
408 header_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800409 if (!RSAVerify(firmware_key, image->kernel_key_signature,
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800410 siglen_map[image->firmware_sign_algorithm],
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800411 image->firmware_sign_algorithm,
412 header_digest)) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700413 debug("VerifyKernelImage(): Key signature check failed.\n");
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800414 error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
415 goto verify_failure;
416 }
417 }
418
419 /* Get kernel signing key to verify the rest of the kernel. */
420 kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm);
421 kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key,
422 kernel_sign_key_size);
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800423 kernel_signature_size = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800424
425 /* Verify kernel config signature. */
426 DigestInit(&ctx, image->kernel_sign_algorithm);
427 DigestUpdate(&ctx, (uint8_t*) &image->kernel_version,
428 FIELD_LEN(kernel_version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800429 DigestUpdate(&ctx, (uint8_t*) image->options.version,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800430 FIELD_LEN(options.version));
Gaurav Shah4f393862010-03-12 18:13:24 -0800431 DigestUpdate(&ctx, (uint8_t*) image->options.cmd_line,
432 FIELD_LEN(options.cmd_line));
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800433 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_len,
434 FIELD_LEN(options.kernel_len));
435 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_load_addr,
436 FIELD_LEN(options.kernel_load_addr));
437 DigestUpdate(&ctx, (uint8_t*) &image->options.kernel_entry_addr,
438 FIELD_LEN(options.kernel_entry_addr));
439 config_digest = DigestFinal(&ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800440 if (!RSAVerify(kernel_sign_key, image->config_signature,
441 kernel_signature_size, image->kernel_sign_algorithm,
442 config_digest)) {
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800443 error_code = VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
444 goto verify_failure;
445 }
446
Gaurav Shah463be3f2010-03-29 16:13:45 -0700447 /* Verify kernel signature - kernel signature is computed on the contents
448 of kernel version + kernel options + kernel_data. */
449 DigestInit(&kernel_ctx, image->kernel_sign_algorithm);
450 DigestUpdate(&kernel_ctx, (uint8_t*) &image->kernel_version,
451 FIELD_LEN(kernel_version));
452 DigestUpdate(&kernel_ctx, (uint8_t*) image->options.version,
453 FIELD_LEN(options.version));
454 DigestUpdate(&kernel_ctx, (uint8_t*) image->options.cmd_line,
455 FIELD_LEN(options.cmd_line));
456 DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_len,
457 FIELD_LEN(options.kernel_len));
458 DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_load_addr,
459 FIELD_LEN(options.kernel_load_addr));
460 DigestUpdate(&kernel_ctx, (uint8_t*) &image->options.kernel_entry_addr,
461 FIELD_LEN(options.kernel_entry_addr));
462 DigestUpdate(&kernel_ctx, image->kernel_data, image->options.kernel_len);
463 kernel_digest = DigestFinal(&kernel_ctx);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800464 if (!RSAVerify(kernel_sign_key, image->kernel_signature,
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800465 kernel_signature_size, image->kernel_sign_algorithm,
466 kernel_digest)) {
467 error_code = VERIFY_KERNEL_SIGNATURE_FAILED;
468 goto verify_failure;
469 }
470
471verify_failure:
Gaurav Shah259de402010-03-12 17:42:03 -0800472 RSAPublicKeyFree(kernel_sign_key);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800473 Free(kernel_digest);
474 Free(config_digest);
475 Free(header_digest);
476 return error_code;
477}
478
479const char* VerifyKernelErrorString(int error) {
480 return kVerifyKernelErrors[error];
481}
482
483int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) {
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800484 uint8_t* header_blob = NULL;
Gaurav Shah259de402010-03-12 17:42:03 -0800485 uint8_t* signature = NULL;
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800486 int signature_len = siglen_map[image->firmware_sign_algorithm];
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800487 if (!image || !firmware_key_file)
488 return 0;
489 header_blob = GetKernelHeaderBlob(image);
490 if (!header_blob)
491 return 0;
492 if (!(signature = SignatureBuf(header_blob,
493 GetKernelHeaderLen(image),
494 firmware_key_file,
495 image->firmware_sign_algorithm))) {
496 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800497 return 0;
498 }
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800499 image->kernel_key_signature = Malloc(signature_len);
500 Memcpy(image->kernel_key_signature, signature, signature_len);
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800501 Free(signature);
502 Free(header_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800503 return 1;
504}
505
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800506int AddKernelSignature(KernelImage* image,
507 const char* kernel_signing_key_file) {
Gaurav Shah259de402010-03-12 17:42:03 -0800508 uint8_t* config_blob = NULL;
509 uint8_t* config_signature = NULL;
510 uint8_t* kernel_signature = NULL;
Gaurav Shah463be3f2010-03-29 16:13:45 -0700511 uint8_t* kernel_buf;
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800512 int signature_len = siglen_map[image->kernel_sign_algorithm];
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800513
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800514 config_blob = GetKernelConfigBlob(image);
515 if (!(config_signature = SignatureBuf(config_blob,
Gaurav Shah463be3f2010-03-29 16:13:45 -0700516 GetKernelConfigLen(),
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800517 kernel_signing_key_file,
518 image->kernel_sign_algorithm))) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700519 debug("Could not compute signature on the kernel config.\n");
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800520 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800521 return 0;
522 }
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800523
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800524 image->config_signature = (uint8_t*) Malloc(signature_len);
525 Memcpy(image->config_signature, config_signature, signature_len);
526 Free(config_signature);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700527 /* Kernel signature muse be calculated on the kernel version, options and
528 * kernel data to avoid splicing attacks. */
529 kernel_buf = (uint8_t*) Malloc(GetKernelConfigLen() +
530 image->options.kernel_len);
531 Memcpy(kernel_buf, config_blob, GetKernelConfigLen());
532 Memcpy(kernel_buf + GetKernelConfigLen(), image->kernel_data,
533 image->options.kernel_len);
534 if (!(kernel_signature = SignatureBuf(kernel_buf,
535 GetKernelConfigLen() +
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800536 image->options.kernel_len,
537 kernel_signing_key_file,
538 image->kernel_sign_algorithm))) {
Gaurav Shah463be3f2010-03-29 16:13:45 -0700539 Free(config_blob);
540 Free(kernel_buf);
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700541 debug("Could not compute signature on the kernel.\n");
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800542 return 0;
543 }
544 image->kernel_signature = (uint8_t*) Malloc(signature_len);
545 Memcpy(image->kernel_signature, kernel_signature, signature_len);
546 Free(kernel_signature);
Gaurav Shah463be3f2010-03-29 16:13:45 -0700547 Free(kernel_buf);
548 Free(config_blob);
Gaurav Shahf67bcaa2010-02-28 19:18:24 -0800549 return 1;
550}
Gaurav Shaha82bf262010-03-26 10:38:08 -0700551
Gaurav Shaha82bf262010-03-26 10:38:08 -0700552void PrintKernelEntry(kernel_entry* entry) {
Gaurav Shahed9c96a2010-03-30 18:56:07 -0700553 debug("Boot Priority = %d\n", entry->boot_priority);
554 debug("Boot Tries Remaining = %d\n", entry->boot_tries_remaining);
555 debug("Boot Success Flag = %d\n", entry->boot_success_flag);
Gaurav Shaha82bf262010-03-26 10:38:08 -0700556}