/* Copyright 2017 The ChromiumOS Authors * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "config.h" #include #include #include #include #include #include #include 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 -o \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 \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; }