| Index: src/platform/vboot_reference/utils/firmware_image.c
|
| diff --git a/src/platform/vboot_reference/utils/firmware_image.c b/src/platform/vboot_reference/utils/firmware_image.c
|
| index ae89490ce128b8cbe1dea67f994e053cbc98dc9c..07aa8bd46b09153824ad2337f8415b87e74874ca 100644
|
| --- a/src/platform/vboot_reference/utils/firmware_image.c
|
| +++ b/src/platform/vboot_reference/utils/firmware_image.c
|
| @@ -14,11 +14,15 @@
|
| #include <sys/stat.h>
|
| #include <unistd.h>
|
|
|
| +#include "file_keys.h"
|
| #include "padding.h"
|
| #include "rsa_utility.h"
|
| #include "sha_utility.h"
|
| #include "utility.h"
|
|
|
| +/* Macro to determine the size of a field structure in the FirmwareImage
|
| + * structure. */
|
| +#define FIELD_LEN(field) (sizeof(((FirmwareImage*)0)->field))
|
|
|
| FirmwareImage* FirmwareImageNew(void) {
|
| FirmwareImage* fw = (FirmwareImage*) Malloc(sizeof(FirmwareImage));
|
| @@ -33,9 +37,8 @@ void FirmwareImageFree(FirmwareImage* image) {
|
| Free(image->firmware_data);
|
| }
|
|
|
| -
|
| -FirmwareImage* ReadFirmware(const char* input_file,
|
| - FirmwareImage* image) {
|
| +FirmwareImage* ReadFirmwareImage(const char* input_file,
|
| + FirmwareImage* image) {
|
| int fd;
|
| struct stat fd_stat;
|
|
|
| @@ -78,7 +81,7 @@ FirmwareImage* ReadFirmware(const char* input_file,
|
| if (!StatefulMemcpy(&st, &image->magic, FIRMWARE_MAGIC_SIZE))
|
| goto parse_failure;
|
|
|
| - if (!SafeMemcmp(image->magic, FIRMWARE_MAGIC, FIRMWARE_MAGIC_SIZE)) {
|
| + if (SafeMemcmp(image->magic, FIRMWARE_MAGIC, FIRMWARE_MAGIC_SIZE)) {
|
| fprintf(stderr, "Wrong Firmware Magic.\n");
|
| goto parse_failure;
|
| }
|
| @@ -99,7 +102,7 @@ FirmwareImage* ReadFirmware(const char* input_file,
|
| /* Check whether the header length is correct. */
|
| header_len = (sizeof(image->header_len) + sizeof(image->sign_algorithm) +
|
| sizeof(image->key_version) +
|
| - sizeof(image->header_hash));
|
| + sizeof(image->header_checksum));
|
| if (header_len != image->header_len) {
|
| fprintf(stderr, "Header length mismatch.");
|
| goto parse_failure;
|
| @@ -109,7 +112,7 @@ FirmwareImage* ReadFirmware(const char* input_file,
|
| image->sign_key = (uint8_t*) Malloc(sign_key_len);
|
| StatefulMemcpy(&st, image->sign_key, sign_key_len);
|
| StatefulMemcpy(&st, &image->key_version, sizeof(image->key_version));
|
| - StatefulMemcpy(&st, image->header_hash, sizeof(image->header_hash));
|
| + StatefulMemcpy(&st, image->header_checksum, sizeof(image->header_checksum));
|
|
|
| /* Read key signature. */
|
| StatefulMemcpy(&st, image->key_signature, sizeof(image->key_signature));
|
| @@ -147,10 +150,10 @@ void WriteFirmwareHeader(int fd, FirmwareImage* image) {
|
| sign_key_len = (image->header_len - sizeof(image->header_len) -
|
| sizeof(image->sign_algorithm) -
|
| sizeof(image->key_version) -
|
| - sizeof(image->header_hash));
|
| + sizeof(image->header_checksum));
|
| write(fd, image->sign_key, sign_key_len);
|
| write(fd, &image->key_version, sizeof(image->key_version));
|
| - write(fd, &image->header_hash, sizeof(image->header_hash));
|
| + write(fd, &image->header_checksum, sizeof(image->header_checksum));
|
| }
|
|
|
| void WriteFirmwarePreamble(int fd, FirmwareImage* image) {
|
| @@ -160,31 +163,29 @@ void WriteFirmwarePreamble(int fd, FirmwareImage* image) {
|
| write(fd, image->preamble, sizeof(image->preamble));
|
| }
|
|
|
| +FirmwareImage* WriteFirmwareImage(const char* input_file,
|
| + FirmwareImage* image) {
|
| + int fd;
|
| + int signature_len;
|
|
|
| -FirmwareImage* WriteFirmware(const char* input_file,
|
| - FirmwareImage* image) {
|
| - int fd;
|
| - int signature_len;
|
| -
|
| - if (!image)
|
| - return NULL;
|
| -
|
| - if (-1 == (fd = open(input_file, O_WRONLY))) {
|
| - fprintf(stderr, "Couldn't open file for writing.\n");
|
| - return NULL;
|
| - }
|
| + if (!image)
|
| + return NULL;
|
| + if (-1 == (fd = creat(input_file, S_IRWXU))) {
|
| + fprintf(stderr, "Couldn't open file for writing.\n");
|
| + return NULL;
|
| + }
|
|
|
| - write(fd, &image->magic, sizeof(image->magic));
|
| - WriteFirmwareHeader(fd, image);
|
| - write(fd, image->key_signature, sizeof(image->key_signature));
|
| - signature_len = siglen_map[image->sign_algorithm] * sizeof(uint32_t);
|
| - WriteFirmwarePreamble(fd, image);
|
| - write(fd, image->preamble_signature, signature_len);
|
| - write(fd, image->firmware_signature, signature_len);
|
| - write(fd, image->firmware_data, image->firmware_len);
|
| + write(fd, image->magic, sizeof(image->magic));
|
| + WriteFirmwareHeader(fd, image);
|
| + write(fd, image->key_signature, sizeof(image->key_signature));
|
| + signature_len = siglen_map[image->sign_algorithm] * sizeof(uint32_t);
|
| + WriteFirmwarePreamble(fd, image);
|
| + write(fd, image->preamble_signature, signature_len);
|
| + write(fd, image->firmware_signature, signature_len);
|
| + write(fd, image->firmware_data, image->firmware_len);
|
|
|
| - close(fd);
|
| - return image;
|
| + close(fd);
|
| + return image;
|
| }
|
|
|
| void PrintFirmware(const FirmwareImage* image) {
|
| @@ -209,9 +210,169 @@ void PrintFirmware(const FirmwareImage* image) {
|
| /* Output key signature here? */
|
| }
|
|
|
| -int VerifyFirmware(const RSAPublicKey* root_key,
|
| - const FirmwareImage* image,
|
| +char* kVerifyFirmwareErrors[VERIFY_FIRMWARE_MAX] = {
|
| + "Success.",
|
| + "Invalid Image.",
|
| + "Root Key Signature Failed.",
|
| + "Invalid Verification Algorithm.",
|
| + "Preamble Signature Failed.",
|
| + "Firmware Signature Failed.",
|
| + "Wrong Firmware Magic.",
|
| +};
|
| +
|
| +int VerifyFirmwareHeader(const uint8_t* root_key_blob,
|
| + const uint8_t* header_blob,
|
| + const int dev_mode,
|
| + int* algorithm,
|
| + int* header_len) {
|
| + int sign_key_len;
|
| + int root_key_len;
|
| + uint16_t hlen, algo;
|
| + uint8_t* header_checksum = NULL;
|
| +
|
| + /* Base Offset for the header_checksum field. Actual offset is
|
| + * this + sign_key_len. */
|
| + int base_header_checksum_offset = (FIELD_LEN(header_len) +
|
| + FIELD_LEN(sign_algorithm) +
|
| + FIELD_LEN(key_version));
|
| +
|
| +
|
| + root_key_len = RSAProcessedKeySize(ROOT_SIGNATURE_ALGORITHM);
|
| + Memcpy(&hlen, header_blob, sizeof(hlen));
|
| + Memcpy(&algo,
|
| + header_blob + FIELD_LEN(sign_algorithm),
|
| + sizeof(algo));
|
| + if (algo >= kNumAlgorithms)
|
| + return VERIFY_FIRMWARE_INVALID_ALGORITHM;
|
| + *algorithm = (int) algo;
|
| + sign_key_len = RSAProcessedKeySize(*algorithm);
|
| +
|
| + /* Verify if header len is correct? */
|
| + if (hlen != (base_header_checksum_offset +
|
| + sign_key_len +
|
| + FIELD_LEN(header_checksum)))
|
| + return VERIFY_FIRMWARE_INVALID_IMAGE;
|
| +
|
| + *header_len = (int) hlen;
|
| +
|
| + /* Verify if the hash of the header is correct. */
|
| + header_checksum = DigestBuf(header_blob,
|
| + *header_len - FIELD_LEN(header_checksum),
|
| + SHA512_DIGEST_ALGORITHM);
|
| + if (SafeMemcmp(header_checksum,
|
| + header_blob + (base_header_checksum_offset + sign_key_len),
|
| + FIELD_LEN(header_checksum))) {
|
| + Free(header_checksum);
|
| + return VERIFY_FIRMWARE_INVALID_IMAGE;
|
| + }
|
| + Free(header_checksum);
|
| +
|
| + /* Verify root key signature unless we are in dev mode. */
|
| + if (!dev_mode) {
|
| + if (!RSAVerifyBinary_f(root_key_blob, NULL, /* Key to use */
|
| + header_blob, /* Data to verify */
|
| + *header_len, /* Length of data */
|
| + header_blob + *header_len, /* Expected Signature */
|
| + ROOT_SIGNATURE_ALGORITHM))
|
| + return VERIFY_FIRMWARE_ROOT_SIGNATURE_FAILED;
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +int VerifyFirmwarePreamble(RSAPublicKey* sign_key,
|
| + const uint8_t* preamble_blob,
|
| + int algorithm,
|
| + int* firmware_len) {
|
| + uint32_t len;
|
| + int preamble_len;
|
| + preamble_len = (FIELD_LEN(firmware_version) +
|
| + FIELD_LEN(firmware_len) +
|
| + FIELD_LEN(preamble));
|
| + if (!RSAVerifyBinary_f(NULL, sign_key, /* Key to use */
|
| + preamble_blob, /* Data to verify */
|
| + preamble_len, /* Length of data */
|
| + preamble_blob + preamble_len, /* Expected Signature */
|
| + algorithm))
|
| + return VERIFY_FIRMWARE_PREAMBLE_SIGNATURE_FAILED;
|
| +
|
| + Memcpy(&len, preamble_blob + FIELD_LEN(firmware_version),
|
| + sizeof(len));
|
| + *firmware_len = (int) len;
|
| + return 0;
|
| +}
|
| +
|
| +int VerifyFirmwareData(RSAPublicKey* sign_key,
|
| + const uint8_t* firmware_data_start,
|
| + int firmware_len,
|
| + int algorithm) {
|
| + int signature_len = siglen_map[algorithm] * sizeof(uint32_t);
|
| + if (!RSAVerifyBinary_f(NULL, sign_key, /* Key to use. */
|
| + firmware_data_start + signature_len, /* Data to
|
| + * verify */
|
| + firmware_len, /* Length of data. */
|
| + firmware_data_start, /* Expected Signature */
|
| + algorithm))
|
| + return VERIFY_FIRMWARE_SIGNATURE_FAILED;
|
| + return 0;
|
| +}
|
| +
|
| +int VerifyFirmware(const uint8_t* root_key_blob,
|
| + const uint8_t* firmware_blob,
|
| const int dev_mode) {
|
| + int error_code;
|
| + int algorithm; /* Signing key algorithm. */
|
| + RSAPublicKey* sign_key;
|
| + int sign_key_len, signature_len, header_len, firmware_len;
|
| + const uint8_t* header_ptr; /* Pointer to header. */
|
| + const uint8_t* sign_key_ptr; /* Pointer to signing key. */
|
| + const uint8_t* preamble_ptr; /* Pointer to preamble block. */
|
| + const uint8_t* firmware_ptr; /* Pointer to firmware signature/data. */
|
| +
|
| + /* Note: All the offset calculations are based on struct FirmwareImage which
|
| + * is defined in include/firmware_image.h. */
|
| +
|
| + /* Compare magic bytes. */
|
| + if (SafeMemcmp(firmware_blob, FIRMWARE_MAGIC, FIRMWARE_MAGIC_SIZE))
|
| + return VERIFY_FIRMWARE_WRONG_MAGIC;
|
| + header_ptr = firmware_blob + FIRMWARE_MAGIC_SIZE;
|
| +
|
| + /* Only continue if header verification succeeds. */
|
| + if ((error_code = VerifyFirmwareHeader(root_key_blob, header_ptr, dev_mode,
|
| + &algorithm, &header_len)))
|
| + return error_code; /* AKA jump to revovery. */
|
| +
|
| + /* Parse signing key into RSAPublicKey structure since it is required multiple
|
| + * times. */
|
| + sign_key_len = RSAProcessedKeySize(algorithm);
|
| + sign_key_ptr = header_ptr + (FIELD_LEN(header_len) +
|
| + FIELD_LEN(sign_algorithm));
|
| + sign_key = RSAPublicKeyFromBuf(sign_key_ptr, sign_key_len);
|
| + signature_len = siglen_map[algorithm] * sizeof(uint32_t);
|
| +
|
| + /* Only continue if preamble verification succeeds. */
|
| + preamble_ptr = (header_ptr + header_len +
|
| + FIELD_LEN(key_signature));
|
| + if ((error_code = VerifyFirmwarePreamble(sign_key, preamble_ptr, algorithm,
|
| + &firmware_len)))
|
| + return error_code; /* AKA jump to recovery. */
|
| +
|
| + /* Only continue if firmware data verification succeeds. */
|
| + firmware_ptr = (preamble_ptr +
|
| + FIELD_LEN(firmware_version) +
|
| + FIELD_LEN(firmware_len) +
|
| + FIELD_LEN(preamble) +
|
| + signature_len);
|
| +
|
| + if ((error_code = VerifyFirmwareData(sign_key, firmware_ptr, firmware_len,
|
| + algorithm)))
|
| + return error_code; /* AKA jump to recovery. */
|
| +
|
| + return 0; /* Success! */
|
| +}
|
| +
|
| +int VerifyFirmwareImage(const RSAPublicKey* root_key,
|
| + const FirmwareImage* image,
|
| + const int dev_mode) {
|
| RSAPublicKey* sign_key;
|
| uint8_t* header_digest = NULL;
|
| uint8_t* preamble_digest = NULL;
|
| @@ -222,10 +383,15 @@ int VerifyFirmware(const RSAPublicKey* root_key,
|
| DigestContext ctx;
|
|
|
| if (!image)
|
| - return VERIFY_INVALID_IMAGE;
|
| + return VERIFY_FIRMWARE_INVALID_IMAGE;
|
|
|
| /* Verify root key signature on the sign key header if we
|
| - * are not in dev mode. */
|
| + * are not in dev mode.
|
| + *
|
| + * TODO(gauravsh): Add additional sanity checks here for:
|
| + * 1) verifying the header length is correct.
|
| + * 2) header_checksum is correct.
|
| + */
|
| if (!dev_mode) {
|
| DigestInit(&ctx, ROOT_SIGNATURE_ALGORITHM);
|
| DigestUpdate(&ctx, (uint8_t*) &image->header_len,
|
| @@ -236,14 +402,14 @@ int VerifyFirmware(const RSAPublicKey* root_key,
|
| RSAProcessedKeySize(image->sign_algorithm));
|
| DigestUpdate(&ctx, (uint8_t*) &image->key_version,
|
| sizeof(image->key_version));
|
| - DigestUpdate(&ctx, image->header_hash,
|
| - sizeof(image->header_hash));
|
| + DigestUpdate(&ctx, image->header_checksum,
|
| + sizeof(image->header_checksum));
|
| header_digest = DigestFinal(&ctx);
|
| if (!RSA_verify(root_key, image->key_signature,
|
| sizeof(image->key_signature),
|
| ROOT_SIGNATURE_ALGORITHM,
|
| header_digest)) {
|
| - error_code = VERIFY_ROOT_SIGNATURE_FAILED;
|
| + error_code = VERIFY_FIRMWARE_ROOT_SIGNATURE_FAILED;
|
| goto verify_failure;
|
| }
|
| }
|
| @@ -255,7 +421,7 @@ int VerifyFirmware(const RSAPublicKey* root_key,
|
| signature_size = siglen_map[image->sign_algorithm] * sizeof(uint32_t);
|
|
|
| if (image->sign_algorithm >= kNumAlgorithms)
|
| - return VERIFY_INVALID_ALGORITHM;
|
| + return VERIFY_FIRMWARE_INVALID_ALGORITHM;
|
|
|
| /* Verify firmware preamble signature. */
|
| DigestInit(&ctx, image->sign_algorithm);
|
| @@ -269,7 +435,7 @@ int VerifyFirmware(const RSAPublicKey* root_key,
|
| if (!RSA_verify(sign_key, image->preamble_signature,
|
| signature_size, image->sign_algorithm,
|
| preamble_digest)) {
|
| - error_code = VERIFY_PREAMBLE_SIGNATURE_FAILED;
|
| + error_code = VERIFY_FIRMWARE_PREAMBLE_SIGNATURE_FAILED;
|
| goto verify_failure;
|
| }
|
|
|
| @@ -291,52 +457,6 @@ verify_failure:
|
| return error_code;
|
| }
|
|
|
| -char* kVerifyFirmwareErrors[VERIFY_MAX] = {
|
| - "Success.",
|
| - "Invalid Image.",
|
| - "Root Key Signature Failed.",
|
| - "Invalid Verification Algorithm.",
|
| - "Preamble Signature Failed.",
|
| - "Firmware Signature Failed.",
|
| -};
|
| -
|
| -uint8_t* SignatureFile(char* input_file, char* key_file, int algorithm) {
|
| - char* sign_utility = "./sign_data.sh";
|
| - char* cmd; /* Command line to invoke. */
|
| - int cmd_len;
|
| - FILE* cmd_out; /* File descriptor to command output. */
|
| - uint8_t* signature = NULL;
|
| - int signature_size = siglen_map[algorithm] * sizeof(uint32_t);
|
| -
|
| - /* Build command line:
|
| - * sign_data.sh <algorithm> <key file> <input file>
|
| - */
|
| - cmd_len = (strlen(sign_utility) + 1 + /* +1 for space. */
|
| - 2 + 1 + /* For [algorithm]. */
|
| - strlen(key_file) + 1 + /* +1 for space. */
|
| - strlen(input_file) +
|
| - 1); /* For the trailing '\0'. */
|
| - cmd = (char*) Malloc(cmd_len);
|
| - snprintf(cmd, cmd_len, "%s %d %s %s", sign_utility, algorithm, key_file,
|
| - input_file);
|
| - cmd_out = popen(cmd, "r");
|
| - Free(cmd);
|
| - if (!cmd_out) {
|
| - fprintf(stderr, "Couldn't execute: %s\n", cmd);
|
| - return NULL;
|
| - }
|
| -
|
| - signature = (uint8_t*) Malloc(signature_size);
|
| - if (fread(signature, signature_size, 1, cmd_out) != 1) {
|
| - fprintf(stderr, "Couldn't read signature.\n");
|
| - pclose(cmd_out);
|
| - Free(signature);
|
| - return NULL;
|
| - }
|
| -
|
| - pclose(cmd_out);
|
| - return signature;
|
| -}
|
|
|
| int AddKeySignature(FirmwareImage* image, char* root_key_file) {
|
| int tmp_hdr_fd;
|
| @@ -371,7 +491,7 @@ int AddFirmwareSignature(FirmwareImage* image, char* signing_key_file,
|
| /* Write preamble to a file. */
|
| if(-1 == (tmp_preamble_fd = creat(tmp_preamble_file, S_IRWXU))) {
|
| fprintf(stderr, "Could not open temporary file for writing "
|
| - "firmware praemble.\n");
|
| + "firmware preamble.\n");
|
| return 0;
|
| }
|
| WriteFirmwarePreamble(tmp_preamble_fd, image);
|
|
|