mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-08 01:14:43 +00:00
synaptics-rmi: Support parsing and writing signed firmware
Validate the firmware signature if provided
This commit is contained in:
parent
643d7b16b1
commit
edc0c08065
@ -262,6 +262,9 @@ else
|
|||||||
if get_option('plugin_uefi_pk')
|
if get_option('plugin_uefi_pk')
|
||||||
error('plugin_uefi_pk needs -Dgnutls=true to work')
|
error('plugin_uefi_pk needs -Dgnutls=true to work')
|
||||||
endif
|
endif
|
||||||
|
if get_option('plugin_synaptics_rmi')
|
||||||
|
error('plugin_synaptics_rmi needs -Dgnutls=true to work')
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
platform_deps = []
|
platform_deps = []
|
||||||
|
@ -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_dummy', type : 'boolean', value : false, description : 'enable the dummy device')
|
||||||
option('plugin_emmc', type : 'boolean', value : true, description : 'enable eMMC support')
|
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_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_thunderbolt', type : 'boolean', value : true, description : 'enable Thunderbolt support')
|
||||||
option('plugin_redfish', type : 'boolean', value : true, description : 'enable Redfish 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')
|
option('plugin_uefi_capsule', type : 'boolean', value : true, description : 'enable UEFI capsule support')
|
||||||
|
@ -25,11 +25,14 @@ subdir('ata')
|
|||||||
subdir('elantp')
|
subdir('elantp')
|
||||||
subdir('optionrom')
|
subdir('optionrom')
|
||||||
subdir('superio')
|
subdir('superio')
|
||||||
subdir('synaptics-rmi')
|
|
||||||
subdir('thelio-io')
|
subdir('thelio-io')
|
||||||
subdir('wacom-raw')
|
subdir('wacom-raw')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if get_option('gudev') and get_option('plugin_synaptics_rmi')
|
||||||
|
subdir('synaptics-rmi')
|
||||||
|
endif
|
||||||
|
|
||||||
if get_option('gudev') and get_option('gusb')
|
if get_option('gudev') and get_option('gusb')
|
||||||
subdir('logitech-hidpp')
|
subdir('logitech-hidpp')
|
||||||
endif
|
endif
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
|
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
#include <gnutls/abstract.h>
|
||||||
|
#include <gnutls/crypto.h>
|
||||||
|
|
||||||
#include "fu-common.h"
|
#include "fu-common.h"
|
||||||
#include "fu-io-channel.h"
|
#include "fu-io-channel.h"
|
||||||
#include "fu-synaptics-rmi-common.h"
|
#include "fu-synaptics-rmi-common.h"
|
||||||
@ -30,6 +33,14 @@
|
|||||||
#define RMI_FUNCTION_VERSION_MASK 0x60
|
#define RMI_FUNCTION_VERSION_MASK 0x60
|
||||||
#define RMI_FUNCTION_INTERRUPT_SOURCES_MASK 0x7
|
#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
|
guint32
|
||||||
fu_synaptics_rmi_generate_checksum (const guint8 *data, gsize len)
|
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),
|
return fu_io_channel_write_raw (io, (const guint8 *) buf, strlen (buf),
|
||||||
1000, FU_IO_CHANNEL_FLAG_NONE, error);
|
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;
|
||||||
|
}
|
||||||
|
@ -34,3 +34,7 @@ FuSynapticsRmiFunction *fu_synaptics_rmi_function_parse (GByteArray *buf,
|
|||||||
gboolean fu_synaptics_rmi_device_writeln (const gchar *fn,
|
gboolean fu_synaptics_rmi_device_writeln (const gchar *fn,
|
||||||
const gchar *buf,
|
const gchar *buf,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
gboolean fu_synaptics_verify_sha256_signature (GBytes *payload,
|
||||||
|
GBytes *pubkey,
|
||||||
|
GBytes *signature,
|
||||||
|
GError **error);
|
||||||
|
@ -91,6 +91,7 @@ typedef struct
|
|||||||
FuSynapticsRmiFunction *f01;
|
FuSynapticsRmiFunction *f01;
|
||||||
FuSynapticsRmiFunction *f34;
|
FuSynapticsRmiFunction *f34;
|
||||||
guint8 current_page;
|
guint8 current_page;
|
||||||
|
guint16 sig_size; /* 0x0 for non-secure update */
|
||||||
} FuSynapticsRmiDevicePrivate;
|
} FuSynapticsRmiDevicePrivate;
|
||||||
|
|
||||||
G_DEFINE_TYPE_WITH_PRIVATE (FuSynapticsRmiDevice, fu_synaptics_rmi_device, FU_TYPE_UDEV_DEVICE)
|
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);
|
FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device);
|
||||||
FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self);
|
FuSynapticsRmiDevicePrivate *priv = GET_PRIVATE (self);
|
||||||
fu_common_string_append_kx (str, idt, "CurrentPage", priv->current_page);
|
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) {
|
if (priv->f34 != NULL) {
|
||||||
fu_common_string_append_kx (str, idt, "BlVer",
|
fu_common_string_append_kx (str, idt, "BlVer",
|
||||||
priv->f34->function_version + 0x5);
|
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);
|
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
|
gboolean
|
||||||
fu_synaptics_rmi_device_write (FuSynapticsRmiDevice *self, guint16 addr, GByteArray *req, GError **error)
|
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;
|
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 {
|
typedef enum {
|
||||||
HID_RMI4_MODE_MOUSE = 0,
|
HID_RMI4_MODE_MOUSE = 0,
|
||||||
HID_RMI4_MODE_ATTN_REPORTS = 1,
|
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);
|
bytes_bin = fu_firmware_get_image_by_id_bytes (firmware, "ui", error);
|
||||||
if (bytes_bin == NULL)
|
if (bytes_bin == NULL)
|
||||||
return 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) {
|
if (g_bytes_get_size (bytes_bin) != size_expected) {
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
FWUPD_ERROR,
|
FWUPD_ERROR,
|
||||||
|
@ -54,6 +54,10 @@ GByteArray *fu_synaptics_rmi_device_read (FuSynapticsRmiDevice *self,
|
|||||||
guint16 addr,
|
guint16 addr,
|
||||||
gsize req_sz,
|
gsize req_sz,
|
||||||
GError **error);
|
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,
|
gboolean fu_synaptics_rmi_device_write (FuSynapticsRmiDevice *self,
|
||||||
guint16 addr,
|
guint16 addr,
|
||||||
GByteArray *req,
|
GByteArray *req,
|
||||||
@ -74,3 +78,6 @@ gboolean fu_synaptics_rmi_device_rebind_driver (FuSynapticsRmiDevice *self,
|
|||||||
GError **error);
|
GError **error);
|
||||||
gboolean fu_synaptics_rmi_device_poll_wait (FuSynapticsRmiDevice *self,
|
gboolean fu_synaptics_rmi_device_poll_wait (FuSynapticsRmiDevice *self,
|
||||||
GError **error);
|
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);
|
||||||
|
@ -31,6 +31,7 @@ struct _FuSynapticsRmiFirmware {
|
|||||||
guint32 package_id;
|
guint32 package_id;
|
||||||
guint16 product_info;
|
guint16 product_info;
|
||||||
gchar *product_id;
|
gchar *product_id;
|
||||||
|
guint32 sig_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE (FuSynapticsRmiFirmware, fu_synaptics_rmi_firmware, FU_TYPE_FIRMWARE)
|
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_CONFIG_SIZE_OFFSET 0x0c
|
||||||
#define RMI_IMG_PACKAGE_ID_OFFSET 0x1a
|
#define RMI_IMG_PACKAGE_ID_OFFSET 0x1a
|
||||||
#define RMI_IMG_FW_BUILD_ID_OFFSET 0x50
|
#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_ID_OFFSET 0x10
|
||||||
#define RMI_IMG_PRODUCT_INFO_OFFSET 0x1e
|
#define RMI_IMG_PRODUCT_INFO_OFFSET 0x1e
|
||||||
#define RMI_IMG_FW_OFFSET 0x100
|
#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, "BuildId", self->build_id);
|
||||||
fu_common_string_append_kx (str, idt, "PackageId", self->package_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, "ProductInfo", self->product_info);
|
||||||
|
fu_common_string_append_kx (str, idt, "SigSize", self->sig_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -318,6 +321,7 @@ fu_synaptics_rmi_firmware_parse_v10 (FuFirmware *firmware, GBytes *fw, GError **
|
|||||||
static gboolean
|
static gboolean
|
||||||
fu_synaptics_rmi_firmware_parse_v0x (FuFirmware *firmware, GBytes *fw, GError **error)
|
fu_synaptics_rmi_firmware_parse_v0x (FuFirmware *firmware, GBytes *fw, GError **error)
|
||||||
{
|
{
|
||||||
|
FuSynapticsRmiFirmware *self = FU_SYNAPTICS_RMI_FIRMWARE (firmware);
|
||||||
guint32 cfg_sz;
|
guint32 cfg_sz;
|
||||||
guint32 img_sz = 0;
|
guint32 img_sz = 0;
|
||||||
gsize sz = 0;
|
gsize sz = 0;
|
||||||
@ -331,6 +335,15 @@ fu_synaptics_rmi_firmware_parse_v0x (FuFirmware *firmware, GBytes *fw, GError **
|
|||||||
error))
|
error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (img_sz > 0) {
|
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,
|
if (!fu_synaptics_rmi_firmware_add_image (firmware, "ui", fw,
|
||||||
RMI_IMG_FW_OFFSET,
|
RMI_IMG_FW_OFFSET,
|
||||||
img_sz, error))
|
img_sz, error))
|
||||||
@ -363,6 +376,7 @@ fu_synaptics_rmi_firmware_parse (FuFirmware *firmware,
|
|||||||
FuSynapticsRmiFirmware *self = FU_SYNAPTICS_RMI_FIRMWARE (firmware);
|
FuSynapticsRmiFirmware *self = FU_SYNAPTICS_RMI_FIRMWARE (firmware);
|
||||||
gsize sz = 0;
|
gsize sz = 0;
|
||||||
guint32 checksum_calculated;
|
guint32 checksum_calculated;
|
||||||
|
guint32 firmware_size = 0;
|
||||||
const guint8 *data = g_bytes_get_data (fw, &sz);
|
const guint8 *data = g_bytes_get_data (fw, &sz);
|
||||||
|
|
||||||
/* check minimum size */
|
/* check minimum size */
|
||||||
@ -425,6 +439,12 @@ fu_synaptics_rmi_firmware_parse (FuFirmware *firmware,
|
|||||||
G_LITTLE_ENDIAN,
|
G_LITTLE_ENDIAN,
|
||||||
error))
|
error))
|
||||||
return FALSE;
|
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 */
|
/* parse partitions, but ignore lockdown */
|
||||||
switch (self->bootloader_version) {
|
switch (self->bootloader_version) {
|
||||||
@ -433,6 +453,14 @@ fu_synaptics_rmi_firmware_parse (FuFirmware *firmware,
|
|||||||
case 4:
|
case 4:
|
||||||
case 5:
|
case 5:
|
||||||
case 6:
|
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))
|
if (!fu_synaptics_rmi_firmware_parse_v0x (firmware, fw, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
self->kind = RMI_FIRMWARE_KIND_0X;
|
self->kind = RMI_FIRMWARE_KIND_0X;
|
||||||
@ -455,6 +483,12 @@ fu_synaptics_rmi_firmware_parse (FuFirmware *firmware,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guint32
|
||||||
|
fu_synaptics_rmi_firmware_get_sig_size (FuSynapticsRmiFirmware *self)
|
||||||
|
{
|
||||||
|
return self->sig_size;
|
||||||
|
}
|
||||||
|
|
||||||
static GBytes *
|
static GBytes *
|
||||||
fu_synaptics_rmi_firmware_write_v0x (FuFirmware *firmware, GError **error)
|
fu_synaptics_rmi_firmware_write_v0x (FuFirmware *firmware, GError **error)
|
||||||
{
|
{
|
||||||
|
@ -12,3 +12,4 @@
|
|||||||
G_DECLARE_FINAL_TYPE (FuSynapticsRmiFirmware, fu_synaptics_rmi_firmware, FU, SYNAPTICS_RMI_FIRMWARE, FuFirmware)
|
G_DECLARE_FINAL_TYPE (FuSynapticsRmiFirmware, fu_synaptics_rmi_firmware, FU, SYNAPTICS_RMI_FIRMWARE, FuFirmware)
|
||||||
|
|
||||||
FuFirmware *fu_synaptics_rmi_firmware_new (void);
|
FuFirmware *fu_synaptics_rmi_firmware_new (void);
|
||||||
|
guint32 fu_synaptics_rmi_firmware_get_sig_size (FuSynapticsRmiFirmware *self);
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "fu-chunk.h"
|
#include "fu-chunk.h"
|
||||||
#include "fu-common.h"
|
#include "fu-common.h"
|
||||||
|
#include "fu-synaptics-rmi-firmware.h"
|
||||||
#include "fu-synaptics-rmi-v5-device.h"
|
#include "fu-synaptics-rmi-v5-device.h"
|
||||||
|
|
||||||
#include "fwupd-error.h"
|
#include "fwupd-error.h"
|
||||||
@ -18,6 +19,7 @@
|
|||||||
#define RMI_F34_ERASE_ALL 0x03
|
#define RMI_F34_ERASE_ALL 0x03
|
||||||
#define RMI_F34_WRITE_LOCKDOWN_BLOCK 0x04
|
#define RMI_F34_WRITE_LOCKDOWN_BLOCK 0x04
|
||||||
#define RMI_F34_WRITE_CONFIG_BLOCK 0x06
|
#define RMI_F34_WRITE_CONFIG_BLOCK 0x06
|
||||||
|
#define RMI_F34_WRITE_SIGNATURE 0x0b
|
||||||
#define RMI_F34_ENABLE_FLASH_PROG 0x0f
|
#define RMI_F34_ENABLE_FLASH_PROG 0x0f
|
||||||
|
|
||||||
#define RMI_F34_BLOCK_SIZE_OFFSET 1
|
#define RMI_F34_BLOCK_SIZE_OFFSET 1
|
||||||
@ -118,19 +120,110 @@ fu_synaptics_rmi_v5_device_write_block (FuSynapticsRmiDevice *self,
|
|||||||
return TRUE;
|
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
|
gboolean
|
||||||
fu_synaptics_rmi_v5_device_write_firmware (FuDevice *device,
|
fu_synaptics_rmi_v5_device_write_firmware (FuDevice *device,
|
||||||
FuFirmware *firmware,
|
FuFirmware *firmware,
|
||||||
FwupdInstallFlags flags,
|
FwupdInstallFlags flags,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
|
|
||||||
FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device);
|
FuSynapticsRmiDevice *self = FU_SYNAPTICS_RMI_DEVICE (device);
|
||||||
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash (self);
|
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash (self);
|
||||||
FuSynapticsRmiFunction *f34;
|
FuSynapticsRmiFunction *f34;
|
||||||
|
FuSynapticsRmiFirmware *rmi_firmware = FU_SYNAPTICS_RMI_FIRMWARE (firmware);
|
||||||
guint32 address;
|
guint32 address;
|
||||||
g_autoptr(GBytes) bytes_bin = NULL;
|
g_autoptr(GBytes) bytes_bin = NULL;
|
||||||
g_autoptr(GBytes) bytes_cfg = NULL;
|
g_autoptr(GBytes) bytes_cfg = NULL;
|
||||||
|
g_autoptr(GBytes) signature_bin = NULL;
|
||||||
g_autoptr(GPtrArray) chunks_bin = NULL;
|
g_autoptr(GPtrArray) chunks_bin = NULL;
|
||||||
g_autoptr(GPtrArray) chunks_cfg = NULL;
|
g_autoptr(GPtrArray) chunks_cfg = NULL;
|
||||||
g_autoptr(GByteArray) req_addr = g_byte_array_new ();
|
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: ");
|
g_prefix_error (error, "not idle: ");
|
||||||
return FALSE;
|
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 */
|
||||||
f34 = fu_synaptics_rmi_device_get_function (self, 0x34, error);
|
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)
|
if (bytes_cfg == NULL)
|
||||||
return FALSE;
|
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 */
|
/* disable powersaving */
|
||||||
if (!fu_synaptics_rmi_device_disable_sleep (self, error)) {
|
if (!fu_synaptics_rmi_device_disable_sleep (self, error)) {
|
||||||
g_prefix_error (error, "failed to disable sleep: ");
|
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);
|
(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 */
|
/* program the configuration image */
|
||||||
if (!fu_synaptics_rmi_device_write (self, f34->data_base, req_addr, error)) {
|
if (!fu_synaptics_rmi_device_write (self, f34->data_base, req_addr, error)) {
|
||||||
g_prefix_error (error, "failed to 2nd write address zero: ");
|
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;
|
FuSynapticsRmiFunction *f34;
|
||||||
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash (self);
|
FuSynapticsRmiFlash *flash = fu_synaptics_rmi_device_get_flash (self);
|
||||||
|
guint8 flash_properties2 = 0;
|
||||||
g_autoptr(GByteArray) f34_data0 = NULL;
|
g_autoptr(GByteArray) f34_data0 = NULL;
|
||||||
g_autoptr(GByteArray) f34_data2 = NULL;
|
g_autoptr(GByteArray) f34_data2 = NULL;
|
||||||
|
g_autoptr(GByteArray) buf_flash_properties2 = NULL;
|
||||||
|
|
||||||
/* f34 */
|
/* f34 */
|
||||||
f34 = fu_synaptics_rmi_device_get_function (self, 0x34, error);
|
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[0] = f34_data0->data[0];
|
||||||
flash->bootloader_id[1] = f34_data0->data[1];
|
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 */
|
/* get flash properties */
|
||||||
f34_data2 = fu_synaptics_rmi_device_read (self, f34->query_base + 0x2, 0x7, error);
|
f34_data2 = fu_synaptics_rmi_device_read (self, f34->query_base + 0x2, 0x7, error);
|
||||||
if (f34_data2 == NULL)
|
if (f34_data2 == NULL)
|
||||||
|
@ -25,6 +25,7 @@ shared_module('fu_plugin_synaptics_rmi',
|
|||||||
c_args : cargs,
|
c_args : cargs,
|
||||||
dependencies : [
|
dependencies : [
|
||||||
plugin_deps,
|
plugin_deps,
|
||||||
|
gnutls,
|
||||||
],
|
],
|
||||||
link_with : [
|
link_with : [
|
||||||
fwupd,
|
fwupd,
|
||||||
|
Loading…
Reference in New Issue
Block a user