mirror of
https://git.proxmox.com/git/fwupd
synced 2025-06-14 03:05:00 +00:00

This allows us to get the OEM Public Key BootGuard hashes. Also add a new HSI test for leaked bootguard keys.
192 lines
5.4 KiB
C
192 lines
5.4 KiB
C
/*
|
|
* Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
|
|
*
|
|
* SPDX-License-Identifier: LGPL-2.1+
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <fwupdplugin.h>
|
|
|
|
#include "fu-intel-me-common.h"
|
|
#include "fu-intel-me-heci-device.h"
|
|
|
|
G_DEFINE_TYPE(FuIntelMeHeciDevice, fu_intel_me_heci_device, FU_TYPE_MEI_DEVICE)
|
|
|
|
#define FU_INTEL_ME_HECI_DEVICE_TIMEOUT 200 /* ms */
|
|
|
|
static gboolean
|
|
fu_intel_me_heci_device_open(FuDevice *device, GError **error)
|
|
{
|
|
/* open then create context */
|
|
if (!FU_DEVICE_CLASS(fu_intel_me_heci_device_parent_class)->open(device, error))
|
|
return FALSE;
|
|
return fu_mei_device_connect(FU_MEI_DEVICE(device), 0, error);
|
|
}
|
|
|
|
static GByteArray *
|
|
fu_intel_me_heci_device_read_file_response(GByteArray *buf_res, guint32 datasz_req, GError **error)
|
|
{
|
|
guint32 datasz_res = 0;
|
|
g_autoptr(GByteArray) buf = g_byte_array_new();
|
|
|
|
/* verify payload size */
|
|
if (!fu_memread_uint32_safe(buf_res->data,
|
|
buf_res->len,
|
|
sizeof(FuMkhiHeader),
|
|
&datasz_res,
|
|
G_LITTLE_ENDIAN,
|
|
error))
|
|
return NULL;
|
|
if (datasz_res > datasz_req || datasz_res == 0x0) {
|
|
g_set_error(error,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_INVALID_DATA,
|
|
"invalid response data size, requested 0x%x and got 0x%x",
|
|
datasz_req,
|
|
datasz_res);
|
|
return NULL;
|
|
}
|
|
|
|
/* copy out payload */
|
|
for (gsize i = 0; i < datasz_res; i++) {
|
|
guint8 tmp = 0;
|
|
if (!fu_memread_uint8_safe(buf_res->data,
|
|
buf_res->len,
|
|
sizeof(FuMkhiHeader) + sizeof(guint32) + i,
|
|
&tmp,
|
|
error))
|
|
return NULL;
|
|
fu_byte_array_append_uint8(buf, tmp);
|
|
}
|
|
|
|
/* success */
|
|
return g_steal_pointer(&buf);
|
|
}
|
|
|
|
GByteArray *
|
|
fu_intel_me_heci_device_read_file(FuIntelMeHeciDevice *self, const gchar *filename, GError **error)
|
|
{
|
|
FuMkhiHeader hdr_res = {0};
|
|
gsize filenamesz = strlen(filename);
|
|
guint datasz_req = 0x80;
|
|
g_autoptr(GByteArray) buf_fn = g_byte_array_new();
|
|
g_autoptr(GByteArray) buf_req = g_byte_array_new();
|
|
g_autoptr(GByteArray) buf_res = g_byte_array_new();
|
|
const FuMkhiHeader hdr_req = {.group_id = MKHI_GROUP_ID_MCA, .command = MCA_READ_FILE_EX};
|
|
|
|
/* filename must be a specific size */
|
|
fu_byte_array_set_size(buf_fn, 0x40, 0x0);
|
|
if (!fu_memcpy_safe(buf_fn->data,
|
|
buf_fn->len - 1,
|
|
0x0,
|
|
(const guint8 *)filename,
|
|
filenamesz,
|
|
0x0,
|
|
filenamesz,
|
|
error))
|
|
return NULL;
|
|
|
|
/* request */
|
|
g_byte_array_append(buf_req, (const guint8 *)&hdr_req, sizeof(hdr_req));
|
|
g_byte_array_append(buf_req, buf_fn->data, buf_fn->len); /* Filename */
|
|
fu_byte_array_append_uint32(buf_req, 0x0, G_LITTLE_ENDIAN); /* Offset */
|
|
fu_byte_array_append_uint32(buf_req, datasz_req, G_LITTLE_ENDIAN); /* DataSize */
|
|
fu_byte_array_append_uint8(buf_req, (1 << 3)); /* Flags?? */
|
|
if (!fu_mei_device_write(FU_MEI_DEVICE(self),
|
|
buf_req->data,
|
|
buf_req->len,
|
|
FU_INTEL_ME_HECI_DEVICE_TIMEOUT,
|
|
error))
|
|
return NULL;
|
|
|
|
/* response */
|
|
fu_byte_array_set_size(buf_res, sizeof(hdr_res) + sizeof(guint32) + datasz_req, 0x0);
|
|
if (!fu_mei_device_read(FU_MEI_DEVICE(self),
|
|
buf_res->data,
|
|
buf_res->len,
|
|
NULL,
|
|
FU_INTEL_ME_HECI_DEVICE_TIMEOUT,
|
|
error))
|
|
return NULL;
|
|
|
|
/* verify header */
|
|
if (!fu_memcpy_safe((guint8 *)&hdr_res,
|
|
sizeof(hdr_res),
|
|
0x0, /* dst */
|
|
buf_res->data,
|
|
buf_res->len,
|
|
0x0, /* src */
|
|
sizeof(hdr_req),
|
|
error))
|
|
return NULL;
|
|
if (!fu_intel_me_mkhi_verify_header(hdr_req, hdr_res, error))
|
|
return NULL;
|
|
return fu_intel_me_heci_device_read_file_response(buf_res, datasz_req, error);
|
|
}
|
|
|
|
GByteArray *
|
|
fu_intel_me_heci_device_read_file_ex(FuIntelMeHeciDevice *self,
|
|
guint32 file_id,
|
|
guint32 section,
|
|
guint32 datasz_req,
|
|
GError **error)
|
|
{
|
|
FuMkhiHeader hdr_res = {0};
|
|
g_autoptr(GByteArray) buf_req = g_byte_array_new();
|
|
g_autoptr(GByteArray) buf_res = g_byte_array_new();
|
|
const FuMkhiHeader hdr_req = {.group_id = MKHI_GROUP_ID_MCA,
|
|
.command = MCA_READ_FILE_EX_CMD};
|
|
|
|
/* request */
|
|
g_byte_array_append(buf_req, (const guint8 *)&hdr_req, sizeof(hdr_req));
|
|
fu_byte_array_append_uint32(buf_req, file_id, G_LITTLE_ENDIAN); /* FileId */
|
|
fu_byte_array_append_uint32(buf_req, 0x0, G_LITTLE_ENDIAN); /* Offset */
|
|
fu_byte_array_append_uint32(buf_req, datasz_req, G_LITTLE_ENDIAN); /* DataSize */
|
|
fu_byte_array_append_uint8(buf_req, section); /* Flags */
|
|
if (!fu_mei_device_write(FU_MEI_DEVICE(self),
|
|
buf_req->data,
|
|
buf_req->len,
|
|
FU_INTEL_ME_HECI_DEVICE_TIMEOUT,
|
|
error))
|
|
return NULL;
|
|
|
|
/* response */
|
|
fu_byte_array_set_size(buf_res, sizeof(hdr_res) + sizeof(guint32) + datasz_req, 0x0);
|
|
if (!fu_mei_device_read(FU_MEI_DEVICE(self),
|
|
buf_res->data,
|
|
buf_res->len,
|
|
NULL,
|
|
FU_INTEL_ME_HECI_DEVICE_TIMEOUT,
|
|
error))
|
|
return NULL;
|
|
|
|
/* verify header */
|
|
if (!fu_memcpy_safe((guint8 *)&hdr_res,
|
|
sizeof(hdr_res),
|
|
0x0, /* dst */
|
|
buf_res->data,
|
|
buf_res->len,
|
|
0x0, /* src */
|
|
sizeof(hdr_req),
|
|
error))
|
|
return NULL;
|
|
if (!fu_intel_me_mkhi_verify_header(hdr_req, hdr_res, error))
|
|
return NULL;
|
|
return fu_intel_me_heci_device_read_file_response(buf_res, datasz_req, error);
|
|
}
|
|
|
|
static void
|
|
fu_intel_me_heci_device_init(FuIntelMeHeciDevice *self)
|
|
{
|
|
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_INTERNAL);
|
|
fu_device_add_icon(FU_DEVICE(self), "computer");
|
|
}
|
|
|
|
static void
|
|
fu_intel_me_heci_device_class_init(FuIntelMeHeciDeviceClass *klass)
|
|
{
|
|
FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass);
|
|
klass_device->open = fu_intel_me_heci_device_open;
|
|
}
|