mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-04 11:17:08 +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')
|
||||
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 = []
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
|
@ -14,6 +14,9 @@
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include <gnutls/abstract.h>
|
||||
#include <gnutls/crypto.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -25,6 +25,7 @@ shared_module('fu_plugin_synaptics_rmi',
|
||||
c_args : cargs,
|
||||
dependencies : [
|
||||
plugin_deps,
|
||||
gnutls,
|
||||
],
|
||||
link_with : [
|
||||
fwupd,
|
||||
|
Loading…
Reference in New Issue
Block a user