static int write_new_preamble(struct bios_area_s *vblock, struct bios_area_s *fw_body, VbPrivateKey *signkey, VbKeyBlockHeader *keyblock) { VbSignature *body_sig; VbFirmwarePreambleHeader *preamble; body_sig = CalculateSignature(fw_body->buf, fw_body->len, signkey); if (!body_sig) { fprintf(stderr, "Error calculating body signature\n"); return 1; } preamble = CreateFirmwarePreamble(sign_option.version, sign_option.kernel_subkey, body_sig, signkey, sign_option.flags); if (!preamble) { fprintf(stderr, "Error creating firmware preamble.\n"); free(body_sig); return 1; } /* Write the new keyblock */ uint32_t more = keyblock->key_block_size; memcpy(vblock->buf, keyblock, more); /* and the new preamble */ memcpy(vblock->buf + more, preamble, preamble->preamble_size); free(preamble); free(body_sig); return 0; }
/* Create a firmware .vblock */ static int Vblock(const char* outfile, const char* keyblock_file, const char* signprivate, uint64_t version, const char* fv_file, const char* kernelkey_file, uint32_t preamble_flags) { VbPrivateKey* signing_key; VbPublicKey* kernel_subkey; VbSignature* body_sig; VbFirmwarePreambleHeader* preamble; VbKeyBlockHeader* key_block; uint64_t key_block_size; uint8_t* fv_data; uint64_t fv_size; FILE* f; uint64_t i; if (!outfile) { VbExError("Must specify output filename\n"); return 1; } if (!keyblock_file || !signprivate || !kernelkey_file) { VbExError("Must specify all keys\n"); return 1; } if (!fv_file) { VbExError("Must specify firmware volume\n"); return 1; } /* Read the key block and keys */ key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size); if (!key_block) { VbExError("Error reading key block.\n"); return 1; } signing_key = PrivateKeyRead(signprivate); if (!signing_key) { VbExError("Error reading signing key.\n"); return 1; } kernel_subkey = PublicKeyRead(kernelkey_file); if (!kernel_subkey) { VbExError("Error reading kernel subkey.\n"); return 1; } /* Read and sign the firmware volume */ fv_data = ReadFile(fv_file, &fv_size); if (!fv_data) return 1; if (!fv_size) { VbExError("Empty firmware volume file\n"); return 1; } body_sig = CalculateSignature(fv_data, fv_size, signing_key); if (!body_sig) { VbExError("Error calculating body signature\n"); return 1; } free(fv_data); /* Create preamble */ preamble = CreateFirmwarePreamble(version, kernel_subkey, body_sig, signing_key, preamble_flags); if (!preamble) { VbExError("Error creating preamble.\n"); return 1; } /* Write the output file */ f = fopen(outfile, "wb"); if (!f) { VbExError("Can't open output file %s\n", outfile); return 1; } i = ((1 != fwrite(key_block, key_block_size, 1, f)) || (1 != fwrite(preamble, preamble->preamble_size, 1, f))); fclose(f); if (i) { VbExError("Can't write output file %s\n", outfile); unlink(outfile); return 1; } /* Success */ return 0; }
static void test_verify_fw_preamble(const VbPublicKey *public_key, const VbPrivateKey *private_key, const VbPublicKey *kernel_subkey) { struct vb2_fw_preamble *hdr; struct vb2_fw_preamble *h; struct vb2_public_key rsa; uint8_t workbuf[VB2_VERIFY_FIRMWARE_PREAMBLE_WORKBUF_BYTES] __attribute__ ((aligned (VB2_WORKBUF_ALIGN))); struct vb2_workbuf wb; uint32_t hsize; vb2_workbuf_init(&wb, workbuf, sizeof(workbuf)); /* Create a dummy signature */ VbSignature *body_sig = SignatureAlloc(56, 78); TEST_SUCC(vb2_unpack_key(&rsa, (uint8_t *)public_key, public_key->key_offset + public_key->key_size), "vb2_verify_fw_preamble() prereq key"); hdr = (struct vb2_fw_preamble *) CreateFirmwarePreamble(0x1234, kernel_subkey, body_sig, private_key, 0x5678); TEST_PTR_NEQ(hdr, NULL, "VerifyFirmwarePreamble() prereq test preamble"); if (!hdr) return; hsize = (uint32_t) hdr->preamble_size; h = (struct vb2_fw_preamble *)malloc(hsize + 16384); Memcpy(h, hdr, hsize); TEST_SUCC(vb2_verify_fw_preamble(h, hsize, &rsa, &wb), "vb2_verify_fw_preamble() ok using key"); Memcpy(h, hdr, hsize); TEST_EQ(vb2_verify_fw_preamble(h, 4, &rsa, &wb), VB2_ERROR_PREAMBLE_TOO_SMALL_FOR_HEADER, "vb2_verify_fw_preamble() size tiny"); Memcpy(h, hdr, hsize); TEST_EQ(vb2_verify_fw_preamble(h, hsize - 1, &rsa, &wb), VB2_ERROR_PREAMBLE_SIZE, "vb2_verify_fw_preamble() size--"); /* Buffer is allowed to be bigger than preamble */ Memcpy(h, hdr, hsize); TEST_SUCC(vb2_verify_fw_preamble(h, hsize + 1, &rsa, &wb), "vb2_verify_fw_preamble() size++"); /* Care about major version but not minor */ Memcpy(h, hdr, hsize); h->header_version_major++; resign_fw_preamble(h, private_key); TEST_EQ(vb2_verify_fw_preamble(h, hsize, &rsa, &wb), VB2_ERROR_PREAMBLE_HEADER_VERSION , "vb2_verify_fw_preamble() major++"); Memcpy(h, hdr, hsize); h->header_version_major--; resign_fw_preamble(h, private_key); TEST_EQ(vb2_verify_fw_preamble(h, hsize, &rsa, &wb), VB2_ERROR_PREAMBLE_HEADER_VERSION, "vb2_verify_fw_preamble() major--"); Memcpy(h, hdr, hsize); h->header_version_minor++; resign_fw_preamble(h, private_key); TEST_SUCC(vb2_verify_fw_preamble(h, hsize, &rsa, &wb), "vb2_verify_fw_preamble() minor++"); Memcpy(h, hdr, hsize); h->header_version_minor--; resign_fw_preamble(h, private_key); TEST_EQ(vb2_verify_fw_preamble(h, hsize, &rsa, &wb), VB2_ERROR_PREAMBLE_HEADER_OLD, "vb2_verify_fw_preamble() 2.0 not supported"); /* Check signature */ Memcpy(h, hdr, hsize); h->preamble_signature.sig_offset = hsize; resign_fw_preamble(h, private_key); TEST_EQ(vb2_verify_fw_preamble(h, hsize, &rsa, &wb), VB2_ERROR_PREAMBLE_SIG_OUTSIDE, "vb2_verify_fw_preamble() sig off end"); Memcpy(h, hdr, hsize); h->preamble_signature.sig_size--; resign_fw_preamble(h, private_key); TEST_EQ(vb2_verify_fw_preamble(h, hsize, &rsa, &wb), VB2_ERROR_PREAMBLE_SIG_INVALID, "vb2_verify_fw_preamble() sig too small"); Memcpy(h, hdr, hsize); ((uint8_t *)vb2_packed_key_data(&h->kernel_subkey))[0] ^= 0x34; TEST_EQ(vb2_verify_fw_preamble(h, hsize, &rsa, &wb), VB2_ERROR_PREAMBLE_SIG_INVALID, "vb2_verify_fw_preamble() sig mismatch"); /* Check that we signed header, kernel subkey, and body sig */ Memcpy(h, hdr, hsize); h->preamble_signature.data_size = 4; h->kernel_subkey.key_offset = 0; h->kernel_subkey.key_size = 0; h->body_signature.sig_offset = 0; h->body_signature.sig_size = 0; resign_fw_preamble(h, private_key); TEST_EQ(vb2_verify_fw_preamble(h, hsize, &rsa, &wb), VB2_ERROR_PREAMBLE_SIGNED_TOO_LITTLE, "vb2_verify_fw_preamble() didn't sign header"); Memcpy(h, hdr, hsize); h->kernel_subkey.key_offset = hsize; resign_fw_preamble(h, private_key); TEST_EQ(vb2_verify_fw_preamble(h, hsize, &rsa, &wb), VB2_ERROR_PREAMBLE_KERNEL_SUBKEY_OUTSIDE, "vb2_verify_fw_preamble() kernel subkey off end"); Memcpy(h, hdr, hsize); h->body_signature.sig_offset = hsize; resign_fw_preamble(h, private_key); TEST_EQ(vb2_verify_fw_preamble(h, hsize, &rsa, &wb), VB2_ERROR_PREAMBLE_BODY_SIG_OUTSIDE, "vb2_verify_fw_preamble() body sig off end"); /* TODO: verify with extra padding at end of header. */ free(h); free(hdr); }