blob: e03c4638f33830fb94ce2d678d92aade039fb112 [file] [log] [blame]
/* Copyright 2017 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <err.h>
#include <getopt.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <openssl/sha.h>
#include "config.h"
static void print_hex(FILE *out, uint8_t *digest, int len, int last)
{
int i;
fputs("{ ", out);
for (i = 0; i < len; i++)
fprintf(out, "0x%02x, ", digest[i]);
fprintf(out, "}%c\n", last ? ';' : ',');
}
/* Output blank hashes */
static int hash_fw_blank(FILE *hashes)
{
uint8_t digest[SHA256_DIGEST_LENGTH] = { 0 };
int len;
fprintf(hashes, "const uint8_t touchpad_fw_hashes[%d][%d] = {\n",
CONFIG_TOUCHPAD_VIRTUAL_SIZE / CONFIG_UPDATE_PDU_SIZE,
SHA256_DIGEST_LENGTH);
for (len = 0; len < CONFIG_TOUCHPAD_VIRTUAL_SIZE;
len += CONFIG_UPDATE_PDU_SIZE) {
print_hex(hashes, digest, sizeof(digest), 0);
}
fputs("};\n", hashes);
fprintf(hashes, "const uint8_t touchpad_fw_full_hash[%d] =\n\t",
SHA256_DIGEST_LENGTH);
print_hex(hashes, digest, SHA256_DIGEST_LENGTH, 1);
return 0;
}
static int hash_fw(FILE *tp_fw, FILE *hashes)
{
uint8_t buffer[CONFIG_UPDATE_PDU_SIZE];
int len = 0;
int rb;
SHA256_CTX ctx;
SHA256_CTX ctx_all;
uint8_t digest[SHA256_DIGEST_LENGTH];
SHA256_Init(&ctx_all);
fprintf(hashes, "const uint8_t touchpad_fw_hashes[%d][%d] = {\n",
CONFIG_TOUCHPAD_VIRTUAL_SIZE / CONFIG_UPDATE_PDU_SIZE,
SHA256_DIGEST_LENGTH);
while (1) {
rb = fread(buffer, 1, sizeof(buffer), tp_fw);
len += rb;
if (rb == 0)
break;
/* Calculate hash for the block. */
SHA256_Init(&ctx);
SHA256_Update(&ctx, buffer, rb);
SHA256_Final(digest, &ctx);
SHA256_Update(&ctx_all, buffer, rb);
print_hex(hashes, digest, sizeof(digest), 0);
if (rb < sizeof(buffer))
break;
}
fputs("};\n", hashes);
SHA256_Final(digest, &ctx_all);
fprintf(hashes, "const uint8_t touchpad_fw_full_hash[%d] =\n\t",
SHA256_DIGEST_LENGTH);
print_hex(hashes, digest, SHA256_DIGEST_LENGTH, 1);
if (!feof(tp_fw) || ferror(tp_fw)) {
warn("Error reading input file");
return 1;
}
if (len != CONFIG_TOUCHPAD_VIRTUAL_SIZE) {
warnx("Incorrect TP FW size (%d vs %d)", len,
CONFIG_TOUCHPAD_VIRTUAL_SIZE);
return 1;
}
return 0;
}
int main(int argc, char **argv)
{
int nopt;
int ret;
const char *out = NULL;
char *tp_fw_name = NULL;
FILE *tp_fw = NULL;
FILE *hashes;
const char short_opt[] = "f:ho:";
const struct option long_opts[] = {
{ "firmware", 1, NULL, 'f' },
{ "help", 0, NULL, 'h' },
{ "out", 1, NULL, 'o' },
{ NULL }
};
const char usage[] = "USAGE: %s -f <touchpad FW> -o <output file>\n";
while ((nopt = getopt_long(argc, argv, short_opt,
long_opts, NULL)) != -1) {
switch (nopt) {
case 'f': /* -f or --firmware */
tp_fw_name = optarg;
break;
case 'h': /* -h or --help */
fprintf(stdout, usage, argv[0]);
return 0;
case 'o': /* -o or --out */
out = optarg;
break;
default: /* Invalid parameter. */
fprintf(stderr, usage, argv[0]);
return 1;
}
};
if (out == NULL)
return 1;
hashes = fopen(out, "we");
if (!hashes)
err(1, "Cannot open output file");
fputs("#include <stdint.h>\n\n", hashes);
if (tp_fw_name) {
tp_fw = fopen(tp_fw_name, "re");
if (!tp_fw) {
warn("Cannot open firmware");
ret = 1;
goto out;
}
ret = hash_fw(tp_fw, hashes);
fclose(tp_fw);
} else {
printf("No touchpad FW provided, outputting blank hashes.\n");
ret = hash_fw_blank(hashes);
}
out:
fclose(hashes);
/* In case of failure, remove output file. */
if (ret != 0)
unlink(out);
return ret;
}