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 *dirname, GError **error) { g_autoptr(GDir) dir = NULL; g_return_val_if_fail (FU_IS_KEYRING (keyring), FALSE); g_return_val_if_fail (dirname != NULL, FALSE); /* setup context */ if (!fu_keyring_setup (keyring, error)) return FALSE; /* search all the public key files */ dir = g_dir_open (dirname, 0, error); if (dir == NULL) return FALSE; do { const gchar *filename; g_autofree gchar *path_tmp = NULL; filename = g_dir_read_name (dir); if (filename == NULL) break; path_tmp = g_build_filename (dirname, filename, NULL); if (!fu_keyring_add_public_key (keyring, path_tmp, error)) return FALSE; } while (TRUE); return TRUE; }
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); }
gboolean fu_keyring_add_public_key (FuKeyring *keyring, const gchar *filename, GError **error) { FuKeyringPrivate *priv = GET_PRIVATE (keyring); gpgme_error_t rc; gpgme_import_result_t result; gpgme_import_status_t s; g_auto(gpgme_data_t) data = NULL; g_return_val_if_fail (FU_IS_KEYRING (keyring), FALSE); g_return_val_if_fail (filename != NULL, FALSE); /* import public key */ g_debug ("Adding 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 (priv->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 (priv->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; }
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); }
static gboolean fu_keyring_setup (FuKeyring *keyring, GError **error) { FuKeyringPrivate *priv = GET_PRIVATE (keyring); gpgme_error_t rc; g_autofree gchar *gpg_home = NULL; g_return_val_if_fail (FU_IS_KEYRING (keyring), FALSE); if (priv->ctx != NULL) return TRUE; /* check version */ gpgme_check_version (NULL); /* startup gpgme */ rc = gpg_err_init (); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to startup GPG: %s", gpgme_strerror (rc)); return FALSE; } /* create a new GPG context */ rc = gpgme_new (&priv->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 (priv->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 */ gpg_home = g_build_filename (LOCALSTATEDIR, "lib", PACKAGE_NAME, "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 (priv->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 (priv->ctx, TRUE); return TRUE; }
gboolean fu_keyring_verify_data (FuKeyring *keyring, GBytes *payload, GBytes *payload_signature, GError **error) { FuKeyringPrivate *priv = GET_PRIVATE (keyring); gpgme_error_t rc; gpgme_signature_t s; gpgme_verify_result_t result; g_auto(gpgme_data_t) data = NULL; g_auto(gpgme_data_t) sig = NULL; g_return_val_if_fail (FU_IS_KEYRING (keyring), FALSE); g_return_val_if_fail (payload != NULL, FALSE); g_return_val_if_fail (payload_signature != NULL, FALSE); /* setup context */ if (!fu_keyring_setup (keyring, error)) return FALSE; /* load file data */ rc = gpgme_data_new_from_mem (&data, g_bytes_get_data (payload, NULL), g_bytes_get_size (payload), 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 FALSE; } rc = gpgme_data_new_from_mem (&sig, g_bytes_get_data (payload_signature, NULL), g_bytes_get_size (payload_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 FALSE; } /* verify */ rc = gpgme_op_verify (priv->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 FALSE; } /* verify the result */ result = gpgme_op_verify_result (priv->ctx); if (result == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "no result record from libgpgme"); return FALSE; } /* look at each signature */ for (s = result->signatures; s != NULL ; s = s->next ) { g_debug ("returned signature fingerprint %s", s->fpr); if (!fu_keyring_check_signature (s, error)) return FALSE; } return TRUE; }
gboolean fu_keyring_verify_file (FuKeyring *keyring, const gchar *filename, const gchar *signature, GError **error) { FuKeyringPrivate *priv = GET_PRIVATE (keyring); gboolean has_header; gpgme_error_t rc; gpgme_signature_t s; gpgme_verify_result_t result; g_auto(gpgme_data_t) data = NULL; g_auto(gpgme_data_t) sig = NULL; g_autoptr(GString) sig_v1 = NULL; g_return_val_if_fail (FU_IS_KEYRING (keyring), FALSE); g_return_val_if_fail (filename != NULL, FALSE); g_return_val_if_fail (signature != NULL, FALSE); /* setup context */ if (!fu_keyring_setup (keyring, error)) return FALSE; /* has header already */ has_header = g_strstr_len (signature, -1, "BEGIN PGP SIGNATURE") != NULL; /* load file data */ 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; } /* load signature */ sig_v1 = g_string_new (""); if (!has_header) { g_string_append (sig_v1, "-----BEGIN PGP SIGNATURE-----\n"); g_string_append (sig_v1, "Version: GnuPG v1\n\n"); } g_string_append_printf (sig_v1, "%s\n", signature); if (!has_header) g_string_append (sig_v1, "-----END PGP SIGNATURE-----\n"); rc = gpgme_data_new_from_mem (&sig, sig_v1->str, sig_v1->len, 0); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to load signature %s: %s", signature, gpgme_strerror (rc)); return FALSE; } /* verify */ rc = gpgme_op_verify (priv->ctx, sig, data, NULL); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to verify %s: %s", filename, gpgme_strerror (rc)); return FALSE; } /* verify the result */ result = gpgme_op_verify_result (priv->ctx); if (result == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "no result record from libgpgme"); return FALSE; } /* look at each signature */ for (s = result->signatures; s != NULL ; s = s->next ) { g_debug ("returned signature fingerprint %s", s->fpr); if (!fu_keyring_check_signature (s, error)) return FALSE; } return TRUE; }