diff --git a/contrib/ci/Dockerfile-fedora.in b/contrib/ci/Dockerfile-fedora.in index b8e18b6ec..1fd649824 100644 --- a/contrib/ci/Dockerfile-fedora.in +++ b/contrib/ci/Dockerfile-fedora.in @@ -6,6 +6,7 @@ ENV LC_ALL en_US.UTF-8 RUN echo fubar > /etc/machine-id RUN dnf -y update RUN echo fubar > /etc/machine-id +RUN dnf -y install https://kojipkgs.fedoraproject.org//packages/libjcat/0.1.0/1.fc31/x86_64/libjcat-0.1.0-1.fc31.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/libjcat/0.1.0/1.fc31/x86_64/libjcat-devel-0.1.0-1.fc31.x86_64.rpm %%%INSTALL_DEPENDENCIES_COMMAND%%% RUN dnf -y update glib2 glib2-devel --releasever=32 RUN mkdir /build diff --git a/contrib/ci/build_windows.sh b/contrib/ci/build_windows.sh index 96e8a71f9..8821d03ae 100755 --- a/contrib/ci/build_windows.sh +++ b/contrib/ci/build_windows.sh @@ -15,7 +15,6 @@ meson .. \ --libexecdir=$target \ --bindir=$target \ -Dbuild=standalone \ - -Dgpg=false \ -Dplugin_coreboot=false \ -Dplugin_flashrom=false \ -Dplugin_uefi=false \ @@ -38,6 +37,9 @@ meson .. \ -Dgcab:tests=false \ -Dlibxmlb:introspection=false \ -Dlibxmlb:gtkdoc=false \ + -Dlibjcat:man=false \ + -Dlibjcat:gpg=false \ + -Dlibjcat:introspection=false \ -Dgudev=false $@ ninja -v diff --git a/contrib/ci/debian.sh b/contrib/ci/debian.sh index 7d50eeff3..b7f62429a 100755 --- a/contrib/ci/debian.sh +++ b/contrib/ci/debian.sh @@ -44,6 +44,8 @@ lintian ../*changes \ --suppress-tags no-symbols-control-file \ --suppress-tags gzip-file-is-not-multi-arch-same-safe \ --suppress-tags binary-is-wrong-architecture \ + --suppress-tags missing-dependency-on-libc \ + --suppress-tags arch-dependent-file-not-in-arch-specific-directory \ --allow-root #if invoked outside of CI diff --git a/contrib/ci/dependencies.xml b/contrib/ci/dependencies.xml index 220b7a5a5..4c5b43375 100644 --- a/contrib/ci/dependencies.xml +++ b/contrib/ci/dependencies.xml @@ -633,6 +633,11 @@ + + + libjcat-devel + + libarchive-devel diff --git a/contrib/debian/rules b/contrib/debian/rules index d362fcd21..6a0a002ec 100755 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -46,6 +46,9 @@ override_dh_auto_configure: else \ export UEFI="-Dplugin_uefi=false -Dplugin_redfish=false -Dplugin_nvme=false"; \ fi; \ + if [ ! -z "$$CI" ]; then \ + export CI="-Dlibjcat:introspection=false $$CI"; \ + fi; \ dh_auto_configure -- $$UEFI $$DELL $$FLASHROM $$CI -Dplugin_dummy=true -Dgtkdoc=true override_dh_install: @@ -56,6 +59,16 @@ override_dh_install: if [ -d debian/tmp/usr/libexec/fwupd/efi/ ]; then \ dh_install -pfwupd usr/libexec/fwupd/efi ;\ fi + #libjcat built as a subproject for CI + if [ ! -z "$$CI" ]; then \ + dh_install -plibfwupd-dev usr/include/libjcat-1; \ + dh_install -plibfwupd2 usr/lib/*/libjcat.so.*; \ + dh_install -plibfwupd-dev usr/lib/*/libjcat.so; \ + dh_install -plibfwupd-dev usr/lib/*/pkgconfig/jcat.pc; \ + dh_install -plibfwupd-dev usr/libexec/jcat-tool; \ + dh_install -plibfwupd-dev usr/share/gir-1.0/Jcat*; \ + dh_install -pfwupd-tests usr/libexec/installed-tests/libjcat; \ + fi dh_missing -a --fail-missing #this is placed in fwupd-tests diff --git a/contrib/setup-win32.nsi b/contrib/setup-win32.nsi index 876b5efea..59a0c655e 100644 --- a/contrib/setup-win32.nsi +++ b/contrib/setup-win32.nsi @@ -60,11 +60,13 @@ Section "fwupd" # fwupd File "dfu-tool.exe" + File "jcat-tool.exe" File "fwupdtool.exe" File "libfwupd-2.dll" File "libfwupdplugin-1.dll" File "libgcab-1.0-0.dll" File "libxmlb-1.dll" + File "libjcat-1.dll" SetOutPath "$INSTDIR\fwupd-plugins-3" File /r "fwupd-plugins-3/libfu_plugin_*.dll" SetOutPath "$INSTDIR\etc\fwupd" diff --git a/data/pki/meson.build b/data/pki/meson.build index eefcc9142..94bb0b6f1 100644 --- a/data/pki/meson.build +++ b/data/pki/meson.build @@ -1,30 +1,26 @@ -if get_option('gpg') - install_data([ - 'GPG-KEY-Hughski-Limited', - 'GPG-KEY-Linux-Foundation-Firmware', - 'GPG-KEY-Linux-Vendor-Firmware-Service', - ], - install_dir : join_paths(sysconfdir, 'pki', 'fwupd') - ) +install_data([ + 'GPG-KEY-Hughski-Limited', + 'GPG-KEY-Linux-Foundation-Firmware', + 'GPG-KEY-Linux-Vendor-Firmware-Service', + ], + install_dir : join_paths(sysconfdir, 'pki', 'fwupd') +) - install_data([ - 'GPG-KEY-Linux-Foundation-Metadata', - 'GPG-KEY-Linux-Vendor-Firmware-Service', - ], - install_dir : join_paths(sysconfdir, 'pki', 'fwupd-metadata') - ) -endif +install_data([ + 'GPG-KEY-Linux-Foundation-Metadata', + 'GPG-KEY-Linux-Vendor-Firmware-Service', + ], + install_dir : join_paths(sysconfdir, 'pki', 'fwupd-metadata') +) -if get_option('pkcs7') - install_data([ - 'LVFS-CA.pem', - ], - install_dir : join_paths(sysconfdir, 'pki', 'fwupd') - ) - install_data([ - 'LVFS-CA.pem', - ], - install_dir : join_paths(sysconfdir, 'pki', 'fwupd-metadata') - ) -endif +install_data([ + 'LVFS-CA.pem', + ], + install_dir : join_paths(sysconfdir, 'pki', 'fwupd') +) +install_data([ + 'LVFS-CA.pem', + ], + install_dir : join_paths(sysconfdir, 'pki', 'fwupd-metadata') +) diff --git a/data/remotes.d/lvfs-testing.conf b/data/remotes.d/lvfs-testing.conf index bbd747301..740a793e8 100644 --- a/data/remotes.d/lvfs-testing.conf +++ b/data/remotes.d/lvfs-testing.conf @@ -3,7 +3,6 @@ # this remote provides metadata and firmware marked as 'testing' from the LVFS Enabled=false Title=Linux Vendor Firmware Service (testing) -Keyring=gpg MetadataURI=https://cdn.fwupd.org/downloads/firmware-testing.xml.gz ReportURI=https://fwupd.org/lvfs/firmware/report Username= diff --git a/data/remotes.d/lvfs.conf b/data/remotes.d/lvfs.conf index 047f94259..1249ef746 100644 --- a/data/remotes.d/lvfs.conf +++ b/data/remotes.d/lvfs.conf @@ -3,7 +3,6 @@ # this remote provides metadata and firmware marked as 'stable' from the LVFS Enabled=true Title=Linux Vendor Firmware Service -Keyring=gpg MetadataURI=https://cdn.fwupd.org/downloads/firmware.xml.gz ReportURI=https://fwupd.org/lvfs/firmware/report OrderBefore=fwupd diff --git a/data/tests/colorhug/meson.build b/data/tests/colorhug/meson.build index 7454c9fa2..5d70f8172 100644 --- a/data/tests/colorhug/meson.build +++ b/data/tests/colorhug/meson.build @@ -9,17 +9,3 @@ colorhug_test_firmware = custom_target('colorhug-test-firmware', gcab, '--create', '--nopath', '@OUTPUT@', '@INPUT@', ], ) - -if get_option('pkcs7') - # generate self-signed detached signature - colorhug_pkcs7_signature = custom_target('firmware.bin.p7c', - input: 'firmware.bin', - output: 'firmware.bin.p7c', - command: [certtool, '--p7-detached-sign', - '--p7-time', - '--load-privkey', pkcs7_privkey, - '--load-certificate', pkcs7_certificate, - '--infile', '@INPUT@', - '--outfile', '@OUTPUT@'], - ) -endif diff --git a/data/tests/meson.build b/data/tests/meson.build index 63c35c62d..a1d0445ec 100644 --- a/data/tests/meson.build +++ b/data/tests/meson.build @@ -1,12 +1,4 @@ -# generate private PKCS7 key -certtool = find_program('certtool') -pkcs7_privkey = custom_target('test-privkey.pem', - output: 'test-privkey.pem', - command: [certtool, '--generate-privkey', '--outfile', '@OUTPUT@'], -) - subdir('builder') -subdir('pki') subdir('colorhug') subdir('missing-hwid') subdir('multiple-rels') diff --git a/data/tests/pki/GPG-KEY-Linux-Vendor-Firmware-Service b/data/tests/pki/GPG-KEY-Linux-Vendor-Firmware-Service deleted file mode 120000 index 27abe4c04..000000000 --- a/data/tests/pki/GPG-KEY-Linux-Vendor-Firmware-Service +++ /dev/null @@ -1 +0,0 @@ -../../pki/GPG-KEY-Linux-Vendor-Firmware-Service \ No newline at end of file diff --git a/data/tests/pki/LVFS-CA.pem b/data/tests/pki/LVFS-CA.pem deleted file mode 120000 index aa5594497..000000000 --- a/data/tests/pki/LVFS-CA.pem +++ /dev/null @@ -1 +0,0 @@ -../../pki/LVFS-CA.pem \ No newline at end of file diff --git a/data/tests/pki/meson.build b/data/tests/pki/meson.build deleted file mode 100644 index f35f2a9ec..000000000 --- a/data/tests/pki/meson.build +++ /dev/null @@ -1,10 +0,0 @@ -# generate certificate -pkcs7_config = join_paths(meson.current_source_dir(), 'test.cfg') -pkcs7_certificate = custom_target('test.pem', - input: pkcs7_privkey, - output: 'test.pem', - command: [certtool, '--generate-self-signed', - '--template', pkcs7_config, - '--load-privkey', '@INPUT@', - '--outfile', '@OUTPUT@'], -) diff --git a/data/tests/pki/test.cfg b/data/tests/pki/test.cfg deleted file mode 100644 index a9422fb52..000000000 --- a/data/tests/pki/test.cfg +++ /dev/null @@ -1,4 +0,0 @@ -organization = "Hughski Limited" -expiration_days = -1 -email = "info@hughski.com" -signing_key diff --git a/libfwupd/fwupd-enums.c b/libfwupd/fwupd-enums.c index 789df10af..186dbed79 100644 --- a/libfwupd/fwupd-enums.c +++ b/libfwupd/fwupd-enums.c @@ -401,6 +401,8 @@ fwupd_keyring_kind_from_string (const gchar *keyring_kind) return FWUPD_KEYRING_KIND_GPG; if (g_strcmp0 (keyring_kind, "pkcs7") == 0) return FWUPD_KEYRING_KIND_PKCS7; + if (g_strcmp0 (keyring_kind, "jcat") == 0) + return FWUPD_KEYRING_KIND_JCAT; return FWUPD_KEYRING_KIND_UNKNOWN; } @@ -423,6 +425,8 @@ fwupd_keyring_kind_to_string (FwupdKeyringKind keyring_kind) return "gpg"; if (keyring_kind == FWUPD_KEYRING_KIND_PKCS7) return "pkcs7"; + if (keyring_kind == FWUPD_KEYRING_KIND_JCAT) + return "jcat"; return NULL; } diff --git a/libfwupd/fwupd-enums.h b/libfwupd/fwupd-enums.h index 9a8fa1115..7a5500277 100644 --- a/libfwupd/fwupd-enums.h +++ b/libfwupd/fwupd-enums.h @@ -232,6 +232,7 @@ typedef enum { * @FWUPD_KEYRING_KIND_NONE: No verification * @FWUPD_KEYRING_KIND_GPG: Verification using GPG * @FWUPD_KEYRING_KIND_PKCS7: Verification using PKCS7 + * @FWUPD_KEYRING_KIND_JCAT: Verification using Jcat * * The update state. **/ @@ -240,6 +241,7 @@ typedef enum { FWUPD_KEYRING_KIND_NONE, /* Since: 0.9.7 */ FWUPD_KEYRING_KIND_GPG, /* Since: 0.9.7 */ FWUPD_KEYRING_KIND_PKCS7, /* Since: 0.9.7 */ + FWUPD_KEYRING_KIND_JCAT, /* Since: 1.4.0 */ /*< private >*/ FWUPD_KEYRING_KIND_LAST } FwupdKeyringKind; diff --git a/libfwupd/fwupd-remote.c b/libfwupd/fwupd-remote.c index 08ad6d5d1..0edecc9cd 100644 --- a/libfwupd/fwupd-remote.c +++ b/libfwupd/fwupd-remote.c @@ -146,16 +146,6 @@ fwupd_remote_set_filename_source (FwupdRemote *self, const gchar *filename_sourc priv->filename_source = g_strdup (filename_source); } -static const gchar * -fwupd_remote_get_suffix_for_keyring_kind (FwupdKeyringKind keyring_kind) -{ - if (keyring_kind == FWUPD_KEYRING_KIND_GPG) - return ".asc"; - if (keyring_kind == FWUPD_KEYRING_KIND_PKCS7) - return ".p7b"; - return NULL; -} - static SoupURI * fwupd_remote_build_uri (FwupdRemote *self, const gchar *url, GError **error) { @@ -231,7 +221,6 @@ static void fwupd_remote_set_metadata_uri (FwupdRemote *self, const gchar *metadata_uri) { FwupdRemotePrivate *priv = GET_PRIVATE (self); - const gchar *suffix; g_autoptr(SoupURI) uri = NULL; /* build the URI */ @@ -243,9 +232,8 @@ fwupd_remote_set_metadata_uri (FwupdRemote *self, const gchar *metadata_uri) priv->metadata_uri = g_strdup (metadata_uri); /* generate the signature URI too */ - suffix = fwupd_remote_get_suffix_for_keyring_kind (priv->keyring_kind); - if (suffix != NULL) - priv->metadata_uri_sig = g_strconcat (metadata_uri, suffix, NULL); + if (priv->keyring_kind == FWUPD_KEYRING_KIND_JCAT) + priv->metadata_uri_sig = g_strconcat (metadata_uri, ".jcat", NULL); } /* note, this has to be set after MetadataURI */ @@ -311,7 +299,6 @@ static void fwupd_remote_set_filename_cache (FwupdRemote *self, const gchar *filename) { FwupdRemotePrivate *priv = GET_PRIVATE (self); - const gchar *suffix; g_return_if_fail (FWUPD_IS_REMOTE (self)); @@ -319,10 +306,9 @@ fwupd_remote_set_filename_cache (FwupdRemote *self, const gchar *filename) priv->filename_cache = g_strdup (filename); /* create for all remote types */ - suffix = fwupd_remote_get_suffix_for_keyring_kind (priv->keyring_kind); - if (suffix != NULL) { + if (priv->keyring_kind == FWUPD_KEYRING_KIND_JCAT) { g_free (priv->filename_cache_sig); - priv->filename_cache_sig = g_strconcat (filename, suffix, NULL); + priv->filename_cache_sig = g_strconcat (filename, ".jcat", NULL); } } @@ -375,7 +361,7 @@ fwupd_remote_load_from_filename (FwupdRemote *self, /* get verification type, falling back to GPG */ keyring_kind = g_key_file_get_string (kf, group, "Keyring", NULL); if (keyring_kind == NULL) { - priv->keyring_kind = FWUPD_KEYRING_KIND_GPG; + priv->keyring_kind = FWUPD_KEYRING_KIND_JCAT; } else { priv->keyring_kind = fwupd_keyring_kind_from_string (keyring_kind); if (priv->keyring_kind == FWUPD_KEYRING_KIND_UNKNOWN) { @@ -386,6 +372,11 @@ fwupd_remote_load_from_filename (FwupdRemote *self, keyring_kind); return FALSE; } + if (priv->keyring_kind == FWUPD_KEYRING_KIND_GPG || + priv->keyring_kind == FWUPD_KEYRING_KIND_PKCS7) { + g_debug ("converting Keyring value to Jcat"); + priv->keyring_kind = FWUPD_KEYRING_KIND_JCAT; + } } /* all remotes need a URI, even if it's file:// to the cache */ diff --git a/libfwupd/fwupd-self-test.c b/libfwupd/fwupd-self-test.c index b72460adb..2acac6ffe 100644 --- a/libfwupd/fwupd-self-test.c +++ b/libfwupd/fwupd-self-test.c @@ -168,14 +168,14 @@ fwupd_remote_download_func (void) "lvfs", "metadata.xml.gz", NULL); - expected_signature = g_strdup_printf ("%s.asc", expected_metadata); + expected_signature = g_strdup_printf ("%s.jcat", expected_metadata); fwupd_remote_set_remotes_dir (remote, directory); fn = g_build_filename (FU_SELF_TEST_REMOTES_DIR, "remotes.d", "lvfs.conf", NULL); ret = fwupd_remote_load_from_filename (remote, fn, NULL, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (fwupd_remote_get_kind (remote), ==, FWUPD_REMOTE_KIND_DOWNLOAD); - g_assert_cmpint (fwupd_remote_get_keyring_kind (remote), ==, FWUPD_KEYRING_KIND_GPG); + g_assert_cmpint (fwupd_remote_get_keyring_kind (remote), ==, FWUPD_KEYRING_KIND_JCAT); g_assert_cmpint (fwupd_remote_get_priority (remote), ==, 0); g_assert (fwupd_remote_get_enabled (remote)); g_assert (fwupd_remote_get_metadata_uri (remote) != NULL); @@ -209,14 +209,14 @@ fwupd_remote_baseuri_func (void) g_assert_no_error (error); g_assert (ret); g_assert_cmpint (fwupd_remote_get_kind (remote), ==, FWUPD_REMOTE_KIND_DOWNLOAD); - g_assert_cmpint (fwupd_remote_get_keyring_kind (remote), ==, FWUPD_KEYRING_KIND_GPG); + g_assert_cmpint (fwupd_remote_get_keyring_kind (remote), ==, FWUPD_KEYRING_KIND_JCAT); g_assert_cmpint (fwupd_remote_get_priority (remote), ==, 0); g_assert (fwupd_remote_get_enabled (remote)); g_assert_cmpstr (fwupd_remote_get_checksum (remote), ==, NULL); g_assert_cmpstr (fwupd_remote_get_metadata_uri (remote), ==, "https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz"); g_assert_cmpstr (fwupd_remote_get_metadata_uri_sig (remote), ==, - "https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz.asc"); + "https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz.jcat"); firmware_uri = fwupd_remote_build_firmware_uri (remote, "http://bbc.co.uk/firmware.cab", &error); g_assert_no_error (error); g_assert_cmpstr (firmware_uri, ==, "https://my.fancy.cdn/firmware.cab"); @@ -245,14 +245,14 @@ fwupd_remote_nopath_func (void) g_assert_no_error (error); g_assert (ret); g_assert_cmpint (fwupd_remote_get_kind (remote), ==, FWUPD_REMOTE_KIND_DOWNLOAD); - g_assert_cmpint (fwupd_remote_get_keyring_kind (remote), ==, FWUPD_KEYRING_KIND_GPG); + g_assert_cmpint (fwupd_remote_get_keyring_kind (remote), ==, FWUPD_KEYRING_KIND_JCAT); g_assert_cmpint (fwupd_remote_get_priority (remote), ==, 0); g_assert (fwupd_remote_get_enabled (remote)); g_assert_cmpstr (fwupd_remote_get_checksum (remote), ==, NULL); g_assert_cmpstr (fwupd_remote_get_metadata_uri (remote), ==, "https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz"); g_assert_cmpstr (fwupd_remote_get_metadata_uri_sig (remote), ==, - "https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz.asc"); + "https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz.jcat"); firmware_uri = fwupd_remote_build_firmware_uri (remote, "firmware.cab", &error); g_assert_no_error (error); g_assert_cmpstr (firmware_uri, ==, "https://s3.amazonaws.com/lvfsbucket/downloads/firmware.cab"); diff --git a/libfwupdplugin/fu-cabinet.c b/libfwupdplugin/fu-cabinet.c index 632981ed8..ef8fe2bc7 100644 --- a/libfwupdplugin/fu-cabinet.c +++ b/libfwupdplugin/fu-cabinet.c @@ -14,6 +14,7 @@ #include "fu-cabinet.h" #include "fu-common.h" +#include "fwupd-enums.h" #include "fwupd-error.h" struct _FuCabinet { @@ -23,6 +24,8 @@ struct _FuCabinet { gchar *container_checksum; XbBuilder *builder; XbSilo *silo; + JcatContext *jcat_context; + JcatFile *jcat_file; }; G_DEFINE_TYPE (FuCabinet, fu_cabinet, G_TYPE_OBJECT) @@ -37,6 +40,8 @@ fu_cabinet_finalize (GObject *obj) g_object_unref (self->builder); g_free (self->container_checksum); g_object_unref (self->gcab_cabinet); + g_object_unref (self->jcat_context); + g_object_unref (self->jcat_file); G_OBJECT_CLASS (fu_cabinet_parent_class)->finalize (obj); } @@ -53,6 +58,8 @@ fu_cabinet_init (FuCabinet *self) self->size_max = 1024 * 1024 * 100; self->gcab_cabinet = gcab_cabinet_new (); self->builder = xb_builder_new (); + self->jcat_file = jcat_file_new (); + self->jcat_context = jcat_context_new (); } /** @@ -71,6 +78,24 @@ fu_cabinet_set_size_max (FuCabinet *self, guint64 size_max) self->size_max = size_max; } +/** + * fu_cabinet_set_jcat_context: (skip): + * @self: A #FuCabinet + * @jcat_context: (nullable): A #JcatContext + * + * Sets the Jcat context, which is used for setting the trust flags on the + * each release in the archive. + * + * Since: 1.4.0 + **/ +void +fu_cabinet_set_jcat_context (FuCabinet *self, JcatContext *jcat_context) +{ + g_return_if_fail (FU_IS_CABINET (self)); + g_return_if_fail (JCAT_IS_CONTEXT (jcat_context)); + g_set_object (&self->jcat_context, jcat_context); +} + /** * fu_cabinet_get_silo: (skip): * @self: A #FuCabinet @@ -111,11 +136,18 @@ fu_cabinet_parse_release (FuCabinet *self, XbNode *release, GError **error) GCabFile *cabfile; GBytes *blob; const gchar *csum_filename = NULL; - const gchar *suffixes[] = { "asc", "p7b", "p7c", NULL }; g_autofree gchar *basename = NULL; - g_autofree gchar *release_key = NULL; g_autoptr(XbNode) csum_tmp = NULL; + g_autoptr(XbNode) metadata_trust = NULL; g_autoptr(XbNode) nsize = NULL; + g_autoptr(JcatItem) item = NULL; + g_autoptr(GBytes) release_flags_blob = NULL; + FwupdReleaseFlags release_flags = FWUPD_RELEASE_FLAG_NONE; + + /* we set this with XbBuilderSource before the silo was created */ + metadata_trust = xb_node_query_first (release, "../../info/metadata_trust", NULL); + if (metadata_trust != NULL) + release_flags |= FWUPD_RELEASE_FLAG_TRUSTED_METADATA; /* ensure we always have a content checksum */ csum_tmp = xb_node_query_first (release, "checksum[@target='content']", NULL); @@ -148,8 +180,7 @@ fu_cabinet_parse_release (FuCabinet *self, XbNode *release, GError **error) } /* set the blob */ - release_key = g_strdup_printf ("fwupd::ReleaseBlob(%s)", basename); - xb_node_set_data (release, release_key, blob); + xb_node_set_data (release, "fwupd::FirmwareBlob", blob); /* set as metadata if unset, but error if specified and incorrect */ nsize = xb_node_query_first (release, "size[@type='installed']", NULL); @@ -185,15 +216,38 @@ fu_cabinet_parse_release (FuCabinet *self, XbNode *release, GError **error) } } - /* if the signing file exists, set that too */ - for (guint i = 0; suffixes[i] != NULL; i++) { + /* find out if the payload is signed, falling back to detached */ + item = jcat_file_get_item_by_id (self->jcat_file, basename, NULL); + if (item != NULL) { + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) results = NULL; + results = jcat_context_verify_item (self->jcat_context, + blob, item, + JCAT_VERIFY_FLAG_REQUIRE_CHECKSUM | + JCAT_VERIFY_FLAG_REQUIRE_SIGNATURE, + &error_local); + if (results == NULL) { + g_debug ("failed to verify payload %s: %s", + basename, error_local->message); + } else { + g_debug ("verified payload %s: %u", + basename, results->len); + release_flags |= FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD; + } + + /* legacy GPG detached signature */ + } else { g_autofree gchar *basename_sig = NULL; - basename_sig = g_strdup_printf ("%s.%s", basename, suffixes[i]); + basename_sig = g_strdup_printf ("%s.asc", basename); cabfile = fu_cabinet_get_file_by_name (self, basename_sig); if (cabfile != NULL) { - g_autofree gchar *release_key_sig = NULL; - blob = gcab_file_get_bytes (cabfile); - if (blob == NULL) { + GBytes *data_sig; + g_autoptr(JcatResult) jcat_result = NULL; + g_autoptr(JcatBlob) jcat_blob = NULL; + g_autoptr(GError) error_local = NULL; + + data_sig = gcab_file_get_bytes (cabfile); + if (data_sig == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, @@ -201,12 +255,25 @@ fu_cabinet_parse_release (FuCabinet *self, XbNode *release, GError **error) basename_sig); return FALSE; } - release_key_sig = g_strdup_printf ("fwupd::ReleaseBlob(%s)", - basename_sig); - xb_node_set_data (release, release_key_sig, blob); + jcat_blob = jcat_blob_new (JCAT_BLOB_KIND_GPG, data_sig); + jcat_result = jcat_context_verify_blob (self->jcat_context, + blob, jcat_blob, + JCAT_VERIFY_FLAG_REQUIRE_SIGNATURE, + &error_local); + if (jcat_result == NULL) { + g_debug ("failed to verify payload %s using detached: %s", + basename, error_local->message); + } else { + g_debug ("verified payload %s using detached", basename); + release_flags |= FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD; + } } } + /* this means we can get the data from fu_keyring_get_release_flags */ + release_flags_blob = g_bytes_new (&release_flags, sizeof(release_flags)); + xb_node_set_data (release, "fwupd::ReleaseFlags", release_flags_blob); + /* success */ return TRUE; } @@ -283,11 +350,22 @@ fu_cabinet_set_container_checksum_cb (XbBuilderFixup *builder_fixup, /* adds each GCabFile to the silo */ static gboolean -fu_cabinet_build_silo_file (FuCabinet *self, GCabFile *cabfile, GError **error) +fu_cabinet_build_silo_file (FuCabinet *self, + GCabFile *cabfile, + FwupdReleaseFlags release_flags, + GError **error) { GBytes *blob; g_autoptr(GError) error_local = NULL; g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autoptr(XbBuilderNode) bn_info = xb_builder_node_new ("info"); + + /* indicate the metainfo file was signed */ + if (release_flags & FWUPD_RELEASE_FLAG_TRUSTED_METADATA) { + g_autoptr(XbBuilderNode) bn_trust = NULL; + xb_builder_node_insert (bn_info, "metadata_trust", NULL); + } + xb_builder_source_set_info (source, bn_info); /* rewrite to be under a components root */ xb_builder_source_set_prefix (source, "components"); @@ -318,6 +396,71 @@ fu_cabinet_build_silo_file (FuCabinet *self, GCabFile *cabfile, GError **error) return TRUE; } +static gboolean +fu_cabinet_build_silo_metainfo (FuCabinet *self, GCabFile *cabfile, GError **error) +{ + FwupdReleaseFlags release_flags = FWUPD_RELEASE_FLAG_NONE; + const gchar *fn = gcab_file_get_extract_name (cabfile); + g_autoptr(JcatItem) item = NULL; + + /* validate against the Jcat file */ + item = jcat_file_get_item_by_id (self->jcat_file, fn, NULL); + if (item == NULL) { + g_debug ("failed to verify %s: no JcatItem", fn); + } else { + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) results = NULL; + results = jcat_context_verify_item (self->jcat_context, + gcab_file_get_bytes (cabfile), + item, + JCAT_VERIFY_FLAG_REQUIRE_CHECKSUM | + JCAT_VERIFY_FLAG_REQUIRE_SIGNATURE, + &error_local); + if (results == NULL) { + g_debug ("failed to verify %s: %s", + fn, error_local->message); + } else { + g_debug ("verified metadata %s: %u", + fn, results->len); + release_flags |= FWUPD_RELEASE_FLAG_TRUSTED_METADATA; + } + } + + /* actually parse the XML now */ + g_debug ("processing file: %s", fn); + if (!fu_cabinet_build_silo_file (self, cabfile, release_flags, error)) { + g_prefix_error (error, "%s could not be loaded: ", + gcab_file_get_extract_name (cabfile)); + return FALSE; + } + + /* success */ + return TRUE; +} + +/* load the firmware.jcat files if included */ +static gboolean +fu_cabinet_build_jcat_folder (FuCabinet *self, GCabFolder *cabfolder, GError **error) +{ + g_autoptr(GSList) cabfiles = gcab_folder_get_files (cabfolder); + for (GSList *l = cabfiles; l != NULL; l = l->next) { + GCabFile *cabfile = GCAB_FILE (l->data); + const gchar *fn = gcab_file_get_extract_name (cabfile); + if (g_str_has_suffix (fn, ".jcat")) { + GBytes *data_jcat = gcab_file_get_bytes (cabfile); + g_autoptr(GInputStream) istream = NULL; + istream = g_memory_input_stream_new_from_bytes (data_jcat); + if (!jcat_file_import_stream (self->jcat_file, + istream, + JCAT_IMPORT_FLAG_NONE, + NULL, + error)) + return FALSE; + } + } + return TRUE; +} + /* adds each GCabFolder to the silo */ static gboolean fu_cabinet_build_silo_folder (FuCabinet *self, GCabFolder *cabfolder, GError **error) @@ -326,14 +469,10 @@ fu_cabinet_build_silo_folder (FuCabinet *self, GCabFolder *cabfolder, GError **e for (GSList *l = cabfiles; l != NULL; l = l->next) { GCabFile *cabfile = GCAB_FILE (l->data); const gchar *fn = gcab_file_get_extract_name (cabfile); - g_debug ("processing file: %s", fn); - if (g_str_has_suffix (fn, ".metainfo.xml")) { - if (!fu_cabinet_build_silo_file (self, cabfile, error)) { - g_prefix_error (error, "%s could not be loaded: ", - gcab_file_get_extract_name (cabfile)); - return FALSE; - } - } + if (!g_str_has_suffix (fn, ".metainfo.xml")) + continue; + if (!fu_cabinet_build_silo_metainfo (self, cabfile, error)) + return FALSE; } return TRUE; } @@ -352,8 +491,17 @@ fu_cabinet_build_silo (FuCabinet *self, GBytes *data, GError **error) XB_SILO_PROFILE_FLAG_DEBUG); } - /* look at each folder */ + /* load Jcat */ folders = gcab_cabinet_get_folders (self->gcab_cabinet); + if (self->jcat_context != NULL) { + for (guint i = 0; i < folders->len; i++) { + GCabFolder *cabfolder = GCAB_FOLDER (g_ptr_array_index (folders, i)); + if (!fu_cabinet_build_jcat_folder (self, cabfolder, error)) + return FALSE; + } + } + + /* adds each metainfo file to the silo */ for (guint i = 0; i < folders->len; i++) { GCabFolder *cabfolder = GCAB_FOLDER (g_ptr_array_index (folders, i)); g_debug ("processing folder: %u/%u", i + 1, folders->len); diff --git a/libfwupdplugin/fu-cabinet.h b/libfwupdplugin/fu-cabinet.h index e340e6901..de26741ec 100644 --- a/libfwupdplugin/fu-cabinet.h +++ b/libfwupdplugin/fu-cabinet.h @@ -8,6 +8,7 @@ #include #include +#include #define FU_TYPE_CABINET (fu_cabinet_get_type ()) @@ -28,6 +29,8 @@ typedef enum { FuCabinet *fu_cabinet_new (void); void fu_cabinet_set_size_max (FuCabinet *self, guint64 size_max); +void fu_cabinet_set_jcat_context (FuCabinet *self, + JcatContext *jcat_context); gboolean fu_cabinet_parse (FuCabinet *self, GBytes *data, FuCabinetParseFlags flags, diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index 80b4ec73d..60b4b18c6 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -746,9 +746,7 @@ fu_common_store_cab_func (void) csum = xb_node_query_first (rel, "checksum[@target='content']", &error); g_assert_nonnull (csum); g_assert_cmpstr (xb_node_get_text (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43"); - blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.dfu)"); - g_assert_nonnull (blob_tmp); - blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.dfu.asc)"); + blob_tmp = xb_node_get_data (rel, "fwupd::FirmwareBlob"); g_assert_nonnull (blob_tmp); req = xb_node_query_first (component, "requires/id", &error); g_assert_no_error (error); @@ -791,10 +789,8 @@ fu_common_store_cab_unsigned_func (void) g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3"); csum = xb_node_query_first (rel, "checksum[@target='content']", &error); g_assert_null (csum); - blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.bin)"); + blob_tmp = xb_node_get_data (rel, "fwupd::FirmwareBlob"); g_assert_nonnull (blob_tmp); - blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.bin.asc)"); - g_assert_null (blob_tmp); } static void @@ -830,7 +826,7 @@ fu_common_store_cab_folder_func (void) g_assert_no_error (error); g_assert_nonnull (rel); g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3"); - blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.bin)"); + blob_tmp = xb_node_get_data (rel, "fwupd::FirmwareBlob"); g_assert_nonnull (blob_tmp); } diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index d140668b8..c07c419e2 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -544,6 +544,7 @@ LIBFWUPDPLUGIN_1.4.0 { fu_cabinet_get_type; fu_cabinet_new; fu_cabinet_parse; + fu_cabinet_set_jcat_context; fu_cabinet_set_size_max; fu_device_get_root; fu_device_set_version_bootloader; diff --git a/libfwupdplugin/meson.build b/libfwupdplugin/meson.build index b73e6325d..40b59668a 100644 --- a/libfwupdplugin/meson.build +++ b/libfwupdplugin/meson.build @@ -79,6 +79,7 @@ fwupdplugin_headers_private = [ introspection_deps = [ libxmlb, + libjcat, giounix, gusb, ] @@ -95,6 +96,7 @@ library_deps = [ libjsonglib, libgcab, valgrind, + libjcat, platform_deps, ] @@ -136,6 +138,7 @@ fwupdplugin_pkgg.generate( 'libgcab-1.0', 'libsoup-2.4', 'xmlb', + 'jcat', ], subdirs : 'fwupd-1', version : meson.project_version(), @@ -218,9 +221,6 @@ if get_option('tests') noreqs_test_firmware, fu_hash, ] - if get_option('pkcs7') - test_deps += colorhug_pkcs7_signature - endif testdatadir_src = join_paths(meson.source_root(), 'data', 'tests') testdatadir_dst = join_paths(meson.build_root(), 'data', 'tests') pluginbuilddir = join_paths(meson.build_root(), 'plugins', 'test') diff --git a/meson.build b/meson.build index c3eb4a436..e192b90ed 100644 --- a/meson.build +++ b/meson.build @@ -187,6 +187,7 @@ else gudev = dependency('', required : false) endif libxmlb = dependency('xmlb', version : '>= 0.1.13', fallback : ['libxmlb', 'libxmlb_dep']) +libjcat = dependency('jcat', version : '>= 0.1.0', fallback : ['libjcat', 'libjcat_dep']) gusb = dependency('gusb', version : '>= 0.2.9', fallback : ['gusb', 'gusb_dep']) sqlite = dependency('sqlite3') libarchive = dependency('libarchive') @@ -206,18 +207,6 @@ if build_daemon udevdir = udev.get_pkgconfig_variable('udevdir') endif endif -if get_option('pkcs7') - gnutls = dependency('gnutls', version : '>= 3.4.4.1') - if gnutls.version().version_compare('>= 3.6.0') - conf.set('HAVE_GNUTLS_3_6_0', '1') - endif - conf.set('ENABLE_PKCS7', '1') -endif -if get_option('gpg') - gpgme = cc.find_library('gpgme') - gpgerror = cc.find_library('gpg-error') - conf.set('ENABLE_GPG', '1') -endif libm = cc.find_library('m', required: false) libgcab = dependency('libgcab-1.0', version : '>= 1.0', fallback : ['gcab', 'gcab_dep']) gcab = find_program('gcab', required : true) diff --git a/meson_options.txt b/meson_options.txt index be0adfef6..3da9b6c44 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -2,13 +2,11 @@ option('build', type : 'combo', choices : ['all', 'standalone', 'library'], valu option('agent', type : 'boolean', value : true, description : 'enable the fwupd agent') option('consolekit', type : 'boolean', value : true, description : 'enable ConsoleKit support') option('firmware-packager', type : 'boolean', value : true, description : 'enable firmware-packager installation') -option('gpg', type : 'boolean', value : true, description : 'enable the GPG verification support') option('gtkdoc', type : 'boolean', value : false, description : 'enable developer documentation') option('introspection', type : 'boolean', value : true, description : 'generate GObject Introspection data') option('lvfs', type : 'boolean', value : true, description : 'enable LVFS remotes') option('man', type : 'boolean', value : true, description : 'enable man pages') option('gudev', type : 'boolean', value : true, description : 'enable GUdev support') -option('pkcs7', type : 'boolean', value : true, description : 'enable the PKCS7 verification support') option('plugin_altos', type : 'boolean', value : true, description : 'enable altos support') option('plugin_amt', type : 'boolean', value : true, description : 'enable Intel AMT support') option('plugin_dell', type : 'boolean', value : true, description : 'enable Dell-specific support') diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 6762aff01..ea688ea8b 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -45,6 +45,31 @@ parts: - -lib/pkgconfig build-packages: - libssl-dev + nettle: + plugin: autotools + source: https://ftp.gnu.org/gnu/nettle/nettle-3.5.tar.gz + build-packages: + - libgmp-dev + prime: + - -include + - -bin + - -share/man + - -lib/pkgconfig + gnutls: + plugin: autotools + source: https://www.gnupg.org/ftp/gcrypt/gnutls/v3.6/gnutls-3.6.12.tar.xz + build-packages: + - libtasn1-6-dev + - libunistring-dev + - libidn2-dev + - libunbound-dev + - libp11-kit-dev + prime: + - -include + - -bin + - -share/man + - -lib/pkgconfig + after: [nettle] meson: plugin: python source: https://github.com/mesonbuild/meson/releases/download/0.51.2/meson-0.51.2.tar.gz @@ -150,7 +175,11 @@ parts: -Dplugin_modem_manager=true, -Dudevdir=$SNAPCRAFT_STAGE/lib/udev, "-Dlibxmlb:gtkdoc=false", - "-Dlibxmlb:introspection=false"] + "-Dlibxmlb:introspection=false", + "-Dlibjcat:man=false", + "-Dlibjcat:gtkdoc=false", + "-Dlibjcat:introspection=false", + "-Dlibjcat:tests=false"] source: . source-type: git override-build: | @@ -159,7 +188,6 @@ parts: build-packages: - bash-completion - gcab - - gnutls-dev - gnu-efi - libarchive-dev - libcairo-dev @@ -236,7 +264,9 @@ parts: - -usr/share/gir-1.0 - -usr/share/upstart - -usr/lib/*/pkgconfig - after: [meson, build-introspection, modemmanager, libmbim, libqmi, tpm2-tss] + # we don't want system gnutls leaking in + - -usr/lib/*/libgnutls* + after: [meson, build-introspection, modemmanager, libmbim, libqmi, tpm2-tss, gnutls] fix-bash-completion: plugin: make source: contrib/snap/fix-bash-completion diff --git a/src/fu-engine.c b/src/fu-engine.c index f17e9d439..5d36ca0cf 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -97,6 +97,7 @@ struct _FuEngine GHashTable *approved_firmware; GHashTable *firmware_gtypes; gchar *host_machine_id; + JcatContext *jcat_context; gboolean loaded; }; @@ -1728,8 +1729,7 @@ fu_engine_install_release (FuEngine *self, FuPlugin *plugin; FwupdVersionFormat fmt; GBytes *blob_fw; - const gchar *tmp = NULL; - g_autofree gchar *release_key = NULL; + const gchar *tmp; g_autofree gchar *version_orig = NULL; g_autofree gchar *version_rel = NULL; g_autoptr(FuDevice) device_tmp = NULL; @@ -1737,19 +1737,13 @@ fu_engine_install_release (FuEngine *self, g_autoptr(GBytes) blob_fw2 = NULL; g_autoptr(GError) error_local = NULL; - /* get the blob */ - tmp = xb_node_query_attr (rel, "checksum[@target='content']", "filename", NULL); - if (tmp == NULL) - tmp = "firmware.bin"; - - /* not all devices have to use the same blob */ - release_key = g_strdup_printf ("fwupd::ReleaseBlob(%s)", tmp); - blob_fw = xb_node_get_data (rel, release_key); + /* get per-release firmware blob */ + blob_fw = xb_node_get_data (rel, "fwupd::FirmwareBlob"); if (blob_fw == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "Failed to get firmware blob using %s", tmp); + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Failed to get firmware blob from release"); return FALSE; } @@ -2994,22 +2988,82 @@ fu_engine_remote_list_changed_cb (FuRemoteList *remote_list, FuEngine *self) fu_engine_emit_changed (self); } -static FuKeyringResult * -fu_engine_get_existing_keyring_result (FuEngine *self, - FuKeyring *kr, - FwupdRemote *remote, - GError **error) +static gint +fu_engine_sort_jcat_results_timestamp_cb (gconstpointer a, gconstpointer b) +{ + JcatResult *ra = *((JcatResult **) a); + JcatResult *rb = *((JcatResult **) b); + if (jcat_result_get_timestamp (ra) < jcat_result_get_timestamp (rb)) + return -1; + if (jcat_result_get_timestamp (ra) > jcat_result_get_timestamp (rb)) + return 1; + return 0; +} + +static JcatResult * +fu_engine_get_system_jcat_result (FuEngine *self, FwupdRemote *remote, GError **error) { g_autoptr(GBytes) blob = NULL; g_autoptr(GBytes) blob_sig = NULL; + g_autoptr(GInputStream) istream = NULL; + g_autoptr(GPtrArray) results = NULL; + g_autoptr(JcatItem) jcat_item = NULL; + g_autoptr(JcatFile) jcat_file = jcat_file_new (); + blob = fu_common_get_contents_bytes (fwupd_remote_get_filename_cache (remote), error); if (blob == NULL) return NULL; blob_sig = fu_common_get_contents_bytes (fwupd_remote_get_filename_cache_sig (remote), error); if (blob_sig == NULL) return NULL; - return fu_keyring_verify_data (kr, blob, blob_sig, - FU_KEYRING_VERIFY_FLAG_NONE, error); + istream = g_memory_input_stream_new_from_bytes (blob_sig); + if (!jcat_file_import_stream (jcat_file, istream, + JCAT_IMPORT_FLAG_NONE, + NULL, error)) + return NULL; + jcat_item = jcat_file_get_item_default (jcat_file, error); + if (jcat_item == NULL) + return NULL; + results = jcat_context_verify_item (self->jcat_context, + blob, jcat_item, + JCAT_VERIFY_FLAG_REQUIRE_CHECKSUM | + JCAT_VERIFY_FLAG_REQUIRE_SIGNATURE, + error); + if (results == NULL) + return NULL; + g_ptr_array_sort (results, fu_engine_sort_jcat_results_timestamp_cb); + + /* return the newest one */ + return g_object_ref (g_ptr_array_index (results, 0)); +} + +static gboolean +fu_engine_validate_result_timestamp (JcatResult *jcat_result, + JcatResult *jcat_result_old, + GError **error) +{ + gint64 delta = 0; + + g_return_val_if_fail (JCAT_IS_RESULT (jcat_result), FALSE); + g_return_val_if_fail (JCAT_IS_RESULT (jcat_result_old), FALSE); + + if (jcat_result_get_timestamp (jcat_result) > 0 && + jcat_result_get_timestamp (jcat_result_old) > 0) { + delta = jcat_result_get_timestamp (jcat_result) - + jcat_result_get_timestamp (jcat_result_old); + } + if (delta < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "new signing timestamp was %" + G_GINT64_FORMAT " seconds older", + -delta); + return FALSE; + } + if (delta > 0) + g_debug ("timestamp increased, so no rollback"); + return TRUE; } /** @@ -3017,7 +3071,7 @@ fu_engine_get_existing_keyring_result (FuEngine *self, * @self: A #FuEngine * @remote_id: A remote ID, e.g. `lvfs` * @bytes_raw: Blob of metadata - * @bytes_sig: Blob of metadata signature + * @bytes_sig: Blob of metadata signature, typically Jcat binary format * @error: A #GError, or %NULL * * Updates the metadata for a specific remote. @@ -3059,31 +3113,41 @@ fu_engine_update_metadata_bytes (FuEngine *self, const gchar *remote_id, /* verify file */ keyring_kind = fwupd_remote_get_keyring_kind (remote); if (keyring_kind != FWUPD_KEYRING_KIND_NONE) { - g_autoptr(FuKeyring) kr = NULL; - g_autoptr(FuKeyringResult) kr_result = NULL; - g_autoptr(FuKeyringResult) kr_result_old = NULL; + JcatResult *jcat_result; g_autoptr(GError) error_local = NULL; - kr = fu_keyring_create_for_kind (keyring_kind, error); - if (kr == NULL) + g_autoptr(GInputStream) istream = NULL; + g_autoptr(GPtrArray) results = NULL; + g_autoptr(JcatFile) jcat_file = jcat_file_new (); + g_autoptr(JcatItem) jcat_item = NULL; + g_autoptr(JcatResult) jcat_result_old = NULL; + + /* load Jcat file */ + istream = g_memory_input_stream_new_from_bytes (bytes_sig); + if (!jcat_file_import_stream (jcat_file, istream, + JCAT_IMPORT_FLAG_NONE, + NULL, error)) return FALSE; - if (!fu_keyring_setup (kr, error)) + + /* this should only be signing one thing */ + jcat_item = jcat_file_get_item_default (jcat_file, error); + if (jcat_item == NULL) return FALSE; - sysconfdir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR); - pki_dir = g_build_filename (sysconfdir, "pki", "fwupd-metadata", NULL); - if (!fu_keyring_add_public_keys (kr, pki_dir, error)) - return FALSE; - kr_result = fu_keyring_verify_data (kr, bytes_raw, bytes_sig, - FU_KEYRING_VERIFY_FLAG_NONE, + results = jcat_context_verify_item (self->jcat_context, + bytes_raw, jcat_item, + JCAT_VERIFY_FLAG_REQUIRE_CHECKSUM | + JCAT_VERIFY_FLAG_REQUIRE_SIGNATURE, error); - if (kr_result == NULL) + if (results == NULL) return FALSE; + /* return the newest one */ + g_ptr_array_sort (results, fu_engine_sort_jcat_results_timestamp_cb); + jcat_result = g_ptr_array_index (results, 0); + /* verify the metadata was signed later than the existing * metadata for this remote to mitigate a rollback attack */ - kr_result_old = fu_engine_get_existing_keyring_result (self, kr, - remote, - &error_local); - if (kr_result_old == NULL) { + jcat_result_old = fu_engine_get_system_jcat_result (self, remote, &error_local); + if (jcat_result_old == NULL) { if (g_error_matches (error_local, G_FILE_ERROR, G_FILE_ERROR_NOENT)) { @@ -3094,23 +3158,10 @@ fu_engine_update_metadata_bytes (FuEngine *self, const gchar *remote_id, error_local->message); } } else { - gint64 delta = 0; - if (fu_keyring_result_get_timestamp (kr_result) > 0 && - fu_keyring_result_get_timestamp (kr_result_old) > 0) { - delta = fu_keyring_result_get_timestamp (kr_result) - - fu_keyring_result_get_timestamp (kr_result_old); - } - if (delta < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "new signing timestamp was %" - G_GINT64_FORMAT " seconds older", - -delta); + if (!fu_engine_validate_result_timestamp (jcat_result, + jcat_result_old, + error)) return FALSE; - } else if (delta > 0) { - g_debug ("timestamp increased, so no rollback"); - } } } @@ -3210,6 +3261,7 @@ fu_engine_get_silo_from_blob (FuEngine *self, GBytes *blob_cab, GError **error) /* load file */ fu_engine_set_status (self, FWUPD_STATUS_DECOMPRESSING); fu_cabinet_set_size_max (cabinet, fu_engine_get_archive_size_max (self)); + fu_cabinet_set_jcat_context (cabinet, self->jcat_context); if (!fu_cabinet_parse (cabinet, blob_cab, FU_CABINET_PARSE_FLAG_NONE, error)) return NULL; silo = fu_cabinet_get_silo (cabinet); @@ -3952,31 +4004,30 @@ fu_engine_add_approved_firmware (FuEngine *self, const gchar *checksum) gchar * fu_engine_self_sign (FuEngine *self, const gchar *value, - FuKeyringSignFlags flags, + JcatSignFlags flags, GError **error) { - g_autoptr(FuKeyring) kr = NULL; - g_autoptr(FuKeyringResult) kr_result = NULL; + g_autoptr(JcatBlob) jcat_signature = NULL; + g_autoptr(JcatEngine) jcat_engine = NULL; + g_autoptr(JcatResult) jcat_result = NULL; g_autoptr(GBytes) payload = NULL; - g_autoptr(GBytes) signature = NULL; /* create detached signature and verify */ - kr = fu_keyring_create_for_kind (FWUPD_KEYRING_KIND_PKCS7, error); - if (kr == NULL) - return NULL; - if (!fu_keyring_setup (kr, error)) + jcat_engine = jcat_context_get_engine (self->jcat_context, + JCAT_BLOB_KIND_PKCS7, + error); + if (jcat_engine == NULL) return NULL; payload = g_bytes_new (value, strlen (value)); - signature = fu_keyring_sign_data (kr, payload, flags, error); - if (signature == NULL) + jcat_signature = jcat_engine_self_sign (jcat_engine, payload, flags, error); + if (jcat_signature == NULL) return NULL; - kr_result = fu_keyring_verify_data (kr, payload, signature, - FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT, - error); - if (kr_result == NULL) + jcat_result = jcat_engine_self_verify (jcat_engine, payload, + jcat_blob_get_data (jcat_signature), + JCAT_VERIFY_FLAG_NONE, error); + if (jcat_result == NULL) return NULL; - return g_strndup (g_bytes_get_data (signature, NULL), - g_bytes_get_size (signature)); + return jcat_blob_get_data_as_string (jcat_signature); } /** @@ -5219,23 +5270,21 @@ fu_engine_udev_uevent_cb (GUdevClient *gudev_client, static void fu_engine_ensure_client_certificate (FuEngine *self) { - g_autoptr(FuKeyring) kr = NULL; g_autoptr(GBytes) blob = g_bytes_new_static ("test\0", 5); - g_autoptr(GBytes) sig = NULL; g_autoptr(GError) error = NULL; + g_autoptr(JcatBlob) jcat_sig = NULL; + g_autoptr(JcatEngine) jcat_engine = NULL; /* create keyring and sign dummy data to ensure certificate exists */ - kr = fu_keyring_create_for_kind (FWUPD_KEYRING_KIND_PKCS7, &error); - if (kr == NULL) { + jcat_engine = jcat_context_get_engine (self->jcat_context, + JCAT_BLOB_KIND_PKCS7, + &error); + if (jcat_engine == NULL) { g_message ("failed to create keyring: %s", error->message); return; } - if (!fu_keyring_setup (kr, &error)) { - g_message ("failed to setup keyring: %s", error->message); - return; - } - sig = fu_keyring_sign_data (kr, blob, FU_KEYRING_SIGN_FLAG_NONE, &error); - if (sig == NULL) { + jcat_sig = jcat_engine_self_sign (jcat_engine, blob, JCAT_SIGN_FLAG_NONE, &error); + if (jcat_sig == NULL) { g_message ("failed to sign using keyring: %s", error->message); return; } @@ -5486,6 +5535,10 @@ fu_engine_init (FuEngine *self) #ifdef HAVE_UTSNAME_H struct utsname uname_tmp; #endif + g_autofree gchar *keyring_path = NULL; + g_autofree gchar *pkidir_fw = NULL; + g_autofree gchar *pkidir_md = NULL; + g_autofree gchar *sysconfdir = NULL; self->percentage = 0; self->status = FWUPD_STATUS_IDLE; self->config = fu_config_new (); @@ -5518,6 +5571,16 @@ fu_engine_init (FuEngine *self) g_signal_connect (self->idle, "notify::status", G_CALLBACK (fu_engine_idle_status_notify_cb), self); + /* setup Jcat context */ + self->jcat_context = jcat_context_new (); + keyring_path = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + jcat_context_set_keyring_path (self->jcat_context, keyring_path); + sysconfdir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR); + pkidir_fw = g_build_filename (sysconfdir, "pki", "fwupd", NULL); + jcat_context_add_public_keys (self->jcat_context, pkidir_fw); + pkidir_md = g_build_filename (sysconfdir, "pki", "fwupd-metadata", NULL); + jcat_context_add_public_keys (self->jcat_context, pkidir_md); + /* add some runtime versions of things the daemon depends on */ fu_engine_add_runtime_version (self, "org.freedesktop.fwupd", VERSION); fu_engine_add_runtime_version (self, "com.redhat.fwupdate", "12"); @@ -5573,6 +5636,7 @@ fu_engine_finalize (GObject *obj) g_object_unref (self->hwids); g_object_unref (self->history); g_object_unref (self->device_list); + g_object_unref (self->jcat_context); g_ptr_array_unref (self->plugin_filter); g_ptr_array_unref (self->udev_subsystems); #ifdef HAVE_GUDEV diff --git a/src/fu-engine.h b/src/fu-engine.h index 482c11de0..044e62018 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -8,12 +8,12 @@ #include #include +#include #include "fwupd-device.h" #include "fwupd-enums.h" #include "fu-common.h" -#include "fu-keyring.h" #include "fu-install-task.h" #include "fu-plugin.h" @@ -147,7 +147,7 @@ void fu_engine_add_approved_firmware (FuEngine *self, const gchar *checksum); gchar *fu_engine_self_sign (FuEngine *self, const gchar *value, - FuKeyringSignFlags flags, + JcatSignFlags flags, GError **error); gboolean fu_engine_modify_config (FuEngine *self, const gchar *key, diff --git a/src/fu-keyring-gpg.c b/src/fu-keyring-gpg.c deleted file mode 100644 index f06449cf2..000000000 --- a/src/fu-keyring-gpg.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#define G_LOG_DOMAIN "FuKeyring" - -#include "config.h" - -#include - -#include "fwupd-error.h" - -#include "fu-common.h" -#include "fu-keyring-gpg.h" - -struct _FuKeyringGpg -{ - FuKeyring parent_instance; - gpgme_ctx_t ctx; -}; - -G_DEFINE_TYPE (FuKeyringGpg, fu_keyring_gpg, FU_TYPE_KEYRING) - -G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gpgme_data_t, gpgme_data_release, NULL) - -static gboolean -fu_keyring_gpg_add_public_key (FuKeyringGpg *self, - const gchar *filename, - GError **error) -{ - gpgme_error_t rc; - gpgme_import_result_t result; - gpgme_import_status_t s; - g_auto(gpgme_data_t) data = NULL; - - /* import public key */ - g_debug ("Adding GnuPG public key %s", filename); - rc = gpgme_data_new_from_file (&data, filename, 1); - if (rc != GPG_ERR_NO_ERROR) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to load %s: %s", - filename, gpgme_strerror (rc)); - return FALSE; - } - rc = gpgme_op_import (self->ctx, data); - if (rc != GPG_ERR_NO_ERROR) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to import %s: %s", - filename, gpgme_strerror (rc)); - return FALSE; - } - - /* print what keys were imported */ - result = gpgme_op_import_result (self->ctx); - for (s = result->imports; s != NULL; s = s->next) { - g_debug ("importing key %s [%u] %s", - s->fpr, s->status, gpgme_strerror (s->result)); - } - - /* make sure keys were really imported */ - if (result->imported == 0 && result->unchanged == 0) { - g_debug("imported: %d, unchanged: %d, not_imported: %d", - result->imported, - result->unchanged, - result->not_imported); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "key import failed %s", - filename); - return FALSE; - } - return TRUE; -} - -static gboolean -fu_keyring_gpg_setup (FuKeyring *keyring, GError **error) -{ - FuKeyringGpg *self = FU_KEYRING_GPG (keyring); - gpgme_error_t rc; - g_autofree gchar *gpg_home = NULL; - g_autofree gchar *localstatedir = NULL; - - if (self->ctx != NULL) - return TRUE; - - /* startup gpgme */ - rc = gpg_err_init (); - if (rc != GPG_ERR_NO_ERROR) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to init: %s", - gpgme_strerror (rc)); - return FALSE; - } - - /* create a new GPG context */ - rc = gpgme_new (&self->ctx); - if (rc != GPG_ERR_NO_ERROR) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to create context: %s", - gpgme_strerror (rc)); - return FALSE; - } - - /* set the protocol */ - rc = gpgme_set_protocol (self->ctx, GPGME_PROTOCOL_OpenPGP); - if (rc != GPG_ERR_NO_ERROR) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to set protocol: %s", - gpgme_strerror (rc)); - return FALSE; - } - - /* set a custom home directory */ - localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); - gpg_home = g_build_filename (localstatedir, "gnupg", NULL); - if (g_mkdir_with_parents (gpg_home, 0700) < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to create %s", - gpg_home); - return FALSE; - } - g_debug ("Using keyring at %s", gpg_home); - rc = gpgme_ctx_set_engine_info (self->ctx, - GPGME_PROTOCOL_OpenPGP, - NULL, - gpg_home); - if (rc != GPG_ERR_NO_ERROR) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to set protocol: %s", - gpgme_strerror (rc)); - return FALSE; - } - - /* enable armor mode */ - gpgme_set_armor (self->ctx, TRUE); - return TRUE; -} - -static gboolean -fu_keyring_gpg_add_public_keys (FuKeyring *keyring, - const gchar *path, - GError **error) -{ - FuKeyringGpg *self = FU_KEYRING_GPG (keyring); - const gchar *fn_tmp; - g_autoptr(GDir) dir = NULL; - - /* search all the public key files */ - dir = g_dir_open (path, 0, error); - if (dir == NULL) - return FALSE; - while ((fn_tmp = g_dir_read_name (dir)) != NULL) { - g_autofree gchar *path_tmp = NULL; - if (!g_str_has_prefix (fn_tmp, "GPG-KEY-")) - continue; - path_tmp = g_build_filename (path, fn_tmp, NULL); - if (!fu_keyring_gpg_add_public_key (self, path_tmp, error)) - return FALSE; - } - return TRUE; -} - -static gboolean -fu_keyring_gpg_check_signature (gpgme_signature_t signature, GError **error) -{ - gboolean ret = FALSE; - - /* look at the signature status */ - switch (gpgme_err_code (signature->status)) { - case GPG_ERR_NO_ERROR: - ret = TRUE; - break; - case GPG_ERR_SIG_EXPIRED: - case GPG_ERR_KEY_EXPIRED: - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "valid signature '%s' has expired", - signature->fpr); - break; - case GPG_ERR_CERT_REVOKED: - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "valid signature '%s' has been revoked", - signature->fpr); - break; - case GPG_ERR_BAD_SIGNATURE: - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "'%s' is not a valid signature", - signature->fpr); - break; - case GPG_ERR_NO_PUBKEY: - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "Could not check signature '%s' as no public key", - signature->fpr); - break; - default: - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "gpgme failed to verify signature '%s'", - signature->fpr); - break; - } - return ret; -} - -static FuKeyringResult * -fu_keyring_gpg_verify_data (FuKeyring *keyring, - GBytes *blob, - GBytes *blob_signature, - FuKeyringVerifyFlags flags, - GError **error) -{ - FuKeyringGpg *self = FU_KEYRING_GPG (keyring); - gpgme_error_t rc; - gpgme_signature_t s; - gpgme_verify_result_t result; - gint64 timestamp_newest = 0; - g_auto(gpgme_data_t) data = NULL; - g_auto(gpgme_data_t) sig = NULL; - g_autoptr(GString) authority_newest = g_string_new (NULL); - - /* not supported */ - if (flags & FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "no GPG client certificate support"); - return NULL; - } - - /* load file data */ - rc = gpgme_data_new_from_mem (&data, - g_bytes_get_data (blob, NULL), - g_bytes_get_size (blob), 0); - if (rc != GPG_ERR_NO_ERROR) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to load data: %s", - gpgme_strerror (rc)); - return NULL; - } - rc = gpgme_data_new_from_mem (&sig, - g_bytes_get_data (blob_signature, NULL), - g_bytes_get_size (blob_signature), 0); - if (rc != GPG_ERR_NO_ERROR) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to load signature: %s", - gpgme_strerror (rc)); - return NULL; - } - - /* verify */ - rc = gpgme_op_verify (self->ctx, sig, data, NULL); - if (rc != GPG_ERR_NO_ERROR) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to verify data: %s", - gpgme_strerror (rc)); - return NULL; - } - - - /* verify the result */ - result = gpgme_op_verify_result (self->ctx); - if (result == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "no result record from libgpgme"); - return NULL; - } - - /* look at each signature */ - for (s = result->signatures; s != NULL ; s = s->next ) { - g_debug ("returned signature fingerprint %s", s->fpr); - if (!fu_keyring_gpg_check_signature (s, error)) - return NULL; - - /* save details about the key for the result */ - if ((gint64) s->timestamp > timestamp_newest) { - timestamp_newest = (gint64) s->timestamp; - g_string_assign (authority_newest, s->fpr); - } - } - return FU_KEYRING_RESULT (g_object_new (FU_TYPE_KEYRING_RESULT, - "timestamp", timestamp_newest, - "authority", authority_newest->str, - NULL)); -} - -static void -fu_keyring_gpg_finalize (GObject *object) -{ - FuKeyringGpg *self = FU_KEYRING_GPG (object); - if (self->ctx != NULL) - gpgme_release (self->ctx); - G_OBJECT_CLASS (fu_keyring_gpg_parent_class)->finalize (object); -} - -static void -fu_keyring_gpg_class_init (FuKeyringGpgClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - FuKeyringClass *klass_app = FU_KEYRING_CLASS (klass); - klass_app->setup = fu_keyring_gpg_setup; - klass_app->add_public_keys = fu_keyring_gpg_add_public_keys; - klass_app->verify_data = fu_keyring_gpg_verify_data; - object_class->finalize = fu_keyring_gpg_finalize; -} - -static void -fu_keyring_gpg_init (FuKeyringGpg *self) -{ - FuKeyring *keyring = FU_KEYRING (self); - g_autofree gchar *name = NULL; - name = g_strdup_printf ("gpgme-v%s", gpgme_check_version (NULL)); - fu_keyring_set_name (keyring, name); -} - -FuKeyring * -fu_keyring_gpg_new (void) -{ - return FU_KEYRING (g_object_new (FU_TYPE_KEYRING_GPG, NULL)); -} diff --git a/src/fu-keyring-gpg.h b/src/fu-keyring-gpg.h deleted file mode 100644 index 8c5c7f89d..000000000 --- a/src/fu-keyring-gpg.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include "fu-keyring.h" - -#define FU_TYPE_KEYRING_GPG (fu_keyring_gpg_get_type ()) - -G_DECLARE_FINAL_TYPE (FuKeyringGpg, fu_keyring_gpg, FU, KEYRING_GPG, FuKeyring) - -FuKeyring *fu_keyring_gpg_new (void); diff --git a/src/fu-keyring-pkcs7.c b/src/fu-keyring-pkcs7.c deleted file mode 100644 index a42feaa7e..000000000 --- a/src/fu-keyring-pkcs7.c +++ /dev/null @@ -1,836 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#define G_LOG_DOMAIN "FuKeyring" - -#include "config.h" - -#include -#include -#include - -#include "fu-common.h" -#include "fu-keyring-pkcs7.h" - -#include "fwupd-error.h" - -struct _FuKeyringPkcs7 -{ - FuKeyring parent_instance; - gnutls_x509_trust_list_t tl; -}; - -G_DEFINE_TYPE (FuKeyringPkcs7, fu_keyring_pkcs7, FU_TYPE_KEYRING) - -typedef guchar gnutls_data_t; - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_pkcs7_t, gnutls_pkcs7_deinit, NULL) -G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_privkey_t, gnutls_privkey_deinit, NULL) -G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_pubkey_t, gnutls_pubkey_deinit, NULL) -G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_x509_crt_t, gnutls_x509_crt_deinit, NULL) -G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_x509_dn_t, gnutls_x509_dn_deinit, NULL) -G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_x509_privkey_t, gnutls_x509_privkey_deinit, NULL) -#ifdef HAVE_GNUTLS_3_6_0 -G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_x509_spki_t, gnutls_x509_spki_deinit, NULL) -#endif -G_DEFINE_AUTOPTR_CLEANUP_FUNC(gnutls_data_t, gnutls_free) -#pragma clang diagnostic pop - -static gnutls_x509_crt_t -fu_keyring_pkcs7_load_crt_from_filename (const gchar *filename, - gnutls_x509_crt_fmt_t format, - GError **error) -{ - gnutls_datum_t d = { 0 }; - gsize bufsz = 0; - int rc; - g_autofree gchar *buf = NULL; - g_auto(gnutls_x509_crt_t) crt = NULL; - - /* create certificate */ - rc = gnutls_x509_crt_init (&crt); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "crt_init: %s [%i]", - gnutls_strerror (rc), rc); - return NULL; - } - - /* import the certificate */ - if (!g_file_get_contents (filename, &buf, &bufsz, error)) - return NULL; - d.size = bufsz; - d.data = (unsigned char *) buf; - rc = gnutls_x509_crt_import (crt, &d, GNUTLS_X509_FMT_PEM); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "crt_import: %s [%i]", - gnutls_strerror (rc), rc); - return NULL; - } - return g_steal_pointer (&crt); -} - -static gboolean -fu_keyring_pkcs7_add_public_key (FuKeyringPkcs7 *self, - const gchar *filename, - gnutls_x509_crt_fmt_t format, - GError **error) -{ - guint key_usage = 0; - int rc; - g_auto(gnutls_x509_crt_t) crt = NULL; - - /* load file and add to the trust list */ - g_debug ("trying to load certificate from %s", filename); - crt = fu_keyring_pkcs7_load_crt_from_filename (filename, format, error); - if (crt == NULL) - return FALSE; - rc = gnutls_x509_crt_get_key_usage (crt, &key_usage, NULL); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "failed to get key usage: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - if ((key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE) == 0 && - (key_usage & GNUTLS_KEY_KEY_CERT_SIGN) == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "certificate %s not suitable for use [0x%x]", - filename, key_usage); - return FALSE; - } - rc = gnutls_x509_trust_list_add_cas (self->tl, &crt, 1, 0); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "failed to add to trust list: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - g_debug ("loaded %i certificates", rc); - - /* confusingly the trust list does not copy the certificate */ - crt = NULL; - return TRUE; -} - -static gboolean -fu_keyring_pkcs7_add_public_keys (FuKeyring *keyring, - const gchar *path, - GError **error) -{ - FuKeyringPkcs7 *self = FU_KEYRING_PKCS7 (keyring); - const gchar *fn_tmp; - g_autoptr(GDir) dir = NULL; - - /* search all the public key files */ - dir = g_dir_open (path, 0, error); - if (dir == NULL) - return FALSE; - while ((fn_tmp = g_dir_read_name (dir)) != NULL) { - g_autofree gchar *path_tmp = NULL; - path_tmp = g_build_filename (path, fn_tmp, NULL); - if (g_str_has_suffix (fn_tmp, ".pem")) { - if (!fu_keyring_pkcs7_add_public_key (self, path_tmp, - GNUTLS_X509_FMT_PEM, - error)) - return FALSE; - } - if (g_str_has_suffix (fn_tmp, ".cer") || - g_str_has_suffix (fn_tmp, ".crt") || - g_str_has_suffix (fn_tmp, ".der")) { - if (!fu_keyring_pkcs7_add_public_key (self, path_tmp, - GNUTLS_X509_FMT_DER, - error)) - return FALSE; - } - } - return TRUE; -} - -static gnutls_privkey_t -fu_keyring_pkcs7_load_privkey (FuKeyringPkcs7 *self, GError **error) -{ - int rc; - gnutls_datum_t d = { 0 }; - gsize bufsz = 0; - g_autofree gchar *buf = NULL; - g_autofree gchar *fn = NULL; - g_autofree gchar *localstatedir = NULL; - g_auto(gnutls_privkey_t) key = NULL; - - /* load the private key */ - rc = gnutls_privkey_init (&key); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "privkey_init: %s [%i]", - gnutls_strerror (rc), rc); - return NULL; - } - localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); - fn = g_build_filename (localstatedir, "pki", "secret.key", NULL); - if (!g_file_get_contents (fn, &buf, &bufsz, error)) - return NULL; - d.size = bufsz; - d.data = (unsigned char *) buf; - rc = gnutls_privkey_import_x509_raw (key, &d, GNUTLS_X509_FMT_PEM, NULL, 0); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "privkey_import_x509_raw: %s [%i]", - gnutls_strerror (rc), rc); - return NULL; - } - return g_steal_pointer (&key); -} - -static gnutls_x509_crt_t -fu_keyring_pkcs7_load_client_certificate (FuKeyringPkcs7 *self, GError **error) -{ - g_autofree gchar *filename = NULL; - g_autofree gchar *localstatedir = NULL; - localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); - filename = g_build_filename (localstatedir, "pki", "client.pem", NULL); - return fu_keyring_pkcs7_load_crt_from_filename (filename, - GNUTLS_X509_FMT_PEM, - error); -} - -static gnutls_pubkey_t -fu_keyring_pkcs7_load_pubkey_from_privkey (gnutls_privkey_t privkey, GError **error) -{ - g_auto(gnutls_pubkey_t) pubkey = NULL; - int rc; - - /* get the public key part of the private key */ - rc = gnutls_pubkey_init (&pubkey); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "pubkey_init: %s [%i]", - gnutls_strerror (rc), rc); - return NULL; - } - rc = gnutls_pubkey_import_privkey (pubkey, privkey, 0, 0); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "pubkey_import_privkey: %s [%i]", - gnutls_strerror (rc), rc); - return NULL; - } - - /* success */ - return g_steal_pointer (&pubkey); -} - -/* generates a private key just like: - * `certtool --generate-privkey` */ -static gboolean -fu_keyring_pkcs7_ensure_private_key (FuKeyringPkcs7 *self, GError **error) -{ -#ifdef HAVE_GNUTLS_3_6_0 - gnutls_datum_t d = { 0 }; - int bits; - int key_type = GNUTLS_PK_RSA; - int rc; - g_autofree gchar *fn = NULL; - g_autofree gchar *localstatedir = NULL; - g_auto(gnutls_x509_privkey_t) key = NULL; - g_auto(gnutls_x509_spki_t) spki = NULL; - g_autoptr(GFile) file = NULL; - g_autoptr(gnutls_data_t) d_payload = NULL; - - /* check exists */ - localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); - fn = g_build_filename (localstatedir, "pki", "secret.key", NULL); - if (g_file_test (fn, G_FILE_TEST_EXISTS)) - return TRUE; - - /* initialize key and SPKI */ - rc = gnutls_x509_privkey_init (&key); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "privkey_init: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - rc = gnutls_x509_spki_init (&spki); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "spki_init: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - - /* generate key */ - bits = gnutls_sec_param_to_pk_bits (key_type, GNUTLS_SEC_PARAM_HIGH); - g_debug ("generating a %d bit %s private key...", - bits, gnutls_pk_algorithm_get_name (key_type)); - rc = gnutls_x509_privkey_generate2(key, key_type, bits, 0, NULL, 0); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "privkey_generate2: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - rc = gnutls_x509_privkey_verify_params (key); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "privkey_verify_params: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - - /* create parents if required */ - if (!fu_common_mkdir_parent (fn, error)) - return FALSE; - - /* save to file */ - rc = gnutls_x509_privkey_export2 (key, GNUTLS_X509_FMT_PEM, &d); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "privkey_export2: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - d_payload = d.data; - file = g_file_new_for_path (fn); - return g_file_replace_contents (file, (const char *) d_payload, d.size, - NULL, FALSE, G_FILE_CREATE_PRIVATE, NULL, - NULL, error); -#else - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "cannot build private key as GnuTLS version is too old"); - return FALSE; -#endif -} - -/* generates a self signed certificate just like: - * `certtool --generate-self-signed --load-privkey priv.pem` */ -static gboolean -fu_keyring_pkcs7_ensure_client_certificate (FuKeyringPkcs7 *self, GError **error) -{ - int rc; - gnutls_datum_t d = { 0 }; - guchar sha1buf[20]; - gsize sha1bufsz = sizeof(sha1buf); - g_autofree gchar *fn = NULL; - g_autofree gchar *localstatedir = NULL; - g_auto(gnutls_privkey_t) key = NULL; - g_auto(gnutls_pubkey_t) pubkey = NULL; - g_auto(gnutls_x509_crt_t) crt = NULL; - g_autoptr(gnutls_data_t) d_payload = NULL; - - /* check exists */ - localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); - fn = g_build_filename (localstatedir, "pki", "client.pem", NULL); - if (g_file_test (fn, G_FILE_TEST_EXISTS)) - return TRUE; - - /* ensure the private key exists */ - if (!fu_keyring_pkcs7_ensure_private_key (self, error)) { - g_prefix_error (error, "failed to generate private key: "); - return FALSE; - } - - /* load private key */ - key = fu_keyring_pkcs7_load_privkey (self, error); - if (key == NULL) - return FALSE; - - /* load the public key from the private key */ - pubkey = fu_keyring_pkcs7_load_pubkey_from_privkey (key, error); - if (pubkey == NULL) - return FALSE; - - /* create certificate */ - rc = gnutls_x509_crt_init (&crt); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "crt_init: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - - /* set public key */ - rc = gnutls_x509_crt_set_pubkey (crt, pubkey); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "crt_set_pubkey: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - - /* set positive random serial number */ - rc = gnutls_rnd (GNUTLS_RND_NONCE, sha1buf, sizeof(sha1buf)); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "gnutls_rnd: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - sha1buf[0] &= 0x7f; - rc = gnutls_x509_crt_set_serial(crt, sha1buf, sizeof(sha1buf)); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "crt_set_serial: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - - /* set activation */ - rc = gnutls_x509_crt_set_activation_time (crt, time (NULL)); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "set_activation_time: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - - /* set expiration */ - rc = gnutls_x509_crt_set_expiration_time (crt, (time_t) -1); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "set_expiration_time: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - - /* set basic constraints */ - rc = gnutls_x509_crt_set_basic_constraints (crt, 0, -1); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "set_basic_constraints: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - - /* set usage */ - rc = gnutls_x509_crt_set_key_usage (crt, GNUTLS_KEY_DIGITAL_SIGNATURE); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "set_key_usage: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - - /* set subject key ID */ - rc = gnutls_x509_crt_get_key_id (crt, GNUTLS_KEYID_USE_SHA1, sha1buf, &sha1bufsz); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "get_key_id: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - rc = gnutls_x509_crt_set_subject_key_id (crt, sha1buf, sha1bufsz); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "set_subject_key_id: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - - /* set version */ - rc = gnutls_x509_crt_set_version (crt, 3); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "error setting certificate version: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - - /* self-sign certificate */ - rc = gnutls_x509_crt_privkey_sign (crt, crt, key, GNUTLS_DIG_SHA256, 0); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "crt_privkey_sign: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - - /* export to file */ - rc = gnutls_x509_crt_export2 (crt, GNUTLS_X509_FMT_PEM, &d); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "crt_export2: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - d_payload = d.data; - return g_file_set_contents (fn, (const gchar *) d_payload, d.size, error); -} - -static gboolean -fu_keyring_pkcs7_setup (FuKeyring *keyring, GError **error) -{ - FuKeyringPkcs7 *self = FU_KEYRING_PKCS7 (keyring); - int rc; - - if (self->tl != NULL) - return TRUE; - - /* create trust list, a bit like a keyring */ - rc = gnutls_x509_trust_list_init (&self->tl, 0); - if (rc != GNUTLS_E_SUCCESS) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "failed to create trust list: %s [%i]", - gnutls_strerror (rc), rc); - return FALSE; - } - return TRUE; -} - -static void -_gnutls_datum_deinit (gnutls_datum_t *d) -{ - gnutls_free (d->data); - gnutls_free (d); -} - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -G_DEFINE_AUTOPTR_CLEANUP_FUNC(gnutls_datum_t, _gnutls_datum_deinit) -#pragma clang diagnostic pop - -static gchar * -fu_keyring_pkcs7_datum_to_dn_str (const gnutls_datum_t *raw) -{ - g_auto(gnutls_x509_dn_t) dn = NULL; - g_autoptr(gnutls_datum_t) str = NULL; - int rc; - rc = gnutls_x509_dn_init (&dn); - if (rc < 0) - return NULL; - rc = gnutls_x509_dn_import (dn, raw); - if (rc < 0) - return NULL; - str = (gnutls_datum_t *) gnutls_malloc (sizeof (gnutls_datum_t)); - str->data = NULL; - rc = gnutls_x509_dn_get_str2 (dn, str, 0); - if (rc < 0) - return NULL; - return g_strndup ((const gchar *) str->data, str->size); -} - -/* verifies a detached signature just like: - * `certtool --p7-verify --load-certificate client.pem --infile=test.p7b` */ -static FuKeyringResult * -fu_keyring_pkcs7_verify_data (FuKeyring *keyring, - GBytes *blob, - GBytes *blob_signature, - FuKeyringVerifyFlags flags, - GError **error) -{ - FuKeyringPkcs7 *self = FU_KEYRING_PKCS7 (keyring); - gnutls_datum_t datum = { 0 }; - gint64 timestamp_newest = 0; - int count; - int rc; - g_auto(gnutls_pkcs7_t) pkcs7 = NULL; - g_auto(gnutls_x509_crt_t) crt = NULL; - g_autoptr(GString) authority_newest = g_string_new (NULL); - - /* startup */ - rc = gnutls_pkcs7_init (&pkcs7); - if (rc != GNUTLS_E_SUCCESS) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "failed to init pkcs7: %s [%i]", - gnutls_strerror (rc), rc); - return NULL; - } - - /* import the signature */ - datum.data = (guchar *) g_bytes_get_data (blob_signature, NULL); - datum.size = g_bytes_get_size (blob_signature); - rc = gnutls_pkcs7_import (pkcs7, &datum, GNUTLS_X509_FMT_PEM); - if (rc != GNUTLS_E_SUCCESS) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "failed to import the PKCS7 signature: %s [%i]", - gnutls_strerror (rc), rc); - return NULL; - } - - /* verify the blob */ - datum.data = (guchar *) g_bytes_get_data (blob, NULL); - datum.size = g_bytes_get_size (blob); - count = gnutls_pkcs7_get_signature_count (pkcs7); - g_debug ("got %i PKCS7 signatures", count); - if (count == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "no PKCS7 signatures found"); - return NULL; - } - - /* use client certificate */ - if (flags & FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT) { - if (!fu_keyring_pkcs7_ensure_client_certificate (self, error)) { - g_prefix_error (error, "failed to generate client certificate: "); - return NULL; - } - crt = fu_keyring_pkcs7_load_client_certificate (self, error); - if (crt == NULL) - return NULL; - } - - for (gint i = 0; i < count; i++) { - gnutls_pkcs7_signature_info_st info; - gint64 signing_time = 0; - gnutls_certificate_verify_flags verify_flags = 0; - - /* use with care */ - if (flags & FU_KEYRING_VERIFY_FLAG_DISABLE_TIME_CHECKS) { - g_debug ("WARNING: disabling time checks"); - verify_flags |= GNUTLS_VERIFY_DISABLE_TIME_CHECKS; - verify_flags |= GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS; - } - - /* verify the data against the detached signature */ - if (flags & FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT) { - rc = gnutls_pkcs7_verify_direct (pkcs7, crt, i, &datum, 0); - } else { - rc = gnutls_pkcs7_verify (pkcs7, self->tl, - NULL, /* vdata */ - 0, /* vdata_size */ - i, /* index */ - &datum, /* data */ - verify_flags); - } - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "failed to verify data: %s [%i]", - gnutls_strerror (rc), rc); - return NULL; - } - - /* save details about the key for the result */ - rc = gnutls_pkcs7_get_signature_info (pkcs7, i, &info); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "failed to get signature info: %s [%i]", - gnutls_strerror (rc), rc); - return NULL; - } - signing_time = info.signing_time > 0 ? (gint64) info.signing_time : 1; - if (signing_time > timestamp_newest) { - g_autofree gchar *dn = NULL; - timestamp_newest = signing_time; - dn = fu_keyring_pkcs7_datum_to_dn_str (&info.issuer_dn); - if (dn != NULL) - g_string_assign (authority_newest, dn); - } - gnutls_pkcs7_signature_info_deinit (&info); - } - - /* success */ - return FU_KEYRING_RESULT (g_object_new (FU_TYPE_KEYRING_RESULT, - "timestamp", timestamp_newest, - "authority", authority_newest->str, - NULL)); -} - -/* creates a detached signature just like: - * `certtool --p7-detached-sign --load-certificate client.pem \ - * --load-privkey secret.pem --outfile=test.p7b` */ -static GBytes * -fu_keyring_pkcs7_sign_data (FuKeyring *keyring, - GBytes *blob, - FuKeyringSignFlags flags, - GError **error) -{ - FuKeyringPkcs7 *self = FU_KEYRING_PKCS7 (keyring); - gnutls_datum_t d = { 0 }; - gnutls_digest_algorithm_t dig = GNUTLS_DIG_NULL; - guint gnutls_flags = 0; - int rc; - g_auto(gnutls_pkcs7_t) pkcs7 = NULL; - g_auto(gnutls_privkey_t) key = NULL; - g_auto(gnutls_pubkey_t) pubkey = NULL; - g_auto(gnutls_x509_crt_t) crt = NULL; - g_autoptr(gnutls_data_t) d_payload = NULL; - - /* ensure the client certificate exists */ - if (!fu_keyring_pkcs7_ensure_client_certificate (self, error)) { - g_prefix_error (error, "failed to generate client certificate: "); - return NULL; - } - - /* import the keys */ - crt = fu_keyring_pkcs7_load_client_certificate (self, error); - if (crt == NULL) - return NULL; - key = fu_keyring_pkcs7_load_privkey (self, error); - if (key == NULL) - return NULL; - - /* get the digest algorithm from the publix key */ - pubkey = fu_keyring_pkcs7_load_pubkey_from_privkey (key, error); - if (pubkey == NULL) - return NULL; - rc = gnutls_pubkey_get_preferred_hash_algorithm (pubkey, &dig, NULL); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "preferred_hash_algorithm: %s [%i]", - gnutls_strerror (rc), rc); - return NULL; - } - - /* create container */ - rc = gnutls_pkcs7_init (&pkcs7); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "pkcs7_init: %s [%i]", - gnutls_strerror (rc), rc); - return NULL; - } - - /* sign data */ - d.data = (unsigned char *) g_bytes_get_data (blob, NULL); - d.size = g_bytes_get_size (blob); - if (flags & FU_KEYRING_SIGN_FLAG_ADD_TIMESTAMP) - gnutls_flags |= GNUTLS_PKCS7_INCLUDE_TIME; - if (flags & FU_KEYRING_SIGN_FLAG_ADD_CERT) - gnutls_flags |= GNUTLS_PKCS7_INCLUDE_CERT; - rc = gnutls_pkcs7_sign (pkcs7, crt, key, &d, NULL, NULL, dig, gnutls_flags); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "pkcs7_sign: %s [%i]", - gnutls_strerror (rc), rc); - return NULL; - } - - /* set certificate */ - if (flags & FU_KEYRING_SIGN_FLAG_ADD_CERT) { - rc = gnutls_pkcs7_set_crt (pkcs7, crt); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "pkcs7_set_cr: %s", gnutls_strerror (rc)); - return NULL; - } - } - - /* export */ - rc = gnutls_pkcs7_export2 (pkcs7, GNUTLS_X509_FMT_PEM, &d); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "pkcs7_export: %s", gnutls_strerror (rc)); - return NULL; - } - d_payload = d.data; - return g_bytes_new (d_payload, d.size); -} - -static void -fu_keyring_pkcs7_finalize (GObject *object) -{ - FuKeyringPkcs7 *self = FU_KEYRING_PKCS7 (object); - gnutls_x509_trust_list_deinit (self->tl, 1); - G_OBJECT_CLASS (fu_keyring_pkcs7_parent_class)->finalize (object); -} - -static void -fu_keyring_pkcs7_class_init (FuKeyringPkcs7Class *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - FuKeyringClass *klass_app = FU_KEYRING_CLASS (klass); - klass_app->setup = fu_keyring_pkcs7_setup; - klass_app->add_public_keys = fu_keyring_pkcs7_add_public_keys; - klass_app->sign_data = fu_keyring_pkcs7_sign_data; - klass_app->verify_data = fu_keyring_pkcs7_verify_data; - object_class->finalize = fu_keyring_pkcs7_finalize; -} - -static void -fu_keyring_pkcs7_init (FuKeyringPkcs7 *self) -{ - FuKeyring *keyring = FU_KEYRING (self); - g_autofree gchar *name = NULL; - name = g_strdup_printf ("gnutls-v%s", gnutls_check_version (NULL)); - fu_keyring_set_name (keyring, name); -} - -FuKeyring * -fu_keyring_pkcs7_new (void) -{ - return FU_KEYRING (g_object_new (FU_TYPE_KEYRING_PKCS7, NULL)); -} diff --git a/src/fu-keyring-pkcs7.h b/src/fu-keyring-pkcs7.h deleted file mode 100644 index eda168f27..000000000 --- a/src/fu-keyring-pkcs7.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include "fu-keyring.h" - -#define FU_TYPE_KEYRING_PKCS7 (fu_keyring_pkcs7_get_type ()) - -G_DECLARE_FINAL_TYPE (FuKeyringPkcs7, fu_keyring_pkcs7, FU, KEYRING_PKCS7, FuKeyring) - -FuKeyring *fu_keyring_pkcs7_new (void); diff --git a/src/fu-keyring-result.c b/src/fu-keyring-result.c deleted file mode 100644 index 42f024387..000000000 --- a/src/fu-keyring-result.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#define G_LOG_DOMAIN "FuKeyring" - -#include "config.h" - -#include "fwupd-error.h" - -#include "fu-keyring-result.h" - -struct _FuKeyringResult -{ - GObject parent_instance; - gint64 timestamp; - gchar *authority; -}; - -G_DEFINE_TYPE (FuKeyringResult, fu_keyring_result, G_TYPE_OBJECT) - -enum { - PROP_0, - PROP_TIMESTAMP, - PROP_AUTHORITY, - PROP_LAST -}; - -gint64 -fu_keyring_result_get_timestamp (FuKeyringResult *self) -{ - g_return_val_if_fail (FU_IS_KEYRING_RESULT (self), 0); - return self->timestamp; -} - -const gchar * -fu_keyring_result_get_authority (FuKeyringResult *self) -{ - g_return_val_if_fail (FU_IS_KEYRING_RESULT (self), NULL); - return self->authority; -} - -static void -fu_keyring_result_finalize (GObject *object) -{ - FuKeyringResult *self = FU_KEYRING_RESULT (object); - g_free (self->authority); - G_OBJECT_CLASS (fu_keyring_result_parent_class)->finalize (object); -} - -static void -fu_keyring_result_get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - FuKeyringResult *self = FU_KEYRING_RESULT (object); - switch (prop_id) { - case PROP_TIMESTAMP: - g_value_set_int64 (value, self->timestamp); - break; - case PROP_AUTHORITY: - g_value_set_string (value, self->authority); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -fu_keyring_result_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - FuKeyringResult *self = FU_KEYRING_RESULT (object); - switch (prop_id) { - case PROP_TIMESTAMP: - self->timestamp = g_value_get_int64 (value); - break; - case PROP_AUTHORITY: - self->authority = g_value_dup_string (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -fu_keyring_result_class_init (FuKeyringResultClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *pspec; - - object_class->get_property = fu_keyring_result_get_property; - object_class->set_property = fu_keyring_result_set_property; - object_class->finalize = fu_keyring_result_finalize; - - pspec = g_param_spec_int64 ("timestamp", NULL, NULL, - 0, G_MAXINT64, 0, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_NAME); - g_object_class_install_property (object_class, PROP_TIMESTAMP, pspec); - - pspec = g_param_spec_string ("authority", NULL, NULL, NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_NAME); - g_object_class_install_property (object_class, PROP_AUTHORITY, pspec); -} - -static void -fu_keyring_result_init (FuKeyringResult *self) -{ -} diff --git a/src/fu-keyring-result.h b/src/fu-keyring-result.h deleted file mode 100644 index 14a5acd29..000000000 --- a/src/fu-keyring-result.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include - -#define FU_TYPE_KEYRING_RESULT (fu_keyring_result_get_type ()) - -G_DECLARE_FINAL_TYPE (FuKeyringResult, fu_keyring_result, FU, KEYRING_RESULT, GObject) - -gint64 fu_keyring_result_get_timestamp (FuKeyringResult *self); -const gchar *fu_keyring_result_get_authority (FuKeyringResult *self); diff --git a/src/fu-keyring-utils.c b/src/fu-keyring-utils.c index f14068ba4..f4e09de64 100644 --- a/src/fu-keyring-utils.c +++ b/src/fu-keyring-utils.c @@ -1,70 +1,15 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017-2020 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ -#define G_LOG_DOMAIN "FuKeyring" - #include #include "fwupd-error.h" -#include "fu-common.h" #include "fu-keyring-utils.h" -#ifdef ENABLE_GPG -#include "fu-keyring-gpg.h" -#endif -#ifdef ENABLE_PKCS7 -#include "fu-keyring-pkcs7.h" -#endif - -/** - * fu_keyring_create_for_kind: - * @kind: A #FwupdKeyringKind, e.g. %FWUPD_KEYRING_KIND_GPG - * @error: A #GError, or %NULL - * - * Creates a new keyring of the specified kind. - * - * If the keyring cannot be created (for example, if fwupd is compiled without - * GPG support) then an error is returned. - * - * Returns: (transfer full): a new #FuKeyring, or %NULL for error - **/ -FuKeyring * -fu_keyring_create_for_kind (FwupdKeyringKind kind, GError **error) -{ - if (kind == FWUPD_KEYRING_KIND_GPG) { -#ifdef ENABLE_GPG - return fu_keyring_gpg_new (); -#else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Not compiled with GPG support"); - return NULL; -#endif - } - if (kind == FWUPD_KEYRING_KIND_PKCS7) { -#ifdef ENABLE_PKCS7 - return fu_keyring_pkcs7_new (); -#else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Not compiled with PKCS7 support"); - return NULL; -#endif - } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Keyring kind %s not supported", - fwupd_keyring_kind_to_string (kind)); - return NULL; -} - /** * fu_keyring_get_release_flags: * @release: A #XbNode, e.g. %FWUPD_KEYRING_KIND_GPG @@ -80,97 +25,27 @@ fu_keyring_get_release_flags (XbNode *release, FwupdReleaseFlags *flags, GError **error) { - FwupdKeyringKind keyring_kind = FWUPD_KEYRING_KIND_UNKNOWN; - GBytes *blob_payload; - GBytes *blob_signature; - const gchar *fn; - g_autofree gchar *pki_dir = NULL; - g_autofree gchar *release_key = NULL; - g_autofree gchar *sysconfdir = NULL; - g_autoptr(GError) error_local = NULL; - g_autoptr(FuKeyring) kr = NULL; - g_autoptr(FuKeyringResult) kr_result = NULL; - struct { - FwupdKeyringKind kind; - const gchar *ext; - } keyrings[] = { - { FWUPD_KEYRING_KIND_GPG, "asc" }, - { FWUPD_KEYRING_KIND_PKCS7, "p7b" }, - { FWUPD_KEYRING_KIND_PKCS7, "p7c" }, - { FWUPD_KEYRING_KIND_NONE, NULL } - }; + GBytes *blob; - /* custom filename specified */ - fn = xb_node_query_attr (release, "checksum[@target='content']", "filename", NULL); - if (fn == NULL) - fn = "filename.bin"; - - /* no signature == no trust */ - for (guint i = 0; keyrings[i].ext != NULL; i++) { - g_autofree gchar *fn_tmp = NULL; - fn_tmp = g_strdup_printf ("fwupd::ReleaseBlob(%s.%s)", - fn, keyrings[i].ext); - blob_signature = g_object_get_data (G_OBJECT (release), fn_tmp); - if (blob_signature != NULL) { - keyring_kind = keyrings[i].kind; - break; - } - } - if (keyring_kind == FWUPD_KEYRING_KIND_UNKNOWN) { - g_debug ("firmware archive contained no signature"); + blob = g_object_get_data (G_OBJECT (release), "fwupd::ReleaseFlags"); + if (blob == NULL) { + g_debug ("no fwupd::ReleaseFlags set by loader"); return TRUE; - } - - /* get payload */ - release_key = g_strdup_printf ("fwupd::ReleaseBlob(%s)", fn); - blob_payload = g_object_get_data (G_OBJECT (release), release_key); - if (blob_payload == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "no payload"); + "no fwupd::ReleaseFlags set by loader"); return FALSE; } - - /* check we were installed correctly */ - sysconfdir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR); - pki_dir = g_build_filename (sysconfdir, "pki", PACKAGE_NAME, NULL); -#if defined(ENABLE_PKCS7) || defined(ENABLE_PKCS7) - if (!g_file_test (pki_dir, G_FILE_TEST_EXISTS)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "PKI directory %s not found", pki_dir); - return FALSE; - } -#endif - - /* verify against the system trusted keys */ - kr = fu_keyring_create_for_kind (keyring_kind, error); - if (kr == NULL) - return FALSE; - if (!fu_keyring_setup (kr, error)) { - g_prefix_error (error, "failed to set up %s keyring: ", - fu_keyring_get_name (kr)); - return FALSE; - } - if (!fu_keyring_add_public_keys (kr, pki_dir, error)) { - g_prefix_error (error, "failed to add public keys to %s keyring: ", - fu_keyring_get_name (kr)); - return FALSE; - } - kr_result = fu_keyring_verify_data (kr, blob_payload, blob_signature, - FU_KEYRING_VERIFY_FLAG_NONE, - &error_local); - if (kr_result == NULL) { - g_warning ("untrusted as failed to verify from %s keyring: %s", - fu_keyring_get_name (kr), - error_local->message); + if (g_bytes_get_size (blob) != sizeof(FwupdReleaseFlags)) { + g_critical ("invalid fwupd::ReleaseFlags set by loader"); return TRUE; + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid fwupd::ReleaseFlags set by loader"); + return FALSE; } - - /* awesome! */ - g_debug ("marking payload as trusted"); - *flags |= FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD; + memcpy (flags, g_bytes_get_data (blob, NULL), sizeof(FwupdReleaseFlags)); return TRUE; } diff --git a/src/fu-keyring-utils.h b/src/fu-keyring-utils.h index 5a95b2d26..92f66bba9 100644 --- a/src/fu-keyring-utils.h +++ b/src/fu-keyring-utils.h @@ -7,12 +7,10 @@ #pragma once #include +#include -#include "fu-keyring.h" #include "fwupd-enums.h" -FuKeyring *fu_keyring_create_for_kind (FwupdKeyringKind kind, - GError **error); gboolean fu_keyring_get_release_flags (XbNode *release, FwupdReleaseFlags *flags, GError **error); diff --git a/src/fu-keyring.c b/src/fu-keyring.c deleted file mode 100644 index 1265e4c76..000000000 --- a/src/fu-keyring.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#define G_LOG_DOMAIN "FuKeyring" - -#include "config.h" - -#include "fwupd-error.h" - -#include "fu-keyring.h" - -typedef struct { - gchar *name; -} FuKeyringPrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (FuKeyring, fu_keyring, G_TYPE_OBJECT) -#define GET_PRIVATE(o) (fu_keyring_get_instance_private (o)) - -gboolean -fu_keyring_setup (FuKeyring *keyring, GError **error) -{ - FuKeyringClass *klass = FU_KEYRING_GET_CLASS (keyring); - g_return_val_if_fail (FU_IS_KEYRING (keyring), FALSE); - return klass->setup (keyring, error); -} - -gboolean -fu_keyring_add_public_keys (FuKeyring *keyring, const gchar *path, GError **error) -{ - FuKeyringClass *klass = FU_KEYRING_GET_CLASS (keyring); - g_return_val_if_fail (FU_IS_KEYRING (keyring), FALSE); - g_return_val_if_fail (path != NULL, FALSE); - return klass->add_public_keys (keyring, path, error); -} - -FuKeyringResult * -fu_keyring_verify_data (FuKeyring *keyring, - GBytes *blob, - GBytes *blob_signature, - FuKeyringVerifyFlags flags, - GError **error) -{ - FuKeyringClass *klass = FU_KEYRING_GET_CLASS (keyring); - g_return_val_if_fail (FU_IS_KEYRING (keyring), NULL); - g_return_val_if_fail (blob != NULL, NULL); - g_return_val_if_fail (blob_signature != NULL, NULL); - return klass->verify_data (keyring, blob, blob_signature, flags, error); -} - -GBytes * -fu_keyring_sign_data (FuKeyring *keyring, - GBytes *blob, - FuKeyringSignFlags flags, - GError **error) -{ - FuKeyringClass *klass = FU_KEYRING_GET_CLASS (keyring); - g_return_val_if_fail (FU_IS_KEYRING (keyring), NULL); - g_return_val_if_fail (blob != NULL, NULL); - if (klass->sign_data == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "signing data is not supported"); - return NULL; - } - return klass->sign_data (keyring, blob, flags, error); -} - -const gchar * -fu_keyring_get_name (FuKeyring *self) -{ - FuKeyringPrivate *priv = GET_PRIVATE (self); - return priv->name; -} - -void -fu_keyring_set_name (FuKeyring *self, const gchar *name) -{ - FuKeyringPrivate *priv = GET_PRIVATE (self); - g_free (priv->name); - priv->name = g_strdup (name); -} - -static void -fu_keyring_finalize (GObject *object) -{ - FuKeyring *self = FU_KEYRING (object); - FuKeyringPrivate *priv = GET_PRIVATE (self); - g_free (priv->name); - G_OBJECT_CLASS (fu_keyring_parent_class)->finalize (object); -} - -static void -fu_keyring_class_init (FuKeyringClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->finalize = fu_keyring_finalize; -} - -static void -fu_keyring_init (FuKeyring *keyring) -{ -} diff --git a/src/fu-keyring.h b/src/fu-keyring.h deleted file mode 100644 index beca1a6c6..000000000 --- a/src/fu-keyring.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2017 Richard Hughes - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include -#include - -#include "fu-keyring-result.h" - -#define FU_TYPE_KEYRING (fu_keyring_get_type ()) -G_DECLARE_DERIVABLE_TYPE (FuKeyring, fu_keyring, FU, KEYRING, GObject) - -/** - * FuKeyringVerifyFlags: - * @FU_KEYRING_VERIFY_FLAG_NONE: No flags set - * @FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT: Use client certificate to verify - * @FU_KEYRING_VERIFY_FLAG_DISABLE_TIME_CHECKS: Disable checking of validity periods - * - * The flags to use when interacting with a keyring - **/ -typedef enum { - FU_KEYRING_VERIFY_FLAG_NONE = 0, - FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT = 1 << 1, - FU_KEYRING_VERIFY_FLAG_DISABLE_TIME_CHECKS = 1 << 2, - /*< private >*/ - FU_KEYRING_VERIFY_FLAG_LAST -} FuKeyringVerifyFlags; - -/** - * FuKeyringSignFlags: - * @FU_KEYRING_SIGN_FLAG_NONE: No flags set - * @FU_KEYRING_SIGN_FLAG_ADD_TIMESTAMP: Add a timestamp - * @FU_KEYRING_SIGN_FLAG_ADD_CERT: Add a certificate - * - * The flags to when signing a binary - **/ -typedef enum { - FU_KEYRING_SIGN_FLAG_NONE = 0, - FU_KEYRING_SIGN_FLAG_ADD_TIMESTAMP = 1 << 0, - FU_KEYRING_SIGN_FLAG_ADD_CERT = 1 << 1, - /*< private >*/ - FU_KEYRING_SIGN_FLAG_LAST -} FuKeyringSignFlags; - -struct _FuKeyringClass -{ - GObjectClass parent_class; - gboolean (*setup) (FuKeyring *keyring, - GError **error); - gboolean (*add_public_keys) (FuKeyring *keyring, - const gchar *path, - GError **error); - FuKeyringResult *(*verify_data) (FuKeyring *keyring, - GBytes *payload, - GBytes *payload_signature, - FuKeyringVerifyFlags flags, - GError **error); - GBytes *(*sign_data) (FuKeyring *keyring, - GBytes *payload, - FuKeyringSignFlags flags, - GError **error); -}; - -gboolean fu_keyring_setup (FuKeyring *keyring, - GError **error); -gboolean fu_keyring_add_public_keys (FuKeyring *keyring, - const gchar *path, - GError **error); -FuKeyringResult *fu_keyring_verify_data (FuKeyring *keyring, - GBytes *blob, - GBytes *blob_signature, - FuKeyringVerifyFlags flags, - GError **error); -GBytes *fu_keyring_sign_data (FuKeyring *keyring, - GBytes *blob, - FuKeyringSignFlags flags, - GError **error); -const gchar *fu_keyring_get_name (FuKeyring *self); -void fu_keyring_set_name (FuKeyring *self, - const gchar *name); diff --git a/src/fu-main.c b/src/fu-main.c index bb6077da4..347b26530 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "fwupd-device-private.h" #include "fwupd-release-private.h" @@ -900,10 +901,10 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, g_debug ("got option %s", prop_key); if (g_strcmp0 (prop_key, "add-timestamp") == 0 && g_variant_get_boolean (prop_value) == TRUE) - helper->flags |= FU_KEYRING_SIGN_FLAG_ADD_TIMESTAMP; + helper->flags |= JCAT_SIGN_FLAG_ADD_TIMESTAMP; if (g_strcmp0 (prop_key, "add-cert") == 0 && g_variant_get_boolean (prop_value) == TRUE) - helper->flags |= FU_KEYRING_SIGN_FLAG_ADD_CERT; + helper->flags |= JCAT_SIGN_FLAG_ADD_CERT; g_variant_unref (prop_value); } diff --git a/src/fu-self-test.c b/src/fu-self-test.c index e05fa731b..40decb5cf 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -19,7 +19,6 @@ #include "fu-device-list.h" #include "fu-device-private.h" #include "fu-engine.h" -#include "fu-keyring.h" #include "fu-history.h" #include "fu-install-task.h" #include "fu-plugin-private.h" @@ -28,13 +27,6 @@ #include "fu-hash.h" #include "fu-smbios-private.h" -#ifdef ENABLE_GPG -#include "fu-keyring-gpg.h" -#endif -#ifdef ENABLE_PKCS7 -#include "fu-keyring-pkcs7.h" -#endif - typedef struct { FuPlugin *plugin; } FuTest; @@ -2591,185 +2583,6 @@ fu_history_func (gconstpointer user_data) g_assert_cmpstr (g_ptr_array_index (approved_firmware, 1), ==, "bar"); } -static void -fu_keyring_gpg_func (gconstpointer user_data) -{ -#ifdef ENABLE_GPG - gboolean ret; - g_autofree gchar *fw_fail = NULL; - g_autofree gchar *fw_pass = NULL; - g_autofree gchar *pki_dir = NULL; - g_autoptr(FuKeyring) keyring = NULL; - g_autoptr(FuKeyringResult) result_fail = NULL; - g_autoptr(FuKeyringResult) result_pass = NULL; - g_autoptr(GBytes) blob_fail = NULL; - g_autoptr(GBytes) blob_pass = NULL; - g_autoptr(GBytes) blob_sig = NULL; - g_autoptr(GError) error = NULL; - const gchar *sig_gpgme = - "-----BEGIN PGP SIGNATURE-----\n" - "Version: GnuPG v1\n\n" - "iQEcBAABCAAGBQJVt0B4AAoJEEim2A5FOLrCFb8IAK+QTLY34Wu8xZ8nl6p3JdMu" - "HOaifXAmX7291UrsFRwdabU2m65pqxQLwcoFrqGv738KuaKtu4oIwo9LIrmmTbEh" - "IID8uszxBt0bMdcIHrvwd+ADx+MqL4hR3guXEE3YOBTLvv2RF1UBcJPInNf/7Ui1" - "3lW1c3trL8RAJyx1B5RdKqAMlyfwiuvKM5oT4SN4uRSbQf+9mt78ZSWfJVZZH/RR" - "H9q7PzR5GdmbsRPM0DgC27Trvqjo3MzoVtoLjIyEb/aWqyulUbnJUNKPYTnZgkzM" - "v2yVofWKIM3e3wX5+MOtf6EV58mWa2cHJQ4MCYmpKxbIvAIZagZ4c9A8BA6tQWg=" - "=fkit\n" - "-----END PGP SIGNATURE-----\n"; - - /* add keys to keyring */ - keyring = fu_keyring_gpg_new (); - ret = fu_keyring_setup (keyring, &error); - g_assert_no_error (error); - g_assert_true (ret); - pki_dir = g_build_filename (TESTDATADIR_SRC, "pki", NULL); - ret = fu_keyring_add_public_keys (keyring, pki_dir, &error); - g_assert_no_error (error); - g_assert_true (ret); - - /* verify with GnuPG */ - fw_pass = g_build_filename (TESTDATADIR_SRC, "colorhug", "firmware.bin", NULL); - blob_pass = fu_common_get_contents_bytes (fw_pass, &error); - g_assert_no_error (error); - g_assert_nonnull (blob_pass); - blob_sig = g_bytes_new_static (sig_gpgme, strlen (sig_gpgme)); - result_pass = fu_keyring_verify_data (keyring, blob_pass, blob_sig, - FU_KEYRING_VERIFY_FLAG_NONE, - &error); - g_assert_no_error (error); - g_assert_nonnull (result_pass); - g_assert_cmpint (fu_keyring_result_get_timestamp (result_pass), == , 1438072952); - g_assert_cmpstr (fu_keyring_result_get_authority (result_pass), == , - "3FC6B804410ED0840D8F2F9748A6D80E4538BAC2"); - - /* verify will fail with GnuPG */ - fw_fail = g_build_filename (TESTDATADIR_DST, "colorhug", "colorhug-als-3.0.2.cab", NULL); - blob_fail = fu_common_get_contents_bytes (fw_fail, &error); - g_assert_no_error (error); - g_assert_nonnull (blob_fail); - result_fail = fu_keyring_verify_data (keyring, blob_fail, blob_sig, - FU_KEYRING_VERIFY_FLAG_NONE, &error); - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID); - g_assert_null (result_fail); - g_clear_error (&error); -#else - g_test_skip ("no GnuPG support enabled"); -#endif -} - -static void -fu_keyring_pkcs7_func (gconstpointer user_data) -{ -#ifdef ENABLE_PKCS7 - gboolean ret; - g_autofree gchar *fw_fail = NULL; - g_autofree gchar *fw_pass = NULL; - g_autofree gchar *pki_dir = NULL; - g_autofree gchar *sig_fn = NULL; - g_autofree gchar *sig_fn2 = NULL; - g_autoptr(FuKeyring) keyring = NULL; - g_autoptr(FuKeyringResult) result_fail = NULL; - g_autoptr(FuKeyringResult) result_pass = NULL; - g_autoptr(GBytes) blob_fail = NULL; - g_autoptr(GBytes) blob_pass = NULL; - g_autoptr(GBytes) blob_sig = NULL; - g_autoptr(GBytes) blob_sig2 = NULL; - g_autoptr(GError) error = NULL; - - /* add keys to keyring */ - keyring = fu_keyring_pkcs7_new (); - ret = fu_keyring_setup (keyring, &error); - g_assert_no_error (error); - g_assert_true (ret); - pki_dir = g_build_filename (TESTDATADIR_SRC, "pki", NULL); - ret = fu_keyring_add_public_keys (keyring, pki_dir, &error); - g_assert_no_error (error); - g_assert_true (ret); - - /* verify with a signature from the old LVFS */ - fw_pass = g_build_filename (TESTDATADIR_SRC, "colorhug", "firmware.bin", NULL); - blob_pass = fu_common_get_contents_bytes (fw_pass, &error); - g_assert_no_error (error); - g_assert_nonnull (blob_pass); - sig_fn = g_build_filename (TESTDATADIR_SRC, "colorhug", "firmware.bin.p7b", NULL); - blob_sig = fu_common_get_contents_bytes (sig_fn, &error); - g_assert_no_error (error); - g_assert_nonnull (blob_sig); - result_pass = fu_keyring_verify_data (keyring, blob_pass, blob_sig, - FU_KEYRING_VERIFY_FLAG_DISABLE_TIME_CHECKS, - &error); - g_assert_no_error (error); - g_assert_nonnull (result_pass); - g_assert_cmpint (fu_keyring_result_get_timestamp (result_pass), >= , 1502871248); - g_assert_cmpstr (fu_keyring_result_get_authority (result_pass), == , "O=Linux Vendor Firmware Project,CN=LVFS CA"); - - /* verify will fail with a self-signed signature */ - sig_fn2 = g_build_filename (TESTDATADIR_DST, "colorhug", "firmware.bin.p7c", NULL); - blob_sig2 = fu_common_get_contents_bytes (sig_fn2, &error); - g_assert_no_error (error); - g_assert_nonnull (blob_sig2); - result_fail = fu_keyring_verify_data (keyring, blob_pass, blob_sig2, - FU_KEYRING_VERIFY_FLAG_NONE, &error); - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID); - g_assert_null (result_fail); - g_clear_error (&error); - - /* verify will fail with valid signature and different data */ - fw_fail = g_build_filename (TESTDATADIR_DST, "colorhug", "colorhug-als-3.0.2.cab", NULL); - blob_fail = fu_common_get_contents_bytes (fw_fail, &error); - g_assert_no_error (error); - g_assert_nonnull (blob_fail); - result_fail = fu_keyring_verify_data (keyring, blob_fail, blob_sig, - FU_KEYRING_VERIFY_FLAG_NONE, &error); - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID); - g_assert_null (result_fail); - g_clear_error (&error); -#else - g_test_skip ("no GnuTLS support enabled"); -#endif -} - -static void -fu_keyring_pkcs7_self_signed_func (gconstpointer user_data) -{ -#ifdef ENABLE_PKCS7 - gboolean ret; - g_autoptr(FuKeyring) kr = NULL; - g_autoptr(FuKeyringResult) kr_result = NULL; - g_autoptr(GBytes) payload = NULL; - g_autoptr(GBytes) signature = NULL; - g_autoptr(GError) error = NULL; - -#ifndef HAVE_GNUTLS_3_6_0 - /* required to create the private key correctly */ - g_test_skip ("GnuTLS version too old"); - return; -#endif - - /* create detached signature and verify */ - kr = fu_keyring_pkcs7_new (); - ret = fu_keyring_setup (kr, &error); - g_assert_no_error (error); - g_assert_true (ret); - payload = fu_common_get_contents_bytes ("/etc/machine-id", &error); - g_assert_no_error (error); - g_assert_nonnull (payload); - signature = fu_keyring_sign_data (kr, payload, FU_KEYRING_SIGN_FLAG_ADD_TIMESTAMP, &error); - g_assert_no_error (error); - g_assert_nonnull (signature); - ret = fu_common_set_contents_bytes ("/tmp/test.p7b", signature, &error); - g_assert_no_error (error); - g_assert_true (ret); - kr_result = fu_keyring_verify_data (kr, payload, signature, - FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT, &error); - g_assert_no_error (error); - g_assert_nonnull (kr_result); -#else - g_test_skip ("no GnuTLS support enabled"); -#endif -} - static GBytes * _build_cab (GCabCompression compression, ...) { @@ -3209,11 +3022,5 @@ main (int argc, char **argv) fu_plugin_list_func); g_test_add_data_func ("/fwupd/plugin-list{depsolve}", self, fu_plugin_list_depsolve_func); - g_test_add_data_func ("/fwupd/keyring{gpg}", self, - fu_keyring_gpg_func); - g_test_add_data_func ("/fwupd/keyring{pkcs7}", self, - fu_keyring_pkcs7_func); - g_test_add_data_func ("/fwupd/keyring{pkcs7-self-signed}", self, - fu_keyring_pkcs7_self_signed_func); return g_test_run (); } diff --git a/src/fu-tool.c b/src/fu-tool.c index 5c18c7ec2..dce0a6368 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "fu-device-private.h" #include "fu-engine.h" @@ -1376,8 +1377,8 @@ fu_util_self_sign (FuUtilPrivate *priv, gchar **values, GError **error) if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) return FALSE; sig = fu_engine_self_sign (priv->engine, values[0], - FU_KEYRING_SIGN_FLAG_ADD_TIMESTAMP | - FU_KEYRING_SIGN_FLAG_ADD_CERT, error); + JCAT_SIGN_FLAG_ADD_TIMESTAMP | + JCAT_SIGN_FLAG_ADD_CERT, error); if (sig == NULL) return FALSE; g_print ("%s\n", sig); diff --git a/src/meson.build b/src/meson.build index e9aac607e..aae719fef 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,21 +4,8 @@ if build_daemon ) endif -keyring_deps = [] -keyring_src = [] systemd_src = [] -if get_option('gpg') - keyring_src += 'fu-keyring-gpg.c' - keyring_deps += gpgme - keyring_deps += gpgerror -endif - -if get_option('pkcs7') - keyring_src += 'fu-keyring-pkcs7.c' - keyring_deps += gnutls -endif - if get_option('systemd') systemd_src += 'fu-systemd.c' endif @@ -132,7 +119,6 @@ fwupdtool = executable( export_dynamic : true, sources : [ 'fu-tool.c', - keyring_src, 'fu-config.c', 'fu-debug.c', 'fu-device-list.c', @@ -141,8 +127,6 @@ fwupdtool = executable( 'fu-history.c', 'fu-idle.c', 'fu-install-task.c', - 'fu-keyring.c', - 'fu-keyring-result.c', 'fu-keyring-utils.c', 'fu-plugin-list.c', 'fu-progressbar.c', @@ -156,7 +140,7 @@ fwupdtool = executable( fwupdplugin_incdir, ], dependencies : [ - keyring_deps, + libjcat, libxmlb, libgcab, giounix, @@ -233,7 +217,6 @@ executable( resources_src, fu_hash, sources : [ - keyring_src, 'fu-config.c', 'fu-debug.c', 'fu-device-list.c', @@ -242,8 +225,6 @@ executable( 'fu-history.c', 'fu-idle.c', 'fu-install-task.c', - 'fu-keyring.c', - 'fu-keyring-result.c', 'fu-keyring-utils.c', 'fu-main.c', 'fu-plugin-list.c', @@ -256,7 +237,7 @@ executable( fwupdplugin_incdir, ], dependencies : [ - keyring_deps, + libjcat, libxmlb, libgcab, giounix, @@ -272,7 +253,7 @@ executable( ], link_with : [ fwupd, - fwupdplugin + fwupdplugin, ], c_args : [ '-DFU_OFFLINE_DESTDIR=""', @@ -293,7 +274,6 @@ if get_option('tests') test_deps, fu_hash, sources : [ - keyring_src, 'fu-config.c', 'fu-device-list.c', 'fu-engine.c', @@ -301,8 +281,6 @@ if get_option('tests') 'fu-history.c', 'fu-idle.c', 'fu-install-task.c', - 'fu-keyring.c', - 'fu-keyring-result.c', 'fu-keyring-utils.c', 'fu-plugin-list.c', 'fu-progressbar.c', @@ -316,7 +294,7 @@ if get_option('tests') fwupdplugin_incdir, ], dependencies : [ - keyring_deps, + libjcat, libxmlb, libgcab, giounix, diff --git a/subprojects/.gitignore b/subprojects/.gitignore index 4d276a280..c607d93e3 100644 --- a/subprojects/.gitignore +++ b/subprojects/.gitignore @@ -1,4 +1,5 @@ gusb gcab flashrom +libjcat libxmlb diff --git a/subprojects/libjcat.wrap b/subprojects/libjcat.wrap new file mode 100644 index 000000000..15615559a --- /dev/null +++ b/subprojects/libjcat.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory = libjcat +url = https://github.com/hughsie/libjcat.git +revision = master