| 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 |