summaryrefslogtreecommitdiffstats
path: root/panels/firmware-security
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:45:20 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:45:20 +0000
commitae1c76ff830d146d41e88d6fba724c0a54bce868 (patch)
tree3c354bec95af07be35fc71a4b738268496f1a1c4 /panels/firmware-security
parentInitial commit. (diff)
downloadgnome-control-center-ae1c76ff830d146d41e88d6fba724c0a54bce868.tar.xz
gnome-control-center-ae1c76ff830d146d41e88d6fba724c0a54bce868.zip
Adding upstream version 1:43.6.upstream/1%43.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'panels/firmware-security')
-rw-r--r--panels/firmware-security/cc-firmware-security-boot-dialog.c113
-rw-r--r--panels/firmware-security/cc-firmware-security-boot-dialog.h37
-rw-r--r--panels/firmware-security/cc-firmware-security-boot-dialog.ui63
-rw-r--r--panels/firmware-security/cc-firmware-security-dialog.c442
-rw-r--r--panels/firmware-security/cc-firmware-security-dialog.h38
-rw-r--r--panels/firmware-security/cc-firmware-security-dialog.ui271
-rw-r--r--panels/firmware-security/cc-firmware-security-panel.c717
-rw-r--r--panels/firmware-security/cc-firmware-security-panel.h34
-rw-r--r--panels/firmware-security/cc-firmware-security-panel.ui176
-rw-r--r--panels/firmware-security/cc-firmware-security-utils.c373
-rw-r--r--panels/firmware-security/cc-firmware-security-utils.h133
-rw-r--r--panels/firmware-security/firmware-security.gresource.xml9
-rw-r--r--panels/firmware-security/gnome-firmware-security-panel.desktop.in.in19
-rw-r--r--panels/firmware-security/meson.build44
-rw-r--r--panels/firmware-security/security-level.css119
15 files changed, 2588 insertions, 0 deletions
diff --git a/panels/firmware-security/cc-firmware-security-boot-dialog.c b/panels/firmware-security/cc-firmware-security-boot-dialog.c
new file mode 100644
index 0000000..bf8a0e7
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-boot-dialog.c
@@ -0,0 +1,113 @@
+/* cc-firmware-security-boot-dialog.c
+ *
+ * Copyright (C) 2021 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Kate Hsuan <hpa@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+
+#include "cc-firmware-security-boot-dialog.h"
+
+struct _CcFirmwareSecurityBootDialog
+{
+ GtkDialog parent;
+
+ GtkWidget *secure_boot_icon;
+ GtkWidget *secure_boot_title;
+ GtkWidget *secure_boot_description;
+};
+
+G_DEFINE_TYPE (CcFirmwareSecurityBootDialog, cc_firmware_security_boot_dialog, GTK_TYPE_DIALOG)
+
+static void
+cc_firmware_security_boot_dialog_class_init (CcFirmwareSecurityBootDialogClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/firmware-security/cc-firmware-security-boot-dialog.ui");
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityBootDialog, secure_boot_title);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityBootDialog, secure_boot_icon);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityBootDialog, secure_boot_description);
+}
+
+static void
+cc_firmware_security_boot_dialog_init (CcFirmwareSecurityBootDialog *dialog)
+{
+ gtk_widget_init_template (GTK_WIDGET (dialog));
+ load_custom_css ("/org/gnome/control-center/firmware-security/security-level.css");
+}
+
+GtkWidget *
+cc_firmware_security_boot_dialog_new (SecureBootState secure_boot_state)
+{
+ CcFirmwareSecurityBootDialog *dialog;
+ g_autofree gchar *status_description = NULL;
+
+ dialog = g_object_new (CC_TYPE_FIRMWARE_SECURITY_BOOT_DIALOG,
+ "use-header-bar", TRUE,
+ NULL);
+
+ switch (secure_boot_state)
+ {
+ case SECURE_BOOT_STATE_ACTIVE:
+ /* TRANSLATORS: secure boot refers to the system firmware security mode */
+ gtk_label_set_text (GTK_LABEL(dialog->secure_boot_title), _("Secure Boot is Active"));
+ gtk_image_set_from_icon_name (GTK_IMAGE (dialog->secure_boot_icon), "channel-secure-symbolic");
+ gtk_widget_add_css_class (dialog->secure_boot_icon, "good");
+ status_description = g_strdup_printf ("%s",
+ /* TRANSLATORS: this is the first section of the decription */
+ _("Secure boot prevents malicious software from being loaded when the device starts. "
+ "It is currently turned on and is functioning correctly."));
+ break;
+
+ case SECURE_BOOT_STATE_PROBLEMS:
+ /* TRANSLATORS: secure boot refers to the system firmware security mode */
+ gtk_label_set_text (GTK_LABEL (dialog->secure_boot_title), _("Secure Boot Has Problems"));
+ gtk_widget_add_css_class (dialog->secure_boot_icon, "error");
+ status_description = g_strdup_printf ("%s\n\n%s\n\n%s",
+ /* TRANSLATORS: this is the first section of the decription. */
+ _("Secure boot prevents malicious software from being loaded when the device "
+ "starts. It is currently turned on, but will not work due to having an invalid key."),
+ /* TRANSLATORS: this is the second section of description. */
+ _("Secure boot problems can often be resolved from your computer's UEFI firmware settings "
+ "(BIOS) and your hardware manufacturer may provide information on how to do this."),
+ /* TRANSLATORS: this is the third section of description. */
+ _("For help, contact your hardware manufacturer or IT support provider."));
+ break;
+
+ case SECURE_BOOT_STATE_INACTIVE:
+ case SECURE_BOOT_STATE_UNKNOWN:
+ /* TRANSLATORS: secure boot refers to the system firmware security mode */
+ gtk_label_set_text (GTK_LABEL (dialog->secure_boot_title), _("Secure Boot is Turned Off"));
+ gtk_widget_add_css_class (dialog->secure_boot_icon, "error");
+ status_description = g_strdup_printf ("%s\n\n%s",
+ /* TRANSLATORS: this is the first section of the description. */
+ _("Secure boot prevents malicious software from being loaded when the device starts. It is "
+ "currently turned off."),
+ /* TRANSLATORS: this is the second section of the description. */
+ _("Secure boot can often be turned on from your computer's UEFI firmware settings (BIOS). "
+ "For help, contact your hardware manufacturer or IT support provider."));
+ break;
+ }
+ gtk_label_set_text (GTK_LABEL(dialog->secure_boot_description), status_description);
+
+ return GTK_WIDGET (dialog);
+}
diff --git a/panels/firmware-security/cc-firmware-security-boot-dialog.h b/panels/firmware-security/cc-firmware-security-boot-dialog.h
new file mode 100644
index 0000000..78b7d3a
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-boot-dialog.h
@@ -0,0 +1,37 @@
+/* cc-firmware-security-boot-dialog.h
+ *
+ * Copyright (C) 2021 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Kate Hsuan <hpa@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include "cc-firmware-security-utils.h"
+
+G_BEGIN_DECLS
+
+#define CC_TYPE_FIRMWARE_SECURITY_BOOT_DIALOG (cc_firmware_security_boot_dialog_get_type ())
+G_DECLARE_FINAL_TYPE (CcFirmwareSecurityBootDialog, cc_firmware_security_boot_dialog,
+ CC, FIRMWARE_SECURITY_BOOT_DIALOG, GtkDialog)
+
+GtkWidget *cc_firmware_security_boot_dialog_new (SecureBootState secure_boot_state);
+
+G_END_DECLS
diff --git a/panels/firmware-security/cc-firmware-security-boot-dialog.ui b/panels/firmware-security/cc-firmware-security-boot-dialog.ui
new file mode 100644
index 0000000..8b8957e
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-boot-dialog.ui
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="CcFirmwareSecurityBootDialog" parent="GtkDialog">
+ <property name="use-header-bar">True</property>
+ <property name="default-width">400</property>
+ <property name="modal">True</property>
+ <child internal-child="headerbar">
+ <object class="GtkHeaderBar">
+ <property name="show_title_buttons">True</property>
+ <child type="title">
+ <object class="AdwBin" />
+ </child>
+ <style>
+ <class name="flat" />
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <property name="margin-start">32</property>
+ <property name="margin-end">32</property>
+ <property name="margin-bottom">32</property>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <property name="spacing">16</property>
+ <child>
+ <object class="GtkImage" id="secure_boot_icon">
+ <property name="pixel-size">32</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="icon-name">channel-insecure</property>
+ <style>
+ <class name="security-level-icon"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="secure_boot_title">
+ <property name="wrap">True</property>
+ <style>
+ <class name="title-2" />
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="secure_boot_description">
+ <property name="wrap">True</property>
+ <property name="width-chars">40</property>
+ <property name="max-width-chars">40</property>
+ <property name="justify">left</property>
+ <property name="label" translatable="yes">Secure boot prevents malicious software from being loaded when the device starts.
+
+For more information, contact the hardware manufacturer or IT support.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/panels/firmware-security/cc-firmware-security-dialog.c b/panels/firmware-security/cc-firmware-security-dialog.c
new file mode 100644
index 0000000..2109aa5
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-dialog.c
@@ -0,0 +1,442 @@
+/* cc-firmware-security-dialog.c
+ *
+ * Copyright (C) 2021 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Kate Hsuan <hpa@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+
+#include "cc-firmware-security-panel.h"
+#include "cc-firmware-security-dialog.h"
+#include "cc-firmware-security-utils.h"
+
+struct _CcFirmwareSecurityDialog
+{
+ AdwWindow parent;
+
+ GtkWidget *dialog_hsi_circle_box;
+ GtkWidget *dialog_hsi_circle_number;
+
+ GtkWidget *hsi1_icon;
+ GtkWidget *hsi2_icon;
+ GtkWidget *hsi3_icon;
+ GtkWidget *hsi1_title;
+ GtkWidget *hsi2_title;
+ GtkWidget *hsi3_title;
+
+ GtkWidget *firmware_security_dialog_title_label;
+ GtkWidget *firmware_security_dialog_body_label;
+ GtkWidget *firmware_security_dialog_min_row;
+ GtkWidget *firmware_security_dialog_basic_row;
+ GtkWidget *firmware_security_dialog_extend_row;
+ GtkWidget *firmware_security_dialog_hsi1_pg;
+ GtkWidget *firmware_security_dialog_hsi2_pg;
+ GtkWidget *firmware_security_dialog_hsi3_pg;
+ GtkWidget *firmware_security_dialog_hsi_label;
+ AdwLeaflet *leaflet;
+ AdwWindowTitle *second_page_title;
+
+ gboolean is_created;
+
+ GHashTable *hsi1_dict;
+ GHashTable *hsi2_dict;
+ GHashTable *hsi3_dict;
+ GHashTable *hsi4_dict;
+
+ guint hsi_number;
+};
+
+G_DEFINE_TYPE (CcFirmwareSecurityDialog, cc_firmware_security_dialog, ADW_TYPE_WINDOW)
+
+static void
+set_dialog_item_layer1 (CcFirmwareSecurityDialog *self,
+ const gchar *circle_str,
+ const gchar *title,
+ const gchar *body)
+{
+ g_autofree gchar *str = NULL;
+
+ gtk_label_set_label (GTK_LABEL (self->dialog_hsi_circle_number), circle_str);
+ gtk_label_set_text (GTK_LABEL (self->firmware_security_dialog_title_label), title);
+ gtk_label_set_text (GTK_LABEL (self->firmware_security_dialog_body_label), body);
+
+ if (self->hsi_number == G_MAXUINT)
+ {
+ gtk_widget_add_css_class (self->dialog_hsi_circle_box, "level1");
+ gtk_widget_add_css_class (self->dialog_hsi_circle_number, "hsi1");
+ gtk_widget_hide (self->hsi1_icon);
+ gtk_widget_hide (self->hsi2_icon);
+ gtk_widget_hide (self->hsi3_icon);
+ gtk_widget_hide (self->hsi1_title);
+ gtk_widget_hide (self->hsi2_title);
+ gtk_widget_hide (self->hsi3_title);
+ gtk_widget_hide (self->firmware_security_dialog_hsi_label);
+ return;
+ }
+
+ gtk_image_set_from_icon_name (GTK_IMAGE (self->hsi1_icon), self->hsi_number >= 1 ? "emblem-ok" : "process-stop");
+ gtk_label_set_text (GTK_LABEL (self->hsi1_title), self->hsi_number >= 1 ? _("Passed") : _("Failed"));
+ gtk_image_set_from_icon_name (GTK_IMAGE (self->hsi2_icon), self->hsi_number >= 2 ? "emblem-ok" : "process-stop");
+ gtk_label_set_text (GTK_LABEL (self->hsi2_title), self->hsi_number >= 2 ? _("Passed") : _("Failed"));
+ gtk_image_set_from_icon_name (GTK_IMAGE (self->hsi3_icon), self->hsi_number >= 3 ? "emblem-ok" : "process-stop");
+ gtk_label_set_text (GTK_LABEL (self->hsi3_title), self->hsi_number >= 3 ? _("Passed") : _("Failed"));
+
+ gtk_widget_add_css_class (self->firmware_security_dialog_min_row,
+ self->hsi_number >= 1 ? "success-hsi-icon" : "error-hsi-icon");
+ gtk_widget_add_css_class (self->firmware_security_dialog_min_row,
+ self->hsi_number >= 1 ? "success-title" : "error-title");
+ gtk_widget_add_css_class (self->firmware_security_dialog_basic_row,
+ self->hsi_number >= 2 ? "success-hsi-icon" : "error-hsi-icon");
+ gtk_widget_add_css_class (self->firmware_security_dialog_basic_row,
+ self->hsi_number >= 2 ? "success-title" : "error-title");
+ gtk_widget_add_css_class (self->firmware_security_dialog_extend_row,
+ self->hsi_number >= 3 ? "success-hsi-icon" : "error-hsi-icon");
+ gtk_widget_add_css_class (self->firmware_security_dialog_extend_row,
+ self->hsi_number >= 3 ? "success-title" : "error-title");
+
+ switch (self->hsi_number)
+ {
+ case 0:
+ gtk_widget_add_css_class (self->dialog_hsi_circle_box, "level0");
+ gtk_widget_add_css_class (self->dialog_hsi_circle_number, "hsi0");
+ break;
+ case 1:
+ gtk_widget_add_css_class (self->dialog_hsi_circle_box, "level1");
+ gtk_widget_add_css_class (self->dialog_hsi_circle_number, "hsi1");
+ break;
+ case 2:
+ gtk_widget_add_css_class (self->dialog_hsi_circle_box, "level2");
+ gtk_widget_add_css_class (self->dialog_hsi_circle_number, "hsi2");
+ break;
+ case 3:
+ case 4:
+ gtk_widget_add_css_class (self->dialog_hsi_circle_box, "level3");
+ gtk_widget_add_css_class (self->dialog_hsi_circle_number, "hsi3");
+ break;
+ }
+
+ /* TRANSLATORS: HSI stands for Host Security ID and device refers to the computer as a whole */
+ str = g_strdup_printf (_("Device conforms to HSI level %d"), self->hsi_number);
+ gtk_label_set_text (GTK_LABEL (self->firmware_security_dialog_hsi_label), str);
+}
+
+static void
+update_dialog (CcFirmwareSecurityDialog *self)
+{
+ switch (self->hsi_number)
+ {
+ case 0:
+ set_dialog_item_layer1 (self,
+ "0",
+ _("Security Level 0"),
+ _("This device has no protection against hardware security issues. This could "
+ "be because of a hardware or firmware configuration issue. It is "
+ "recommended to contact your IT support provider."));
+ break;
+
+ case 1:
+ set_dialog_item_layer1 (self,
+ "1",
+ _("Security Level 1"),
+ _("This device has minimal protection against hardware security issues. This "
+ "is the lowest device security level and only provides protection against "
+ "simple security threats."));
+ break;
+
+ case 2:
+ set_dialog_item_layer1 (self,
+ "2",
+ _("Security Level 2"),
+ _("This device has basic protection against hardware security issues. This "
+ "provides protection against some common security threats."));
+ break;
+
+ case 3:
+ case 4:
+ set_dialog_item_layer1 (self,
+ "3",
+ _("Security Level 3"),
+ _("This device has extended protection against hardware security issues. This "
+ "is the highest device security level and provides protection against "
+ "advanced security threats."));
+ break;
+
+ default:
+ set_dialog_item_layer1 (self,
+ "?",
+ _("Security Level"),
+ _("Security levels are not available for this device."));
+ }
+}
+
+static gchar *
+fu_security_attr_get_description_for_dialog (FwupdSecurityAttr *attr)
+{
+ GString *str = g_string_new (attr->description);
+
+ if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM &&
+ attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW &&
+ attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW)
+ {
+ g_string_append_printf (str, "\n\n%s %s",
+ /* TRANSLATORS: hardware manufacturer as in OEM */
+ _("Contact your hardware manufacturer for help with security updates."),
+ /* TRANSLATORS: support technician as in someone with root */
+ _("It might be possible to resolve this issue in the device’s UEFI "
+ "firmware settings, or by a support technician."));
+ }
+ else if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM &&
+ attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW)
+ {
+ g_string_append_printf (str, "\n\n%s %s",
+ /* TRANSLATORS: hardware manufacturer as in OEM */
+ _("Contact your hardware manufacturer for help with security updates."),
+ _("It might be possible to resolve this issue in the device’s UEFI firmware settings."));
+ }
+ else if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM)
+ {
+ g_string_append_printf (str, "\n\n%s",
+ /* TRANSLATORS: hardware manufacturer as in OEM */
+ _("Contact your hardware manufacturer for help with security updates."));
+ }
+ else if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW)
+ {
+ g_string_append_printf (str, "\n\n%s",
+ _("It might be possible to resolve this issue in the device’s UEFI firmware settings."));
+ }
+ else if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_OS)
+ {
+ g_string_append_printf (str, "\n\n%s",
+ /* TRANSLATORS: support technician as in someone with root */
+ _("It might be possible for a support technician to resolve this issue."));
+ }
+
+ return g_string_free (str, FALSE);
+}
+
+static GtkWidget *
+hsi_create_pg_row (const gchar *icon_name,
+ const gchar *style,
+ FwupdSecurityAttr *attr)
+{
+ GtkWidget *row;
+ GtkWidget *status_icon;
+ GtkWidget *status_label;
+ GtkWidget *actions_parent;
+ const gchar *result_str = NULL;
+
+ row = adw_expander_row_new ();
+ adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), attr->title);
+
+ result_str = fwupd_security_attr_result_to_string(attr->result);
+ if (result_str)
+ {
+ status_label = gtk_label_new (result_str);
+ if (firmware_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS))
+ status_icon = gtk_image_new_from_icon_name ("emblem-ok");
+ else
+ status_icon = gtk_image_new_from_icon_name ("process-stop");
+
+ adw_expander_row_add_action (ADW_EXPANDER_ROW (row), status_label);
+ adw_expander_row_add_action (ADW_EXPANDER_ROW (row), status_icon);
+
+ gtk_widget_add_css_class (status_icon, "icon");
+ gtk_widget_add_css_class (status_label, "hsi_label");
+
+ actions_parent = gtk_widget_get_parent (status_icon);
+ gtk_box_set_spacing (GTK_BOX (actions_parent), 6);
+ gtk_widget_set_margin_end (actions_parent, 12);
+ }
+
+ if (attr->description != NULL)
+ {
+ GtkWidget *subrow = adw_action_row_new ();
+ g_autofree gchar *str = fu_security_attr_get_description_for_dialog (attr);
+ adw_action_row_set_subtitle (ADW_ACTION_ROW (subrow), str);
+ adw_expander_row_add_row (ADW_EXPANDER_ROW (row), subrow);
+ gtk_widget_add_css_class (subrow, "security-description-row");
+ }
+ else
+ {
+ adw_expander_row_set_enable_expansion (ADW_EXPANDER_ROW (row), FALSE);
+ gtk_widget_add_css_class (row, "hide-arrow");
+ }
+
+ return row;
+}
+
+static void
+update_hsi_listbox (CcFirmwareSecurityDialog *self,
+ const gint hsi_level)
+{
+ g_autoptr (GList) hash_keys = NULL;
+ GHashTable *hsi_dict = NULL;
+ GtkWidget *pg_row;
+ GtkWidget *hsi_pg;
+
+ switch (hsi_level)
+ {
+ case 1:
+ hsi_dict = self->hsi1_dict;
+ hsi_pg = self->firmware_security_dialog_hsi1_pg;
+ break;
+ case 2:
+ hsi_dict = self->hsi2_dict;
+ hsi_pg = self->firmware_security_dialog_hsi2_pg;
+ break;
+ case 3:
+ hsi_dict = self->hsi3_dict;
+ hsi_pg = self->firmware_security_dialog_hsi3_pg;
+ break;
+ case 4:
+ hsi_dict = self->hsi4_dict;
+ hsi_pg = self->firmware_security_dialog_hsi3_pg;
+ break;
+ }
+
+ hash_keys = g_hash_table_get_keys (hsi_dict);
+ for (GList *item = g_list_first (hash_keys); item != NULL; item = g_list_next (item))
+ {
+ FwupdSecurityAttr *attr = g_hash_table_lookup (hsi_dict, item->data);
+ if (g_strcmp0 (attr->appstream_id, FWUPD_SECURITY_ATTR_ID_SUPPORTED_CPU) == 0)
+ continue;
+ if (attr->title == NULL)
+ continue;
+ if (firmware_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS))
+ {
+ pg_row = hsi_create_pg_row ("emblem-ok", "color_green", attr);
+ gtk_widget_add_css_class (pg_row, "success-icon");
+ gtk_widget_add_css_class (pg_row, "success-title");
+ }
+ else
+ {
+ pg_row = hsi_create_pg_row ("process-stop", "color_dim", attr);
+ gtk_widget_add_css_class (pg_row, "error-icon");
+ gtk_widget_add_css_class (pg_row, "error-title");
+ }
+ adw_preferences_group_add (ADW_PREFERENCES_GROUP (hsi_pg), GTK_WIDGET (pg_row));
+ }
+ self->is_created = TRUE;
+}
+
+static void
+on_hsi_clicked_cb (GtkWidget *widget,
+ CcFirmwareSecurityDialog *self)
+{
+ adw_leaflet_navigate (self->leaflet, ADW_NAVIGATION_DIRECTION_FORWARD);
+
+ if (!self->is_created)
+ {
+ update_hsi_listbox (self, 1);
+ update_hsi_listbox (self, 2);
+ update_hsi_listbox (self, 3);
+ update_hsi_listbox (self, 4);
+ self->is_created = TRUE;
+ }
+
+ if (widget == self->firmware_security_dialog_min_row)
+ {
+ adw_window_title_set_title (self->second_page_title, _("Security Level 1"));
+ gtk_widget_set_visible (self->firmware_security_dialog_hsi1_pg, TRUE);
+ }
+ else if (widget == self->firmware_security_dialog_basic_row)
+ {
+ adw_window_title_set_title (self->second_page_title, _("Security Level 2"));
+ gtk_widget_set_visible (self->firmware_security_dialog_hsi2_pg, TRUE);
+ }
+ else if (widget == self->firmware_security_dialog_extend_row)
+ {
+ adw_window_title_set_title (self->second_page_title, _("Security Level 3"));
+ gtk_widget_set_visible (self->firmware_security_dialog_hsi3_pg, TRUE);
+ }
+}
+
+static void
+on_fw_back_button_clicked_cb (GtkWidget *widget,
+ gpointer data)
+{
+ CcFirmwareSecurityDialog *self = CC_FIRMWARE_SECURITY_DIALOG (data);
+
+ adw_leaflet_navigate (self->leaflet, ADW_NAVIGATION_DIRECTION_BACK);
+
+ gtk_widget_set_visible (self->firmware_security_dialog_hsi1_pg, FALSE);
+ gtk_widget_set_visible (self->firmware_security_dialog_hsi2_pg, FALSE);
+ gtk_widget_set_visible (self->firmware_security_dialog_hsi3_pg, FALSE);
+}
+
+static void
+cc_firmware_security_dialog_class_init (CcFirmwareSecurityDialogClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/firmware-security/cc-firmware-security-dialog.ui");
+
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, dialog_hsi_circle_box);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, dialog_hsi_circle_number);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, hsi1_icon);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, hsi2_icon);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, hsi3_icon);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, hsi1_title);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, hsi2_title);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, hsi3_title);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_title_label);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_body_label);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_hsi_label);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_min_row);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_basic_row);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_extend_row);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_hsi1_pg);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_hsi2_pg);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_hsi3_pg);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, leaflet);
+ gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, second_page_title);
+
+ gtk_widget_class_bind_template_callback (widget_class, on_hsi_clicked_cb);
+ gtk_widget_class_bind_template_callback (widget_class, on_fw_back_button_clicked_cb);
+}
+
+static void
+cc_firmware_security_dialog_init (CcFirmwareSecurityDialog *dialog)
+{
+ gtk_widget_init_template (GTK_WIDGET (dialog));
+ load_custom_css ("/org/gnome/control-center/firmware-security/security-level.css");
+}
+
+GtkWidget *
+cc_firmware_security_dialog_new (guint hsi_number,
+ GHashTable *hsi1_dict,
+ GHashTable *hsi2_dict,
+ GHashTable *hsi3_dict,
+ GHashTable *hsi4_dict)
+{
+ CcFirmwareSecurityDialog *dialog;
+
+ dialog = g_object_new (CC_TYPE_FIRMWARE_SECURITY_DIALOG, NULL);
+ dialog->hsi_number = hsi_number;
+ dialog->is_created = FALSE;
+ dialog->hsi1_dict = hsi1_dict;
+ dialog->hsi2_dict = hsi2_dict;
+ dialog->hsi3_dict = hsi3_dict;
+ dialog->hsi4_dict = hsi4_dict;
+ update_dialog (dialog);
+
+ return GTK_WIDGET (dialog);
+}
diff --git a/panels/firmware-security/cc-firmware-security-dialog.h b/panels/firmware-security/cc-firmware-security-dialog.h
new file mode 100644
index 0000000..3857fb2
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-dialog.h
@@ -0,0 +1,38 @@
+/* cc-firmware-security-dialog.h
+ *
+ * Copyright (C) 2021 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Kate Hsuan <hpa@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#pragma once
+
+#include <adwaita.h>
+
+G_BEGIN_DECLS
+
+#define CC_TYPE_FIRMWARE_SECURITY_DIALOG (cc_firmware_security_dialog_get_type ())
+G_DECLARE_FINAL_TYPE (CcFirmwareSecurityDialog, cc_firmware_security_dialog, CC, FIRMWARE_SECURITY_DIALOG, AdwWindow)
+
+GtkWidget * cc_firmware_security_dialog_new (guint hsi_number,
+ GHashTable *hsi1_dict,
+ GHashTable *hsi2_dict,
+ GHashTable *hsi3_dict,
+ GHashTable *hsi4_dict);
+
+G_END_DECLS
diff --git a/panels/firmware-security/cc-firmware-security-dialog.ui b/panels/firmware-security/cc-firmware-security-dialog.ui
new file mode 100644
index 0000000..c1a3a67
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-dialog.ui
@@ -0,0 +1,271 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="CcFirmwareSecurityDialog" parent="AdwWindow">
+ <property name="default-width">500</property>
+ <property name="default-height">550</property>
+ <property name="modal">True</property>
+ <child>
+ <object class="AdwLeaflet" id="leaflet">
+ <property name="can-unfold">False</property>
+ <child>
+ <object class="AdwLeafletPage">
+ <property name="child">
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+
+ <child>
+ <object class="GtkHeaderBar">
+ <property name="valign">start</property>
+ <property name="show-title-buttons">True</property>
+ <property name="title-widget">
+ <object class="AdwWindowTitle">
+ <property name="title" translatable="yes">Security Level</property>
+ </object>
+ </property>
+ </object>
+ </child>
+
+ <child>
+ <object class="AdwPreferencesPage">
+ <property name="vexpand-set">True</property>
+
+ <child>
+ <object class="AdwPreferencesGroup">
+ <child>
+ <object class="GtkBox" id="dialog_hsi_circle_box">
+ <property name="orientation">vertical</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <child>
+ <object class="GtkLabel" id="dialog_hsi_circle_number">
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="vexpand">True</property>
+ <property name="justify">center</property>
+ <property name="label">9</property>
+ <style>
+ <class name="hsi-level-font" />
+ </style>
+ </object>
+ </child>
+ <style>
+ <class name="hsi-level-box" />
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+
+ <child>
+ <object class="AdwPreferencesGroup">
+ <child>
+ <object class="GtkLabel" id="firmware_security_dialog_title_label">
+ <style>
+ <class name="title-2" />
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+
+ <child>
+ <object class="AdwPreferencesGroup">
+ <child>
+ <object class="GtkLabel" id="firmware_security_dialog_body_label">
+ <property name="wrap">True</property>
+ <property name="justify">center</property>
+ </object>
+ </child>
+ </object>
+ </child>
+
+ <child>
+ <object class="AdwPreferencesGroup">
+ <child>
+ <object class="AdwActionRow" id="firmware_security_dialog_min_row">
+ <property name="use-underline">True</property>
+ <property name="activatable">True</property>
+ <property name="title" translatable="yes">Level 1</property>
+ <signal name="activated" handler="on_hsi_clicked_cb" swapped="no" />
+ <child>
+ <object class="GtkImage" id="hsi1_icon">
+ <property name="icon-name">process-stop</property>
+ <style>
+ <class name="hsi_icon" />
+ <class name="error-hsi-icon" />
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="hsi1_title">
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <property name="vexpand">True</property>
+ <property name="justify">left</property>
+ <property name="label">Failed</property>
+ <property name="margin-end">6</property>
+ <style>
+ <class name="hsi_label" />
+ <class name="error-title" />
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">go-next-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwActionRow" id="firmware_security_dialog_basic_row">
+ <property name="use-underline">True</property>
+ <property name="activatable">True</property>
+ <property name="title" translatable="yes">Level 2</property>
+ <signal name="activated" handler="on_hsi_clicked_cb" swapped="no" />
+ <child>
+ <object class="GtkImage" id="hsi2_icon">
+ <property name="icon-name">process-stop</property>
+ <style>
+ <class name="hsi_icon" />
+ <class name="error-hsi-icon" />
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="hsi2_title">
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <property name="vexpand">True</property>
+ <property name="justify">left</property>
+ <property name="label">Failed</property>
+ <property name="margin-end">6</property>
+ <style>
+ <class name="hsi_label" />
+ <class name="error-title" />
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">go-next-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwActionRow" id="firmware_security_dialog_extend_row">
+ <property name="use-underline">True</property>
+ <property name="activatable">True</property>
+ <property name="title" translatable="yes">Level 3</property>
+ <signal name="activated" handler="on_hsi_clicked_cb" swapped="no" />
+ <child>
+ <object class="GtkImage" id="hsi3_icon">
+ <property name="icon-name">process-stop</property>
+ <style>
+ <class name="hsi_icon" />
+ <class name="error-hsi-icon" />
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="hsi3_title">
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <property name="vexpand">True</property>
+ <property name="justify">left</property>
+ <property name="label">Failed</property>
+ <property name="margin-end">6</property>
+ <style>
+ <class name="hsi_label" />
+ <class name="error-title" />
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">go-next-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+
+ <child>
+ <object class="AdwPreferencesGroup">
+ <child>
+ <object class="GtkLabel" id="firmware_security_dialog_hsi_label">
+ <property name="label">Device conform text</property>
+ <style>
+ <class name="dim-label" />
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+
+ </object>
+ </child>
+
+ </object>
+ </property>
+ </object>
+ </child>
+
+ <child>
+ <object class="AdwLeafletPage">
+ <property name="child">
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+
+ <child>
+ <object class="GtkHeaderBar">
+ <property name="valign">start</property>
+ <property name="show-title-buttons">True</property>
+ <property name="title-widget">
+ <object class="AdwWindowTitle" id="second_page_title" />
+ </property>
+ <child>
+ <object class="GtkButton">
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="icon-name">go-previous-symbolic</property>
+ <signal name="clicked" handler="on_fw_back_button_clicked_cb" swapped="no" />
+ <style>
+ <class name="image-button" />
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+
+ <child>
+ <object class="AdwPreferencesPage">
+ <child>
+ <object class="AdwPreferencesGroup" id="firmware_security_dialog_hsi1_pg">
+ <property name="visible">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="AdwPreferencesGroup" id="firmware_security_dialog_hsi2_pg">
+ <property name="visible">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="AdwPreferencesGroup" id="firmware_security_dialog_hsi3_pg">
+ <property name="visible">False</property>
+ </object>
+ </child>
+ </object>
+ </child>
+
+ </object>
+ </property>
+ </object>
+ </child>
+
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/panels/firmware-security/cc-firmware-security-panel.c b/panels/firmware-security/cc-firmware-security-panel.c
new file mode 100644
index 0000000..d48e7ab
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-panel.c
@@ -0,0 +1,717 @@
+/* cc-firmware-security-panel.c
+ *
+ * Copyright (C) 2021 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Kate Hsuan <hpa@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "shell/cc-application.h"
+
+#include "cc-firmware-security-panel.h"
+#include "cc-firmware-security-resources.h"
+#include "cc-firmware-security-dialog.h"
+#include "cc-firmware-security-boot-dialog.h"
+#include "cc-firmware-security-utils.h"
+#include "cc-util.h"
+
+#include <gio/gdesktopappinfo.h>
+#include <glib/gi18n.h>
+
+struct _CcfirmwareSecurityPanel
+{
+ CcPanel parent_instance;
+
+ GtkButton *hsi_button;
+ GtkButton *secure_boot_button;
+
+ /* HSI button */
+ GtkWidget *hsi_grid;
+
+ GtkWidget *hsi_circle_box;
+ GtkWidget *hsi_circle_number;
+
+ GtkWidget *hsi_label;
+ GtkWidget *hsi_description;
+
+ /* secure boot button */
+ GtkWidget *secure_boot_button_grid;
+ GtkWidget *secure_boot_icon;
+ GtkWidget *secure_boot_label;
+ GtkWidget *secure_boot_description;
+
+ /* event listbox */
+ GtkWidget *firmware_security_log_listbox;
+ GtkWidget *firmware_security_log_stack;
+ GtkWidget *firmware_security_log_pgroup;
+
+ GDBusProxy *bus_proxy;
+ GDBusProxy *properties_bus_proxy;
+
+ GHashTable *hsi1_dict;
+ GHashTable *hsi2_dict;
+ GHashTable *hsi3_dict;
+ GHashTable *hsi4_dict;
+
+ guint hsi_number;
+ SecureBootState secure_boot_state;
+};
+
+CC_PANEL_REGISTER (CcfirmwareSecurityPanel, cc_firmware_security_panel)
+
+static void
+set_hsi_button_view (CcfirmwareSecurityPanel *self);
+
+static void
+set_secure_boot_button_view (CcfirmwareSecurityPanel *self)
+{
+ FwupdSecurityAttr *attr;
+ guint64 sb_flags = 0;
+ guint64 pk_flags = 0;
+
+ /* get HSI-1 flags if set */
+ attr = g_hash_table_lookup (self->hsi1_dict, FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT);
+ if (attr != NULL)
+ sb_flags = attr->flags;
+ attr = g_hash_table_lookup (self->hsi1_dict, FWUPD_SECURITY_ATTR_ID_UEFI_PK);
+ if (attr != NULL)
+ pk_flags = attr->flags;
+
+ /* enabled and valid */
+ if ((sb_flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS) > 0 &&
+ (pk_flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS) > 0)
+ {
+ self->secure_boot_state = SECURE_BOOT_STATE_ACTIVE;
+ }
+ else if ((sb_flags & FWUPD_SECURITY_ATTR_RESULT_ENABLED) > 0)
+ {
+ self->secure_boot_state = SECURE_BOOT_STATE_PROBLEMS;
+ }
+ else
+ {
+ self->secure_boot_state = SECURE_BOOT_STATE_INACTIVE;
+ }
+
+ /* update UI */
+ if (self->secure_boot_state == SECURE_BOOT_STATE_ACTIVE)
+ {
+ gtk_label_set_text (GTK_LABEL (self->secure_boot_label), _("Secure Boot is Active"));
+ gtk_label_set_text (GTK_LABEL (self->secure_boot_description), _("Protected against malicious software when the device starts."));
+ gtk_image_set_from_icon_name (GTK_IMAGE (self->secure_boot_icon), "channel-secure-symbolic");
+ gtk_widget_add_css_class (self->secure_boot_icon, "good");
+ }
+ else if (self->secure_boot_state == SECURE_BOOT_STATE_PROBLEMS)
+ {
+ gtk_label_set_text (GTK_LABEL (self->secure_boot_label), _("Secure Boot has Problems"));
+ gtk_label_set_text (GTK_LABEL (self->secure_boot_description), _("Some protection when the device is started."));
+ gtk_widget_add_css_class (self->secure_boot_icon, "error");
+ }
+ else
+ {
+ gtk_label_set_text (GTK_LABEL (self->secure_boot_label), _("Secure Boot is Off"));
+ gtk_label_set_text (GTK_LABEL (self->secure_boot_description), _("No protection when the device is started."));
+ gtk_widget_add_css_class (self->secure_boot_icon, "error");
+ }
+}
+
+static gchar *
+fu_security_attr_get_description_for_eventlog (FwupdSecurityAttr *attr)
+{
+ GString *str = g_string_new (attr->description);
+
+ /* nothing to do */
+ if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS)
+ return g_string_free (str, FALSE);
+
+ if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM &&
+ attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW)
+ {
+ g_string_append_printf (str, "\n\n%s",
+ /* TRANSLATORS: this is to explain an event that has already happened */
+ _("This issue could have been caused by a change in UEFI firmware "
+ "settings, an operating system configuration change, or because of "
+ "malicious software on this system."));
+ }
+ else if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW)
+ {
+ g_string_append_printf (str, "\n\n%s",
+ /* TRANSLATORS: this is to explain an event that has already happened */
+ _("This issue could have been caused by a change in the UEFI firmware "
+ "settings, or because of malicious software on this system."));
+ }
+ else if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_OS)
+ {
+ g_string_append_printf (str, "\n\n%s",
+ /* TRANSLATORS: this is to explain an event that has already happened */
+ _("This issue could have been caused by an operating system configuration "
+ "change, or because of malicious software on this system."));
+ }
+
+ return g_string_free (str, FALSE);
+}
+
+static void
+parse_event_variant_iter (CcfirmwareSecurityPanel *self,
+ GVariantIter *iter)
+{
+ g_autofree gchar *date_string = NULL;
+ g_autoptr (GDateTime) date = NULL;
+ g_autoptr (FwupdSecurityAttr) attr = fu_security_attr_new_from_variant(iter);
+ GtkWidget *row;
+
+ /* unknown to us */
+ if (attr->appstream_id == NULL || attr->title == NULL)
+ return;
+
+ /* skip events that have either been added or removed with no prior value */
+ if (attr->result == FWUPD_SECURITY_ATTR_RESULT_UNKNOWN ||
+ attr->result_fallback == FWUPD_SECURITY_ATTR_RESULT_UNKNOWN)
+ return;
+
+ /* build new row */
+ date = g_date_time_new_from_unix_local (attr->timestamp);
+ date_string = g_date_time_format (date, "\%F \%H:\%m:\%S");
+
+ row = adw_expander_row_new ();
+ if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS)
+ {
+ adw_expander_row_set_icon_name (ADW_EXPANDER_ROW (row), "emblem-ok");
+ gtk_widget_add_css_class (row, "success-icon");
+ }
+ else
+ {
+ adw_expander_row_set_icon_name (ADW_EXPANDER_ROW (row), "process-stop");
+ gtk_widget_add_css_class (row, "error-icon");
+ }
+
+ if (attr->description != NULL)
+ {
+ GtkWidget *subrow = adw_action_row_new ();
+ g_autofree gchar *str = fu_security_attr_get_description_for_eventlog (attr);
+ adw_action_row_set_subtitle (ADW_ACTION_ROW (subrow), str);
+ adw_expander_row_add_row (ADW_EXPANDER_ROW (row), subrow);
+ }
+ else
+ {
+ adw_expander_row_set_enable_expansion (ADW_EXPANDER_ROW (row), FALSE);
+ gtk_widget_add_css_class (row, "hide-arrow");
+ }
+
+ adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), attr->title);
+ adw_expander_row_set_subtitle (ADW_EXPANDER_ROW (row), date_string);
+ adw_preferences_group_add (ADW_PREFERENCES_GROUP (self->firmware_security_log_pgroup), GTK_WIDGET (row));
+
+ adw_view_stack_set_visible_child_name (ADW_VIEW_STACK (self->firmware_security_log_stack), "page2");
+}
+
+static void
+parse_variant_iter (CcfirmwareSecurityPanel *self,
+ GVariantIter *iter)
+{
+ g_autoptr (FwupdSecurityAttr) attr = fu_security_attr_new_from_variant(iter);
+ const gchar *appstream_id = attr->appstream_id;
+
+ /* invalid */
+ if (appstream_id == NULL)
+ return;
+
+ /* in fwupd <= 1.8.3 org.fwupd.hsi.Uefi.SecureBoot was incorrectly marked as HSI-0,
+ * so lower the HSI number forcefully if this attribute failed -- the correct thing
+ * to do of course is to update fwupd to a newer build */
+ if (g_strcmp0 (attr->appstream_id, FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT) == 0 &&
+ (attr->flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS) == 0)
+ {
+ self->hsi_number = 0;
+ set_hsi_button_view (self);
+ }
+
+ /* insert into correct hash table */
+ switch (attr->hsi_level)
+ {
+ case 1:
+ g_hash_table_insert (self->hsi1_dict,
+ g_strdup (appstream_id),
+ g_steal_pointer (&attr));
+ break;
+ case 2:
+ g_hash_table_insert (self->hsi2_dict,
+ g_strdup (appstream_id),
+ g_steal_pointer (&attr));
+ break;
+ case 3:
+ g_hash_table_insert (self->hsi3_dict,
+ g_strdup (appstream_id),
+ g_steal_pointer (&attr));
+ break;
+ case 4:
+ g_hash_table_insert (self->hsi4_dict,
+ g_strdup (appstream_id),
+ g_steal_pointer (&attr));
+ break;
+ }
+}
+
+static void
+parse_data_from_variant (CcfirmwareSecurityPanel *self,
+ GVariant *value,
+ const gboolean is_event)
+{
+ const gchar *type_string;
+ g_autoptr (GVariantIter) iter = NULL;
+
+ type_string = g_variant_get_type_string (value);
+ if (g_strcmp0 (type_string, "(a{sv})") == 0)
+ {
+ g_variant_get (value, "(a{sv})", &iter);
+ if (is_event)
+ parse_event_variant_iter (self, iter);
+ else
+ parse_variant_iter (self, iter);
+ }
+ else if (g_strcmp0 (type_string, "a{sv}") == 0)
+ {
+ g_variant_get (value, "a{sv}", &iter);
+ if (is_event)
+ parse_event_variant_iter (self, iter);
+ else
+ parse_variant_iter (self, iter);
+ }
+ else
+ {
+ g_warning ("type %s not known", type_string);
+ }
+}
+
+static void
+parse_array_from_variant (CcfirmwareSecurityPanel *self,
+ GVariant *value,
+ const gboolean is_event)
+{
+ gsize sz;
+ g_autoptr (GVariant) untuple = NULL;
+
+ untuple = g_variant_get_child_value (value, 0);
+ sz = g_variant_n_children (untuple);
+ for (guint i = 0; i < sz; i++)
+ {
+ g_autoptr (GVariant) data = NULL;
+ data = g_variant_get_child_value (untuple, i);
+ if (is_event)
+ parse_data_from_variant (self, data, TRUE);
+ else
+ parse_data_from_variant (self, data, FALSE);
+ }
+}
+
+static void
+on_bus_event_done_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ g_autoptr (GError) error = NULL;
+ g_autoptr (GVariant) val = NULL;
+ CcfirmwareSecurityPanel *self = CC_FIRMWARE_SECURITY_PANEL (user_data);
+
+ val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error);
+ if (val == NULL)
+ {
+ g_warning ("failed to get Security Attribute Event: %s", error->message);
+ return;
+ }
+
+ parse_array_from_variant (self, val, TRUE);
+}
+
+static void
+on_bus_done (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ CcfirmwareSecurityPanel *self = CC_FIRMWARE_SECURITY_PANEL (user_data);
+ g_autoptr (GError) error = NULL;
+ g_autoptr (GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error);
+ if (val == NULL)
+ {
+ CcApplication *application = CC_APPLICATION (g_application_get_default ());
+ g_warning ("failed to get Security Attribute: %s", error->message);
+ cc_shell_model_set_panel_visibility (cc_application_get_model (application),
+ "firmware-security",
+ CC_PANEL_HIDDEN);
+ set_secure_boot_button_view (self);
+ return;
+ }
+
+ parse_array_from_variant (self, val, FALSE);
+ set_secure_boot_button_view (self);
+}
+
+static void
+on_bus_ready_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ g_autoptr (GError) error = NULL;
+ CcfirmwareSecurityPanel *self = CC_FIRMWARE_SECURITY_PANEL (user_data);
+
+ self->bus_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
+ if (self->bus_proxy == NULL)
+ {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("failed to connect fwupd: %s", error->message);
+
+ return;
+ }
+
+ g_dbus_proxy_call (self->bus_proxy,
+ "GetHostSecurityAttrs",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cc_panel_get_cancellable (CC_PANEL (self)),
+ on_bus_done,
+ self);
+ g_dbus_proxy_call (self->bus_proxy,
+ "GetHostSecurityEvents",
+ g_variant_new ("(u)",
+ 100),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cc_panel_get_cancellable (CC_PANEL (self)),
+ on_bus_event_done_cb,
+ self);
+}
+
+static void
+on_hsi_button_clicked_cb (GtkWidget *widget,
+ gpointer data)
+{
+ GtkWidget *toplevel;
+ CcShell *shell;
+ GtkWidget *dialog;
+ CcfirmwareSecurityPanel *self = CC_FIRMWARE_SECURITY_PANEL (data);
+
+ dialog = cc_firmware_security_dialog_new (self->hsi_number,
+ self->hsi1_dict,
+ self->hsi2_dict,
+ self->hsi3_dict,
+ self->hsi4_dict);
+ shell = cc_panel_get_shell (CC_PANEL (self));
+ toplevel = cc_shell_get_toplevel (shell);
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (toplevel));
+ gtk_widget_show (GTK_WIDGET (dialog));
+}
+
+static void
+on_secure_boot_button_clicked_cb (GtkWidget *widget,
+ gpointer data)
+{
+ GtkWidget *toplevel;
+ CcShell *shell;
+ GtkWidget *boot_dialog;
+ CcfirmwareSecurityPanel *self = CC_FIRMWARE_SECURITY_PANEL (data);
+
+ boot_dialog = cc_firmware_security_boot_dialog_new (self->secure_boot_state);
+ shell = cc_panel_get_shell (CC_PANEL (self));
+ toplevel = cc_shell_get_toplevel (shell);
+ gtk_window_set_transient_for (GTK_WINDOW (boot_dialog), GTK_WINDOW (toplevel));
+ gtk_widget_show (boot_dialog);
+}
+
+static void
+set_hsi_button_view_contain (CcfirmwareSecurityPanel *self,
+ guint hsi_number,
+ gchar *title,
+ const gchar *description)
+{
+ switch (hsi_number)
+ {
+ case 0:
+ gtk_label_set_label (GTK_LABEL (self->hsi_circle_number), "0");
+ gtk_widget_add_css_class (self->hsi_circle_box, "level0");
+ gtk_widget_add_css_class (self->hsi_circle_number, "hsi0");
+ break;
+ case 1:
+ gtk_label_set_label (GTK_LABEL (self->hsi_circle_number), "1");
+ gtk_widget_add_css_class (self->hsi_circle_box, "level1");
+ gtk_widget_add_css_class (self->hsi_circle_number, "hsi1");
+ break;
+ case 2:
+ gtk_label_set_label (GTK_LABEL (self->hsi_circle_number), "2");
+ gtk_widget_add_css_class (self->hsi_circle_box, "level2");
+ gtk_widget_add_css_class (self->hsi_circle_number, "hsi2");
+ break;
+ case 3:
+ case 4:
+ gtk_label_set_label (GTK_LABEL (self->hsi_circle_number), "3");
+ gtk_widget_add_css_class (self->hsi_circle_box, "level3");
+ gtk_widget_add_css_class (self->hsi_circle_number, "hsi3");
+ break;
+ default:
+ gtk_label_set_label (GTK_LABEL (self->hsi_circle_number), "?");
+ gtk_widget_add_css_class (self->hsi_circle_box, "level1");
+ gtk_widget_add_css_class (self->hsi_circle_number, "hsi1");
+ break;
+ }
+
+ gtk_label_set_text (GTK_LABEL (self->hsi_label), title);
+ gtk_label_set_text (GTK_LABEL (self->hsi_description), description);
+}
+
+static void
+set_hsi_button_view (CcfirmwareSecurityPanel *self)
+{
+ switch (self->hsi_number)
+ {
+ case 0:
+ set_hsi_button_view_contain (self,
+ self->hsi_number,
+ /* TRANSLATORS: in reference to firmware protection: 0/4 stars */
+ _("Security Level 0"),
+ _("Exposed to serious security threats."));
+ break;
+ case 1:
+ set_hsi_button_view_contain (self,
+ self->hsi_number,
+ /* TRANSLATORS: in reference to firmware protection: 1/4 stars */
+ _("Security Level 1"),
+ _("Limited protection against simple security threats."));
+ break;
+ case 2:
+ set_hsi_button_view_contain (self,
+ self->hsi_number,
+ /* TRANSLATORS: in reference to firmware protection: 2/4 stars */
+ _("Security Level 2"),
+ _("Protected against common security threats."));
+ break;
+ case 3:
+ set_hsi_button_view_contain (self,
+ self->hsi_number,
+ /* TRANSLATORS: in reference to firmware protection: 3/4 stars */
+ _("Security Level 3"),
+ _("Protected against a wide range of security threats."));
+ break;
+ case 4:
+ set_hsi_button_view_contain (self,
+ /* Based on current HSI definition, the max HSI value would be 3. */
+ 3,
+ /* TRANSLATORS: in reference to firmware protection: 4/4 stars */
+ _("Comprehensive Protection"),
+ _("Protected against a wide range of security threats."));
+ break;
+ case G_MAXUINT:
+ set_hsi_button_view_contain (self,
+ self->hsi_number,
+ /* TRANSLATORS: in reference to firmware protection: ??? stars */
+ _("Security Level"),
+ _("Security levels are not available for this device."));
+ break;
+ default:
+ g_warning ("incorrect HSI number %u", self->hsi_number);
+ }
+}
+
+static void
+on_properties_bus_done_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ g_autoptr (GError) error = NULL;
+ g_autoptr (GVariant) val = NULL;
+ const gchar *hsi_str = NULL;
+ CcfirmwareSecurityPanel *self = CC_FIRMWARE_SECURITY_PANEL (user_data);
+
+ val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error);
+ if (val == NULL)
+ {
+ g_warning ("failed to get HSI number");
+ return;
+ }
+
+ /* parse value */
+ hsi_str = g_variant_get_data (val);
+ if (hsi_str != NULL && g_str_has_prefix (hsi_str, "HSI:INVALID"))
+ {
+ self->hsi_number = G_MAXUINT;
+ }
+ else if (hsi_str != NULL && g_str_has_prefix (hsi_str, "HSI:"))
+ {
+ self->hsi_number = g_ascii_strtoll (hsi_str + 4, NULL, 10);
+ }
+ set_hsi_button_view (self);
+}
+
+static void
+on_properties_bus_ready_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ CcfirmwareSecurityPanel *self = CC_FIRMWARE_SECURITY_PANEL (user_data);
+ g_autoptr (GError) error = NULL;
+
+ self->properties_bus_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
+ if (self->properties_bus_proxy == NULL)
+ {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("failed to connect fwupd: %s", error->message);
+
+ return;
+ }
+
+ g_dbus_proxy_call (self->properties_bus_proxy,
+ "Get",
+ g_variant_new ("(ss)",
+ "org.freedesktop.fwupd",
+ "HostSecurityId"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cc_panel_get_cancellable (CC_PANEL (self)),
+ on_properties_bus_done_cb,
+ self);
+}
+
+static void
+update_panel_visibility (const gchar *chassis_type)
+{
+ CcApplication *application;
+ gboolean visible = TRUE;
+
+ /* there's no point showing this */
+ if (g_strcmp0 (chassis_type, "vm") == 0 || g_strcmp0 (chassis_type, "") == 0)
+ visible = FALSE;
+ application = CC_APPLICATION (g_application_get_default ());
+ cc_shell_model_set_panel_visibility (cc_application_get_model (application),
+ "firmware-security",
+ visible ? CC_PANEL_VISIBLE : CC_PANEL_HIDDEN);
+ g_debug ("Firmware Security panel visible: %s as chassis was %s",
+ visible ? "yes" : "no",
+ chassis_type);
+}
+
+void
+cc_firmware_security_panel_static_init_func (void)
+{
+ g_autoptr(GDBusConnection) connection = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) inner = NULL;
+ g_autoptr(GVariant) variant = NULL;
+
+ connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (!connection)
+ {
+ g_warning ("system bus not available: %s", error->message);
+ return;
+ }
+ variant = g_dbus_connection_call_sync (connection,
+ "org.freedesktop.hostname1",
+ "/org/freedesktop/hostname1",
+ "org.freedesktop.DBus.Properties",
+ "Get",
+ g_variant_new ("(ss)",
+ "org.freedesktop.hostname1",
+ "Chassis"),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (!variant)
+ {
+ g_warning ("Cannot get org.freedesktop.hostname1.Chassis: %s", error->message);
+ return;
+ }
+ g_variant_get (variant, "(v)", &inner);
+ update_panel_visibility (g_variant_get_string (inner, NULL));
+}
+
+static void
+cc_firmware_security_panel_finalize (GObject *object)
+{
+ CcfirmwareSecurityPanel *self = CC_FIRMWARE_SECURITY_PANEL (object);
+
+ g_clear_pointer (&self->hsi1_dict, g_hash_table_unref);
+ g_clear_pointer (&self->hsi2_dict, g_hash_table_unref);
+ g_clear_pointer (&self->hsi3_dict, g_hash_table_unref);
+ g_clear_pointer (&self->hsi4_dict, g_hash_table_unref);
+
+ g_clear_object (&self->bus_proxy);
+ g_clear_object (&self->properties_bus_proxy);
+
+ G_OBJECT_CLASS (cc_firmware_security_panel_parent_class)->finalize (object);
+}
+
+
+static void
+cc_firmware_security_panel_class_init (CcfirmwareSecurityPanelClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = cc_firmware_security_panel_finalize;
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/firmware-security/cc-firmware-security-panel.ui");
+
+ gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, firmware_security_log_pgroup);
+ gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, firmware_security_log_stack);
+ gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, hsi_button);
+ gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, hsi_description);
+ gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, hsi_circle_box);
+ gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, hsi_circle_number);
+ gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, hsi_label);
+ gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, secure_boot_button);
+ gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, secure_boot_description);
+ gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, secure_boot_icon);
+ gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, secure_boot_label);
+
+ gtk_widget_class_bind_template_callback (widget_class, on_hsi_button_clicked_cb);
+ gtk_widget_class_bind_template_callback (widget_class, on_secure_boot_button_clicked_cb);
+}
+
+static void
+cc_firmware_security_panel_init (CcfirmwareSecurityPanel *self)
+{
+ g_resources_register (cc_firmware_security_get_resource ());
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ self->hsi1_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) fu_security_attr_free);
+ self->hsi2_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) fu_security_attr_free);
+ self->hsi3_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) fu_security_attr_free);
+ self->hsi4_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) fu_security_attr_free);
+
+ load_custom_css ("/org/gnome/control-center/firmware-security/security-level.css");
+
+ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.freedesktop.fwupd",
+ "/",
+ "org.freedesktop.DBus.Properties",
+ cc_panel_get_cancellable (CC_PANEL (self)),
+ on_properties_bus_ready_cb,
+ self);
+ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.freedesktop.fwupd",
+ "/",
+ "org.freedesktop.fwupd",
+ cc_panel_get_cancellable (CC_PANEL (self)),
+ on_bus_ready_cb,
+ self);
+}
diff --git a/panels/firmware-security/cc-firmware-security-panel.h b/panels/firmware-security/cc-firmware-security-panel.h
new file mode 100644
index 0000000..1c7a024
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-panel.h
@@ -0,0 +1,34 @@
+/* cc-firmware-security-panel.h
+ *
+ * Copyright (C) 2021 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Kate Hsuan <hpa@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#pragma once
+
+#include <shell/cc-panel.h>
+
+G_BEGIN_DECLS
+
+#define CC_TYPE_FIRMWARE_SECURITY_PANEL (cc_firmware_security_panel_get_type ())
+G_DECLARE_FINAL_TYPE (CcfirmwareSecurityPanel, cc_firmware_security_panel, CC, FIRMWARE_SECURITY_PANEL, CcPanel)
+
+void cc_firmware_security_panel_static_init_func (void);
+
+G_END_DECLS
diff --git a/panels/firmware-security/cc-firmware-security-panel.ui b/panels/firmware-security/cc-firmware-security-panel.ui
new file mode 100644
index 0000000..f975ee7
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-panel.ui
@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="CcfirmwareSecurityPanel" parent="CcPanel">
+ <child type="content">
+ <object class="AdwPreferencesPage">
+
+ <child>
+ <object class="AdwPreferencesGroup">
+
+ <child>
+ <object class="GtkBox" id="firmware_security_hbox">
+ <property name="spacing">24</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkButton" id="hsi_button">
+ <property name="receives-default">True</property>
+ <property name="sensitive">True</property>
+ <property name="vexpand-set">True</property>
+ <signal name="clicked" handler="on_hsi_button_clicked_cb" swapped="no" />
+ <style>
+ <class name="card" />
+ </style>
+ <child>
+ <object class="GtkBox" id="hsi_box">
+ <property name="orientation">vertical</property>
+ <property name="halign">fill</property>
+ <property name="valign">start</property>
+ <property name="margin-start">12</property>
+ <property name="margin-end">12</property>
+ <property name="margin-top">24</property>
+ <property name="margin-bottom">24</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkBox" id="hsi_circle_box">
+ <property name="orientation">vertical</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="margin-bottom">6</property>
+ <child>
+ <object class="GtkLabel" id="hsi_circle_number">
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="vexpand">True</property>
+ <property name="justify">center</property>
+ <property name="label">9</property>
+ <style>
+ <class name="hsi-level-font" />
+ </style>
+ </object>
+ </child>
+ <style>
+ <class name="hsi-level-box" />
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="hsi_label">
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
+ <style>
+ <class name="heading" />
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="hsi_description">
+ <property name="wrap">True</property>
+ <property name="justify">center</property>
+ <property name="ellipsize">none</property>
+ <property name="lines">2</property>
+ <style>
+ <class name="caption" />
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="secure_boot_button">
+ <property name="receives-default">True</property>
+ <signal name="clicked" handler="on_secure_boot_button_clicked_cb" swapped="no" />
+ <style>
+ <class name="card" />
+ </style>
+ <child>
+ <object class="GtkBox" id="secure_boot_box">
+ <property name="orientation">vertical</property>
+ <property name="halign">fill</property>
+ <property name="valign">start</property>
+ <property name="margin-start">12</property>
+ <property name="margin-end">12</property>
+ <property name="margin-top">24</property>
+ <property name="margin-bottom">24</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="secure_boot_icon">
+ <property name="pixel-size">32</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="icon-name">channel-insecure</property>
+ <property name="margin-bottom">6</property>
+ <style>
+ <class name="security-level-icon" />
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="secure_boot_label">
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
+ <style>
+ <class name="heading" />
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="secure_boot_description">
+ <property name="wrap">True</property>
+ <property name="justify">center</property>
+ <property name="ellipsize">none</property>
+ <property name="lines">2</property>
+ <style>
+ <class name="caption" />
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+
+ <child>
+ <object class="AdwPreferencesGroup">
+ <property name="title">Security Events</property>
+ <child>
+ <object class="AdwViewStack" id="firmware_security_log_stack">
+ <child>
+ <object class="AdwViewStackPage">
+ <property name="name">no_event</property>
+ <property name="child">
+ <object class="AdwStatusPage">
+ <property name="vexpand">True</property>
+ <property name="opacity">0.5</property>
+ <property name="title" translatable="yes">No Events</property>
+ <property name="icon-name">document-open-recent-symbolic</property>
+ <style>
+ <class name="card" />
+ <class name="compact" />
+ </style>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="AdwViewStackPage">
+ <property name="name">page2</property>
+ <property name="child">
+ <object class="AdwPreferencesGroup" id="firmware_security_log_pgroup" />
+ </property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/panels/firmware-security/cc-firmware-security-utils.c b/panels/firmware-security/cc-firmware-security-utils.c
new file mode 100644
index 0000000..f6df3ae
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-utils.c
@@ -0,0 +1,373 @@
+/* cc-firmware-security-utils.c
+ *
+ * Copyright (C) 2021 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Kate Hsuan <hpa@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+
+#include "cc-firmware-security-utils.h"
+
+/* we don't need to keep this up to date, as any new attrs added by fwupd >= 1.8.3 will also
+ * come with translated titles *and* descriptions */
+static const gchar *
+fu_security_attr_get_title_fallback (const gchar *appstream_id)
+{
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE) == 0)
+ {
+ /* TRANSLATORS: Title: firmware refers to the flash chip in the computer */
+ return _("Firmware Write Protection");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SPI_BLE) == 0)
+ {
+ /* TRANSLATORS: Title: firmware refers to the flash chip in the computer */
+ return _("Firmware Write Protection Lock");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP) == 0)
+ {
+ /* TRANSLATORS: Title: SPI refers to the flash chip in the computer */
+ return _("Firmware BIOS Region");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SPI_DESCRIPTOR) == 0)
+ {
+ /* TRANSLATORS: Title: firmware refers to the flash chip in the computer */
+ return _("Firmware BIOS Descriptor");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_PREBOOT_DMA_PROTECTION) == 0)
+ {
+ /* TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack */
+ return _("Pre-boot DMA Protection");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED) == 0)
+ {
+ /* TRANSLATORS: Title: BootGuard is a trademark from Intel */
+ return _("Intel BootGuard");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED) == 0)
+ {
+ /* TRANSLATORS: Title: BootGuard is a trademark from Intel,
+ * verified boot refers to the way the boot process is verified */
+ return _("Intel BootGuard Verified Boot");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM) == 0)
+ {
+ /* TRANSLATORS: Title: BootGuard is a trademark from Intel,
+ * ACM means to verify the integrity of Initial Boot Block */
+ return _("Intel BootGuard ACM Protected");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY) == 0)
+ {
+ /* TRANSLATORS: Title: BootGuard is a trademark from Intel,
+ * error policy is what to do on failure */
+ return _("Intel BootGuard Error Policy");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP) == 0)
+ {
+ /* TRANSLATORS: Title: BootGuard is a trademark from Intel */
+ return _("Intel BootGuard Fuse");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_CET_ENABLED) == 0)
+ {
+ /* TRANSLATORS: Title: CET = Control-flow Enforcement Technology,
+ * enabled means supported by the processor */
+ return _("Intel CET Enabled");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_CET_ACTIVE) == 0)
+ {
+ /* TRANSLATORS: Title: CET = Control-flow Enforcement Technology,
+ * active means being used by the OS */
+ return _("Intel CET Active");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_SMAP) == 0)
+ {
+ /* TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention */
+ return _("Intel SMAP");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM) == 0)
+ {
+ /* TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME */
+ return _("Encrypted RAM");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_IOMMU) == 0)
+ {
+ /* TRANSLATORS: Title:
+ * https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit */
+ return _("IOMMU Protection");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN) == 0)
+ {
+ /* TRANSLATORS: Title: lockdown is a security mode of the kernel */
+ return _("Linux Kernel Lockdown");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED) == 0)
+ {
+ /* TRANSLATORS: Title: if it's tainted or not */
+ return _("Linux Kernel Verification");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP) == 0)
+ {
+ /* TRANSLATORS: Title: swap space or swap partition */
+ return _("Linux Swap");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM) == 0)
+ {
+ /* TRANSLATORS: Title: sleep state */
+ return _("Suspend To RAM");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE) == 0)
+ {
+ /* TRANSLATORS: Title: a better sleep state */
+ return _("Suspend To Idle");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_UEFI_PK) == 0)
+ {
+ /* TRANSLATORS: Title: PK is the 'platform key' for the machine */
+ return _("UEFI Platform Key");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT) == 0)
+ {
+ /* TRANSLATORS: Title: SB is a way of locking down UEFI */
+ return _("UEFI Secure Boot");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_TPM_EMPTY_PCR) == 0)
+ {
+ /* TRANSLATORS: Title: PCRs (Platform Configuration Registers) shouldn't be empty */
+ return _("TPM Platform Configuration");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0) == 0)
+ {
+ /* TRANSLATORS: Title: the PCR is rebuilt from the TPM event log */
+ return _("TPM Reconstruction");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20) == 0)
+ {
+ /* TRANSLATORS: Title: TPM = Trusted Platform Module */
+ return _("TPM v2.0");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE) == 0)
+ {
+ /* TRANSLATORS: Title: MEI = Intel Management Engine */
+ return _("Intel Management Engine Manufacturing Mode");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP) == 0)
+ {
+ /* TRANSLATORS: Title: MEI = Intel Management Engine, and the "override" is enabled
+ * with a jumper -- luckily it is probably not accessible to end users on consumer
+ * boards */
+ return _("Intel Management Engine Override");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_VERSION) == 0)
+ {
+ /* TRANSLATORS: Title: MEI = Intel Management Engine */
+ return _("Intel Management Engine Version");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES) == 0)
+ {
+ /* TRANSLATORS: Title: if firmware updates are available */
+ return _("Firmware Updates");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION) == 0)
+ {
+ /* TRANSLATORS: Title: if we can verify the firmware checksums */
+ return _("Firmware Attestation");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS) == 0)
+ {
+ /* TRANSLATORS: Title: if the fwupd plugins are all present and correct */
+ return _("Firmware Updater Verification");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_ENABLED) == 0 ||
+ g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_LOCKED) == 0)
+ {
+ /* TRANSLATORS: Title: Allows debugging of parts using proprietary hardware */
+ return _("Platform Debugging");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SUPPORTED_CPU) == 0)
+ {
+ /* TRANSLATORS: Title: if fwupd supports HSI on this chip */
+ return _("Processor Security Checks");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_AMD_ROLLBACK_PROTECTION) == 0)
+ {
+ /* TRANSLATORS: Title: if firmware enforces rollback protection */
+ return _("AMD Rollback Protection");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_AMD_SPI_REPLAY_PROTECTION) == 0)
+ {
+ /* TRANSLATORS: Title: if hardware enforces control of SPI replays */
+ return _("AMD Firmware Replay Protection");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_AMD_SPI_WRITE_PROTECTION) == 0)
+ {
+ /* TRANSLATORS: Title: if hardware enforces control of SPI writes */
+ return _("AMD Firmware Write Protection");
+ }
+ if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_PLATFORM_FUSED) == 0)
+ {
+ /* TRANSLATORS: Title: if the part has been fused */
+ return _("Fused Platform");
+ }
+ return NULL;
+}
+
+const gchar *
+fwupd_security_attr_result_to_string (FwupdSecurityAttrResult result)
+{
+ if (result == FWUPD_SECURITY_ATTR_RESULT_VALID)
+ {
+ /* TRANSLATORS: if the stauts is valid. For example security check is valid and key is valid. */
+ return _("Valid");
+ }
+ if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_VALID)
+ {
+ /* TRANSLATORS: if the status or key is not valid. */
+ return _("Not Valid");
+ }
+ if (result == FWUPD_SECURITY_ATTR_RESULT_ENABLED)
+ {
+ /* TRANSLATORS: if the function is enabled through BIOS or OS settings. */
+ return _("Enabled");
+ }
+ if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED)
+ {
+ /* TRANSLATORS: if the function is not enabled through BIOS or OS settings. */
+ return _("Not Enabled");
+ }
+ if (result == FWUPD_SECURITY_ATTR_RESULT_LOCKED)
+ {
+ /* TRANSLATORS: the memory space or system mode is locked to prevent from malicious modification. */
+ return _("Locked");
+ }
+ if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED)
+ {
+ /* TRANSLATORS: the memory space or system mode is not locked. */
+ return _("Not Locked");
+ }
+ if (result == FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED)
+ {
+ /* TRANSLATORS: The data is encrypted to prevent from malicious reading. */
+ return _("Encrypted");
+ }
+ if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED)
+ {
+ /* TRANSLATORS: the data in memory is plane text. */
+ return _("Not Encrypted");
+ }
+ if (result == FWUPD_SECURITY_ATTR_RESULT_TAINTED)
+ {
+ /* TRANSLATORS: Linux kernel is tainted by third party kernel module. */
+ return _("Tainted");
+ }
+ if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED)
+ {
+ /* TRANSLATORS: All the loaded kernel module are licensed. */
+ return _("Not Tainted");
+ }
+ if (result == FWUPD_SECURITY_ATTR_RESULT_FOUND)
+ {
+ /* TRANSLATORS: the feature can be detected. */
+ return _("Found");
+ }
+ if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND)
+ {
+ /* TRANSLATORS: the feature can't be detected. */
+ return _("Not Found");
+ }
+ if (result == FWUPD_SECURITY_ATTR_RESULT_SUPPORTED)
+ {
+ /* TRANSLATORS: the function is supported by hardware. */
+ return _("Supported");
+ }
+ if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED)
+ {
+ /* TRANSLATORS: the function isn't supported by hardware. */
+ return _("Not Supported");
+ }
+ return NULL;
+}
+
+
+/* ->summary and ->description are translated */
+FwupdSecurityAttr *
+fu_security_attr_new_from_variant (GVariantIter *iter)
+{
+ FwupdSecurityAttr *attr = g_new0 (FwupdSecurityAttr, 1);
+ const gchar *key;
+ GVariant *value;
+
+ while (g_variant_iter_next (iter, "{&sv}", &key, &value))
+ {
+ if (g_strcmp0 (key, "AppstreamId") == 0)
+ attr->appstream_id = g_variant_dup_string (value, NULL);
+ else if (g_strcmp0 (key, "Flags") == 0)
+ attr->flags = g_variant_get_uint64(value);
+ else if (g_strcmp0 (key, "HsiLevel") == 0)
+ attr->hsi_level = g_variant_get_uint32 (value);
+ else if (g_strcmp0 (key, "HsiResult") == 0)
+ attr->result = g_variant_get_uint32 (value);
+ else if (g_strcmp0 (key, "HsiResultFallback") == 0)
+ attr->result_fallback = g_variant_get_uint32 (value);
+ else if (g_strcmp0 (key, "Created") == 0)
+ attr->timestamp = g_variant_get_uint64 (value);
+ else if (g_strcmp0 (key, "Description") == 0)
+ attr->description = g_strdup (dgettext ("fwupd", g_variant_get_string (value, NULL)));
+ else if (g_strcmp0 (key, "Summary") == 0)
+ attr->title = g_strdup (dgettext ("fwupd", g_variant_get_string (value, NULL)));
+ g_variant_unref (value);
+ }
+
+ /* in fwupd <= 1.8.3 org.fwupd.hsi.Uefi.SecureBoot was incorrectly marked as HSI-0 */
+ if (g_strcmp0 (attr->appstream_id, FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT) == 0)
+ attr->hsi_level = 1;
+
+ /* fallback for older fwupd versions */
+ if (attr->appstream_id != NULL && attr->title == NULL)
+ attr->title = g_strdup (fu_security_attr_get_title_fallback (attr->appstream_id));
+
+ /* success */
+ return attr;
+}
+
+void
+fu_security_attr_free (FwupdSecurityAttr *attr)
+{
+ g_free (attr->appstream_id);
+ g_free (attr->title);
+ g_free (attr->description);
+ g_free (attr);
+}
+
+gboolean
+firmware_security_attr_has_flag (FwupdSecurityAttr *attr,
+ FwupdSecurityAttrFlags flag)
+{
+ return (attr->flags & flag) > 0;
+}
+
+void
+load_custom_css (const char *path)
+{
+ g_autoptr (GtkCssProvider) provider = gtk_css_provider_new ();
+ gtk_css_provider_load_from_resource (provider, path);
+ gtk_style_context_add_provider_for_display (gdk_display_get_default (),
+ GTK_STYLE_PROVIDER (provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+}
diff --git a/panels/firmware-security/cc-firmware-security-utils.h b/panels/firmware-security/cc-firmware-security-utils.h
new file mode 100644
index 0000000..08343f5
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-utils.h
@@ -0,0 +1,133 @@
+/* cc-firmware-security-utils.h
+ *
+ * Copyright (C) 2021 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Kate Hsuan <hpa@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+/* we don't need to keep this up to date and from fwupd >= 1.8.3 we only need the defines
+ * for the things we actually query, e.g. FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT */
+#define FWUPD_SECURITY_ATTR_ID_ACPI_DMAR "org.fwupd.hsi.AcpiDmar"
+#define FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM "org.fwupd.hsi.EncryptedRam"
+#define FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION "org.fwupd.hsi.Fwupd.Attestation"
+#define FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS "org.fwupd.hsi.Fwupd.Plugins"
+#define FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES "org.fwupd.hsi.Fwupd.Updates"
+#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED "org.fwupd.hsi.IntelBootguard.Enabled"
+#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED "org.fwupd.hsi.IntelBootguard.Verified"
+#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM "org.fwupd.hsi.IntelBootguard.Acm"
+#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY "org.fwupd.hsi.IntelBootguard.Policy"
+#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP "org.fwupd.hsi.IntelBootguard.Otp"
+#define FWUPD_SECURITY_ATTR_ID_INTEL_CET_ENABLED "org.fwupd.hsi.IntelCet.Enabled"
+#define FWUPD_SECURITY_ATTR_ID_INTEL_CET_ACTIVE "org.fwupd.hsi.IntelCet.Active"
+#define FWUPD_SECURITY_ATTR_ID_INTEL_SMAP "org.fwupd.hsi.IntelSmap"
+#define FWUPD_SECURITY_ATTR_ID_IOMMU "org.fwupd.hsi.Iommu"
+#define FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN "org.fwupd.hsi.Kernel.Lockdown"
+#define FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP "org.fwupd.hsi.Kernel.Swap"
+#define FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED "org.fwupd.hsi.Kernel.Tainted"
+#define FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE "org.fwupd.hsi.Mei.ManufacturingMode"
+#define FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP "org.fwupd.hsi.Mei.OverrideStrap"
+#define FWUPD_SECURITY_ATTR_ID_MEI_VERSION "org.fwupd.hsi.Mei.Version"
+#define FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE "org.fwupd.hsi.Spi.Bioswe"
+#define FWUPD_SECURITY_ATTR_ID_SPI_BLE "org.fwupd.hsi.Spi.Ble"
+#define FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP "org.fwupd.hsi.Spi.SmmBwp"
+#define FWUPD_SECURITY_ATTR_ID_SPI_DESCRIPTOR "org.fwupd.hsi.Spi.Descriptor"
+#define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE "org.fwupd.hsi.SuspendToIdle"
+#define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM "org.fwupd.hsi.SuspendToRam"
+#define FWUPD_SECURITY_ATTR_ID_TPM_EMPTY_PCR "org.fwupd.hsi.Tpm.EmptyPcr"
+#define FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0 "org.fwupd.hsi.Tpm.ReconstructionPcr0"
+#define FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20 "org.fwupd.hsi.Tpm.Version20"
+#define FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT "org.fwupd.hsi.Uefi.SecureBoot"
+#define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_ENABLED "org.fwupd.hsi.IntelDci.Enabled"
+#define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_LOCKED "org.fwupd.hsi.IntelDci.Locked"
+#define FWUPD_SECURITY_ATTR_ID_UEFI_PK "org.fwupd.hsi.Uefi.Pk"
+#define FWUPD_SECURITY_ATTR_ID_PREBOOT_DMA_PROTECTION "org.fwupd.hsi.PrebootDma"
+#define FWUPD_SECURITY_ATTR_ID_SUPPORTED_CPU "org.fwupd.hsi.SupportedCpu"
+#define FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_LOCKED "org.fwupd.hsi.PlatformDebugLocked"
+#define FWUPD_SECURITY_ATTR_ID_AMD_ROLLBACK_PROTECTION "org.fwupd.hsi.Amd.RollbackProtection"
+#define FWUPD_SECURITY_ATTR_ID_AMD_SPI_WRITE_PROTECTION "org.fwupd.hsi.Amd.SpiWriteProtection"
+#define FWUPD_SECURITY_ATTR_ID_AMD_SPI_REPLAY_PROTECTION "org.fwupd.hsi.Amd.SpiReplayProtection"
+#define FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_ENABLED "org.fwupd.hsi.PlatformDebugEnabled"
+#define FWUPD_SECURITY_ATTR_ID_PLATFORM_FUSED "org.fwupd.hsi.PlatformFused"
+
+typedef enum {
+ SECURE_BOOT_STATE_UNKNOWN,
+ SECURE_BOOT_STATE_ACTIVE,
+ SECURE_BOOT_STATE_INACTIVE,
+ SECURE_BOOT_STATE_PROBLEMS,
+} SecureBootState;
+
+typedef enum {
+ FWUPD_SECURITY_ATTR_FLAG_NONE = 0,
+ FWUPD_SECURITY_ATTR_FLAG_SUCCESS = 1 << 0,
+ FWUPD_SECURITY_ATTR_FLAG_OBSOLETED = 1 << 1,
+ FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES = 1 << 8,
+ FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION = 1 << 9,
+ FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE = 1 << 10,
+ FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM = 1 << 11,
+ FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW = 1 << 12,
+ FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_OS = 1 << 13,
+} FwupdSecurityAttrFlags;
+
+typedef enum {
+ FWUPD_SECURITY_ATTR_RESULT_UNKNOWN,
+ FWUPD_SECURITY_ATTR_RESULT_ENABLED,
+ FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED,
+ FWUPD_SECURITY_ATTR_RESULT_VALID,
+ FWUPD_SECURITY_ATTR_RESULT_NOT_VALID,
+ FWUPD_SECURITY_ATTR_RESULT_LOCKED,
+ FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED,
+ FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED,
+ FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED,
+ FWUPD_SECURITY_ATTR_RESULT_TAINTED,
+ FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED,
+ FWUPD_SECURITY_ATTR_RESULT_FOUND,
+ FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND,
+ FWUPD_SECURITY_ATTR_RESULT_SUPPORTED,
+ FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED,
+ FWUPD_SECURITY_ATTR_RESULT_LAST
+} FwupdSecurityAttrResult;
+
+typedef struct {
+ FwupdSecurityAttrResult result;
+ FwupdSecurityAttrResult result_fallback;
+ FwupdSecurityAttrFlags flags;
+ guint32 hsi_level;
+ guint64 timestamp;
+ gchar *appstream_id;
+ gchar *title;
+ gchar *description;
+} FwupdSecurityAttr;
+
+FwupdSecurityAttr *fu_security_attr_new_from_variant (GVariantIter *iter);
+void fu_security_attr_free (FwupdSecurityAttr *attr);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (FwupdSecurityAttr, fu_security_attr_free)
+
+gboolean firmware_security_attr_has_flag (FwupdSecurityAttr *attr,
+ FwupdSecurityAttrFlags flag);
+void load_custom_css (const char *path);
+const gchar *fwupd_security_attr_result_to_string (FwupdSecurityAttrResult result);
+gboolean fwupd_get_result_status (FwupdSecurityAttrResult result);
+
+G_END_DECLS
diff --git a/panels/firmware-security/firmware-security.gresource.xml b/panels/firmware-security/firmware-security.gresource.xml
new file mode 100644
index 0000000..f44f6fb
--- /dev/null
+++ b/panels/firmware-security/firmware-security.gresource.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gnome/control-center/firmware-security">
+ <file preprocess="xml-stripblanks">cc-firmware-security-panel.ui</file>
+ <file preprocess="xml-stripblanks">cc-firmware-security-dialog.ui</file>
+ <file preprocess="xml-stripblanks">cc-firmware-security-boot-dialog.ui</file>
+ <file>security-level.css</file>
+ </gresource>
+</gresources>
diff --git a/panels/firmware-security/gnome-firmware-security-panel.desktop.in.in b/panels/firmware-security/gnome-firmware-security-panel.desktop.in.in
new file mode 100644
index 0000000..184ee22
--- /dev/null
+++ b/panels/firmware-security/gnome-firmware-security-panel.desktop.in.in
@@ -0,0 +1,19 @@
+[Desktop Entry]
+Name=Device Security
+Comment=Host firmware security status
+Exec=gnome-control-center firmware-security
+# FIXME
+# Translators: Do NOT translate or transliterate this text (this is an icon file name)!
+Icon=security-high-symbolic
+Terminal=false
+Type=Application
+NoDisplay=true
+StartupNotify=true
+Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-PrivacySettings;
+OnlyShowIn=GNOME;Unity;
+X-GNOME-Bugzilla-Bugzilla=GNOME
+X-GNOME-Bugzilla-Product=gnome-control-center
+X-GNOME-Bugzilla-Component=privacy
+X-GNOME-Bugzilla-Version=@VERSION@
+# Translators: Search terms to find the Privacy panel. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
+Keywords=screen;lock;diagnostics;crash;private;recent;temporary;tmp;index;name;network;identity;privacy;
diff --git a/panels/firmware-security/meson.build b/panels/firmware-security/meson.build
new file mode 100644
index 0000000..0325568
--- /dev/null
+++ b/panels/firmware-security/meson.build
@@ -0,0 +1,44 @@
+panels_list += cappletname
+desktop = 'gnome-@0@-panel.desktop'.format(cappletname)
+
+desktop_in = configure_file(
+ input: desktop + '.in.in',
+ output: desktop + '.in',
+ configuration: desktop_conf
+)
+
+i18n.merge_file(
+ type: 'desktop',
+ input: desktop_in,
+ output: desktop,
+ po_dir: po_dir,
+ install: true,
+ install_dir: control_center_desktopdir
+)
+
+sources = files('cc-firmware-security-utils.c',
+ 'cc-firmware-security-panel.c',
+ 'cc-firmware-security-dialog.c',
+ 'cc-firmware-security-boot-dialog.c')
+
+resource_data = files('cc-firmware-security-panel.ui',
+ 'cc-firmware-security-dialog.ui',
+ 'cc-firmware-security-boot-dialog.ui')
+
+sources += gnome.compile_resources(
+ 'cc-' + cappletname + '-resources',
+ cappletname + '.gresource.xml',
+ c_name: 'cc_' + cappletname.underscorify (),
+ dependencies: resource_data,
+ export: true
+)
+
+cflags += '-DGNOMELOCALEDIR="@0@"'.format(control_center_localedir)
+
+panels_libs += static_library(
+ cappletname,
+ sources: sources,
+ include_directories: [top_inc, common_inc],
+ dependencies: common_deps,
+ c_args: cflags
+)
diff --git a/panels/firmware-security/security-level.css b/panels/firmware-security/security-level.css
new file mode 100644
index 0000000..64d724f
--- /dev/null
+++ b/panels/firmware-security/security-level.css
@@ -0,0 +1,119 @@
+.hsi-level-box {
+ border-radius: 9999px;
+ min-width: 64px;
+ min-height: 64px;
+
+}
+
+.hsi-level-box.level0 {
+ background-color: alpha(@error_color, .25);
+}
+
+.hsi-level-box.level1 {
+ background-color: alpha(@light_4, .25);
+}
+
+.hsi-level-box.level2 {
+ background-color: alpha(@warning_color, .25);
+}
+
+.hsi-level-box.level3 {
+ background-color: alpha(@success_color, .25);
+}
+
+.hsi-level-font {
+ font-size: 32px;
+ font-weight: 800;
+}
+
+.hsi-level-font.hsi0 {
+ color: @error_color;
+}
+
+.hsi-level-font.hsi1 {
+ color: @light_4;
+}
+
+.hsi-level-font.hsi2 {
+ color: @warning_color;
+}
+
+.hsi-level-font.hsi3 {
+ color: @success_color;
+}
+
+.security-level-icon {
+ border-radius: 9999px;
+ min-width: 64px;
+ min-height: 64px;
+}
+
+.security-level-icon.good {
+ color: @success_color;
+ background-color: alpha(@success_color, .25);
+}
+
+.security-level-icon.error {
+ color: @error_color;
+ background-color: alpha(@error_color, .25);
+}
+
+.security-level-icon.warning {
+ color: @warning_color;
+ background-color: alpha(@warning_color, .25);
+}
+
+.security-level-icon.neutral {
+ color: @light_4;
+ background-color: alpha(@light_4, .25);
+}
+
+#color_green {
+ color: @success_color;
+}
+
+#color_dim {
+ color: @light_4f;
+}
+
+row.success-icon image.icon {
+ color: @success_color;
+}
+
+row.warning-icon image.icon {
+ color: @warning_color;
+}
+
+row.error-icon image.icon {
+ color: @error_color;
+}
+
+row.gray-icon image {
+ color: @light_4;
+}
+
+row.success-hsi-icon image.hsi_icon {
+ color: @success_color;
+}
+
+row.error-hsi-icon image.hsi_icon {
+ color: @error_color;
+}
+
+row.success-title label.hsi_label {
+ font-weight: bold;
+ color: @success_color;
+}
+
+row.error-title label.hsi_label {
+ font-weight: bold;
+ color: @error_color;
+}
+
+row.security-description-row label.subtitle {
+ padding: 12px 0;
+}
+
+row.hide-arrow image.expander-row-arrow {
+ opacity: 0;
+}