diff --git a/tests/vboot_common2_tests.c b/tests/vboot_common2_tests.c index 1b7d4a1936..86a560f069 100644 --- a/tests/vboot_common2_tests.c +++ b/tests/vboot_common2_tests.c @@ -45,8 +45,8 @@ static void VerifyDataTest(const VbPublicKey* public_key, const VbPrivateKey* private_key) { const uint8_t test_data[] = "This is some test data to sign."; - VbSignature *sig; - RSAPublicKey *rsa; + VbSignature* sig; + RSAPublicKey* rsa; sig = CalculateSignature(test_data, sizeof(test_data), private_key); rsa = PublicKeyToRSA(public_key); @@ -68,6 +68,32 @@ static void VerifyDataTest(const VbPublicKey* public_key, } +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), 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"); + + RSAPublicKeyFree(rsa); + Free(sig); + Free(digest); +} + + static void ReSignKernelPreamble(VbKernelPreambleHeader *h, const VbPrivateKey *key) { VbSignature *sig = CalculateSignature((const uint8_t*)h, @@ -201,6 +227,7 @@ int main(int argc, char* argv[]) { VerifyPublicKeyToRSA(public_key); VerifyDataTest(public_key, private_key); + VerifyDigestTest(public_key, private_key); VerifyKernelPreambleTest(public_key, private_key); if (public_key) diff --git a/vboot_firmware/lib/include/vboot_common.h b/vboot_firmware/lib/include/vboot_common.h index 407746b953..1d81198528 100644 --- a/vboot_firmware/lib/include/vboot_common.h +++ b/vboot_firmware/lib/include/vboot_common.h @@ -67,6 +67,12 @@ int VerifyData(const uint8_t* data, const VbSignature* sig, const RSAPublicKey* key); +/* Verifies a secure hash digest from DigestBuf() or DigestFinal(), + * using [key]. */ +int VerifyDigest(const uint8_t* digest, const VbSignature *sig, + const RSAPublicKey* key); + + /* Checks the sanity of a key block of size [size] bytes, using public * key [key]. If [key]==NULL, uses only the block checksum to verify * the key block. Header fields are also checked for sanity. Does not diff --git a/vboot_firmware/lib/vboot_common.c b/vboot_firmware/lib/vboot_common.c index 3eac471ec9..1256b676d3 100644 --- a/vboot_firmware/lib/vboot_common.c +++ b/vboot_firmware/lib/vboot_common.c @@ -122,6 +122,22 @@ int VerifyData(const uint8_t* data, const VbSignature *sig, } +int VerifyDigest(const uint8_t* digest, const VbSignature *sig, + const RSAPublicKey* key) { + + if (sig->sig_size != siglen_map[key->algorithm]) { + debug("Wrong signature size for algorithm.\n"); + return 1; + } + + if (!RSAVerifyBinaryWithDigest_f(NULL, key, digest, + GetSignatureDataC(sig), key->algorithm)) + return 1; + + return 0; +} + + int KeyBlockVerify(const VbKeyBlockHeader* block, uint64_t size, const VbPublicKey *key) { diff --git a/vboot_firmware/lib/vboot_firmware.c b/vboot_firmware/lib/vboot_firmware.c index e0cfc6ae01..8ff673c201 100644 --- a/vboot_firmware/lib/vboot_firmware.c +++ b/vboot_firmware/lib/vboot_firmware.c @@ -13,9 +13,23 @@ #include "utility.h" #include "vboot_common.h" +/* Static variables for UpdateFirmwareBodyHash(). It's less than + * optimal to have static variables in a library, but in UEFI the + * caller is deep inside a different firmware stack and doesn't have a + * good way to pass the params struct back to us. */ +static DigestContext ctx; +static uint64_t body_size_accum = 0; +static int inside_load_firmware = 0; void UpdateFirmwareBodyHash2(uint8_t* data, uint64_t size) { - /* TODO: actually update the hash. */ + + if (!inside_load_firmware) { + debug("UpdateFirmwareBodyHash() called outside LoadFirmware()\n"); + return; + } + + DigestUpdate(&ctx, data, size); + body_size_accum += size; } @@ -56,6 +70,7 @@ int LoadFirmware2(LoadFirmwareParams* params) { uint64_t key_version; uint8_t* body_data; uint64_t body_size; + uint8_t* body_digest; /* Verify the key block */ if (0 == index) { @@ -112,23 +127,29 @@ int LoadFirmware2(LoadFirmwareParams* params) { continue; /* Read the firmware data */ - /* TODO: should set up hash for UpdateFirmwareBodyHash(). */ + DigestInit(&ctx, data_key->algorithm); + body_size_accum = 0; + inside_load_firmware = 1; body_data = GetFirmwareBody(index, &body_size); - if (!body_data || (body_size != preamble->body_signature.data_size)) { + inside_load_firmware = 0; + body_digest = DigestFinal(&ctx); + if (!body_data || (body_size != preamble->body_signature.data_size) || + (body_size_accum != body_size)) { RSAPublicKeyFree(data_key); + Free(body_digest); continue; } /* Verify firmware data */ - /* TODO: should use hash from UpdateFirmwareBodyHash() rather than - * recalculating it in VerifyData(). */ - if (0 != VerifyData(body_data, &preamble->body_signature, data_key)) { + if (0 != VerifyDigest(body_digest, &preamble->body_signature, data_key)) { RSAPublicKeyFree(data_key); + Free(body_digest); continue; } - /* Done with the data key, so can free it now */ + /* Done with the digest and data key, so can free them now */ RSAPublicKeyFree(data_key); + Free(body_digest); /* If we're still here, the firmware is valid. */ /* Save the first good firmware we find; that's the one we'll boot */ diff --git a/vboot_firmware/linktest/main.c b/vboot_firmware/linktest/main.c index 212f99de5c..169b657824 100644 --- a/vboot_firmware/linktest/main.c +++ b/vboot_firmware/linktest/main.c @@ -79,6 +79,7 @@ int main(void) VerifySignatureInside(0, 0, 0); PublicKeyToRSA(0); VerifyData(0, 0, 0); + VerifyDigest(0, 0, 0); KeyBlockVerify(0, 0, 0); VerifyFirmwarePreamble2(0, 0, 0); VerifyKernelPreamble2(0, 0, 0);