From 173acd2e07d6e1508d435708cd851a879e5b9c3d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 11 May 2020 17:11:10 +0100 Subject: [PATCH] Add FwupdSecurityAttr to libfwupd This will be used to store security attributes about platform security. --- libfwupd/fwupd-enums-private.h | 2 + libfwupd/fwupd-security-attr-private.h | 21 + libfwupd/fwupd-security-attr.c | 696 +++++++++++++++++++++++++ libfwupd/fwupd-security-attr.h | 107 ++++ libfwupd/fwupd.h | 1 + libfwupd/fwupd.map | 29 ++ libfwupd/meson.build | 5 + 7 files changed, 861 insertions(+) create mode 100644 libfwupd/fwupd-security-attr-private.h create mode 100644 libfwupd/fwupd-security-attr.c create mode 100644 libfwupd/fwupd-security-attr.h diff --git a/libfwupd/fwupd-enums-private.h b/libfwupd/fwupd-enums-private.h index 477b600cc..abb556895 100644 --- a/libfwupd/fwupd-enums-private.h +++ b/libfwupd/fwupd-enums-private.h @@ -23,6 +23,8 @@ G_BEGIN_DECLS #define FWUPD_RESULT_KEY_FLAGS "Flags" /* t */ #define FWUPD_RESULT_KEY_FLASHES_LEFT "FlashesLeft" /* u */ #define FWUPD_RESULT_KEY_URGENCY "Urgency" /* u */ +#define FWUPD_RESULT_KEY_HSI_LEVEL "HsiLevel" /* u */ +#define FWUPD_RESULT_KEY_HSI_RESULT "HsiResult" /* s */ #define FWUPD_RESULT_KEY_INSTALL_DURATION "InstallDuration" /* u */ #define FWUPD_RESULT_KEY_GUID "Guid" /* as */ #define FWUPD_RESULT_KEY_INSTANCE_IDS "InstanceIds" /* as */ diff --git a/libfwupd/fwupd-security-attr-private.h b/libfwupd/fwupd-security-attr-private.h new file mode 100644 index 000000000..6106ec1cb --- /dev/null +++ b/libfwupd/fwupd-security-attr-private.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +#include "fwupd-security-attr.h" + +G_BEGIN_DECLS + +GVariant *fwupd_security_attr_to_variant (FwupdSecurityAttr *self); +void fwupd_security_attr_to_json (FwupdSecurityAttr *self, + JsonBuilder *builder); + +G_END_DECLS + diff --git a/libfwupd/fwupd-security-attr.c b/libfwupd/fwupd-security-attr.c new file mode 100644 index 000000000..7ce33b1d3 --- /dev/null +++ b/libfwupd/fwupd-security-attr.c @@ -0,0 +1,696 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fwupd-common-private.h" +#include "fwupd-enums-private.h" +#include "fwupd-security-attr-private.h" + +/** + * SECTION:fwupd-security-attr + * + * An object that represents an Host Security ID attribute. + */ + +static void fwupd_security_attr_finalize (GObject *object); + +typedef struct { + gchar *appstream_id; + GPtrArray *obsoletes; + gchar *name; + gchar *result; + FwupdSecurityAttrLevel level; + FwupdSecurityAttrFlags flags; +} FwupdSecurityAttrPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FwupdSecurityAttr, fwupd_security_attr, G_TYPE_OBJECT) +#define GET_PRIVATE(o) (fwupd_security_attr_get_instance_private (o)) + +/** + * fwupd_security_attr_flag_to_string: + * @flag: A #FwupdSecurityAttrFlags, e.g. %FWUPD_SECURITY_ATTR_FLAG_SUCCESS + * + * Returns the printable string for the flag. + * + * Returns: string, or %NULL + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_flag_to_string (FwupdSecurityAttrFlags flag) +{ + if (flag == FWUPD_SECURITY_ATTR_FLAG_NONE) + return "none"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_SUCCESS) + return "success"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_OBSOLETED) + return "obsoleted"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES) + return "runtime-updates"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION) + return "runtime-attestation"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE) + return "runtime-issue"; + return NULL; +} + +/** + * fwupd_security_attr_flag_to_suffix: + * @flag: A #FwupdSecurityAttrFlags, e.g. %FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES + * + * Returns the string suffix for the flag. + * + * Returns: string, or %NULL + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_flag_to_suffix (FwupdSecurityAttrFlags flag) +{ + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES) + return "U"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION) + return "A"; + if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE) + return "!"; + return NULL; +} + +/** + * fwupd_security_attr_get_obsoletes: + * @self: A #FwupdSecurityAttr + * + * Gets the list of attribute obsoletes. The obsoleted attributes will not + * contribute to the calculated HSI value or be visible in command line tools. + * + * Returns: (element-type utf8) (transfer none): the obsoletes, which may be empty + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_security_attr_get_obsoletes (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + return priv->obsoletes; +} + +/** + * fwupd_security_attr_add_obsolete: + * @self: A #FwupdSecurityAttr + * @appstream_id: the appstream_id + * + * Adds an attribute appstream_id to obsolete. The obsoleted attribute will not + * contribute to the calculated HSI value or be visible in command line tools. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_add_obsolete (FwupdSecurityAttr *self, const gchar *appstream_id) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + g_return_if_fail (appstream_id != NULL); + if (fwupd_security_attr_has_obsolete (self, appstream_id)) + return; + g_ptr_array_add (priv->obsoletes, g_strdup (appstream_id)); +} + +/** + * fwupd_security_attr_has_obsolete: + * @self: A #FwupdSecurityAttr + * @appstream_id: the attribute appstream_id + * + * Finds out if the attribute obsoletes a specific appstream_id. + * + * Returns: %TRUE if the self matches + * + * Since: 1.5.0 + **/ +gboolean +fwupd_security_attr_has_obsolete (FwupdSecurityAttr *self, const gchar *appstream_id) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), FALSE); + g_return_val_if_fail (appstream_id != NULL, FALSE); + for (guint i = 0; i < priv->obsoletes->len; i++) { + const gchar *obsolete_tmp = g_ptr_array_index (priv->obsoletes, i); + if (g_strcmp0 (obsolete_tmp, appstream_id) == 0) + return TRUE; + } + return FALSE; +} + +/** + * fwupd_security_attr_get_appstream_id: + * @self: A #FwupdSecurityAttr + * + * Gets the AppStream ID. + * + * Returns: the AppStream ID, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_get_appstream_id (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + return priv->appstream_id; +} + +/** + * fwupd_security_attr_set_appstream_id: + * @self: A #FwupdSecurityAttr + * @appstream_id: the AppStream component ID, e.g. `com.intel.BiosGuard` + * + * Sets the AppStream ID. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_appstream_id (FwupdSecurityAttr *self, const gchar *appstream_id) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + g_free (priv->appstream_id); + priv->appstream_id = g_strdup (appstream_id); +} + +/** + * fwupd_security_attr_get_result: + * @self: A #FwupdSecurityAttr + * + * Gets the attribute result. + * + * Returns: the attribute result, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_get_result (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + return priv->result; +} + +/** + * fwupd_security_attr_set_name: + * @self: A #FwupdSecurityAttr + * @result: the attribute one line result + * + * Sets the attribute name. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_name (FwupdSecurityAttr *self, const gchar *name) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + g_free (priv->name); + priv->name = g_strdup (name); +} + +/** + * fwupd_security_attr_set_result: + * @self: A #FwupdSecurityAttr + * @result: the attribute one line result + * + * Sets the attribute result. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_result (FwupdSecurityAttr *self, const gchar *result) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + g_free (priv->result); + priv->result = g_strdup (result); +} + +/** + * fwupd_security_attr_get_name: + * @self: A #FwupdSecurityAttr + * + * Gets the attribute name. + * + * Returns: the attribute name, or %NULL if unset + * + * Since: 1.5.0 + **/ +const gchar * +fwupd_security_attr_get_name (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + return priv->name; +} + +/** + * fwupd_security_attr_get_flags: + * @self: A #FwupdSecurityAttr + * + * Gets the self flags. + * + * Returns: the self flags, or 0 if unset + * + * Since: 1.5.0 + **/ +FwupdSecurityAttrFlags +fwupd_security_attr_get_flags (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), 0); + return priv->flags; +} + +/** + * fwupd_security_attr_set_flags: + * @self: A #FwupdSecurityAttr + * @flags: the self flags, e.g. %FWUPD_SECURITY_ATTR_FLAG_TRUSTED_PAYLOAD + * + * Sets the self flags. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_flags (FwupdSecurityAttr *self, FwupdSecurityAttrFlags flags) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + priv->flags = flags; +} + +/** + * fwupd_security_attr_add_flag: + * @self: A #FwupdSecurityAttr + * @flag: the #FwupdSecurityAttrFlags + * + * Adds a specific self flag to the self. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_add_flag (FwupdSecurityAttr *self, FwupdSecurityAttrFlags flag) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + priv->flags |= flag; +} + +/** + * fwupd_security_attr_has_flag: + * @self: A #FwupdSecurityAttr + * @flag: the #FwupdSecurityAttrFlags + * + * Finds if the self has a specific self flag. + * + * Returns: %TRUE if the flag is set + * + * Since: 1.5.0 + **/ +gboolean +fwupd_security_attr_has_flag (FwupdSecurityAttr *self, FwupdSecurityAttrFlags flag) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), FALSE); + return (priv->flags & flag) > 0; +} + +/** + * fwupd_security_attr_get_level: + * @self: A #FwupdSecurityAttr + * + * Gets the HSI level. + * + * Returns: the #FwupdSecurityAttrLevel, or %FWUPD_SECURITY_ATTR_LEVEL_NONE if unset + * + * Since: 1.5.0 + **/ +FwupdSecurityAttrLevel +fwupd_security_attr_get_level (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), 0); + return priv->level; +} + +/** + * fwupd_security_attr_set_level: + * @self: A #FwupdSecurityAttr + * @level: A #FwupdSecurityAttrLevel, e.g. %FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT + * + * Sets the HSI level. A @level of %FWUPD_SECURITY_ATTR_LEVEL_NONE is not used + * for the HSI calculation. + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_set_level (FwupdSecurityAttr *self, FwupdSecurityAttrLevel level) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + priv->level = level; +} + +/** + * fwupd_security_attr_to_variant: + * @self: A #FwupdSecurityAttr + * + * Creates a GVariant from the self data. + * + * Returns: the GVariant, or %NULL for error + * + * Since: 1.5.0 + **/ +GVariant * +fwupd_security_attr_to_variant (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + GVariantBuilder builder; + + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + if (priv->appstream_id != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_APPSTREAM_ID, + g_variant_new_string (priv->appstream_id)); + } + if (priv->name != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_NAME, + g_variant_new_string (priv->name)); + } + if (priv->result != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_HSI_RESULT, + g_variant_new_string (priv->result)); + } + if (priv->obsoletes->len > 0) { + g_autofree const gchar **strv = g_new0 (const gchar *, priv->obsoletes->len + 1); + for (guint i = 0; i < priv->obsoletes->len; i++) + strv[i] = (const gchar *) g_ptr_array_index (priv->obsoletes, i); + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_CATEGORIES, + g_variant_new_strv (strv, -1)); + } + if (priv->flags != 0) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_FLAGS, + g_variant_new_uint64 (priv->flags)); + } + if (priv->level > 0) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_HSI_LEVEL, + g_variant_new_uint32 (priv->level)); + } + return g_variant_new ("a{sv}", &builder); +} + +static void +fwupd_security_attr_from_key_value (FwupdSecurityAttr *self, const gchar *key, GVariant *value) +{ + if (g_strcmp0 (key, FWUPD_RESULT_KEY_APPSTREAM_ID) == 0) { + fwupd_security_attr_set_appstream_id (self, g_variant_get_string (value, NULL)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_NAME) == 0) { + fwupd_security_attr_set_name (self, g_variant_get_string (value, NULL)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_HSI_RESULT) == 0) { + fwupd_security_attr_set_result (self, g_variant_get_string (value, NULL)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_FLAGS) == 0) { + fwupd_security_attr_set_flags (self, g_variant_get_uint64 (value)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_HSI_LEVEL) == 0) { + fwupd_security_attr_set_level (self, g_variant_get_uint32 (value)); + return; + } +} + +static void +fwupd_pad_kv_str (GString *str, const gchar *key, const gchar *value) +{ + /* ignore */ + if (key == NULL || value == NULL) + return; + g_string_append_printf (str, " %s: ", key); + for (gsize i = strlen (key); i < 20; i++) + g_string_append (str, " "); + g_string_append_printf (str, "%s\n", value); +} + +static void +fwupd_pad_kv_tfl (GString *str, const gchar *key, FwupdSecurityAttrFlags security_attr_flags) +{ + g_autoptr(GString) tmp = g_string_new (""); + for (guint i = 0; i < 64; i++) { + if ((security_attr_flags & ((guint64) 1 << i)) == 0) + continue; + g_string_append_printf (tmp, "%s|", + fwupd_security_attr_flag_to_string ((guint64) 1 << i)); + } + if (tmp->len == 0) { + g_string_append (tmp, fwupd_security_attr_flag_to_string (0)); + } else { + g_string_truncate (tmp, tmp->len - 1); + } + fwupd_pad_kv_str (str, key, tmp->str); +} + +static void +fwupd_pad_kv_int (GString *str, const gchar *key, guint32 value) +{ + g_autofree gchar *tmp = NULL; + + /* ignore */ + if (value == 0) + return; + tmp = g_strdup_printf("%" G_GUINT32_FORMAT, value); + fwupd_pad_kv_str (str, key, tmp); +} + +static void +fwupd_security_attr_json_add_string (JsonBuilder *builder, const gchar *key, const gchar *str) +{ + if (str == NULL) + return; + json_builder_set_member_name (builder, key); + json_builder_add_string_value (builder, str); +} + +static void +fwupd_security_attr_json_add_int (JsonBuilder *builder, const gchar *key, guint64 num) +{ + if (num == 0) + return; + json_builder_set_member_name (builder, key); + json_builder_add_int_value (builder, num); +} + +/** + * fwupd_security_attr_to_json: + * @self: A #FwupdSecurityAttr + * @builder: A #JsonBuilder + * + * Adds a fwupd self to a JSON builder + * + * Since: 1.5.0 + **/ +void +fwupd_security_attr_to_json (FwupdSecurityAttr *self, JsonBuilder *builder) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + g_autoptr(GList) keys = NULL; + + g_return_if_fail (FWUPD_IS_SECURITY_ATTR (self)); + g_return_if_fail (builder != NULL); + + fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->appstream_id); + fwupd_security_attr_json_add_int (builder, FWUPD_RESULT_KEY_HSI_LEVEL, priv->level); + fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_NAME, priv->name); + fwupd_security_attr_json_add_string (builder, FWUPD_RESULT_KEY_HSI_RESULT, priv->result); + if (priv->flags != FWUPD_SECURITY_ATTR_FLAG_NONE) { + json_builder_set_member_name (builder, FWUPD_RESULT_KEY_FLAGS); + json_builder_begin_array (builder); + for (guint i = 0; i < 64; i++) { + const gchar *tmp; + if ((priv->flags & ((guint64) 1 << i)) == 0) + continue; + tmp = fwupd_security_attr_flag_to_string ((guint64) 1 << i); + json_builder_add_string_value (builder, tmp); + } + json_builder_end_array (builder); + } +} + +/** + * fwupd_security_attr_to_string: + * @self: A #FwupdSecurityAttr + * + * Builds a text representation of the object. + * + * Returns: text, or %NULL for invalid + * + * Since: 1.5.0 + **/ +gchar * +fwupd_security_attr_to_string (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + GString *str; + g_autoptr(GList) keys = NULL; + + g_return_val_if_fail (FWUPD_IS_SECURITY_ATTR (self), NULL); + + str = g_string_new (""); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->appstream_id); + fwupd_pad_kv_int (str, FWUPD_RESULT_KEY_HSI_LEVEL, priv->level); + if (priv->flags != FWUPD_SECURITY_ATTR_FLAG_NONE) + fwupd_pad_kv_tfl (str, FWUPD_RESULT_KEY_FLAGS, priv->flags); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_NAME, priv->name); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_HSI_RESULT, priv->result); + for (guint i = 0; i < priv->obsoletes->len; i++) { + const gchar *appstream_id = g_ptr_array_index (priv->obsoletes, i); + fwupd_pad_kv_str (str, "Obsolete", appstream_id); + } + + return g_string_free (str, FALSE); +} + +static void +fwupd_security_attr_class_init (FwupdSecurityAttrClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fwupd_security_attr_finalize; +} + +static void +fwupd_security_attr_init (FwupdSecurityAttr *self) +{ + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + priv->obsoletes = g_ptr_array_new_with_free_func (g_free); +} + +static void +fwupd_security_attr_finalize (GObject *object) +{ + FwupdSecurityAttr *self = FWUPD_SECURITY_ATTR (object); + FwupdSecurityAttrPrivate *priv = GET_PRIVATE (self); + + g_free (priv->appstream_id); + g_free (priv->name); + g_free (priv->result); + g_ptr_array_unref (priv->obsoletes); + + G_OBJECT_CLASS (fwupd_security_attr_parent_class)->finalize (object); +} + +static void +fwupd_security_attr_set_from_variant_iter (FwupdSecurityAttr *self, GVariantIter *iter) +{ + GVariant *value; + const gchar *key; + while (g_variant_iter_next (iter, "{&sv}", &key, &value)) { + fwupd_security_attr_from_key_value (self, key, value); + g_variant_unref (value); + } +} + +/** + * fwupd_security_attr_from_variant: + * @value: a #GVariant + * + * Creates a new self using packed data. + * + * Returns: (transfer full): a new #FwupdSecurityAttr, or %NULL if @value was invalid + * + * Since: 1.5.0 + **/ +FwupdSecurityAttr * +fwupd_security_attr_from_variant (GVariant *value) +{ + FwupdSecurityAttr *rel = NULL; + 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) { + rel = fwupd_security_attr_new (NULL); + g_variant_get (value, "(a{sv})", &iter); + fwupd_security_attr_set_from_variant_iter (rel, iter); + } else if (g_strcmp0 (type_string, "a{sv}") == 0) { + rel = fwupd_security_attr_new (NULL); + g_variant_get (value, "a{sv}", &iter); + fwupd_security_attr_set_from_variant_iter (rel, iter); + } else { + g_warning ("type %s not known", type_string); + } + return rel; +} + +/** + * fwupd_security_attr_array_from_variant: + * @value: a #GVariant + * + * Creates an array of new security_attrs using packed data. + * + * Returns: (transfer container) (element-type FwupdSecurityAttr): attributes, or %NULL if @value was invalid + * + * Since: 1.5.0 + **/ +GPtrArray * +fwupd_security_attr_array_from_variant (GVariant *value) +{ + GPtrArray *array = NULL; + gsize sz; + g_autoptr(GVariant) untuple = NULL; + + array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + untuple = g_variant_get_child_value (value, 0); + sz = g_variant_n_children (untuple); + for (guint i = 0; i < sz; i++) { + FwupdSecurityAttr *rel; + g_autoptr(GVariant) data = NULL; + data = g_variant_get_child_value (untuple, i); + rel = fwupd_security_attr_from_variant (data); + if (rel == NULL) + continue; + g_ptr_array_add (array, rel); + } + return array; +} + +/** + * fwupd_security_attr_new: + * @appstream_id: (allow-none): the AppStream component ID, e.g. `com.intel.BiosGuard` + * + * Creates a new self. + * + * Returns: a new #FwupdSecurityAttr + * + * Since: 1.5.0 + **/ +FwupdSecurityAttr * +fwupd_security_attr_new (const gchar *appstream_id) +{ + FwupdSecurityAttr *self; + self = g_object_new (FWUPD_TYPE_SECURITY_ATTR, NULL); + if (appstream_id != NULL) + fwupd_security_attr_set_appstream_id (self, appstream_id); + return FWUPD_SECURITY_ATTR (self); +} diff --git a/libfwupd/fwupd-security-attr.h b/libfwupd/fwupd-security-attr.h new file mode 100644 index 000000000..089b56e70 --- /dev/null +++ b/libfwupd/fwupd-security-attr.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fwupd-enums.h" + +G_BEGIN_DECLS + +#define FWUPD_TYPE_SECURITY_ATTR (fwupd_security_attr_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FwupdSecurityAttr, fwupd_security_attr, FWUPD, SECURITY_ATTR, GObject) + +struct _FwupdSecurityAttrClass +{ + GObjectClass parent_class; + /*< private >*/ + void (*_fwupd_reserved1) (void); + void (*_fwupd_reserved2) (void); + void (*_fwupd_reserved3) (void); + void (*_fwupd_reserved4) (void); + void (*_fwupd_reserved5) (void); + void (*_fwupd_reserved6) (void); + void (*_fwupd_reserved7) (void); +}; + + +/** + * FwupdSecurityAttrFlags: + * @FWUPD_SECURITY_ATTR_FLAG_NONE: No flags set + * @FWUPD_SECURITY_ATTR_FLAG_SUCCESS: Success + * @FWUPD_SECURITY_ATTR_FLAG_OBSOLETED: Obsoleted by another attribute + * @FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES: Suffix `U` + * @FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION: Suffix `A` + * @FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE: Suffix `!` + * + * The flags available for HSI attributes. + **/ +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; + +/** + * FwupdSecurityAttrLevel: + * @FWUPD_SECURITY_ATTR_LEVEL_NONE: Very few detected firmware protections + * @FWUPD_SECURITY_ATTR_LEVEL_CRITICAL: The most basic of security protections + * @FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT: Firmware security issues considered important + * @FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL: Firmware security issues that pose a theoretical concern + * @FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION: Out-of-band protection of the system firmware + * @FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_ATTESTATION: Out-of-band attestation of the system firmware + * + * The HSI level. + **/ +typedef enum { + FWUPD_SECURITY_ATTR_LEVEL_NONE = 0, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_LEVEL_CRITICAL = 1, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT = 2, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL = 3, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION = 4, /* Since: 1.5.0 */ + FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_ATTESTATION = 5, /* Since: 1.5.0 */ + /*< private >*/ + FWUPD_SECURITY_ATTR_LEVEL_LAST = 6 /* perhaps increased in the future */ +} FwupdSecurityAttrLevel; + +FwupdSecurityAttr *fwupd_security_attr_new (const gchar *appstream_id); +gchar *fwupd_security_attr_to_string (FwupdSecurityAttr *self); + +const gchar *fwupd_security_attr_get_appstream_id (FwupdSecurityAttr *self); +void fwupd_security_attr_set_appstream_id (FwupdSecurityAttr *self, + const gchar *appstream_id); +FwupdSecurityAttrLevel fwupd_security_attr_get_level (FwupdSecurityAttr *self); +void fwupd_security_attr_set_level (FwupdSecurityAttr *self, + FwupdSecurityAttrLevel level); +const gchar *fwupd_security_attr_get_name (FwupdSecurityAttr *self); +void fwupd_security_attr_set_name (FwupdSecurityAttr *self, + const gchar *name); +const gchar *fwupd_security_attr_get_result (FwupdSecurityAttr *self); +void fwupd_security_attr_set_result (FwupdSecurityAttr *self, + const gchar *result); +GPtrArray *fwupd_security_attr_get_obsoletes (FwupdSecurityAttr *self); +void fwupd_security_attr_add_obsolete (FwupdSecurityAttr *self, + const gchar *appstream_id); +gboolean fwupd_security_attr_has_obsolete (FwupdSecurityAttr *self, + const gchar *appstream_id); +FwupdSecurityAttrFlags fwupd_security_attr_get_flags (FwupdSecurityAttr *self); +void fwupd_security_attr_set_flags (FwupdSecurityAttr *self, + FwupdSecurityAttrFlags flags); +void fwupd_security_attr_add_flag (FwupdSecurityAttr *self, + FwupdSecurityAttrFlags flag); +gboolean fwupd_security_attr_has_flag (FwupdSecurityAttr *self, + FwupdSecurityAttrFlags flag); +const gchar *fwupd_security_attr_flag_to_string (FwupdSecurityAttrFlags flag); +const gchar *fwupd_security_attr_flag_to_suffix (FwupdSecurityAttrFlags flag); + +FwupdSecurityAttr *fwupd_security_attr_from_variant (GVariant *value); +GPtrArray *fwupd_security_attr_array_from_variant (GVariant *value); + +G_END_DECLS diff --git a/libfwupd/fwupd.h b/libfwupd/fwupd.h index 82571aa26..149f47862 100644 --- a/libfwupd/fwupd.h +++ b/libfwupd/fwupd.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 6c2d00192..94266d11e 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -446,3 +446,32 @@ LIBFWUPD_1.4.1 { fwupd_device_id_is_valid; local: *; } LIBFWUPD_1.4.0; + +LIBFWUPD_1.5.0 { + global: + fwupd_security_attr_add_flag; + fwupd_security_attr_add_obsolete; + fwupd_security_attr_array_from_variant; + fwupd_security_attr_flag_to_string; + fwupd_security_attr_flag_to_suffix; + fwupd_security_attr_from_variant; + fwupd_security_attr_get_appstream_id; + fwupd_security_attr_get_flags; + fwupd_security_attr_get_level; + fwupd_security_attr_get_name; + fwupd_security_attr_get_obsoletes; + fwupd_security_attr_get_result; + fwupd_security_attr_get_type; + fwupd_security_attr_has_flag; + fwupd_security_attr_has_obsolete; + fwupd_security_attr_new; + fwupd_security_attr_set_appstream_id; + fwupd_security_attr_set_flags; + fwupd_security_attr_set_level; + fwupd_security_attr_set_name; + fwupd_security_attr_set_result; + fwupd_security_attr_to_json; + fwupd_security_attr_to_string; + fwupd_security_attr_to_variant; + local: *; +} LIBFWUPD_1.4.1; diff --git a/libfwupd/meson.build b/libfwupd/meson.build index 9fe6cec3f..a8772030c 100644 --- a/libfwupd/meson.build +++ b/libfwupd/meson.build @@ -21,6 +21,7 @@ install_headers([ 'fwupd-enums.h', 'fwupd-error.h', 'fwupd-remote.h', + 'fwupd-security-attr.h', 'fwupd-release.h', fwupd_version_h, ], @@ -37,6 +38,7 @@ fwupd = shared_library( 'fwupd-device.c', 'fwupd-enums.c', 'fwupd-error.c', + 'fwupd-security-attr.c', 'fwupd-release.c', 'fwupd-remote.c', ], @@ -85,6 +87,9 @@ if get_option('introspection') 'fwupd-enums-private.h', 'fwupd-error.c', 'fwupd-error.h', + 'fwupd-security-attr.c', + 'fwupd-security-attr.h', + 'fwupd-security-attr-private.h', 'fwupd-release.c', 'fwupd-release.h', 'fwupd-release-private.h',