From 0fbd5e17fe585f06b028d1f8e7023b9e24e14e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20PORTAY?= Date: Tue, 31 May 2022 16:32:38 +0200 Subject: [PATCH] genesys: scaler: Remove FuGenesysMtkFooter and XOR encryption --- plugins/genesys/fu-genesys-scaler-device.c | 93 +++----- plugins/genesys/fu-genesys-scaler-firmware.c | 236 ++++--------------- plugins/genesys/fu-genesys-scaler-firmware.h | 127 ---------- plugins/genesys/tests/genesys-scaler.bin | Bin 797 -> 541 bytes 4 files changed, 80 insertions(+), 376 deletions(-) diff --git a/plugins/genesys/fu-genesys-scaler-device.c b/plugins/genesys/fu-genesys-scaler-device.c index 7c3c8f6e4..0de7a0d3a 100644 --- a/plugins/genesys/fu-genesys-scaler-device.c +++ b/plugins/genesys/fu-genesys-scaler-device.c @@ -15,6 +15,8 @@ #include "fu-genesys-scaler-device.h" #include "fu-genesys-scaler-firmware.h" +#define GENESYS_SCALER_BANK_SIZE 0x200000U + #define GENESYS_SCALER_MSTAR_READ 0x7a #define GENESYS_SCALER_MSTAR_WRITE 0x7b #define GENESYS_SCALER_MSTAR_DATA_OUT 0x7c @@ -72,7 +74,6 @@ struct _FuGenesysScalerDevice { guint16 gpio_out_reg; guint16 gpio_en_reg; guint8 gpio_val; - FuGenesysMtkFooter footer; }; G_DEFINE_TYPE(FuGenesysScalerDevice, fu_genesys_scaler_device, FU_TYPE_DEVICE) @@ -1720,70 +1721,27 @@ fu_genesys_scaler_device_prepare_firmware(FuDevice *device, { FuGenesysScalerDevice *self = FU_GENESYS_SCALER_DEVICE(device); g_autoptr(FuFirmware) firmware = fu_genesys_scaler_firmware_new(); - g_autoptr(FuFirmware) footer = fu_firmware_new(); - g_autoptr(FuFirmware) payload = fu_firmware_new(); - g_autoptr(GBytes) fw_payload = NULL; - g_autoptr(GBytes) fw_footer = NULL; + g_autoptr(GBytes) blob_payload = NULL; + g_autoptr(GBytes) blob_public_key = NULL; /* parse firmware */ if (!fu_firmware_parse(firmware, fw, flags, error)) return NULL; - /* payload */ - fw_payload = fu_common_bytes_new_offset(fw, - 0, - g_bytes_get_size(fw) - sizeof(FuGenesysMtkFooter), - error); - if (fw_payload == NULL) + /* check public-key */ + blob_public_key = + fu_firmware_get_image_by_id_bytes(firmware, FU_FIRMWARE_ID_SIGNATURE, error); + if (blob_public_key == NULL) return NULL; - if (!fu_firmware_parse(payload, fw_payload, flags, error)) - return NULL; - fu_firmware_set_id(payload, FU_FIRMWARE_ID_PAYLOAD); - fu_firmware_add_image(firmware, payload); - - /* check size */ - if (g_bytes_get_size(fw_payload) > fu_device_get_firmware_size_max(device)) { - g_set_error(error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware too large, got 0x%x, expected <= 0x%x", - (guint)g_bytes_get_size(fw_payload), - (guint)fu_device_get_firmware_size_max(device)); - return NULL; - } - - /* footer */ - fw_footer = fu_common_bytes_new_offset(fw, - g_bytes_get_size(fw) - sizeof(FuGenesysMtkFooter), - sizeof(FuGenesysMtkFooter), - error); - if (!fu_firmware_parse(footer, fw_footer, flags, error)) - return NULL; - if (!fu_memcpy_safe((guint8 *)&self->footer, - sizeof(self->footer), - 0, /* dst */ - g_bytes_get_data(fw_footer, NULL), - g_bytes_get_size(fw_footer), - 0, /* src */ - sizeof(self->footer), - error)) - return NULL; - fu_genesys_scaler_firmware_decrypt((guint8 *)&self->footer, sizeof(self->footer)); if (g_getenv("FWUPD_GENESYS_SCALER_VERBOSE") != NULL) { fu_common_dump_raw(G_LOG_DOMAIN, - "Footer", - (const guint8 *)&self->footer, - sizeof(self->footer)); + "PublicKey", + g_bytes_get_data(blob_public_key, NULL), + g_bytes_get_size(blob_public_key)); } - if (memcmp(self->footer.data.header.default_head, - MTK_RSA_HEADER, - sizeof(self->footer.data.header.default_head)) != 0) { - g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "invalid footer"); - return NULL; - } - if (memcmp(&self->footer.data.public_key, + if (memcmp(g_bytes_get_data(blob_public_key, NULL), &self->public_key, - sizeof(self->footer.data.public_key) && sizeof(self->public_key)) != 0 && + sizeof(self->public_key)) != 0 && (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { g_set_error_literal(error, FWUPD_ERROR, @@ -1791,8 +1749,20 @@ fu_genesys_scaler_device_prepare_firmware(FuDevice *device, "mismatch public-key"); return NULL; } - fu_firmware_set_id(footer, FU_FIRMWARE_ID_HEADER); - fu_firmware_add_image(firmware, footer); + + /* check size */ + blob_payload = fu_firmware_get_image_by_id_bytes(firmware, FU_FIRMWARE_ID_PAYLOAD, error); + if (blob_payload == NULL) + return NULL; + if (g_bytes_get_size(blob_payload) > fu_device_get_firmware_size_max(device)) { + g_set_error(error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware too large, got 0x%x, expected <= 0x%x", + (guint)g_bytes_get_size(blob_payload), + (guint)fu_device_get_firmware_size_max(device)); + return NULL; + } /* success */ return g_steal_pointer(&firmware); @@ -1806,7 +1776,7 @@ fu_genesys_scaler_device_write_firmware(FuDevice *device, GError **error) { FuGenesysScalerDevice *self = FU_GENESYS_SCALER_DEVICE(device); - guint addr = fu_firmware_get_addr(firmware); + guint addr = 0; gsize size; const guint8 *data; g_autofree guint8 *buf = NULL; @@ -1818,11 +1788,8 @@ fu_genesys_scaler_device_write_firmware(FuDevice *device, fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 54, NULL); fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_VERIFY, 42, NULL); - /* sanity check */ - if (fu_device_has_flag(device, FWUPD_DEVICE_FLAG_DUAL_IMAGE) && addr == 0) { - g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "invalid address"); - return FALSE; - } + if (fu_device_has_flag(device, FWUPD_DEVICE_FLAG_DUAL_IMAGE)) + addr = GENESYS_SCALER_BANK_SIZE; payload = fu_firmware_get_image_by_id(firmware, FU_FIRMWARE_ID_PAYLOAD, error); if (payload == NULL) diff --git a/plugins/genesys/fu-genesys-scaler-firmware.c b/plugins/genesys/fu-genesys-scaler-firmware.c index cdc0dbd22..b485245c6 100644 --- a/plugins/genesys/fu-genesys-scaler-firmware.c +++ b/plugins/genesys/fu-genesys-scaler-firmware.c @@ -12,26 +12,11 @@ struct _FuGenesysScalerFirmware { FuFirmwareClass parent_instance; - FuGenesysMtkFooter footer; - guint protect_sector_addr[2]; - gsize protect_sector_size[2]; - guint public_key_addr; - gsize public_key_size; - guint second_image_program_addr; + FuGenesysPublicKey public_key; }; G_DEFINE_TYPE(FuGenesysScalerFirmware, fu_genesys_scaler_firmware, FU_TYPE_FIRMWARE) -void -fu_genesys_scaler_firmware_decrypt(guint8 *buf, gsize bufsz) -{ - const gchar *key = "mstar"; - const gsize keylen = strlen(key); - - for (guint i = 0; i < bufsz; i++) - buf[i] ^= key[i % keylen]; -} - static gboolean fu_genesys_scaler_firmware_parse(FuFirmware *firmware, GBytes *fw, @@ -43,87 +28,41 @@ fu_genesys_scaler_firmware_parse(FuFirmware *firmware, FuGenesysScalerFirmware *self = FU_GENESYS_SCALER_FIRMWARE(firmware); gsize bufsz = 0; const guint8 *buf = g_bytes_get_data(fw, &bufsz); + g_autoptr(FuFirmware) firmware_payload = NULL; + g_autoptr(FuFirmware) firmware_public_key = NULL; + g_autoptr(GBytes) blob_payload = NULL; + g_autoptr(GBytes) blob_public_key = NULL; - if (!fu_memcpy_safe((guint8 *)&self->footer, - sizeof(self->footer), + if (!fu_memcpy_safe((guint8 *)&self->public_key, + sizeof(self->public_key), 0, /* dst */ buf, bufsz, - bufsz - sizeof(self->footer), /* src */ - sizeof(self->footer), + bufsz - sizeof(self->public_key), /* src */ + sizeof(self->public_key), error)) return FALSE; - fu_genesys_scaler_firmware_decrypt((guint8 *)&self->footer, sizeof(self->footer)); - if (memcmp(self->footer.data.header.default_head, - MTK_RSA_HEADER, - sizeof(self->footer.data.header.default_head)) != 0) { - g_autofree gchar *str = NULL; - str = fu_common_strsafe((const gchar *)self->footer.data.header.default_head, - sizeof(self->footer.data.header.default_head)); - g_set_error(error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "invalid footer, expected %s, and got %s", - MTK_RSA_HEADER, - str); + fu_common_dump_raw(G_LOG_DOMAIN, + "PublicKey", + (const guint8 *)&self->public_key, + sizeof(self->public_key)); + if (memcmp(self->public_key.N, "N = ", 4) != 0 || + memcmp(self->public_key.E, "E = ", 4) != 0) { + g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "invalid public-key"); return FALSE; } - if (self->footer.data.header.configuration_setting.bits.second_image) { - guint32 addr; - if (!fu_common_read_uint32_safe( - self->footer.data.header.second_image_program_addr, - sizeof(self->footer.data.header.second_image_program_addr), - 0, - &addr, - G_LITTLE_ENDIAN, - error)) - return FALSE; - if (addr % GENESYS_SCALER_BANK_SIZE != 0) { - g_set_error(error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid address, expected a multiple of 0x%x, and got 0x%x", - GENESYS_SCALER_BANK_SIZE, - addr); - return FALSE; - } - self->second_image_program_addr = addr; - fu_firmware_set_addr(firmware, addr); - } - if (self->footer.data.header.configuration_setting.bits.decrypt_mode) { - if (!fu_common_read_uint32_safe( - self->footer.data.header.scaler_public_key_addr, - sizeof(self->footer.data.header.scaler_public_key_addr), - 0, - &self->public_key_addr, - G_LITTLE_ENDIAN, - error)) - return FALSE; - self->public_key_size = 0x1000; - } + /* set payload */ + blob_payload = g_bytes_new(buf, bufsz - sizeof(self->public_key)); + firmware_payload = fu_firmware_new_from_bytes(blob_payload); + fu_firmware_set_id(firmware_payload, FU_FIRMWARE_ID_PAYLOAD); + fu_firmware_add_image(firmware, firmware_payload); - if (self->footer.data.header.configuration_setting.bits.special_protect_sector) { - if (self->footer.data.header.protect_sector[0].area.size) { - self->protect_sector_addr[0] = - (self->footer.data.header.protect_sector[0].area.addr_high << 16) | - (self->footer.data.header.protect_sector[0].area.addr_low[1] << 8) | - (self->footer.data.header.protect_sector[0].area.addr_low[0]); - self->protect_sector_addr[0] *= 0x1000; - self->protect_sector_size[0] = - self->footer.data.header.protect_sector[0].area.size * 0x1000; - } - - if (self->footer.data.header.protect_sector[1].area.size) { - self->protect_sector_addr[1] = - (self->footer.data.header.protect_sector[1].area.addr_high << 16) | - (self->footer.data.header.protect_sector[1].area.addr_low[1] << 8) | - (self->footer.data.header.protect_sector[1].area.addr_low[0]); - self->protect_sector_addr[1] *= 0x1000; - self->protect_sector_size[1] = - self->footer.data.header.protect_sector[1].area.size * 0x1000; - } - } + /* set public-key */ + blob_public_key = g_bytes_new(&self->public_key, sizeof(self->public_key)); + firmware_public_key = fu_firmware_new_from_bytes(blob_public_key); + fu_firmware_set_id(firmware_public_key, FU_FIRMWARE_ID_SIGNATURE); + fu_firmware_add_image(firmware, firmware_public_key); /* success */ return TRUE; @@ -135,82 +74,14 @@ fu_genesys_scaler_firmware_export(FuFirmware *firmware, XbBuilderNode *bn) { FuGenesysScalerFirmware *self = FU_GENESYS_SCALER_FIRMWARE(firmware); + gchar N[0x200 + 1] = {'\0'}; + gchar E[0x006 + 1] = {'\0'}; - if (self->footer.data.header.model_name[0] != '\0') { - fu_xmlb_builder_insert_kv(bn, - "model_name", - (const gchar *)self->footer.data.header.model_name); - } - if (self->footer.data.header.scaler_group[0] != '\0') { - fu_xmlb_builder_insert_kv(bn, - "scaler_group", - (const gchar *)self->footer.data.header.scaler_group); - } - if (self->footer.data.header.panel_type[0] != '\0') { - fu_xmlb_builder_insert_kv(bn, - "panel_type", - (const gchar *)self->footer.data.header.panel_type); - } - if (self->footer.data.header.scaler_packet_date[0] != '\0') { - fu_xmlb_builder_insert_kv( - bn, - "scaler_packet_date", - (const gchar *)self->footer.data.header.scaler_packet_date); - } - if (self->footer.data.header.scaler_packet_version[0] != '\0') { - fu_xmlb_builder_insert_kv( - bn, - "scaler_packet_version", - (const gchar *)self->footer.data.header.scaler_packet_version); - } - fu_xmlb_builder_insert_kx(bn, - "configuration_setting", - self->footer.data.header.configuration_setting.r8); + memcpy(N, self->public_key.N + 4, sizeof(N) - 1); + fu_xmlb_builder_insert_kv(bn, "N", N); - if (self->footer.data.header.configuration_setting.bits.second_image) - fu_xmlb_builder_insert_kx(bn, - "second_image_program_addr", - self->second_image_program_addr); - - if (self->footer.data.header.configuration_setting.bits.decrypt_mode) { - gchar N[0x200 + 1] = {'\0'}; - gchar E[0x006 + 1] = {'\0'}; - - fu_xmlb_builder_insert_kx(bn, "public_key_addr", self->public_key_addr); - fu_xmlb_builder_insert_kx(bn, "public_key_size", self->public_key_size); - - memcpy(N, self->footer.data.public_key.N + 4, sizeof(N) - 1); - fu_xmlb_builder_insert_kv(bn, "N", N); - - memcpy(E, self->footer.data.public_key.E + 4, sizeof(E) - 1); - fu_xmlb_builder_insert_kv(bn, "E", E); - } - - if (self->footer.data.header.configuration_setting.bits.special_protect_sector) { - if (self->protect_sector_size[0]) { - fu_xmlb_builder_insert_kx(bn, - "protect_sector_addr0", - self->protect_sector_addr[0]); - fu_xmlb_builder_insert_kx(bn, - "protect_sector_size0", - self->protect_sector_size[0]); - } - - if (self->protect_sector_size[1]) { - fu_xmlb_builder_insert_kx(bn, - "protect_sector_addr1", - self->protect_sector_addr[1]); - fu_xmlb_builder_insert_kx(bn, - "protect_sector_size1", - self->protect_sector_size[1]); - } - } - - if (self->footer.data.header.configuration_setting.bits.boot_code_size_in_header) { - fu_xmlb_builder_insert_kx(bn, - "boot_code_size", - self->footer.data.header.boot_code_size); - } + memcpy(E, self->public_key.E + 4, sizeof(E) - 1); + fu_xmlb_builder_insert_kv(bn, "E", E); } static gboolean @@ -220,10 +91,23 @@ fu_genesys_scaler_firmware_build(FuFirmware *firmware, XbNode *n, GError **error const gchar *tmp; /* optional properties */ - tmp = xb_node_query_text(n, "model_name", NULL); + tmp = xb_node_query_text(n, "N", NULL); if (tmp != NULL) { - if (!fu_memcpy_safe((guint8 *)&self->footer.data.header.model_name, - sizeof(self->footer.data.header.model_name), + if (!fu_memcpy_safe((guint8 *)&self->public_key.N, + sizeof(self->public_key.N), + 0x0, /* dst */ + (const guint8 *)tmp, + strlen(tmp), + 0x0, /* src */ + strlen(tmp), + error)) + return FALSE; + } + + tmp = xb_node_query_text(n, "E", NULL); + if (tmp != NULL) { + if (!fu_memcpy_safe((guint8 *)&self->public_key.E, + sizeof(self->public_key.E), 0x0, /* dst */ (const guint8 *)tmp, strlen(tmp), @@ -241,7 +125,6 @@ static GBytes * fu_genesys_scaler_firmware_write(FuFirmware *firmware, GError **error) { FuGenesysScalerFirmware *self = FU_GENESYS_SCALER_FIRMWARE(firmware); - FuGenesysMtkFooter footer = {0x0}; g_autoptr(GByteArray) buf = g_byte_array_new(); g_autoptr(GBytes) blob = NULL; @@ -251,27 +134,8 @@ fu_genesys_scaler_firmware_write(FuFirmware *firmware, GError **error) return NULL; fu_byte_array_append_bytes(buf, blob); - /* "encrypted" footer */ - if (!fu_memcpy_safe((guint8 *)&footer, - sizeof(footer), - 0, /* dst */ - (guint8 *)&self->footer, - sizeof(self->footer), - 0, /* src */ - sizeof(footer), - error)) - return NULL; - if (!fu_memcpy_safe((guint8 *)&footer.data.header.default_head, - sizeof(footer.data.header.default_head), - 0, /* dst */ - (guint8 *)&MTK_RSA_HEADER, - strlen(MTK_RSA_HEADER), - 0, /* src */ - strlen(MTK_RSA_HEADER), - error)) - return NULL; - fu_genesys_scaler_firmware_decrypt((guint8 *)&footer, sizeof(footer)); - g_byte_array_append(buf, (const guint8 *)&footer, sizeof(footer)); + /* public-key */ + g_byte_array_append(buf, (const guint8 *)&self->public_key, sizeof(self->public_key)); /* success */ return g_byte_array_free_to_bytes(g_steal_pointer(&buf)); diff --git a/plugins/genesys/fu-genesys-scaler-firmware.h b/plugins/genesys/fu-genesys-scaler-firmware.h index 05de39bc7..bab466f4b 100644 --- a/plugins/genesys/fu-genesys-scaler-firmware.h +++ b/plugins/genesys/fu-genesys-scaler-firmware.h @@ -19,132 +19,5 @@ G_DECLARE_FINAL_TYPE(FuGenesysScalerFirmware, #define GENESYS_SCALER_BANK_SIZE 0x200000U -#define MTK_RSA_HEADER "MTK_RSA_HEADER" - -typedef struct __attribute__((packed)) { - guint8 default_head[14]; - guint8 reserved_0e_0f[2]; - guint8 model_name[16]; - guint8 reserved_20; - guint8 size[2]; - guint8 reserved_23_27[5]; - guint8 scaler_group[10]; - guint8 reserved_32_53[34]; - guint8 panel_type[10]; - guint8 scaler_packet_date[8]; - guint8 reserved_66_67[2]; - guint8 scaler_packet_version[4]; - guint8 reserved_6c_7f[20]; - union { - guint8 r8; - struct { - /* - * Decrypt Mode: - * - * 0: Scaler decrypt - * 1: ISP Tool decrypt - */ - guint8 decrypt_mode : 1; - - /* - * Second Image: - * - * 0: 1st image or dual image; programming address at 0x000000 - * 1: 2nd image; programming address set by .second_image_program_addr - */ - guint8 second_image : 1; - - /* - * Dual image turn: - * - * 0: fix second programing address set by .second_image_program_addr - * 1: support “Dual image turn” rule - * - TSUM: Not supported - * - MST9U: ISP Tool need update to DUT least version image address - * - HAWK: Not supported - */ - guint8 dual_image_turn : 1; - - /* - * Special Protect Sector: - * - * 0: No Special Protect sector - * 1: Support Special Protect sector - */ - guint8 special_protect_sector : 1; - - /* - * HAWK bypass mode - * - * 0: No support HAWK bypass mode - * 1: Support HAWK bypass mode - */ - guint8 hawk_bypass_mode : 1; - - /* - * Boot Code Size in header - * - * 0: Follow original search bin address rule - * 1: Get Boot code size from header set by .boot_code_size - */ - guint8 boot_code_size_in_header : 1; - - /* Reserved */ - guint8 reserved_6_7 : 2; - } __attribute__((packed)) bits; - } configuration_setting; - - guint8 reserved_81_85[5]; - - /* If configuration_setting.bits.second_image set */ - guint8 second_image_program_addr[4]; - - /* - * If configuration_setting.bits.decrypt is set - * - * TSUM/HAWK: ISP Tool need protect flash public address can’t erase and write - * MST9U: Not supported - */ - guint8 scaler_public_key_addr[4]; - - /* - * If configuration_setting.bits.special_protect_sector is set - * - * ISP Tool can't erase "Special Protect Sector" area. - * - * [19:00]: Protect continuous sector start. - * [23:20]: Protect sector continuous number. - * - * Examples: If need to protect FA000 ~FFFFF, Special Protect sector = 0x6000FA; - * If need to protect FA000 only, Special Protect sector = 0x1000FA; - * If no need to protect, Special Protect sector = 0x000000; - */ - union { - guint8 r24[3]; - struct { - guint8 addr_low[2]; - guint8 addr_high : 4; - guint8 size : 4; - } __attribute__((packed)) area; - } protect_sector[2]; - - /* - * If configuration.bits .second_image and .dual_image_turn are set - * and .boot_code_size. - */ - guint32 boot_code_size; -} FuGenesysMtkRsaHeader; - -typedef union __attribute__((packed)) { - guint8 raw[0x312]; - struct { - FuGenesysPublicKey public_key; - FuGenesysMtkRsaHeader header; - } data; -} FuGenesysMtkFooter; - -void -fu_genesys_scaler_firmware_decrypt(guint8 *buf, gsize bufsz); - FuFirmware * fu_genesys_scaler_firmware_new(void); diff --git a/plugins/genesys/tests/genesys-scaler.bin b/plugins/genesys/tests/genesys-scaler.bin index 4ce1ccd05a654d83d409c93c4c795ae033105028..baa3648c4a5d3eec4c2c9710aa957935aa2f95eb 100644 GIT binary patch literal 541 Zcmc~u&B@7ED9