OLD | NEW |
| (Empty) |
1 /* 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. | |
6 * (Userland portion) | |
7 */ | |
8 #include "kernel_image.h" | |
9 | |
10 #include <fcntl.h> | |
11 #include <stddef.h> | |
12 #include <stdio.h> | |
13 #include <sys/types.h> | |
14 #include <sys/stat.h> | |
15 #include <unistd.h> | |
16 | |
17 #include "cryptolib.h" | |
18 #include "file_keys.h" | |
19 #include "kernel_blob.h" | |
20 #include "rollback_index.h" | |
21 #include "signature_digest.h" | |
22 #include "stateful_util.h" | |
23 #include "utility.h" | |
24 | |
25 /* Macro to determine the size of a field structure in the KernelImage | |
26 * structure. */ | |
27 #define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field)) | |
28 | |
29 KernelImage* KernelImageNew(void) { | |
30 KernelImage* image = (KernelImage*) Malloc(sizeof(KernelImage)); | |
31 if (image) { | |
32 image->kernel_sign_key = NULL; | |
33 image->kernel_key_signature = NULL; | |
34 image->preamble_signature = NULL; | |
35 image->kernel_signature = NULL; | |
36 image->kernel_data = NULL; | |
37 image->padded_header_size = 0x4000; | |
38 } | |
39 return image; | |
40 } | |
41 | |
42 void KernelImageFree(KernelImage* image) { | |
43 if (image) { | |
44 Free(image->kernel_sign_key); | |
45 Free(image->kernel_key_signature); | |
46 Free(image->preamble_signature); | |
47 Free(image->kernel_signature); | |
48 Free(image->kernel_data); | |
49 Free(image); | |
50 } | |
51 } | |
52 | |
53 uint64_t GetHeaderSizeOnDisk(const KernelImage* image) { | |
54 uint64_t kernel_signature_len = siglen_map[image->kernel_sign_algorithm]; | |
55 uint64_t kernel_key_signature_len = | |
56 siglen_map[image->firmware_sign_algorithm]; | |
57 | |
58 return FIELD_LEN(magic) + | |
59 GetKernelHeaderLen(image) + | |
60 kernel_key_signature_len + | |
61 GetKernelPreambleLen(image->kernel_sign_algorithm) + | |
62 kernel_signature_len; | |
63 } | |
64 | |
65 | |
66 KernelImage* ReadKernelImage(const char* input_file) { | |
67 uint64_t file_size; | |
68 uint64_t on_disk_header_size; | |
69 uint64_t on_disk_padding; | |
70 int header_len = 0; | |
71 int kernel_key_signature_len; | |
72 int kernel_sign_key_len; | |
73 int kernel_signature_len; | |
74 uint8_t* kernel_buf; | |
75 uint8_t header_checksum[FIELD_LEN(header_checksum)]; | |
76 MemcpyState st; | |
77 KernelImage* image = KernelImageNew(); | |
78 | |
79 if (!image) | |
80 return NULL; | |
81 | |
82 kernel_buf = BufferFromFile(input_file, &file_size); | |
83 | |
84 st.remaining_len = file_size; | |
85 st.remaining_buf = kernel_buf; | |
86 st.overrun = 0; | |
87 | |
88 /* Read and compare magic bytes. */ | |
89 StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE); | |
90 | |
91 if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) { | |
92 debug("Wrong Kernel Magic.\n"); | |
93 Free(kernel_buf); | |
94 return NULL; | |
95 } | |
96 StatefulMemcpy(&st, &image->header_version, FIELD_LEN(header_version)); | |
97 StatefulMemcpy(&st, &image->header_len, FIELD_LEN(header_len)); | |
98 StatefulMemcpy(&st, &image->firmware_sign_algorithm, | |
99 FIELD_LEN(firmware_sign_algorithm)); | |
100 StatefulMemcpy(&st, &image->kernel_sign_algorithm, | |
101 FIELD_LEN(kernel_sign_algorithm)); | |
102 | |
103 /* Valid Kernel Key signing algorithm. */ | |
104 if (image->firmware_sign_algorithm >= kNumAlgorithms) { | |
105 Free(kernel_buf); | |
106 return NULL; | |
107 } | |
108 | |
109 /* Valid Kernel Signing Algorithm? */ | |
110 if (image->kernel_sign_algorithm >= kNumAlgorithms) { | |
111 Free(kernel_buf); | |
112 return NULL; | |
113 } | |
114 | |
115 /* Compute size of pre-processed RSA public keys and signatures. */ | |
116 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm]; | |
117 kernel_sign_key_len = RSAProcessedKeySize(image->kernel_sign_algorithm); | |
118 kernel_signature_len = siglen_map[image->kernel_sign_algorithm]; | |
119 | |
120 /* Check whether key header length is correct. */ | |
121 header_len = GetKernelHeaderLen(image); | |
122 if (header_len != image->header_len) { | |
123 debug("Header length mismatch. Got: %d, Expected: %d\n", | |
124 image->header_len, header_len); | |
125 Free(kernel_buf); | |
126 return NULL; | |
127 } | |
128 | |
129 /* Read pre-processed public half of the kernel signing key. */ | |
130 StatefulMemcpy(&st, &image->kernel_key_version, | |
131 FIELD_LEN(kernel_key_version)); | |
132 image->kernel_sign_key = (uint8_t*) Malloc(kernel_sign_key_len); | |
133 StatefulMemcpy(&st, image->kernel_sign_key, kernel_sign_key_len); | |
134 StatefulMemcpy(&st, image->header_checksum, FIELD_LEN(header_checksum)); | |
135 | |
136 /* Check whether the header checksum matches. */ | |
137 CalculateKernelHeaderChecksum(image, header_checksum); | |
138 if (SafeMemcmp(header_checksum, image->header_checksum, | |
139 FIELD_LEN(header_checksum))) { | |
140 debug("Invalid kernel header checksum!\n"); | |
141 Free(kernel_buf); | |
142 return NULL; | |
143 } | |
144 | |
145 /* Read key signature. */ | |
146 image->kernel_key_signature = (uint8_t*) Malloc(kernel_key_signature_len); | |
147 StatefulMemcpy(&st, image->kernel_key_signature, | |
148 kernel_key_signature_len); | |
149 | |
150 /* Read the kernel preamble. */ | |
151 StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version)); | |
152 StatefulMemcpy(&st, &image->kernel_len, FIELD_LEN(kernel_len)); | |
153 StatefulMemcpy(&st, &image->bootloader_offset, FIELD_LEN(bootloader_offset)); | |
154 StatefulMemcpy(&st, &image->bootloader_size, FIELD_LEN(bootloader_size)); | |
155 StatefulMemcpy(&st, &image->padded_header_size, | |
156 FIELD_LEN(padded_header_size)); | |
157 | |
158 /* Read preamble and kernel signatures. */ | |
159 image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len); | |
160 StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len); | |
161 image->preamble_signature = (uint8_t*) Malloc(kernel_signature_len); | |
162 StatefulMemcpy(&st, image->preamble_signature, kernel_signature_len); | |
163 | |
164 /* Skip over the rest of the padded header, unless we're already past it. */ | |
165 on_disk_header_size = file_size - st.remaining_len; | |
166 if (image->padded_header_size > on_disk_header_size) { | |
167 on_disk_padding = image->padded_header_size - on_disk_header_size; | |
168 if (st.remaining_len < on_disk_padding) | |
169 st.overrun = -1; | |
170 st.remaining_buf += on_disk_padding; | |
171 st.remaining_len -= on_disk_padding; | |
172 } | |
173 | |
174 /* Read kernel image data. */ | |
175 image->kernel_data = (uint8_t*) Malloc(image->kernel_len); | |
176 StatefulMemcpy(&st, image->kernel_data, image->kernel_len); | |
177 | |
178 if(st.overrun) { | |
179 Free(kernel_buf); | |
180 return NULL; | |
181 } | |
182 Free(kernel_buf); | |
183 return image; | |
184 } | |
185 | |
186 int GetKernelHeaderLen(const KernelImage* image) { | |
187 return (FIELD_LEN(header_version) + FIELD_LEN(header_len) + | |
188 FIELD_LEN(firmware_sign_algorithm) + | |
189 FIELD_LEN(kernel_sign_algorithm) + FIELD_LEN(kernel_key_version) + | |
190 RSAProcessedKeySize(image->kernel_sign_algorithm) + | |
191 FIELD_LEN(header_checksum)); | |
192 } | |
193 | |
194 void CalculateKernelHeaderChecksum(const KernelImage* image, | |
195 uint8_t* header_checksum) { | |
196 uint8_t* checksum; | |
197 DigestContext ctx; | |
198 DigestInit(&ctx, SHA512_DIGEST_ALGORITHM); | |
199 DigestUpdate(&ctx, (uint8_t*) &image->header_version, | |
200 sizeof(image->header_version)); | |
201 DigestUpdate(&ctx, (uint8_t*) &image->header_len, | |
202 sizeof(image->header_len)); | |
203 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm, | |
204 sizeof(image->firmware_sign_algorithm)); | |
205 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm, | |
206 sizeof(image->kernel_sign_algorithm)); | |
207 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version, | |
208 sizeof(image->kernel_key_version)); | |
209 DigestUpdate(&ctx, image->kernel_sign_key, | |
210 RSAProcessedKeySize(image->kernel_sign_algorithm)); | |
211 checksum = DigestFinal(&ctx); | |
212 Memcpy(header_checksum, checksum, FIELD_LEN(header_checksum)); | |
213 Free(checksum); | |
214 return; | |
215 } | |
216 | |
217 uint8_t* GetKernelHeaderBlob(const KernelImage* image) { | |
218 uint8_t* header_blob = NULL; | |
219 MemcpyState st; | |
220 | |
221 header_blob = (uint8_t*) Malloc(GetKernelHeaderLen(image)); | |
222 st.remaining_len = GetKernelHeaderLen(image); | |
223 st.remaining_buf = header_blob; | |
224 st.overrun = 0; | |
225 | |
226 StatefulMemcpy_r(&st, &image->header_version, FIELD_LEN(header_version)); | |
227 StatefulMemcpy_r(&st, &image->header_len, FIELD_LEN(header_len)); | |
228 StatefulMemcpy_r(&st, &image->firmware_sign_algorithm, | |
229 FIELD_LEN(firmware_sign_algorithm)); | |
230 StatefulMemcpy_r(&st, &image->kernel_sign_algorithm, | |
231 FIELD_LEN(kernel_sign_algorithm)); | |
232 StatefulMemcpy_r(&st, &image->kernel_key_version, | |
233 FIELD_LEN(kernel_key_version)); | |
234 StatefulMemcpy_r(&st, image->kernel_sign_key, | |
235 RSAProcessedKeySize(image->kernel_sign_algorithm)); | |
236 StatefulMemcpy_r(&st, &image->header_checksum, FIELD_LEN(header_checksum)); | |
237 | |
238 if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */ | |
239 Free(header_blob); | |
240 return NULL; | |
241 } | |
242 return header_blob; | |
243 } | |
244 | |
245 uint8_t* GetKernelPreambleBlob(const KernelImage* image) { | |
246 uint8_t* preamble_blob = NULL; | |
247 MemcpyState st; | |
248 | |
249 preamble_blob = (uint8_t*) Malloc( | |
250 GetKernelPreambleLen(image->kernel_sign_algorithm)); | |
251 st.remaining_len = GetKernelPreambleLen(image->kernel_sign_algorithm); | |
252 st.remaining_buf = preamble_blob; | |
253 st.overrun = 0; | |
254 | |
255 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version)); | |
256 StatefulMemcpy_r(&st, &image->kernel_len, FIELD_LEN(kernel_len)); | |
257 StatefulMemcpy_r(&st, &image->bootloader_offset, FIELD_LEN(bootloader_offset))
; | |
258 StatefulMemcpy_r(&st, &image->bootloader_size, FIELD_LEN(bootloader_size)); | |
259 StatefulMemcpy_r(&st, &image->padded_header_size, | |
260 FIELD_LEN(padded_header_size)); | |
261 StatefulMemcpy_r(&st, image->kernel_signature, | |
262 siglen_map[image->kernel_sign_algorithm]); | |
263 | |
264 if (st.overrun || st.remaining_len != 0) { /* Overrun or Underrun. */ | |
265 Free(preamble_blob); | |
266 return NULL; | |
267 } | |
268 return preamble_blob; | |
269 } | |
270 | |
271 uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) { | |
272 int kernel_key_signature_len; | |
273 int kernel_signature_len; | |
274 uint8_t* kernel_blob = NULL; | |
275 uint8_t* header_blob = NULL; | |
276 MemcpyState st; | |
277 uint64_t on_disk_header_size; | |
278 uint64_t on_disk_padding = 0; | |
279 | |
280 if (!image) | |
281 return NULL; | |
282 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm]; | |
283 kernel_signature_len = siglen_map[image->kernel_sign_algorithm]; | |
284 on_disk_header_size = GetHeaderSizeOnDisk(image); | |
285 if (image->padded_header_size > on_disk_header_size) | |
286 on_disk_padding = image->padded_header_size - on_disk_header_size; | |
287 *blob_len = on_disk_header_size + on_disk_padding + image->kernel_len; | |
288 kernel_blob = (uint8_t*) Malloc(*blob_len); | |
289 st.remaining_len = *blob_len; | |
290 st.remaining_buf = kernel_blob; | |
291 st.overrun = 0; | |
292 header_blob = GetKernelHeaderBlob(image); | |
293 | |
294 StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic)); | |
295 StatefulMemcpy_r(&st, header_blob, GetKernelHeaderLen(image)); | |
296 StatefulMemcpy_r(&st, image->kernel_key_signature, kernel_key_signature_len); | |
297 /* Copy over kernel preamble blob (including signatures.) */ | |
298 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version)); | |
299 StatefulMemcpy_r(&st, &image->kernel_len, FIELD_LEN(kernel_len)); | |
300 StatefulMemcpy_r(&st, &image->bootloader_offset, | |
301 FIELD_LEN(bootloader_offset)); | |
302 StatefulMemcpy_r(&st, &image->bootloader_size, FIELD_LEN(bootloader_size)); | |
303 StatefulMemcpy_r(&st, &image->padded_header_size, | |
304 FIELD_LEN(padded_header_size)); | |
305 StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len); | |
306 StatefulMemcpy_r(&st, image->preamble_signature, kernel_signature_len); | |
307 /* Copy a bunch of zeros to pad out the header */ | |
308 if (on_disk_padding) | |
309 StatefulMemset_r(&st, 0, on_disk_padding); | |
310 StatefulMemcpy_r(&st, image->kernel_data, image->kernel_len); | |
311 | |
312 Free(header_blob); | |
313 | |
314 if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */ | |
315 debug("GetKernelBlob() failed.\n"); | |
316 Free(kernel_blob); | |
317 return NULL; | |
318 } | |
319 return kernel_blob; | |
320 } | |
321 | |
322 int WriteKernelImage(const char* output_file, | |
323 const KernelImage* image, | |
324 int is_only_vblock, | |
325 int is_subkey_out) { | |
326 int fd; | |
327 int success = 1; | |
328 uint8_t* kernel_blob = NULL; | |
329 uint8_t* subkey_out_buf = NULL; | |
330 uint8_t* subkey_header = NULL; | |
331 uint64_t blob_len; | |
332 | |
333 if (!image) | |
334 return 0; | |
335 if (-1 == (fd = creat(output_file, 0666))) { | |
336 debug("Couldn't open file for writing kernel image: %s\n", | |
337 output_file); | |
338 return 0; | |
339 } | |
340 if (is_subkey_out) { | |
341 blob_len = GetKernelHeaderLen(image) + | |
342 siglen_map[image->firmware_sign_algorithm]; | |
343 subkey_out_buf = (uint8_t*) Malloc(blob_len); | |
344 subkey_header = GetKernelHeaderBlob(image); | |
345 Memcpy(subkey_out_buf, subkey_header, GetKernelHeaderLen(image)); | |
346 Memcpy(subkey_out_buf + GetKernelHeaderLen(image), | |
347 image->kernel_key_signature, | |
348 siglen_map[image->firmware_sign_algorithm]); | |
349 if (blob_len != write(fd, subkey_out_buf, blob_len)) { | |
350 debug("Couldn't write Kernel Subkey header to file: %s\n", | |
351 output_file); | |
352 success = 0; | |
353 } | |
354 Free(subkey_header); | |
355 Free(subkey_out_buf); | |
356 close(fd); | |
357 return success; | |
358 } | |
359 | |
360 kernel_blob = GetKernelBlob(image, &blob_len); | |
361 if (!kernel_blob) { | |
362 debug("Couldn't create kernel blob from KernelImage.\n"); | |
363 return 0; | |
364 } | |
365 if (!is_only_vblock) { | |
366 if (blob_len != write(fd, kernel_blob, blob_len)) { | |
367 debug("Couldn't write Kernel Image to file: %s\n", | |
368 output_file); | |
369 success = 0; | |
370 } | |
371 } else { | |
372 /* Exclude kernel_data. */ | |
373 int vblock_len = blob_len - (image->kernel_len); | |
374 if (vblock_len != write(fd, kernel_blob, vblock_len)) { | |
375 debug("Couldn't write Kernel Image Verification block to file: %s\n", | |
376 output_file); | |
377 success = 0; | |
378 } | |
379 } | |
380 Free(kernel_blob); | |
381 close(fd); | |
382 return success; | |
383 } | |
384 | |
385 void PrintKernelImage(const KernelImage* image) { | |
386 uint64_t header_size; | |
387 | |
388 if (!image) | |
389 return; | |
390 | |
391 header_size = GetHeaderSizeOnDisk(image); | |
392 if (image->padded_header_size > header_size) | |
393 header_size = image->padded_header_size; | |
394 | |
395 | |
396 /* Print header. */ | |
397 printf("Header Version = %d\n" | |
398 "Header Length = %d\n" | |
399 "Kernel Key Signature Algorithm = %s\n" | |
400 "Kernel Signature Algorithm = %s\n" | |
401 "Kernel Key Version = %d\n\n", | |
402 image->header_version, | |
403 image->header_len, | |
404 algo_strings[image->firmware_sign_algorithm], | |
405 algo_strings[image->kernel_sign_algorithm], | |
406 image->kernel_key_version); | |
407 /* TODO(gauravsh): Output hash and key signature here? */ | |
408 /* Print preamble. */ | |
409 printf("Kernel Version = %d\n" | |
410 "kernel Length = %" PRId64 " (0x%" PRIx64 ")\n" | |
411 "Bootloader Offset = %" PRId64 " (0x%" PRIx64 ")\n" | |
412 "Bootloader Size = %" PRId64 " (0x%" PRIx64 ")\n" | |
413 "Padded Header Size = %" PRId64 " (0x%" PRIx64 ")\n\n" | |
414 "Actual Header Size on disk = %" PRIu64 " (0x%" PRIx64 ")\n", | |
415 image->kernel_version, | |
416 image->kernel_len, image->kernel_len, | |
417 image->bootloader_offset, image->bootloader_offset, | |
418 image->bootloader_size, image->bootloader_size, | |
419 image->padded_header_size, image->padded_header_size, | |
420 header_size, header_size); | |
421 /* TODO(gauravsh): Output kernel signature here? */ | |
422 } | |
423 | |
424 | |
425 int VerifyKernelImage(const RSAPublicKey* firmware_key, | |
426 const KernelImage* image, | |
427 const int dev_mode) { | |
428 RSAPublicKey* kernel_sign_key = NULL; | |
429 uint8_t* header_digest = NULL; | |
430 uint8_t* preamble_digest = NULL; | |
431 uint8_t* kernel_digest = NULL; | |
432 int kernel_sign_key_size; | |
433 int kernel_signature_size; | |
434 int error_code = 0; | |
435 DigestContext ctx; | |
436 if (!image) | |
437 return VERIFY_KERNEL_INVALID_IMAGE; | |
438 | |
439 /* Verify kernel key signature on the key header if we | |
440 * are not in dev mode. | |
441 * | |
442 * TODO(gauravsh): Add additional sanity checks here for: | |
443 * 1) verifying the header length is correct. | |
444 * 2) header_checksum is correct. | |
445 */ | |
446 | |
447 if (image->firmware_sign_algorithm >= kNumAlgorithms) | |
448 return VERIFY_KERNEL_INVALID_ALGORITHM; | |
449 if (image->kernel_sign_algorithm >= kNumAlgorithms) | |
450 return VERIFY_KERNEL_INVALID_ALGORITHM; | |
451 | |
452 if (!dev_mode) { | |
453 DigestInit(&ctx, image->firmware_sign_algorithm); | |
454 DigestUpdate(&ctx, (uint8_t*) &image->header_version, | |
455 FIELD_LEN(header_version)); | |
456 DigestUpdate(&ctx, (uint8_t*) &image->header_len, | |
457 FIELD_LEN(header_len)); | |
458 DigestUpdate(&ctx, (uint8_t*) &image->firmware_sign_algorithm, | |
459 FIELD_LEN(firmware_sign_algorithm)); | |
460 DigestUpdate(&ctx, (uint8_t*) &image->kernel_sign_algorithm, | |
461 FIELD_LEN(kernel_sign_algorithm)); | |
462 DigestUpdate(&ctx, (uint8_t*) &image->kernel_key_version, | |
463 FIELD_LEN(kernel_key_version)); | |
464 DigestUpdate(&ctx, image->kernel_sign_key, | |
465 RSAProcessedKeySize(image->kernel_sign_algorithm)); | |
466 DigestUpdate(&ctx, image->header_checksum, | |
467 FIELD_LEN(header_checksum)); | |
468 header_digest = DigestFinal(&ctx); | |
469 if (!RSAVerify(firmware_key, image->kernel_key_signature, | |
470 siglen_map[image->firmware_sign_algorithm], | |
471 image->firmware_sign_algorithm, | |
472 header_digest)) { | |
473 debug("VerifyKernelImage(): Key signature check failed.\n"); | |
474 error_code = VERIFY_KERNEL_KEY_SIGNATURE_FAILED; | |
475 goto verify_failure; | |
476 } | |
477 } | |
478 | |
479 /* Get kernel signing key to verify the rest of the kernel. */ | |
480 kernel_sign_key_size = RSAProcessedKeySize(image->kernel_sign_algorithm); | |
481 kernel_sign_key = RSAPublicKeyFromBuf(image->kernel_sign_key, | |
482 kernel_sign_key_size); | |
483 kernel_signature_size = siglen_map[image->kernel_sign_algorithm]; | |
484 | |
485 /* Verify kernel preamble signature. */ | |
486 DigestInit(&ctx, image->kernel_sign_algorithm); | |
487 DigestUpdate(&ctx, (uint8_t*) &image->kernel_version, | |
488 FIELD_LEN(kernel_version)); | |
489 DigestUpdate(&ctx, (uint8_t*) &image->kernel_len, | |
490 FIELD_LEN(kernel_len)); | |
491 DigestUpdate(&ctx, (uint8_t*) &image->bootloader_offset, | |
492 FIELD_LEN(bootloader_offset)); | |
493 DigestUpdate(&ctx, (uint8_t*) &image->bootloader_size, | |
494 FIELD_LEN(bootloader_size)); | |
495 DigestUpdate(&ctx, (uint8_t*) &image->padded_header_size, | |
496 FIELD_LEN(padded_header_size)); | |
497 DigestUpdate(&ctx, (uint8_t*) image->kernel_signature, | |
498 kernel_signature_size); | |
499 preamble_digest = DigestFinal(&ctx); | |
500 if (!RSAVerify(kernel_sign_key, image->preamble_signature, | |
501 kernel_signature_size, image->kernel_sign_algorithm, | |
502 preamble_digest)) { | |
503 error_code = VERIFY_KERNEL_PREAMBLE_SIGNATURE_FAILED; | |
504 goto verify_failure; | |
505 } | |
506 | |
507 /* Verify kernel signature - kernel signature is computed on the contents | |
508 * of kernel_data. | |
509 * Association between the kernel_data and preamble is maintained by making | |
510 * the kernel signature a part of the preamble and verifying it as part | |
511 * of preamble signature checking. */ | |
512 | |
513 kernel_digest = DigestBuf(image->kernel_data, | |
514 image->kernel_len, | |
515 image->kernel_sign_algorithm); | |
516 if (!RSAVerify(kernel_sign_key, image->kernel_signature, | |
517 kernel_signature_size, image->kernel_sign_algorithm, | |
518 kernel_digest)) { | |
519 error_code = VERIFY_KERNEL_SIGNATURE_FAILED; | |
520 goto verify_failure; | |
521 } | |
522 | |
523 verify_failure: | |
524 RSAPublicKeyFree(kernel_sign_key); | |
525 Free(kernel_digest); | |
526 Free(preamble_digest); | |
527 Free(header_digest); | |
528 return error_code; | |
529 } | |
530 | |
531 const char* VerifyKernelErrorString(int error) { | |
532 return kVerifyKernelErrors[error]; | |
533 } | |
534 | |
535 int AddKernelKeySignature(KernelImage* image, const char* firmware_key_file) { | |
536 uint8_t* header_blob = NULL; | |
537 uint8_t* signature = NULL; | |
538 int signature_len = siglen_map[image->firmware_sign_algorithm]; | |
539 if (!image || !firmware_key_file) | |
540 return 0; | |
541 header_blob = GetKernelHeaderBlob(image); | |
542 if (!header_blob) | |
543 return 0; | |
544 if (!(signature = SignatureBuf(header_blob, | |
545 GetKernelHeaderLen(image), | |
546 firmware_key_file, | |
547 image->firmware_sign_algorithm))) { | |
548 Free(header_blob); | |
549 return 0; | |
550 } | |
551 image->kernel_key_signature = Malloc(signature_len); | |
552 Memcpy(image->kernel_key_signature, signature, signature_len); | |
553 Free(signature); | |
554 Free(header_blob); | |
555 return 1; | |
556 } | |
557 | |
558 int AddKernelSignature(KernelImage* image, | |
559 const char* kernel_signing_key_file) { | |
560 uint8_t* preamble_blob = NULL; | |
561 uint8_t* preamble_signature = NULL; | |
562 uint8_t* kernel_signature = NULL; | |
563 uint8_t* kernel_buf; | |
564 int algorithm = image->kernel_sign_algorithm; | |
565 int signature_len = siglen_map[algorithm]; | |
566 | |
567 /* Kernel signature must be calculated first as its used for computing the | |
568 * preamble signature. */ | |
569 kernel_buf = (uint8_t*) Malloc(image->kernel_len); | |
570 Memcpy(kernel_buf, image->kernel_data, image->kernel_len); | |
571 if (!(kernel_signature = SignatureBuf(kernel_buf, | |
572 image->kernel_len, | |
573 kernel_signing_key_file, | |
574 algorithm))) { | |
575 Free(preamble_blob); | |
576 Free(kernel_buf); | |
577 debug("Could not compute signature on the kernel.\n"); | |
578 return 0; | |
579 } | |
580 image->kernel_signature = (uint8_t*) Malloc(signature_len); | |
581 Memcpy(image->kernel_signature, kernel_signature, signature_len); | |
582 | |
583 | |
584 preamble_blob = GetKernelPreambleBlob(image); | |
585 if (!(preamble_signature = SignatureBuf(preamble_blob, | |
586 GetKernelPreambleLen(algorithm), | |
587 kernel_signing_key_file, | |
588 algorithm))) { | |
589 debug("Could not compute signature on the kernel preamble.\n"); | |
590 Free(preamble_blob); | |
591 return 0; | |
592 } | |
593 image->preamble_signature = (uint8_t*) Malloc(signature_len); | |
594 Memcpy(image->preamble_signature, preamble_signature, signature_len); | |
595 | |
596 Free(preamble_signature); | |
597 Free(preamble_blob); | |
598 Free(kernel_signature); | |
599 Free(kernel_buf); | |
600 return 1; | |
601 } | |
602 | |
603 /* Return the smallest integral multiple of [alignment] that is equal to or | |
604 * greater than [val]. Used to determine the number of | |
605 * pages/sectors/blocks/whatever needed to contain [val] items/bytes/etc. */ | |
606 static uint64_t roundup(uint64_t val, uint64_t alignment) { | |
607 uint64_t rem = val % alignment; | |
608 if ( rem ) | |
609 return val + (alignment - rem); | |
610 return val; | |
611 } | |
612 | |
613 /* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we | |
614 * don't find one, we'll use the whole thing. */ | |
615 static unsigned int find_cmdline_start(char *input, unsigned int max_len) { | |
616 int start = 0; | |
617 int i; | |
618 for(i = 0; i < max_len-1 && input[i]; i++) { | |
619 if (input[i] == '-' && input[i+1] == '-') { /* found a "--" */ | |
620 if ((i == 0 || input[i-1] == ' ') && /* nothing before it */ | |
621 (i+2 >= max_len || input[i+2] == ' ')) { /* nothing after it */ | |
622 start = i+2; /* note: hope there's a trailing '\0' */ | |
623 break; | |
624 } | |
625 } | |
626 } | |
627 while(input[start] == ' ') /* skip leading spaces */ | |
628 start++; | |
629 | |
630 return start; | |
631 } | |
632 | |
633 uint8_t* GenerateKernelBlob(const char* kernel_file, | |
634 const char* config_file, | |
635 const char* bootloader_file, | |
636 uint64_t* ret_blob_len, | |
637 uint64_t* ret_bootloader_offset, | |
638 uint64_t* ret_bootloader_size) { | |
639 uint8_t* kernel_buf; | |
640 uint8_t* config_buf; | |
641 uint8_t* bootloader_buf; | |
642 uint8_t* blob = 0; | |
643 uint64_t kernel_size; | |
644 uint64_t config_size; | |
645 uint64_t bootloader_size; | |
646 uint64_t blob_size; | |
647 uint64_t kernel32_start = 0; | |
648 uint64_t kernel32_size = 0; | |
649 uint64_t bootloader_mem_start; | |
650 uint64_t bootloader_mem_size; | |
651 uint64_t now; | |
652 struct linux_kernel_header *lh = 0; | |
653 struct linux_kernel_params *params = 0; | |
654 uint32_t cmdline_addr; | |
655 uint64_t i; | |
656 | |
657 /* Read the input files. */ | |
658 kernel_buf = BufferFromFile(kernel_file, &kernel_size); | |
659 if (!kernel_buf) | |
660 goto done0; | |
661 | |
662 config_buf = BufferFromFile(config_file, &config_size); | |
663 if (!config_buf) | |
664 goto done1; | |
665 if (config_size >= CROS_CONFIG_SIZE) { /* need room for trailing '\0' */ | |
666 error("config file %s is too large (>= %d bytes)\n", | |
667 config_file, CROS_CONFIG_SIZE); | |
668 goto done1; | |
669 } | |
670 | |
671 /* Replace any newlines with spaces in the config file. */ | |
672 for (i=0; i < config_size; i++) | |
673 if (config_buf[i] == '\n') | |
674 config_buf[i] = ' '; | |
675 | |
676 bootloader_buf = BufferFromFile(bootloader_file, &bootloader_size); | |
677 if (!bootloader_buf) | |
678 goto done2; | |
679 | |
680 /* The first part of vmlinuz is a header, followed by a real-mode boot stub. | |
681 * We only want the 32-bit part. */ | |
682 if (kernel_size) { | |
683 lh = (struct linux_kernel_header *)kernel_buf; | |
684 kernel32_start = (lh->setup_sects+1) << 9; | |
685 kernel32_size = kernel_size - kernel32_start; | |
686 } | |
687 | |
688 /* Allocate and zero the blob we need. */ | |
689 blob_size = roundup(kernel32_size, CROS_ALIGN) + | |
690 CROS_CONFIG_SIZE + | |
691 CROS_PARAMS_SIZE + | |
692 roundup(bootloader_size, CROS_ALIGN); | |
693 blob = (uint8_t *)Malloc(blob_size); | |
694 if (!blob) { | |
695 error("Couldn't allocate %ld bytes.\n", blob_size); | |
696 goto done3; | |
697 } | |
698 Memset(blob, 0, blob_size); | |
699 now = 0; | |
700 | |
701 /* Copy the 32-bit kernel. */ | |
702 if (kernel32_size) | |
703 Memcpy(blob + now, kernel_buf + kernel32_start, kernel32_size); | |
704 now += roundup(now + kernel32_size, CROS_ALIGN); | |
705 | |
706 /* Find the load address of the commandline. We'll need it later. */ | |
707 cmdline_addr = CROS_32BIT_ENTRY_ADDR + now | |
708 + find_cmdline_start((char *)config_buf, config_size); | |
709 | |
710 /* Copy the config. */ | |
711 if (config_size) | |
712 Memcpy(blob + now, config_buf, config_size); | |
713 now += CROS_CONFIG_SIZE; | |
714 | |
715 /* The zeropage data is next. Overlay the linux_kernel_header onto it, and | |
716 * tweak a few fields. */ | |
717 params = (struct linux_kernel_params *)(blob + now); | |
718 | |
719 if (kernel_size) | |
720 Memcpy(&(params->setup_sects), &(lh->setup_sects), | |
721 sizeof(*lh) - offsetof(struct linux_kernel_header, setup_sects)); | |
722 params->boot_flag = 0; | |
723 params->ramdisk_image = 0; /* we don't support initrd */ | |
724 params->ramdisk_size = 0; | |
725 params->type_of_loader = 0xff; | |
726 params->cmd_line_ptr = cmdline_addr; | |
727 now += CROS_PARAMS_SIZE; | |
728 | |
729 /* Finally, append the bootloader. Remember where it will load in memory, too. | |
730 */ | |
731 bootloader_mem_start = CROS_32BIT_ENTRY_ADDR + now; | |
732 bootloader_mem_size = roundup(bootloader_size, CROS_ALIGN); | |
733 if (bootloader_size) | |
734 Memcpy(blob + now, bootloader_buf, bootloader_size); | |
735 now += bootloader_mem_size; | |
736 | |
737 /* Pass back some info. */ | |
738 if (ret_blob_len) | |
739 *ret_blob_len = blob_size; | |
740 if (ret_bootloader_offset) | |
741 *ret_bootloader_offset = bootloader_mem_start; | |
742 if (ret_bootloader_size) | |
743 *ret_bootloader_size = bootloader_mem_size; | |
744 | |
745 /* Clean up and return the blob. */ | |
746 done3: | |
747 Free(bootloader_buf); | |
748 done2: | |
749 Free(config_buf); | |
750 done1: | |
751 Free(kernel_buf); | |
752 done0: | |
753 return blob; | |
754 } | |
OLD | NEW |