[gnome-control-center] Add Firmware Security panel



commit 69598b9e088da2721847e1e299d18722c5bdb1df
Author: Kate Hsuan <hpa redhat com>
Date:   Tue Dec 7 18:57:13 2021 +0800

    Add Firmware Security panel
    
    The Firmware Security panel exposes the host security levels
    and details. The information is generated by fwupd. The panel
    also exposes hardware configuration changes to pinpoint the
    configuration changing time.
    
    Currently this panel shows:
    
     - HSI and secure boot status
     - Details of HSI and secure boot
     - Configuration changelog
     - Digested security level
     - Extended protection

 .../cc-firmware-security-boot-dialog.c             |  88 +++
 .../cc-firmware-security-boot-dialog.h             |  37 ++
 .../cc-firmware-security-boot-dialog.ui            |  63 +++
 .../cc-firmware-security-dialog.c                  | 310 +++++++++++
 .../cc-firmware-security-dialog.h                  |  38 ++
 .../cc-firmware-security-dialog.ui                 | 197 +++++++
 .../firmware-security/cc-firmware-security-panel.c | 587 +++++++++++++++++++++
 .../firmware-security/cc-firmware-security-panel.h |  32 ++
 .../cc-firmware-security-panel.ui                  | 164 ++++++
 .../firmware-security/cc-firmware-security-utils.c | 271 ++++++++++
 .../firmware-security/cc-firmware-security-utils.h | 109 ++++
 .../firmware-security.gresource.xml                |   9 +
 .../gnome-firmware-security-panel.desktop.in.in    |  19 +
 panels/firmware-security/meson.build               |  44 ++
 panels/firmware-security/security-level.css        |  49 ++
 panels/meson.build                                 |   1 +
 po/POTFILES.in                                     |   7 +
 shell/cc-panel-list.c                              |   1 +
 shell/cc-panel-loader.c                            |   2 +
 19 files changed, 2028 insertions(+)
---
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 000000000..9046a8b17
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-boot-dialog.c
@@ -0,0 +1,88 @@
+/* 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;
+};
+
+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);
+}
+
+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;
+
+  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_widget_add_css_class (dialog->secure_boot_icon, "good");
+      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");
+      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 Inactive"));
+      gtk_widget_add_css_class (dialog->secure_boot_icon, "error");
+      break;
+    }
+
+  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 000000000..78b7d3a86
--- /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 000000000..9530ac532
--- /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">system-reboot-symbolic</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">
+                <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 000000000..b693908d4
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-dialog.c
@@ -0,0 +1,310 @@
+/* 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           *firmware_security_dialog_icon;
+  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              *icon_name,
+                        const gchar              *style,
+                        const gchar              *title,
+                        const gchar              *body)
+{
+  g_autofree gchar *str = NULL;
+
+  /* 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_image_set_from_icon_name (GTK_IMAGE (self->firmware_security_dialog_icon), icon_name);
+  gtk_widget_add_css_class (self->firmware_security_dialog_icon, style);
+  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);
+  gtk_label_set_text (GTK_LABEL (self->firmware_security_dialog_hsi_label), str);
+}
+
+static void
+update_dialog (CcFirmwareSecurityDialog *self)
+{
+  adw_action_row_set_icon_name (ADW_ACTION_ROW (self->firmware_security_dialog_min_row), 
"dialog-error-symbolic");
+  adw_action_row_set_icon_name (ADW_ACTION_ROW (self->firmware_security_dialog_basic_row), 
"dialog-error-symbolic");
+  adw_action_row_set_icon_name (ADW_ACTION_ROW (self->firmware_security_dialog_extend_row), 
"dialog-error-symbolic");
+
+  if (self->hsi_number < 1)
+    gtk_widget_add_css_class (self->firmware_security_dialog_min_row, "gray-icon");
+  if (self->hsi_number < 2)
+    gtk_widget_add_css_class (self->firmware_security_dialog_basic_row, "gray-icon");
+  if (self->hsi_number < 3)
+    gtk_widget_add_css_class (self->firmware_security_dialog_extend_row, "gray-icon");
+
+  switch (self->hsi_number)
+    {
+    case 0:
+      set_dialog_item_layer1 (self,
+                              "dialog-warning-symbolic",
+                              "error",
+                              _("No Protection"),
+                              _("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:
+      adw_action_row_set_icon_name (ADW_ACTION_ROW (self->firmware_security_dialog_min_row),
+                                    "emblem-default-symbolic");
+      gtk_widget_add_css_class (self->firmware_security_dialog_min_row, "success-icon");
+      set_dialog_item_layer1 (self,
+                              "security-low-symbolic",
+                              "neutral",
+                              _("Minimal Protection"),
+                              _("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:
+      adw_action_row_set_icon_name (ADW_ACTION_ROW (self->firmware_security_dialog_basic_row),
+                                    "emblem-default-symbolic");
+      gtk_widget_add_css_class (self->firmware_security_dialog_basic_row, "success-icon");
+      set_dialog_item_layer1 (self,
+                              "security-medium-symbolic",
+                              "warning",
+                              _("Basic Protection"),
+                              _("This device has basic protection against hardware security issues. This "
+                                "provides protection against some common security threats."));
+      break;
+
+    case 3:
+    case 4:
+      adw_action_row_set_icon_name (ADW_ACTION_ROW (self->firmware_security_dialog_extend_row),
+                                    "emblem-default-symbolic");
+      gtk_widget_add_css_class (self->firmware_security_dialog_extend_row, "success-icon");
+      set_dialog_item_layer1 (self,
+                              "security-high-symbolic",
+                              "good",
+                              _("Extended Protection"),
+                              _("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,
+                              "dialog-warning-symbolic",
+                              "error",
+                              _("Error: unable to determine HSI level."),
+                              _("Error: unable to determine Incorrect HSI level."));
+    }
+}
+
+static GtkWidget *
+hsi_create_pg_row (const gchar *icon_name,
+                   const gchar *style,
+                   const gchar *item_name)
+{
+  GtkWidget *row;
+
+  row = adw_action_row_new ();
+  adw_action_row_set_icon_name (ADW_ACTION_ROW (row), icon_name);
+  adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), fu_security_attr_get_name (item_name));
+
+  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;
+  guint64 flags = 0;
+
+  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))
+    {
+      flags = GPOINTER_TO_INT (g_hash_table_lookup (hsi_dict, item->data));
+      if (firmware_security_attr_has_flag (flags, FWUPD_SECURITY_ATTR_FLAG_SUCCESS))
+        {
+          pg_row = hsi_create_pg_row ("emblem-default-symbolic", "color_green", item->data);
+          gtk_widget_add_css_class (pg_row, "success-icon");
+        }
+      else
+        {
+          pg_row = hsi_create_pg_row ("dialog-error-symbolic", "color_dim", item->data);
+          gtk_widget_add_css_class (pg_row, "error-icon");
+        }
+      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, _("Minimal Security Protections"));
+      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, _("Basic Security Protections"));
+      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, _("Extended Security Protections"));
+      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, 
firmware_security_dialog_icon);
+  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 000000000..3857fb2f8
--- /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 000000000..edf3317fb
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-dialog.ui
@@ -0,0 +1,197 @@
+<?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">True</property>
+
+                    <child>
+                      <object class="AdwPreferencesGroup">
+                        <child>
+                          <object class="GtkImage" id="firmware_security_dialog_icon">
+                            <property name="margin-start">16</property>
+                            <property name="margin-end">16</property>
+                            <property name="margin-top">16</property>
+                            <property name="pixel-size">32</property>
+                            <property name="halign">center</property>
+                            <property name="valign">center</property>
+                            <property name="icon-name">security-high-symbolic</property>
+                            <style>
+                              <class name="security-level-icon"/>
+                            </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">Minimal Protection</property>
+                            <property name="icon-name">emblem-default-symbolic</property>
+                            <signal name="activated" handler="on_hsi_clicked_cb" swapped="no" />
+                            <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">Basic Protection</property>
+                            <property name="icon-name">emblem-default-symbolic</property>
+                            <signal name="activated" handler="on_hsi_clicked_cb" swapped="no" />
+                            <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">Extended Protection</property>
+                            <property name="icon-name">emblem-default-symbolic</property>
+                            <signal name="activated" handler="on_hsi_clicked_cb" swapped="no" />
+                            <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 000000000..ebd152834
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-panel.c
@@ -0,0 +1,587 @@
+/* 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 "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_icon;
+  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       *hsi0_dict;
+  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_secure_boot_button_view (CcfirmwareSecurityPanel *self)
+{
+  guint64 sb_flags = 0;
+  guint64 pk_flags = 0;
+  guint64 *result;
+
+  /* get HSI-0 flags if set */
+  result = g_hash_table_lookup (self->hsi0_dict, FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT);
+  if (result != NULL)
+    sb_flags = GPOINTER_TO_INT (result);
+  result = g_hash_table_lookup (self->hsi0_dict, FWUPD_SECURITY_ATTR_ID_UEFI_PK);
+  if (result != NULL)
+    pk_flags = GPOINTER_TO_INT (result);
+
+  /* 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_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 Inactive"));
+      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 void
+parse_event_variant_iter (CcfirmwareSecurityPanel *self,
+                          GVariantIter            *iter)
+{
+  FwupdSecurityAttrResult result = 0;
+  FwupdSecurityAttrFlags flags = 0;
+  g_autofree gchar *date_string = NULL;
+  g_autoptr (GDateTime) date = NULL;
+  const gchar *appstream_id = NULL;
+  const gchar *key;
+  const gchar *event_msg;
+  guint64 timestamp = 0;
+  GVariant *value;
+  GtkWidget *row;
+
+  while (g_variant_iter_next (iter, "{&sv}", &key, &value))
+    {
+      if (g_strcmp0 (key, "AppstreamId") == 0)
+        appstream_id = g_variant_get_string (value, NULL);
+      else if (g_strcmp0 (key, "Flags") == 0)
+        flags = g_variant_get_uint64(value);
+      else if (g_strcmp0 (key, "HsiResult") == 0)
+        result = g_variant_get_uint32 (value);
+      else if (g_strcmp0 (key, "Created") == 0)
+        timestamp = g_variant_get_uint64 (value);
+      g_variant_unref (value);
+    }
+
+  /* unknown to us */
+  if (appstream_id == NULL)
+    return;
+
+  event_msg = fwupd_event_to_log (appstream_id, result);
+  if (event_msg == NULL)
+    return;
+
+  /* build new row */
+  date = g_date_time_new_from_unix_local (timestamp);
+  date_string = g_date_time_format (date, "\%F \%H:\%m:\%S");
+  row = adw_action_row_new ();
+  if (flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS)
+    {
+      adw_action_row_set_icon_name (ADW_ACTION_ROW (row), "emblem-default-symbolic");
+      gtk_widget_add_css_class (row, "success-icon");
+    }
+  else
+    {
+      adw_action_row_set_icon_name (ADW_ACTION_ROW (row), "dialog-warning-symbolic");
+      gtk_widget_add_css_class (row, "warning-icon");
+    }
+
+  adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), event_msg);
+  adw_action_row_set_subtitle (ADW_ACTION_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)
+{
+  GVariant *value;
+  const gchar *key;
+  const gchar *appstream_id = NULL;
+  guint64 flags = 0;
+  guint32 hsi_level = 0;
+
+  while (g_variant_iter_next (iter, "{&sv}", &key, &value))
+    {
+      if (g_strcmp0 (key, "AppstreamId") == 0)
+        appstream_id = g_variant_get_string (value, NULL);
+      else if (g_strcmp0 (key, "Flags") == 0)
+        flags = g_variant_get_uint64 (value);
+      else if (g_strcmp0 (key, "HsiLevel") == 0)
+        hsi_level = g_variant_get_uint32 (value);
+      g_variant_unref (value);
+    }
+
+  /* invalid */
+  if (appstream_id == NULL)
+    return;
+
+  /* insert into correct hash table */
+  switch (hsi_level)
+    {
+      case 0:
+        g_hash_table_insert (self->hsi0_dict,
+                             g_strdup (appstream_id),
+                             GINT_TO_POINTER (flags));
+        break;
+      case 1:
+        g_hash_table_insert (self->hsi1_dict,
+                             g_strdup (appstream_id),
+                             GINT_TO_POINTER (flags));
+        break;
+      case 2:
+        g_hash_table_insert (self->hsi2_dict,
+                             g_strdup (appstream_id),
+                             GINT_TO_POINTER (flags));
+        break;
+      case 3:
+        g_hash_table_insert (self->hsi3_dict,
+                             g_strdup (appstream_id),
+                             GINT_TO_POINTER (flags));
+        break;
+      case 4:
+        g_hash_table_insert (self->hsi4_dict,
+                             g_strdup (appstream_id),
+                             GINT_TO_POINTER (flags));
+        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)
+    {
+      g_warning ("failed to get Security Attribute: %s", error->message);
+      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,
+                             const gchar             *icon_name,
+                             const gchar             *style,
+                             gchar                   *title,
+                             const gchar             *description)
+{
+  gtk_image_set_from_icon_name (GTK_IMAGE (self->hsi_icon), icon_name);
+  gtk_widget_add_css_class (self->hsi_icon, style);
+  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, "dialog-warning-symbolic",
+                                     "error",
+                                     /* TRANSLATORS: in reference to firmware protection: 0/4 stars */
+                                     _("No Protection"),
+                                     _("Highly exposed to security threats."));
+        break;
+      case 1:
+        set_hsi_button_view_contain (self, "security-low-symbolic",
+                                     "neutral",
+                                     /* TRANSLATORS: in reference to firmware protection: 1/4 stars */
+                                     _("Minimal Protection"),
+                                     _("Limited protection against simple security threats."));
+        break;
+      case 2:
+        set_hsi_button_view_contain (self, "security-medium-symbolic",
+                                     "warning",
+                                     /* TRANSLATORS: in reference to firmware protection: 2/4 stars */
+                                     _("Basic Protection"),
+                                     _("Protected against common security threats."));
+        break;
+      case 3:
+        set_hsi_button_view_contain (self, "security-high-symbolic",
+                                     "good",
+                                     /* TRANSLATORS: in reference to firmware protection: 3/4 stars */
+                                     _("Extended Protection"),
+                                     _("Protected against a wide range of security threats."));
+        break;
+      case 4:
+        set_hsi_button_view_contain (self, "security-high-symbolic",
+                                     "good",
+                                     /* TRANSLATORS: in reference to firmware protection: 4/4 stars */
+                                     _("Comprehensive Protection"),
+                                     _("Protected against a wide range of security threats."));
+        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:"))
+    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
+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_icon);
+  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->hsi0_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+  self->hsi1_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+  self->hsi2_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+  self->hsi3_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+  self->hsi4_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+  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 000000000..a4afb5dc3
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-panel.h
@@ -0,0 +1,32 @@
+/* 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)
+
+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 000000000..359e39477
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-panel.ui
@@ -0,0 +1,164 @@
+<?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>
+                    <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="GtkImage" id="hsi_icon">
+                            <property name="halign">center</property>
+                            <property name="valign">center</property>
+                            <property name="icon-name">security-low-symbolic</property>
+                            <property name="pixel-size">32</property>
+                            <property name="margin-bottom">6</property>
+                            <style>
+                              <class name="security-level-icon"/>
+                            </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">system-reboot-symbolic</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 000000000..b3298a131
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-utils.c
@@ -0,0 +1,271 @@
+/* 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"
+
+const gchar *
+fu_security_attr_get_name (const gchar *appstream_id)
+{
+  struct
+  {
+    const gchar *id;
+    const gchar *name;
+  } attr_to_name[] = {
+    /* TRANSLATORS: Title: SPI refers to the flash chip in the computer */
+    { FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE, N_("SPI write"), },
+    /* TRANSLATORS: Title: SPI refers to the flash chip in the computer */
+    { FWUPD_SECURITY_ATTR_ID_SPI_BLE, N_("SPI lock"), },
+    /* TRANSLATORS: Title: SPI refers to the flash chip in the computer */
+    { FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP, N_("SPI BIOS region"), },
+    /* TRANSLATORS: Title: SPI refers to the flash chip in the computer */
+    { FWUPD_SECURITY_ATTR_ID_SPI_DESCRIPTOR, N_("SPI BIOS Descriptor"), },
+    /* TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack  */
+    { FWUPD_SECURITY_ATTR_ID_ACPI_DMAR, N_("Pre-boot DMA protection is"), },
+    /* TRANSLATORS: Title: BootGuard is a trademark from Intel */
+    { FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED, N_("Intel BootGuard"), },
+    /* TRANSLATORS: Title: BootGuard is a trademark from Intel,
+     * verified boot refers to the way the boot process is verified */
+    { FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED, N_("Intel BootGuard verified boot"), },
+    /* TRANSLATORS: Title: BootGuard is a trademark from Intel,
+     * ACM means to verify the integrity of Initial Boot Block */
+    { FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM, N_("Intel BootGuard ACM protected"), },
+    /* TRANSLATORS: Title: BootGuard is a trademark from Intel,
+     * error policy is what to do on failure */
+    { FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY, N_("Intel BootGuard error policy"), },
+    /* TRANSLATORS: Title: BootGuard is a trademark from Intel,
+     * OTP = one time programmable */
+    { FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP, N_("Intel BootGuard OTP fuse"), },
+    /* TRANSLATORS: Title: CET = Control-flow Enforcement Technology,
+     * enabled means supported by the processor */
+    { FWUPD_SECURITY_ATTR_ID_INTEL_CET_ENABLED, N_("Intel CET"), },
+    /* TRANSLATORS: Title: CET = Control-flow Enforcement Technology,
+     * active means being used by the OS */
+    { FWUPD_SECURITY_ATTR_ID_INTEL_CET_ACTIVE, N_("Intel CET Active"), },
+    /* TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention */
+    { FWUPD_SECURITY_ATTR_ID_INTEL_SMAP, N_("Intel SMAP"), },
+    /* TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME */
+    { FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM, N_("Encrypted RAM"), },
+    /* TRANSLATORS: Title:
+     * https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit */
+    { FWUPD_SECURITY_ATTR_ID_IOMMU, N_("IOMMU device protection"), },
+    /* TRANSLATORS: Title: lockdown is a security mode of the kernel */
+    { FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN, N_("Kernel lockdown"), },
+    /* TRANSLATORS: Title: if it's tainted or not */
+    { FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED, N_("Kernel tainted"), },
+    /* TRANSLATORS: Title: swap space or swap partition */
+    { FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP, N_("Linux swap"), },
+    /* TRANSLATORS: Title: sleep state */
+    { FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM, N_("Suspend-to-ram"), },
+    /* TRANSLATORS: Title: a better sleep state */
+    { FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE, N_("Suspend-to-idle"), },
+    /* TRANSLATORS: Title: PK is the 'platform key' for the machine */
+    { FWUPD_SECURITY_ATTR_ID_UEFI_PK, N_("UEFI platform key"), },
+    /* TRANSLATORS: Title: SB is a way of locking down UEFI */
+    { FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT, N_("Secure boot"), },
+    /* TRANSLATORS: Title: PCRs (Platform Configuration Registers) shouldn't be empty */
+    { FWUPD_SECURITY_ATTR_ID_TPM_EMPTY_PCR, N_("All TPM PCRs are"), },
+    /* TRANSLATORS: Title: the PCR is rebuilt from the TPM event log */
+    { FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0, N_("TPM PCR0 reconstruction"), },
+    /* TRANSLATORS: Title: TPM = Trusted Platform Module */
+    { FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20, N_("TPM v2.0"), },
+    /* TRANSLATORS: Title: MEI = Intel Management Engine */
+    { FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE, N_("MEI manufacturing mode"), },
+    /* TRANSLATORS: Title: MEI = Intel Management Engine, and the
+     * "override" is the physical PIN that can be driven to
+     * logic high -- luckily it is probably not accessible to
+     * end users on consumer boards */
+    { FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP, N_("MEI override"), },
+    /* TRANSLATORS: Title: MEI = Intel Management Engine */
+    { FWUPD_SECURITY_ATTR_ID_MEI_VERSION, N_("MEI version"), },
+    /* TRANSLATORS: Title: if firmware updates are available */
+    { FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES, N_("Firmware updates"), },
+    /* TRANSLATORS: Title: if we can verify the firmware checksums */
+    { FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION, N_("Firmware attestation"), },
+    /* TRANSLATORS: Title: if the fwupd plugins are all present and correct */
+    { FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS, N_("fwupd plugins"), },
+    /* TRANSLATORS: Title: Direct Connect Interface (DCI) allows
+     * debugging of Intel processors using the USB3 port */
+    { FWUPD_SECURITY_ATTR_ID_INTEL_DCI_ENABLED, N_("Intel DCI debugger"), },
+    { FWUPD_SECURITY_ATTR_ID_INTEL_DCI_LOCKED, N_("Intel DCI debugger"), },
+    /* TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack  */
+    { FWUPD_SECURITY_ATTR_ID_PREBOOT_DMA_PROTECTION, N_("Pre-boot DMA protection"), },
+    /* TRANSLATORS: Title: if fwupd supports HSI on this chip */
+    { FWUPD_SECURITY_ATTR_ID_SUPPORTED_CPU, N_("Supported CPU"), }
+  };
+
+  for (int i = 0; i < G_N_ELEMENTS (attr_to_name); i++)
+  {
+    if (g_strcmp0 (appstream_id, attr_to_name[i].id) == 0)
+      return _(attr_to_name[i].name);
+  }
+
+  return appstream_id;
+}
+
+gboolean
+firmware_security_attr_has_flag (guint64                flags,
+                                 FwupdSecurityAttrFlags flag)
+{
+  return (flags & flag) > 0;
+}
+
+const char *
+fwupd_event_to_log (const char              *appstream_id,
+                    FwupdSecurityAttrResult  result)
+{
+  struct
+  {
+    const gchar                 *appstream_id;
+    FwupdSecurityAttrResult      result;
+    const gchar                 *text;
+  } event_log_items[] = 
+    {
+      {
+        "org.fwupd.hsi.Iommu",
+        FWUPD_SECURITY_ATTR_RESULT_ENABLED,
+        /* TRANSLATORS: HSI event title */
+        N_("IOMMU device protection enabled")
+      },
+      {
+        "org.fwupd.hsi.Iommu",
+        FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND,
+        /* TRANSLATORS: HSI event title */
+        N_("IOMMU device protection disabled")},
+      {
+        "org.fwupd.hsi.Fwupd.Plugins",
+        FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED,
+        NULL
+      },
+      {
+        "org.fwupd.hsi.Fwupd.Plugins",
+        FWUPD_SECURITY_ATTR_RESULT_TAINTED,
+        NULL
+      },
+      {
+        "org.fwupd.hsi.Fwupd.Plugins",
+        FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED,
+        NULL
+      },
+      {
+        "org.fwupd.hsi.Kernel.Tainted",
+        FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED,
+        /* TRANSLATORS: HSI event title */
+        N_("Kernel is no longer tainted")
+      },
+      {
+        "org.fwupd.hsi.Kernel.Tainted",
+        FWUPD_SECURITY_ATTR_RESULT_TAINTED,
+        /* TRANSLATORS: HSI event title */
+        N_("Kernel is tainted")
+      },
+      {
+        "org.fwupd.hsi.Kernel.Lockdown",
+        FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED,
+        /* TRANSLATORS: HSI event title */
+        N_("Kernel lockdown disabled")
+      },
+      {
+        "org.fwupd.hsi.Kernel.Lockdown",
+        FWUPD_SECURITY_ATTR_RESULT_ENABLED,
+        /* TRANSLATORS: HSI event title */
+        N_("Kernel lockdown enabled")
+      },
+      {
+        "org.fwupd.hsi.AcpiDmar",
+        FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED,
+        /* TRANSLATORS: HSI event title */
+        N_("Pre-boot DMA protection is disabled")
+      },
+      {
+        "org.fwupd.hsi.AcpiDmar",
+        FWUPD_SECURITY_ATTR_RESULT_ENABLED,
+        /* TRANSLATORS: HSI event title */
+        N_("Pre-boot DMA protection is enabled")
+      },
+      {
+        "org.fwupd.hsi.Uefi.SecureBoot",
+        FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED,
+        /* TRANSLATORS: HSI event title */
+        N_("Secure Boot disabled")
+      },
+      {
+        "org.fwupd.hsi.Uefi.SecureBoot",
+        FWUPD_SECURITY_ATTR_RESULT_ENABLED,
+        /* TRANSLATORS: HSI event title */
+        N_("Secure Boot enabled")
+      },
+      {
+        "org.fwupd.hsi.Tpm.EmptyPcr",
+        FWUPD_SECURITY_ATTR_RESULT_VALID,
+        /* TRANSLATORS: HSI event title */
+        N_("All TPM PCRs are valid")
+      },
+      {
+        "org.fwupd.hsi.Tpm.EmptyPcr",
+        FWUPD_SECURITY_ATTR_RESULT_NOT_VALID,
+        /* TRANSLATORS: HSI event title */
+        N_("All TPM PCRs are now valid")
+      },
+      {
+        "org.fwupd.hsi.Uefi.SecureBoot",
+        FWUPD_SECURITY_ATTR_RESULT_VALID,
+        /* TRANSLATORS: HSI event title */
+        N_("A TPM PCR is now an invalid value")
+      },
+      {
+        "org.fwupd.hsi.Tpm.ReconstructionPcr0",
+        FWUPD_SECURITY_ATTR_RESULT_NOT_VALID,
+        /* TRANSLATORS: HSI event title */
+        N_("TPM PCR0 reconstruction is invalid")
+      },
+      {
+        NULL,
+        0,
+        NULL
+      }
+    };
+
+  for (int i = 0; event_log_items[i].appstream_id != NULL; i++)
+    {
+      if (g_strcmp0 (appstream_id, event_log_items[i].appstream_id) == 0 &&
+                     result == event_log_items[i].result)
+        {
+          return _(event_log_items[i].text);
+        }
+    }
+
+  return NULL;
+}
+
+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 000000000..38bfc5070
--- /dev/null
+++ b/panels/firmware-security/cc-firmware-security-utils.h
@@ -0,0 +1,109 @@
+/* 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
+
+#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"
+
+
+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,
+} 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;
+
+const gchar *fu_security_attr_get_name       (const gchar             *appstream_id);
+gboolean     firmware_security_attr_has_flag (guint64                  flags,
+                                              FwupdSecurityAttrFlags   flag);
+void         load_custom_css                 (const char              *path);
+const char  *fwupd_event_to_log              (const char              *appstream_id,
+                                              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 000000000..f44f6fbca
--- /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 000000000..184ee2252
--- /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 000000000..0325568ff
--- /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 000000000..33be08778
--- /dev/null
+++ b/panels/firmware-security/security-level.css
@@ -0,0 +1,49 @@
+.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 {
+  color: @success_color;
+}
+
+row.warning-icon image {
+  color: @warning_color;
+}
+
+row.error-icon image {
+  color: @error_color;
+}
+
+row.gray-icon image {
+  color: @light_4;
+}
diff --git a/panels/meson.build b/panels/meson.build
index 75941edcb..8d4661d2d 100644
--- a/panels/meson.build
+++ b/panels/meson.build
@@ -9,6 +9,7 @@ panels = [
   'default-apps',
   'diagnostics',
   'display',
+  'firmware-security',
   'info-overview',
   'keyboard',
   'location',
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 53e9412b4..c88b07336 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -48,6 +48,13 @@ panels/display/cc-display-settings.ui
 panels/display/cc-night-light-page.c
 panels/display/cc-night-light-page.ui
 panels/display/gnome-display-panel.desktop.in.in
+panels/firmware-security/cc-firmware-security-boot-dialog.c
+panels/firmware-security/cc-firmware-security-boot-dialog.ui
+panels/firmware-security/cc-firmware-security-dialog.c
+panels/firmware-security/cc-firmware-security-dialog.ui
+panels/firmware-security/cc-firmware-security-panel.c
+panels/firmware-security/cc-firmware-security-panel.ui
+panels/firmware-security/cc-firmware-security-utils.c
 panels/info-overview/cc-info-overview-panel.c
 panels/info-overview/cc-info-overview-panel.ui
 panels/info-overview/gnome-info-overview-panel.desktop.in.in
diff --git a/shell/cc-panel-list.c b/shell/cc-panel-list.c
index 6cbc16bbd..64bf7ae89 100644
--- a/shell/cc-panel-list.c
+++ b/shell/cc-panel-list.c
@@ -398,6 +398,7 @@ static const gchar * const panel_order[] = {
   "usage",
   "lock",
   "diagnostics",
+  "firmware-security",
 
   /* Devices page */
   "sound",
diff --git a/shell/cc-panel-loader.c b/shell/cc-panel-loader.c
index 1d2b83ac0..57b2d5bed 100644
--- a/shell/cc-panel-loader.c
+++ b/shell/cc-panel-loader.c
@@ -69,6 +69,7 @@ extern GType cc_wacom_panel_get_type (void);
 extern GType cc_wwan_panel_get_type (void);
 #endif /* BUILD_WWAN */
 extern GType cc_location_panel_get_type (void);
+extern GType cc_firmware_security_panel_get_type (void);
 extern GType cc_camera_panel_get_type (void);
 extern GType cc_microphone_panel_get_type (void);
 extern GType cc_usage_panel_get_type (void);
@@ -111,6 +112,7 @@ static CcPanelLoaderVtable default_panels[] =
   PANEL_TYPE("info-overview",    cc_info_overview_panel_get_type,        NULL),
   PANEL_TYPE("keyboard",         cc_keyboard_panel_get_type,             NULL),
   PANEL_TYPE("location",         cc_location_panel_get_type,             NULL),
+  PANEL_TYPE("firmware-security",cc_firmware_security_panel_get_type,    NULL),
   PANEL_TYPE("lock",             cc_lock_panel_get_type,                 NULL),
   PANEL_TYPE("microphone",       cc_microphone_panel_get_type,           NULL),
   PANEL_TYPE("mouse",            cc_mouse_panel_get_type,                NULL),


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]