/* ifx_fw_extract.c * * Copyright (C) 2006-2024 wolfSSL Inc. * * This file is part of wolfTPM. * * wolfTPM is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * wolfTPM is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ /* Tool source based on simple-update example from * Infineon Technologies AG (www.infineon.com). * This is a stand-alone host side tool for extracting the firmware * manifest and data files from a supplied .bin */ #define _DEFAULT_SOURCE #include #include #include #include #include #include #include #include #include /* Endianess helpers */ #if defined(__MACH__) || defined(__APPLE__) #include #include #define htobe16(x) OSSwapHostToBigInt16(x) #define htole16(x) OSSwapHostToLittleInt16(x) #define be16toh(x) OSSwapBigToHostInt16(x) #define le16toh(x) OSSwapLittleToHostInt16(x) #define htobe32(x) OSSwapHostToBigInt32(x) #define htole32(x) OSSwapHostToLittleInt32(x) #define be32toh(x) OSSwapBigToHostInt32(x) #define le32toh(x) OSSwapLittleToHostInt32(x) #define htobe64(x) OSSwapHostToBigInt64(x) #define htole64(x) OSSwapHostToLittleInt64(x) #define be64toh(x) OSSwapBigToHostInt64(x) #define le64toh(x) OSSwapLittleToHostInt64(x) #else #include #endif /* Helper to print file and line */ #define LOG(t) { printf(__FILE__":%i: %s\n", __LINE__, t); } #define READ_BE16(dest, buf, size, off) { \ if (off + sizeof(dest) >= size) { \ LOG("FW file too short"); \ return -1; \ } \ memcpy(&dest, &fw[off], sizeof(dest)); \ dest = be16toh(dest); \ off += sizeof(dest); \ } #define READ_BE32(dest, buf, size, off) { \ if (off + sizeof(dest) >= size) { \ LOG("FW file too short"); \ return -1; \ } \ memcpy(&dest, &fw[off], sizeof(dest)); \ dest = be32toh(dest); \ off += sizeof(dest); \ } /* macros for stdio */ #define XFILE FILE* #define XFOPEN fopen #define XFSEEK fseek #define XFTELL ftell #define XREWIND rewind #define XFREAD fread #define XFWRITE fwrite #define XFCLOSE fclose #define XSEEK_END SEEK_END #define XBADFILE NULL #define XFGETS fgets #define XFEOF feof /* internal error codes */ #define MEMORY_E -125 /* out of memory error */ #define BUFFER_E -132 /* output buffer too small or input too large */ #define BAD_FUNC_ARG -173 /* Bad function argument provided */ static int extractFW( uint8_t *fw, size_t fw_size, uint32_t keygroup_id, uint8_t **manifest, size_t *manifest_size, uint8_t **data, size_t *data_size) { size_t offset = 0, offset2; uint16_t size16, num; uint32_t size32, group; const uint8_t guid[] = { 0x1a, 0x53, 0x66, 0x7a, 0xfb, 0x12, 0x47, 0x9e, 0xac, 0x58, 0xec, 0x99, 0x58, 0x86, 0x10, 0x94 }; if (offset + sizeof(guid) > fw_size) { LOG("FW file too short"); return -1; } if (memcmp(&fw[offset], &guid[0], sizeof(guid)) != 0) { LOG("Wrong GUID"); return -1; } offset += sizeof(guid) + 1; READ_BE16(size16, fw, fw_size, offset); offset += size16 + 1; READ_BE16(size16, fw, fw_size, offset); offset += size16; READ_BE16(size16, fw, fw_size, offset); offset2 = offset; offset += size16; READ_BE16(size16, fw, offset, offset2); offset2 += size16; READ_BE16(num, fw, offset, offset2); *manifest = NULL; for (int i = 0; i < num; i++) { READ_BE32(group, fw, offset, offset2); printf("Found group %08x\n", group); READ_BE16(size16, fw, offset, offset2); if (group == keygroup_id) { printf("Chosen group found: %08x\n", group); *manifest = &fw[offset2]; *manifest_size = size16; } offset2 += size16; } if (*manifest == NULL) { if (keygroup_id == 0) { /* just list key groups */ return 0; } LOG("Chosen group not found"); return -1; } printf("Manifest size is %zi\n", *manifest_size); if (offset2 != offset) { LOG("Bad Manifest size"); return -1; } READ_BE32(size32, fw, fw_size, offset); if (offset + size32 >= fw_size) { LOG("FW file too short"); return -1; } *data = &fw[offset]; *data_size = size32; offset += size32; printf("Data size is %zi\n", *data_size); READ_BE16(size16, fw, fw_size, offset); offset += size16 + 4; if (offset != fw_size) { LOG("Wrong FW file size"); printf("offset at %zi, fw_size at %zi\n", offset, fw_size); return -1; } return 0; } static int readfile(const char* fname, uint8_t** buf, size_t* bufLen) { int ret = 0; ssize_t fileSz, readLen; XFILE fp; if (fname == NULL || buf == NULL || bufLen == NULL) return BAD_FUNC_ARG; /* open file (read-only binary) */ fp = XFOPEN(fname, "rb"); if (fp == XBADFILE) { fprintf(stderr, "Error loading %s\n", fname); return BUFFER_E; } XFSEEK(fp, 0, XSEEK_END); fileSz = XFTELL(fp); XREWIND(fp); if (fileSz > 0) { if (*buf == NULL) { *buf = (uint8_t*)malloc(fileSz); if (*buf == NULL) ret = MEMORY_E; } else if (*buf != NULL && fileSz > (ssize_t)*bufLen) { ret = BUFFER_E; } *bufLen = (size_t)fileSz; if (ret == 0) { readLen = XFREAD(*buf, 1, *bufLen, fp); ret = (readLen == (ssize_t)*bufLen) ? 0 : -1; } } else { ret = BUFFER_E; } XFCLOSE(fp); return ret; } static int writefile(const char* filename, const uint8_t *buf, size_t bufSz) { int rc = -1; XFILE fp; size_t fileSz = 0; if (filename == NULL || buf == NULL) return BAD_FUNC_ARG; fp = XFOPEN(filename, "wb"); if (fp != XBADFILE) { fileSz = XFWRITE(buf, 1, bufSz, fp); /* sanity check */ if (fileSz == bufSz) { rc = 0; } printf("Wrote %d bytes to %s\n", (int)fileSz, filename); XFCLOSE(fp); } return rc; } int main(int argc, char **argv) { int rc; uint8_t *manifest = NULL, *data = NULL, *fw = NULL; size_t manifest_size, data_size, fw_size; uint32_t keygroup_id = 0; if (argc <= 1 || strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[argc-1], "-h") == 0 || strcmp(argv[argc-1], "--help") == 0) { printf("Usage:\n"); printf(" ifx_fw_extract \n"); printf(" ifx_fw_extract \n"); exit(1); } if (argc >= 2) { if (readfile(argv[1], &fw, &fw_size) < 0) { LOG("Cannot read FW file."); rc = EXIT_FAILURE; goto exit; } if (argc >= 3) { if (sscanf(argv[2], "0x%08x", &keygroup_id) != 1 && sscanf(argv[2], "%08x", &keygroup_id) != 1) { LOG("Cannot read keygroup_id."); rc = EXIT_FAILURE; goto exit; } } rc = extractFW(fw, fw_size, keygroup_id, &manifest, &manifest_size, &data, &data_size); if (rc != 0) { printf(__FILE__":%i: Received error 0x%08x\n", __LINE__, rc); goto exit; } if (argc >= 5) { if (writefile(argv[3], manifest, manifest_size) < 0) { rc = EXIT_FAILURE; goto exit; } if (writefile(argv[4], data, data_size) < 0) { rc = EXIT_FAILURE; goto exit; } } rc = 0; } else { printf("Bad arguments.\n"); rc = EXIT_FAILURE; goto exit; } exit: if (fw != NULL) free(fw); return rc; }