static void VerifyDigestTest(const VbPublicKey *public_key, const VbPrivateKey *private_key) { const uint8_t test_data[] = "This is some other test data to sign."; VbSignature *sig; RSAPublicKey *rsa; uint8_t *digest; sig = CalculateSignature(test_data, sizeof(test_data), private_key); rsa = PublicKeyToRSA(public_key); digest = DigestBuf(test_data, sizeof(test_data), (int)public_key->algorithm); TEST_NEQ(sig && rsa && digest, 0, "VerifyData() prerequisites"); if (!sig || !rsa || !digest) return; TEST_EQ(VerifyDigest(digest, sig, rsa), 0, "VerifyDigest() ok"); GetSignatureData(sig)[0] ^= 0x5A; TEST_EQ(VerifyDigest(digest, sig, rsa), 1, "VerifyDigest() wrong sig"); sig->sig_size = 1; TEST_EQ(VerifyDigest(digest, sig, rsa), 1, "VerifyDigest() sig size"); RSAPublicKeyFree(rsa); free(sig); VbExFree(digest); }
int RSAVerifyBinary_f(const uint8_t* key_blob, const RSAPublicKey* key, const uint8_t* buf, int len, const uint8_t* sig, int algorithm) { RSAPublicKey* verification_key = NULL; uint8_t* digest = NULL; int key_size; int sig_size; int success; if (algorithm >= kNumAlgorithms) return 0; /* Invalid algorithm. */ key_size = RSAProcessedKeySize(algorithm); sig_size = siglen_map[algorithm] * sizeof(uint32_t); if (key_blob && !key) verification_key = RSAPublicKeyFromBuf(key_blob, key_size); else if (!key_blob && key) verification_key = (RSAPublicKey*) key; /* Supress const warning. */ else return 0; /* Both can't be NULL or non-NULL. */ digest = DigestBuf(buf, len, algorithm); success = RSA_verify(verification_key, sig, sig_size, algorithm, digest); Free(digest); if (!key) RSAPublicKeyFree(verification_key); /* Only free if we allocated it. */ return success; }
static void VerifyDataTest(const VbPublicKey *public_key, const VbPrivateKey *private_key) { const uint8_t test_data[] = "This is some test data to sign."; const uint64_t test_size = sizeof(test_data); VbSignature *sig; RSAPublicKey *rsa; sig = CalculateSignature(test_data, test_size, private_key); TEST_PTR_NEQ(sig, 0, "VerifyData() calculate signature"); rsa = PublicKeyToRSA(public_key); TEST_PTR_NEQ(rsa, 0, "VerifyData() calculate rsa"); if (!sig || !rsa) return; TEST_EQ(VerifyData(test_data, test_size, sig, rsa), 0, "VerifyData() ok"); sig->sig_size -= 16; TEST_EQ(VerifyData(test_data, test_size, sig, rsa), 1, "VerifyData() wrong sig size"); sig->sig_size += 16; TEST_EQ(VerifyData(test_data, test_size - 1, sig, rsa), 1, "VerifyData() input buffer too small"); GetSignatureData(sig)[0] ^= 0x5A; TEST_EQ(VerifyData(test_data, test_size, sig, rsa), 1, "VerifyData() wrong sig"); RSAPublicKeyFree(rsa); free(sig); }
static void VerifyPublicKeyToRSA(const VbPublicKey *orig_key) { RSAPublicKey *rsa; VbPublicKey *key = PublicKeyAlloc(orig_key->key_size, 0, 0); PublicKeyCopy(key, orig_key); key->algorithm = kNumAlgorithms; TEST_EQ((size_t)PublicKeyToRSA(key), 0, "PublicKeyToRSA() invalid algorithm"); PublicKeyCopy(key, orig_key); key->key_size -= 1; TEST_EQ((size_t)PublicKeyToRSA(key), 0, "PublicKeyToRSA() invalid size"); rsa = PublicKeyToRSA(orig_key); TEST_NEQ((size_t)rsa, 0, "PublicKeyToRSA() ok"); if (rsa) { TEST_EQ((int)rsa->algorithm, (int)key->algorithm, "PublicKeyToRSA() algorithm"); RSAPublicKeyFree(rsa); } }
int main(int argc, char *argv[]) { int error = 0; RSAPublicKey *key; struct vb2_public_key k2; /* Read test key */ if (argc != 2) { fprintf(stderr, "Usage: %s <test public key>\n", argv[0]); return 1; } key = RSAPublicKeyFromFile(argv[1]); if (!key) { fprintf(stderr, "Couldn't read RSA public key for the test.\n"); return 1; } // TODO: why is test key algorithm wrong? key->algorithm = 0; /* Convert test key to Vb2 format */ vb2_public_key_to_vb2(&k2, key); /* Run tests */ test_signatures(&k2); test_verify_digest(&k2); /* Clean up and exit */ RSAPublicKeyFree(key); if (!gTestSuccess) error = 255; return error; }
static void VerifyKernelPreambleTest(const VbPublicKey *public_key, const VbPrivateKey *private_key) { VbKernelPreambleHeader *hdr; VbKernelPreambleHeader *h; RSAPublicKey *rsa; unsigned hsize; /* Create a dummy signature */ VbSignature *body_sig = SignatureAlloc(56, 78); rsa = PublicKeyToRSA(public_key); hdr = CreateKernelPreamble(0x1234, 0x100000, 0x300000, 0x4000, body_sig, 0, 0, 0, 0, private_key); TEST_NEQ(hdr && rsa, 0, "VerifyKernelPreamble() prerequisites"); if (!hdr) return; hsize = (unsigned) hdr->preamble_size; h = (VbKernelPreambleHeader *)malloc(hsize + 16384); TEST_EQ(VerifyKernelPreamble(hdr, hsize, rsa), 0, "VerifyKernelPreamble() ok using key"); TEST_NEQ(VerifyKernelPreamble(hdr, hsize - 1, rsa), 0, "VerifyKernelPreamble() size--"); TEST_NEQ(VerifyKernelPreamble(hdr, 4, rsa), 0, "VerifyKernelPreamble() size tiny"); TEST_EQ(VerifyKernelPreamble(hdr, hsize + 1, rsa), 0, "VerifyKernelPreamble() size++"); /* Care about major version but not minor */ Memcpy(h, hdr, hsize); h->header_version_major++; ReSignKernelPreamble(h, private_key); TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() major++"); Memcpy(h, hdr, hsize); h->header_version_major--; ReSignKernelPreamble(h, private_key); TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() major--"); Memcpy(h, hdr, hsize); h->header_version_minor++; ReSignKernelPreamble(h, private_key); TEST_EQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() minor++"); Memcpy(h, hdr, hsize); h->header_version_minor--; ReSignKernelPreamble(h, private_key); TEST_EQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() minor--"); /* Check signature */ Memcpy(h, hdr, hsize); h->preamble_signature.sig_offset = hsize; ReSignKernelPreamble(h, private_key); TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() sig off end"); Memcpy(h, hdr, hsize); h->preamble_signature.sig_size--; ReSignKernelPreamble(h, private_key); TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() sig too small"); Memcpy(h, hdr, hsize); GetSignatureData(&h->body_signature)[0] ^= 0x34; TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() sig mismatch"); /* Check that we signed header and body sig */ Memcpy(h, hdr, hsize); h->preamble_signature.data_size = 4; h->body_signature.sig_offset = 0; h->body_signature.sig_size = 0; ReSignKernelPreamble(h, private_key); TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() didn't sign header"); Memcpy(h, hdr, hsize); h->body_signature.sig_offset = hsize; ReSignKernelPreamble(h, private_key); TEST_NEQ(VerifyKernelPreamble(h, hsize, rsa), 0, "VerifyKernelPreamble() body sig off end"); /* TODO: verify parser can support a bigger header. */ free(h); RSAPublicKeyFree(rsa); free(hdr); }
int KeyBlockVerify(const VbKeyBlockHeader *block, uint64_t size, const VbPublicKey *key, int hash_only) { const VbSignature *sig; /* Sanity checks before attempting signature of data */ if(size < sizeof(VbKeyBlockHeader)) { VBDEBUG(("Not enough space for key block header.\n")); return VBOOT_KEY_BLOCK_INVALID; } if (SafeMemcmp(block->magic, KEY_BLOCK_MAGIC, KEY_BLOCK_MAGIC_SIZE)) { VBDEBUG(("Not a valid verified boot key block.\n")); return VBOOT_KEY_BLOCK_INVALID; } if (block->header_version_major != KEY_BLOCK_HEADER_VERSION_MAJOR) { VBDEBUG(("Incompatible key block header version.\n")); return VBOOT_KEY_BLOCK_INVALID; } if (size < block->key_block_size) { VBDEBUG(("Not enough data for key block.\n")); return VBOOT_KEY_BLOCK_INVALID; } if (!hash_only && !key) { VBDEBUG(("Missing required public key.\n")); return VBOOT_PUBLIC_KEY_INVALID; } /* * Check signature or hash, depending on the hash_only parameter. Note * that we don't require a key even if the keyblock has a signature, * because the caller may not care if the keyblock itself is signed * (for example, booting a Google-signed kernel in developer mode). */ if (hash_only) { /* Check hash */ uint8_t *header_checksum = NULL; int rv; sig = &block->key_block_checksum; if (VerifySignatureInside(block, block->key_block_size, sig)) { VBDEBUG(("Key block hash off end of block\n")); return VBOOT_KEY_BLOCK_INVALID; } if (sig->sig_size != SHA512_DIGEST_SIZE) { VBDEBUG(("Wrong hash size for key block.\n")); return VBOOT_KEY_BLOCK_INVALID; } /* Make sure advertised signature data sizes are sane. */ if (block->key_block_size < sig->data_size) { VBDEBUG(("Signature calculated past end of block\n")); return VBOOT_KEY_BLOCK_INVALID; } VBDEBUG(("Checking key block hash only...\n")); header_checksum = DigestBuf((const uint8_t *)block, sig->data_size, SHA512_DIGEST_ALGORITHM); rv = SafeMemcmp(header_checksum, GetSignatureDataC(sig), SHA512_DIGEST_SIZE); VbExFree(header_checksum); if (rv) { VBDEBUG(("Invalid key block hash.\n")); return VBOOT_KEY_BLOCK_HASH; } } else { /* Check signature */ RSAPublicKey *rsa; int rv; sig = &block->key_block_signature; if (VerifySignatureInside(block, block->key_block_size, sig)) { VBDEBUG(("Key block signature off end of block\n")); return VBOOT_KEY_BLOCK_INVALID; } rsa = PublicKeyToRSA(key); if (!rsa) { VBDEBUG(("Invalid public key\n")); return VBOOT_PUBLIC_KEY_INVALID; } /* Make sure advertised signature data sizes are sane. */ if (block->key_block_size < sig->data_size) { VBDEBUG(("Signature calculated past end of block\n")); RSAPublicKeyFree(rsa); return VBOOT_KEY_BLOCK_INVALID; } VBDEBUG(("Checking key block signature...\n")); rv = VerifyData((const uint8_t *)block, size, sig, rsa); RSAPublicKeyFree(rsa); if (rv) { VBDEBUG(("Invalid key block signature.\n")); return VBOOT_KEY_BLOCK_SIGNATURE; } } /* Verify we signed enough data */ if (sig->data_size < sizeof(VbKeyBlockHeader)) { VBDEBUG(("Didn't sign enough data\n")); return VBOOT_KEY_BLOCK_INVALID; } /* Verify data key is inside the block and inside signed data */ if (VerifyPublicKeyInside(block, block->key_block_size, &block->data_key)) { VBDEBUG(("Data key off end of key block\n")); return VBOOT_KEY_BLOCK_INVALID; } if (VerifyPublicKeyInside(block, sig->data_size, &block->data_key)) { VBDEBUG(("Data key off end of signed data\n")); return VBOOT_KEY_BLOCK_INVALID; } /* Success */ return VBOOT_SUCCESS; }
int SpeedTestAlgorithm(int algorithm) { int i, key_size; int error_code = 0; double speed, msecs; char file_name[FILE_NAME_SIZE]; uint8_t* digest = NULL; uint8_t* signature = NULL; uint64_t digest_len, sig_len; RSAPublicKey* key = NULL; ClockTimerState ct; char* sha_strings[] = { /* Maps algorithm->SHA algorithm. */ "sha1", "sha256", "sha512", /* RSA-1024 */ "sha1", "sha256", "sha512", /* RSA-2048 */ "sha1", "sha256", "sha512", /* RSA-4096 */ "sha1", "sha256", "sha512", /* RSA-8192 */ }; key_size = siglen_map[algorithm] * 8; /* in bits. */ /* Get key. */ snprintf(file_name, FILE_NAME_SIZE, "testkeys/key_rsa%d.keyb", key_size); key = RSAPublicKeyFromFile(file_name); if (!key) { VBDEBUG(("Couldn't read RSA Public key from file: %s\n", file_name)); error_code = 1; goto failure; } /* Get expected digest. */ snprintf(file_name, FILE_NAME_SIZE, "testcases/test_file.%s.digest", sha_strings[algorithm]); digest = BufferFromFile(file_name, &digest_len); if (!digest) { VBDEBUG(("Couldn't read digest file.\n")); error_code = 1; goto failure; } /* Get signature to verify against. */ snprintf(file_name, FILE_NAME_SIZE, "testcases/test_file.rsa%d_%s.sig", key_size, sha_strings[algorithm]); signature = BufferFromFile(file_name, &sig_len); if (!signature) { VBDEBUG(("Couldn't read signature file.\n")); error_code = 1; goto failure; } StartTimer(&ct); for (i = 0; i < NUM_OPERATIONS; i++) { if (!RSAVerify(key, signature, sig_len, algorithm, digest)) VBDEBUG(("Warning: Signature Check Failed.\n")); } StopTimer(&ct); msecs = (float) GetDurationMsecs(&ct) / NUM_OPERATIONS; speed = 1000.0 / msecs ; fprintf(stderr, "# rsa%d/%s:\tTime taken per verification = %.02f ms," " Speed = %.02f verifications/s\n", key_size, sha_strings[algorithm], msecs, speed); fprintf(stdout, "ms_rsa%d_%s:%.02f\n", key_size, sha_strings[algorithm], msecs); failure: free(signature); free(digest); RSAPublicKeyFree(key); return error_code; }
VbError_t VbVerifyMemoryBootImage(VbCommonParams *cparams, VbSelectAndLoadKernelParams *kparams, void *boot_image, size_t image_size) { VbError_t retval; VbPublicKey* kernel_subkey = NULL; uint8_t *kbuf; VbKeyBlockHeader *key_block; VbSharedDataHeader *shared = (VbSharedDataHeader *)cparams->shared_data_blob; RSAPublicKey *data_key = NULL; VbKernelPreambleHeader *preamble; uint64_t body_offset; int hash_only = 0; int dev_switch; if ((boot_image == NULL) || (image_size == 0)) return VBERROR_INVALID_PARAMETER; /* Clear output params in case we fail. */ kparams->disk_handle = NULL; kparams->partition_number = 0; kparams->bootloader_address = 0; kparams->bootloader_size = 0; kparams->flags = 0; Memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid)); kbuf = boot_image; /* Read GBB Header */ cparams->bmp = NULL; cparams->gbb = VbExMalloc(sizeof(*cparams->gbb)); retval = VbGbbReadHeader_static(cparams, cparams->gbb); if (VBERROR_SUCCESS != retval) { VBDEBUG(("Gbb read header failed.\n")); return retval; } /* * We don't care verifying the image if: * 1. dev-mode switch is on and * 2. GBB_FLAG_FORCE_DEV_BOOT_FASTBOOT_FULL_CAP is set. * * Check only the integrity of the image. */ dev_switch = shared->flags & VBSD_BOOT_DEV_SWITCH_ON; if (dev_switch && (cparams->gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_FASTBOOT_FULL_CAP)) { VBDEBUG(("Only performing integrity-check.\n")); hash_only = 1; } else { /* Get recovery key. */ retval = VbGbbReadRecoveryKey(cparams, &kernel_subkey); if (VBERROR_SUCCESS != retval) { VBDEBUG(("Gbb Read Recovery key failed.\n")); return retval; } } /* If we fail at any step, retval returned would be invalid kernel. */ retval = VBERROR_INVALID_KERNEL_FOUND; /* Verify the key block. */ key_block = (VbKeyBlockHeader *)kbuf; if (0 != KeyBlockVerify(key_block, image_size, kernel_subkey, hash_only)) { VBDEBUG(("Verifying key block signature/hash failed.\n")); goto fail; } /* Check the key block flags against the current boot mode. */ if (!(key_block->key_block_flags & (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 : KEY_BLOCK_FLAG_DEVELOPER_0))) { VBDEBUG(("Key block developer flag mismatch.\n")); if (hash_only == 0) goto fail; } if (!(key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)) { VBDEBUG(("Key block recovery flag mismatch.\n")); if (hash_only == 0) goto fail; } /* Get key for preamble/data verification from the key block. */ data_key = PublicKeyToRSA(&key_block->data_key); if (!data_key) { VBDEBUG(("Data key bad.\n")); goto fail; } /* Verify the preamble, which follows the key block */ preamble = (VbKernelPreambleHeader *)(kbuf + key_block->key_block_size); if ((0 != VerifyKernelPreamble(preamble, image_size - key_block->key_block_size, data_key))) { VBDEBUG(("Preamble verification failed.\n")); goto fail; } VBDEBUG(("Kernel preamble is good.\n")); /* Verify kernel data */ body_offset = key_block->key_block_size + preamble->preamble_size; if (0 != VerifyData((const uint8_t *)(kbuf + body_offset), image_size - body_offset, &preamble->body_signature, data_key)) { VBDEBUG(("Kernel data verification failed.\n")); goto fail; } VBDEBUG(("Kernel is good.\n")); /* Fill in output parameters. */ kparams->kernel_buffer = kbuf + body_offset; kparams->kernel_buffer_size = image_size - body_offset; kparams->bootloader_address = preamble->bootloader_address; kparams->bootloader_size = preamble->bootloader_size; if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS) kparams->flags = preamble->flags; retval = VBERROR_SUCCESS; fail: VbApiKernelFree(cparams); if (NULL != data_key) RSAPublicKeyFree(data_key); if (NULL != kernel_subkey) VbExFree(kernel_subkey); return retval; }