diff --git a/meson.build b/meson.build index 392c56e01..00c2f1e13 100644 --- a/meson.build +++ b/meson.build @@ -262,6 +262,9 @@ else if get_option('plugin_uefi_pk') error('plugin_uefi_pk needs -Dgnutls=true to work') endif + if get_option('plugin_synaptics_rmi') + error('plugin_synaptics_rmi needs -Dgnutls=true to work') + endif endif platform_deps = [] diff --git a/meson_options.txt b/meson_options.txt index 39c232778..d38840056 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -17,6 +17,7 @@ option('plugin_dell', type : 'boolean', value : true, description : 'enable Dell option('plugin_dummy', type : 'boolean', value : false, description : 'enable the dummy device') option('plugin_emmc', type : 'boolean', value : true, description : 'enable eMMC support') option('plugin_synaptics_mst', type: 'boolean', value: true, description : 'enable Synaptics MST hub support') +option('plugin_synaptics_rmi', type: 'boolean', value: true, description : 'enable Synaptics RMI support') option('plugin_thunderbolt', type : 'boolean', value : true, description : 'enable Thunderbolt support') option('plugin_redfish', type : 'boolean', value : true, description : 'enable Redfish support') option('plugin_uefi_capsule', type : 'boolean', value : true, description : 'enable UEFI capsule support') diff --git a/plugins/meson.build b/plugins/meson.build index 55ce7ebf9..8f9dae448 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -25,11 +25,14 @@ subdir('ata') subdir('elantp') subdir('optionrom') subdir('superio') -subdir('synaptics-rmi') subdir('thelio-io') subdir('wacom-raw') endif +if get_option('gudev') and get_option('plugin_synaptics_rmi') +subdir('synaptics-rmi') +endif + if get_option('gudev') and get_option('gusb') subdir('logitech-hidpp') endif diff --git a/plugins/synaptics-rmi/fu-synaptics-rmi-common.c b/plugins/synaptics-rmi/fu-synaptics-rmi-common.c index 3282233d6..7455ff425 100644 --- a/plugins/synaptics-rmi/fu-synaptics-rmi-common.c +++ b/plugins/synaptics-rmi/fu-synaptics-rmi-common.c @@ -14,6 +14,9 @@ #include +#include +#include + #include "fu-common.h" #include "fu-io-channel.h" #include "fu-synaptics-rmi-common.h" @@ -30,6 +33,14 @@ #define RMI_FUNCTION_VERSION_MASK 0x60 #define RMI_FUNCTION_INTERRUPT_SOURCES_MASK 0x7 + +typedef guchar gnutls_data_t; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(gnutls_data_t, gnutls_free) +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_pubkey_t, gnutls_pubkey_deinit, NULL) +#pragma clang diagnostic pop + guint32 fu_synaptics_rmi_generate_checksum (const guint8 *data, gsize len) { @@ -100,3 +111,67 @@ fu_synaptics_rmi_device_writeln (const gchar *fn, const gchar *buf, GError **err return fu_io_channel_write_raw (io, (const guint8 *) buf, strlen (buf), 1000, FU_IO_CHANNEL_FLAG_NONE, error); } + +gboolean +fu_synaptics_verify_sha256_signature (GBytes *payload, + GBytes *pubkey, + GBytes *signature, + GError **error) +{ + gnutls_datum_t hash; + gnutls_datum_t m; + gnutls_datum_t e; + gnutls_datum_t sig; + gnutls_hash_hd_t sha2; + g_auto(gnutls_pubkey_t) pub = NULL; + gint ec; + guint8 exponent[] = { 1, 0, 1 }; + guint hash_length = gnutls_hash_get_len (GNUTLS_DIG_SHA256); + g_autoptr(gnutls_data_t) hash_data = NULL; + + /* hash firmware data */ + hash_data = gnutls_malloc (hash_length); + gnutls_hash_init (&sha2, GNUTLS_DIG_SHA256); + gnutls_hash (sha2, g_bytes_get_data (payload, NULL), g_bytes_get_size (payload)); + gnutls_hash_deinit (sha2, hash_data); + + /* hash */ + hash.size = hash_length; + hash.data = hash_data; + + /* modulus */ + m.size = g_bytes_get_size (pubkey); + m.data = (guint8 *) g_bytes_get_data (pubkey, NULL); + + /* exponent */ + e.size = sizeof(exponent); + e.data = exponent; + + /* signature */ + sig.size = g_bytes_get_size (signature); + sig.data = (guint8 *) g_bytes_get_data (signature, NULL); + + gnutls_pubkey_init (&pub); + ec = gnutls_pubkey_import_rsa_raw (pub, &m, &e); + if (ec < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to import RSA key: %s", + gnutls_strerror (ec)); + return FALSE; + } + ec = gnutls_pubkey_verify_hash2 (pub, GNUTLS_SIGN_RSA_SHA256, + 0, &hash, &sig); + if (ec < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to verify firmware: %s", + gnutls_strerror (ec)); + return FALSE; + } + + /* success */ + return TRUE; +} diff --git a/plugins/synaptics-rmi/fu-synaptics-rmi-common.h b/plugins/synaptics-rmi/fu-synaptics-rmi-common.h index a89f7725c..d2fe93a93 100644 --- a/plugins/synaptics-rmi/fu-synaptics-rmi-common.h +++ b/plugins/synaptics-rmi/fu-synaptics-rmi-common.h @@ -34,3 +34,7 @@ FuSynapticsRmiFunction *fu_synaptics_rmi_function_parse (GByteArray *buf, gboolean fu_synaptics_rmi_device_writeln (const gchar *fn, const gchar *buf, GError **error); +gboolean fu_synaptics_verify_sha256_signature (GBytes *payload, + GBytes *pubkey, + GBytes *signature, + GError **error); diff --git a/plugins/synaptics-rmi/fu-synaptics-rmi-device.c b/plugins/synaptics-rmi/fu-synaptics-rmi-device.c index ba95089c1..16892de49 100644 --- a/plugins/synaptics-rmi/fu-synaptics-rmi-device.c +++ b/plugins/synaptics-rmi/fu-synaptics-rmi-device.c @@ -91,6 +91,7 @@ typedef struct FuSynapticsRmiFunction *f01; FuSynapticsRmiFunction *f34; guint8 current_page; + guint16 sig_size; /* 0x0 for non-secure update */ } FuSynapticsRmiDevicePrivate; G_DEFINE_TYPE_WITH_PRIVATE (FuSynapticsRmiDevice, fu_synaptics_rmi_device, FU_TYPE_UDEV_DEVICE) @@ -127,6 +128,7 @@ fu_synaptics_rmi_device_to_string (FuUdevDevice *device, guint idt, GString *str FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device); FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); fu_common_string_append_kx (str, idt, "CurrentPage", priv->current_page); + fu_common_string_append_kx (str, idt, "SigSize", priv->sig_size); if (priv->f34 != NULL) { fu_common_string_append_kx (str, idt, "BlVer", priv->f34->function_version + 0x5); @@ -265,6 +267,19 @@ fu_synaptics_rmi_device_read (FuSynapticsRmiDevice *self, guint16 addr, gsize re return g_steal_pointer (&buf); } +GByteArray * +fu_synaptics_rmi_device_read_packet_register (FuSynapticsRmiDevice *self, + guint16 addr, + gsize req_sz, + GError **error) +{ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "packet register reads not supported"); + return NULL; +} + gboolean fu_synaptics_rmi_device_write (FuSynapticsRmiDevice *self, guint16 addr, GByteArray *req, GError **error) { @@ -401,6 +416,21 @@ fu_synaptics_rmi_device_scan_pdt (FuSynapticsRmiDevice *self, GError **error) return TRUE; } +void +fu_synaptics_rmi_device_set_sig_size (FuSynapticsRmiDevice *self, + guint16 sig_size) +{ + FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); + priv->sig_size = sig_size; +} + +guint16 +fu_synaptics_rmi_device_get_sig_size (FuSynapticsRmiDevice *self) +{ + FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self); + return priv->sig_size; +} + typedef enum { HID_RMI4_MODE_MOUSE = 0, HID_RMI4_MODE_ATTN_REPORTS = 1, @@ -670,7 +700,8 @@ fu_synaptics_rmi_device_prepare_firmware (FuDevice *device, bytes_bin = fu_firmware_get_image_by_id_bytes (firmware, "ui", error); if (bytes_bin == NULL) return NULL; - size_expected = (gsize) priv->flash.block_count_fw * (gsize) priv->flash.block_size; + size_expected = ((gsize) priv->flash.block_count_fw * (gsize) priv->flash.block_size) + + fu_synaptics_rmi_firmware_get_sig_size (FU_SYNAPTICS_RMI_FIRMWARE (firmware)); if (g_bytes_get_size (bytes_bin) != size_expected) { g_set_error (error, FWUPD_ERROR, diff --git a/plugins/synaptics-rmi/fu-synaptics-rmi-device.h b/plugins/synaptics-rmi/fu-synaptics-rmi-device.h index 058ca942a..22968515a 100644 --- a/plugins/synaptics-rmi/fu-synaptics-rmi-device.h +++ b/plugins/synaptics-rmi/fu-synaptics-rmi-device.h @@ -54,6 +54,10 @@ GByteArray *fu_synaptics_rmi_device_read (FuSynapticsRmiDevice *self, guint16 addr, gsize req_sz, GError **error); +GByteArray *fu_synaptics_rmi_device_read_packet_register (FuSynapticsRmiDevice *self, + guint16 addr, + gsize req_sz, + GError **error); gboolean fu_synaptics_rmi_device_write (FuSynapticsRmiDevice *self, guint16 addr, GByteArray *req, @@ -74,3 +78,6 @@ gboolean fu_synaptics_rmi_device_rebind_driver (FuSynapticsRmiDevice *self, GError **error); gboolean fu_synaptics_rmi_device_poll_wait (FuSynapticsRmiDevice *self, GError **error); +void fu_synaptics_rmi_device_set_sig_size (FuSynapticsRmiDevice *self, + guint16 sig_size); +guint16 fu_synaptics_rmi_device_get_sig_size (FuSynapticsRmiDevice *self); diff --git a/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c b/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c index 1dc62b69f..8f02d206d 100644 --- a/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c +++ b/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c @@ -31,6 +31,7 @@ struct _FuSynapticsRmiFirmware { guint32 package_id; guint16 product_info; gchar *product_id; + guint32 sig_size; }; G_DEFINE_TYPE (FuSynapticsRmiFirmware, fu_synaptics_rmi_firmware, FU_TYPE_FIRMWARE) @@ -42,6 +43,7 @@ G_DEFINE_TYPE (FuSynapticsRmiFirmware, fu_synaptics_rmi_firmware, FU_TYPE_FIRMWA #define RMI_IMG_CONFIG_SIZE_OFFSET 0x0c #define RMI_IMG_PACKAGE_ID_OFFSET 0x1a #define RMI_IMG_FW_BUILD_ID_OFFSET 0x50 +#define RMI_IMG_SIGNATURE_SIZE_OFFSET 0x54 #define RMI_IMG_PRODUCT_ID_OFFSET 0x10 #define RMI_IMG_PRODUCT_INFO_OFFSET 0x1e #define RMI_IMG_FW_OFFSET 0x100 @@ -174,6 +176,7 @@ fu_synaptics_rmi_firmware_to_string (FuFirmware *firmware, guint idt, GString *s fu_common_string_append_kx (str, idt, "BuildId", self->build_id); fu_common_string_append_kx (str, idt, "PackageId", self->package_id); fu_common_string_append_kx (str, idt, "ProductInfo", self->product_info); + fu_common_string_append_kx (str, idt, "SigSize", self->sig_size); } static gboolean @@ -318,6 +321,7 @@ fu_synaptics_rmi_firmware_parse_v10 (FuFirmware *firmware, GBytes *fw, GError ** static gboolean fu_synaptics_rmi_firmware_parse_v0x (FuFirmware *firmware, GBytes *fw, GError **error) { + FuSynapticsRmiFirmware *self = FU_SYNAPTICS_RMI_FIRMWARE (firmware); guint32 cfg_sz; guint32 img_sz = 0; gsize sz = 0; @@ -331,6 +335,15 @@ fu_synaptics_rmi_firmware_parse_v0x (FuFirmware *firmware, GBytes *fw, GError ** error)) return FALSE; if (img_sz > 0) { + /* payload, then signature appended */ + if (self->sig_size > 0) { + img_sz -= self->sig_size; + if (!fu_synaptics_rmi_firmware_add_image (firmware, "sig", fw, + RMI_IMG_FW_OFFSET + img_sz, + self->sig_size, + error)) + return FALSE; + } if (!fu_synaptics_rmi_firmware_add_image (firmware, "ui", fw, RMI_IMG_FW_OFFSET, img_sz, error)) @@ -363,6 +376,7 @@ fu_synaptics_rmi_firmware_parse (FuFirmware *firmware, FuSynapticsRmiFirmware *self = FU_SYNAPTICS_RMI_FIRMWARE (firmware); gsize sz = 0; guint32 checksum_calculated; + guint32 firmware_size = 0; const guint8 *data = g_bytes_get_data (fw, &sz); /* check minimum size */ @@ -425,6 +439,12 @@ fu_synaptics_rmi_firmware_parse (FuFirmware *firmware, G_LITTLE_ENDIAN, error)) return FALSE; + if (!fu_common_read_uint32_safe (data, sz, + RMI_IMG_IMAGE_SIZE_OFFSET, + &firmware_size, + G_LITTLE_ENDIAN, + error)) + return FALSE; /* parse partitions, but ignore lockdown */ switch (self->bootloader_version) { @@ -433,6 +453,14 @@ fu_synaptics_rmi_firmware_parse (FuFirmware *firmware, case 4: case 5: case 6: + if ((self->io & 0x10) >> 1) { + if (!fu_common_read_uint32_safe (data, sz, + RMI_IMG_SIGNATURE_SIZE_OFFSET, + &self->sig_size, + G_LITTLE_ENDIAN, + error)) + return FALSE; + } if (!fu_synaptics_rmi_firmware_parse_v0x (firmware, fw, error)) return FALSE; self->kind = RMI_FIRMWARE_KIND_0X; @@ -455,6 +483,12 @@ fu_synaptics_rmi_firmware_parse (FuFirmware *firmware, return TRUE; } +guint32 +fu_synaptics_rmi_firmware_get_sig_size (FuSynapticsRmiFirmware *self) +{ + return self->sig_size; +} + static GBytes * fu_synaptics_rmi_firmware_write_v0x (FuFirmware *firmware, GError **error) { diff --git a/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.h b/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.h index ff9686d89..bb2e10660 100644 --- a/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.h +++ b/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.h @@ -12,3 +12,4 @@ G_DECLARE_FINAL_TYPE (FuSynapticsRmiFirmware, fu_synaptics_rmi_firmware, FU, SYNAPTICS_RMI_FIRMWARE, FuFirmware) FuFirmware *fu_synaptics_rmi_firmware_new (void); +guint32 fu_synaptics_rmi_firmware_get_sig_size (FuSynapticsRmiFirmware *self); diff --git a/plugins/synaptics-rmi/fu-synaptics-rmi-v5-device.c b/plugins/synaptics-rmi/fu-synaptics-rmi-v5-device.c index dfcd123d7..2918b562e 100644 --- a/plugins/synaptics-rmi/fu-synaptics-rmi-v5-device.c +++ b/plugins/synaptics-rmi/fu-synaptics-rmi-v5-device.c @@ -10,6 +10,7 @@ #include "fu-chunk.h" #include "fu-common.h" +#include "fu-synaptics-rmi-firmware.h" #include "fu-synaptics-rmi-v5-device.h" #include "fwupd-error.h" @@ -18,6 +19,7 @@ #define RMI_F34_ERASE_ALL 0x03 #define RMI_F34_WRITE_LOCKDOWN_BLOCK 0x04 #define RMI_F34_WRITE_CONFIG_BLOCK 0x06 +#define RMI_F34_WRITE_SIGNATURE 0x0b #define RMI_F34_ENABLE_FLASH_PROG 0x0f #define RMI_F34_BLOCK_SIZE_OFFSET 1 @@ -118,19 +120,110 @@ fu_synaptics_rmi_v5_device_write_block (FuSynapticsRmiDevice *self, return TRUE; } +static gboolean +fu_synaptics_rmi_v5_device_secure_check (FuDevice *device, + GBytes *payload, + GBytes *signature, + GError **error) +{ + FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device); + FuSynapticsRmiFunction *f34; + guint16 rsa_pubkey_len = fu_synaptics_rmi_device_get_sig_size (self) / 8; + guint16 rsa_block_cnt = rsa_pubkey_len / 3; + guint16 rsa_block_remain = rsa_pubkey_len % 3; + g_autoptr(GByteArray) pubkey_buf = g_byte_array_new (); + g_autoptr(GBytes) pubkey = NULL; + + if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) + fu_common_dump_bytes (G_LOG_DOMAIN, "Signature", signature); + + f34 = fu_synaptics_rmi_device_get_function (self, 0x34, error); + if (f34 == NULL) + return FALSE; + + /* parse RSA public key modulus */ + if (rsa_block_remain > 0) + rsa_block_cnt += 1; + for (guint retries = 0; ; retries++) { + /* need read another register to reset the offset of packet register */ + if (!fu_synaptics_rmi_v5_device_query_status (self, error)) { + g_prefix_error (error, "failed to read status: "); + return FALSE; + } + for (guint16 block_num = 0; block_num < rsa_block_cnt; block_num++) { + g_autoptr(GByteArray) res = NULL; + res = fu_synaptics_rmi_device_read_packet_register (self, + f34->query_base + 14, /* addr of flash properties + 5 */ + 0x3, + error); + if (res == NULL) + return FALSE; + if (res->len != 0x3) + g_debug ("read %u bytes in return", res->len); + if (rsa_block_remain && block_num + 1 == rsa_block_cnt) { + g_byte_array_remove_range (res, + rsa_block_remain, + res->len - rsa_block_remain); + } + for (guint i = 0 ; i < res->len / 2 ; i++) { + guint8 tmp = res->data[i]; + res->data[i] = res->data[res->len - i - 1]; + res->data[res->len - i - 1] = tmp; + } + if (rsa_block_remain && block_num + 1 == rsa_block_cnt) { + g_byte_array_prepend (pubkey_buf, res->data, rsa_block_remain); + } else { + g_byte_array_prepend (pubkey_buf, res->data, res->len); + } + } + if (rsa_pubkey_len != pubkey_buf->len) { + if (retries++ > 2) { + g_set_error (error, + G_IO_ERROR, G_IO_ERROR_FAILED, + "RSA public key length not matched %u: after %u retries: ", + pubkey_buf->len, retries); + return FALSE; + } + g_byte_array_set_size (pubkey_buf, 0); + continue; + } + + /* success */ + break; + } + if (g_getenv ("FWUPD_SYNAPTICS_RMI_VERBOSE") != NULL) { + fu_common_dump_full (G_LOG_DOMAIN, "RSA public key", + pubkey_buf->data, pubkey_buf->len, + 16, FU_DUMP_FLAGS_NONE); + } + + /* sanity check size */ + if (rsa_pubkey_len != pubkey_buf->len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "RSA public key length did not match: %u != %u: ", + rsa_pubkey_len, pubkey_buf->len); + return FALSE; + } + pubkey = g_bytes_new (pubkey_buf->data, pubkey_buf->len); + return fu_synaptics_verify_sha256_signature (payload, pubkey, signature, error); +} + gboolean fu_synaptics_rmi_v5_device_write_firmware (FuDevice *device, FuFirmware *firmware, FwupdInstallFlags flags, GError **error) { - FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device); FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash (self); FuSynapticsRmiFunction *f34; + FuSynapticsRmiFirmware *rmi_firmware = FU_SYNAPTICS_RMI_FIRMWARE (firmware); guint32 address; g_autoptr(GBytes) bytes_bin = NULL; g_autoptr(GBytes) bytes_cfg = NULL; + g_autoptr(GBytes) signature_bin = NULL; g_autoptr(GPtrArray) chunks_bin = NULL; g_autoptr(GPtrArray) chunks_cfg = NULL; g_autoptr(GByteArray) req_addr = g_byte_array_new (); @@ -151,6 +244,22 @@ fu_synaptics_rmi_v5_device_write_firmware (FuDevice *device, g_prefix_error (error, "not idle: "); return FALSE; } + if (fu_synaptics_rmi_firmware_get_sig_size (rmi_firmware) == 0 && + fu_synaptics_rmi_device_get_sig_size (self) != 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "device secure but firmware not secure"); + return FALSE; + } + if (fu_synaptics_rmi_firmware_get_sig_size (rmi_firmware) != 0 && + fu_synaptics_rmi_device_get_sig_size (self) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "device not secure but firmware secure"); + return FALSE; + } /* f34 */ f34 = fu_synaptics_rmi_device_get_function (self, 0x34, error); @@ -165,6 +274,18 @@ fu_synaptics_rmi_v5_device_write_firmware (FuDevice *device, if (bytes_cfg == NULL) return FALSE; + /* verify signature if set */ + signature_bin = fu_firmware_get_image_by_id_bytes (firmware, "sig", NULL); + if (signature_bin != NULL) { + if (!fu_synaptics_rmi_v5_device_secure_check (device, + bytes_bin, + signature_bin, + error)) { + g_prefix_error (error, "secure check failed: "); + return FALSE; + } + } + /* disable powersaving */ if (!fu_synaptics_rmi_device_disable_sleep (self, error)) { g_prefix_error (error, "failed to disable sleep: "); @@ -220,6 +341,35 @@ fu_synaptics_rmi_v5_device_write_firmware (FuDevice *device, (gsize) chunks_bin->len + chunks_cfg->len); } + /* payload signature */ + if (signature_bin != NULL && + fu_synaptics_rmi_device_get_sig_size (self) != 0) { + g_autoptr(GPtrArray) chunks_sig = NULL; + chunks_sig = fu_chunk_array_new_from_bytes (signature_bin, + 0x00, /* start addr */ + 0x00, /* page_sz */ + flash->block_size); + if (!fu_synaptics_rmi_device_write (self, f34->data_base, req_addr, error)) { + g_prefix_error (error, "failed to write 1st address zero: "); + return FALSE; + } + for (guint i = 0; i < chunks_sig->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks_sig, i); + if (!fu_synaptics_rmi_v5_device_write_block (self, + RMI_F34_WRITE_SIGNATURE, + address, + chk->data, + chk->data_sz, + error)) { + g_prefix_error (error, "failed to write bin block %u: ", chk->idx); + return FALSE; + } + fu_device_set_progress_full (device, (gsize) i, + (gsize) chunks_bin->len + chunks_cfg->len); + } + g_usleep (1000 * 1000); + } + /* program the configuration image */ if (!fu_synaptics_rmi_device_write (self, f34->data_base, req_addr, error)) { g_prefix_error (error, "failed to 2nd write address zero: "); @@ -250,8 +400,10 @@ fu_synaptics_rmi_v5_device_setup (FuSynapticsRmiDevice *self, GError **error) { FuSynapticsRmiFunction *f34; FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash (self); + guint8 flash_properties2 = 0; g_autoptr(GByteArray) f34_data0 = NULL; g_autoptr(GByteArray) f34_data2 = NULL; + g_autoptr(GByteArray) buf_flash_properties2 = NULL; /* f34 */ f34 = fu_synaptics_rmi_device_get_function (self, 0x34, error); @@ -267,6 +419,45 @@ fu_synaptics_rmi_v5_device_setup (FuSynapticsRmiDevice *self, GError **error) flash->bootloader_id[0] = f34_data0->data[0]; flash->bootloader_id[1] = f34_data0->data[1]; + /* get flash properties */ + buf_flash_properties2 = fu_synaptics_rmi_device_read (self, f34->query_base + 0x9, 1, error); + if (buf_flash_properties2 == NULL) { + g_prefix_error (error, "failed to read Flash Properties 2: "); + return FALSE; + } + if (!fu_common_read_uint8_safe (buf_flash_properties2->data, + buf_flash_properties2->len, + 0x0, /* offset */ + &flash_properties2, + error)) { + g_prefix_error (error, "failed to parse Flash Properties 2: "); + return FALSE; + } + if (flash_properties2 & 0x01) { + guint16 sig_size = 0; + g_autoptr(GByteArray) buf_rsa_key = NULL; + buf_rsa_key = fu_synaptics_rmi_device_read (self, + f34->query_base + 0x9 + 0x1, + 2, + error); + if (buf_rsa_key == NULL) { + g_prefix_error (error, "failed to read RSA key length: "); + return FALSE; + } + if (!fu_common_read_uint16_safe (buf_rsa_key->data, + buf_rsa_key->len, + 0x0, /* offset */ + &sig_size, + G_LITTLE_ENDIAN, + error)) { + g_prefix_error (error, "failed to parse RSA key length: "); + return FALSE; + } + fu_synaptics_rmi_device_set_sig_size (self, sig_size); + } else { + fu_synaptics_rmi_device_set_sig_size (self, 0); + } + /* get flash properties */ f34_data2 = fu_synaptics_rmi_device_read (self, f34->query_base + 0x2, 0x7, error); if (f34_data2 == NULL) diff --git a/plugins/synaptics-rmi/meson.build b/plugins/synaptics-rmi/meson.build index fa539157f..ddfbe7693 100644 --- a/plugins/synaptics-rmi/meson.build +++ b/plugins/synaptics-rmi/meson.build @@ -25,6 +25,7 @@ shared_module('fu_plugin_synaptics_rmi', c_args : cargs, dependencies : [ plugin_deps, + gnutls, ], link_with : [ fwupd,