diff --git a/doc/ostree-sections.txt b/doc/ostree-sections.txt index f8fca738..5dd6a2bf 100644 --- a/doc/ostree-sections.txt +++ b/doc/ostree-sections.txt @@ -174,6 +174,8 @@ ostree_gpg_verify_result_count_valid ostree_gpg_verify_result_lookup ostree_gpg_verify_result_get ostree_gpg_verify_result_get_all +OstreeGpgSignatureFormatFlags +ostree_gpg_verify_result_describe <SUBSECTION Standard> OSTREE_GPG_VERIFY_RESULT OSTREE_IS_GPG_VERIFY_RESULT diff --git a/src/libostree/ostree-gpg-verify-result.c b/src/libostree/ostree-gpg-verify-result.c index 7f4b3d83..a9e78bf4 100644 --- a/src/libostree/ostree-gpg-verify-result.c +++ b/src/libostree/ostree-gpg-verify-result.c @@ -20,6 +20,9 @@ #include "config.h" +#include <string.h> + +#include "libglnx.h" #include "libgsystem.h" #include "ostree-gpg-verify-result-private.h" @@ -451,6 +454,147 @@ ostree_gpg_verify_result_get_all (OstreeGpgVerifyResult *result, G_N_ELEMENTS (all_signature_attrs)); } +/** + * ostree_gpg_verify_result_describe: + * @result: an #OstreeGpgVerifyResult + * @signature_index: which signature to describe + * @output_buffer: a #GString to hold the description + * @line_prefix: (allow-none): optional line prefix string + * @flags: flags to adjust the description format + * + * Appends a brief, human-readable description of the GPG signature at + * @signature_index in @result to the @output_buffer. The description + * spans multiple lines. A @line_prefix string, if given, will precede + * each line of the description. + * + * The @flags argument is reserved for future variations to the description + * format. Currently must be 0. + * + * It is a programmer error to request an invalid @signature_index. Use + * ostree_gpg_verify_result_count_all() to find the number of signatures in + * @result. + */ +void +ostree_gpg_verify_result_describe (OstreeGpgVerifyResult *result, + guint signature_index, + GString *output_buffer, + const gchar *line_prefix, + OstreeGpgSignatureFormatFlags flags) +{ + g_autoptr(GVariant) variant = NULL; + g_autoptr(GDateTime) date_time_utc = NULL; + g_autoptr(GDateTime) date_time_local = NULL; + g_autofree char *formatted_date_time = NULL; + gint64 timestamp; + gint64 exp_timestamp; + const char *fingerprint; + const char *pubkey_algo; + const char *user_name; + const char *user_email; + const char *key_id; + gboolean valid; + gboolean sig_expired; + gboolean key_missing; + gsize len; + + g_return_if_fail (OSTREE_IS_GPG_VERIFY_RESULT (result)); + g_return_if_fail (output_buffer != NULL); + + /* The default format roughly mimics the verify output generated by + * check_sig_and_print() in gnupg/g10/mainproc.c, though obviously + * greatly simplified. */ + + variant = ostree_gpg_verify_result_get_all (result, signature_index); + g_return_if_fail (variant != NULL); + + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_VALID, + "b", &valid); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_SIG_EXPIRED, + "b", &sig_expired); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING, + "b", &key_missing); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT, + "&s", &fingerprint); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_TIMESTAMP, + "x", ×tamp); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_EXP_TIMESTAMP, + "x", &exp_timestamp); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_PUBKEY_ALGO_NAME, + "&s", &pubkey_algo); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_USER_NAME, + "&s", &user_name); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL, + "&s", &user_email); + + len = strlen (fingerprint); + key_id = (len > 16) ? fingerprint + len - 16 : fingerprint; + + date_time_utc = g_date_time_new_from_unix_utc (timestamp); + date_time_local = g_date_time_to_local (date_time_utc); + formatted_date_time = g_date_time_format (date_time_local, "%c"); + + if (line_prefix != NULL) + g_string_append (output_buffer, line_prefix); + + g_string_append_printf (output_buffer, + "Signature made %s using %s key ID %s\n", + formatted_date_time, pubkey_algo, key_id); + + g_clear_pointer (&date_time_utc, g_date_time_unref); + g_clear_pointer (&date_time_local, g_date_time_unref); + g_clear_pointer (&formatted_date_time, g_free); + + if (line_prefix != NULL) + g_string_append (output_buffer, line_prefix); + + if (key_missing) + { + g_string_append (output_buffer, + "Can't check signature: public key not found\n"); + } + else if (valid) + { + g_string_append_printf (output_buffer, + "Good signature from \"%s <%s>\"\n", + user_name, user_email); + } + else if (sig_expired) + { + g_string_append_printf (output_buffer, + "Expired signature from \"%s <%s>\"\n", + user_name, user_email); + } + else + { + g_string_append_printf (output_buffer, + "BAD signature from \"%s <%s>\"\n", + user_name, user_email); + } + + if (exp_timestamp > 0) + { + date_time_utc = g_date_time_new_from_unix_utc (exp_timestamp); + date_time_local = g_date_time_to_local (date_time_utc); + formatted_date_time = g_date_time_format (date_time_local, "%c"); + + if (line_prefix != NULL) + g_string_append (output_buffer, line_prefix); + + if (sig_expired) + { + g_string_append_printf (output_buffer, + "Signature expired %s\n", + formatted_date_time); + } + else + { + g_string_append_printf (output_buffer, + "Signature expires %s\n", + formatted_date_time); + } + } +} + void _ostree_gpg_error_to_gio_error (gpgme_error_t gpg_error, GError **error) diff --git a/src/libostree/ostree-gpg-verify-result.h b/src/libostree/ostree-gpg-verify-result.h index eacd357e..a380ce94 100644 --- a/src/libostree/ostree-gpg-verify-result.h +++ b/src/libostree/ostree-gpg-verify-result.h @@ -100,4 +100,23 @@ GVariant * ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result, GVariant * ostree_gpg_verify_result_get_all (OstreeGpgVerifyResult *result, guint signature_index); +/** + * OstreeGpgSignatureFormatFlags: + * @OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT: + * Use the default output format + * + * Formatting flags for ostree_gpg_verify_result_describe(). Currently + * there's only one possible output format, but this enumeration allows + * for future variations. + **/ +typedef enum { + OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT = 0 +} OstreeGpgSignatureFormatFlags; + +void ostree_gpg_verify_result_describe (OstreeGpgVerifyResult *result, + guint signature_index, + GString *output_buffer, + const gchar *line_prefix, + OstreeGpgSignatureFormatFlags flags); + G_END_DECLS diff --git a/src/ostree/ot-builtin-show.c b/src/ostree/ot-builtin-show.c index d45bd677..e471ced7 100644 --- a/src/ostree/ot-builtin-show.c +++ b/src/ostree/ot-builtin-show.c @@ -148,87 +148,6 @@ do_print_metadata_key (OstreeRepo *repo, return ret; } -static void -print_signature (OstreeGpgVerifyResult *result, - guint signature_index) -{ - g_autoptr(GVariant) variant = NULL; - g_autoptr(GDateTime) date_time_utc = NULL; - g_autoptr(GDateTime) date_time_local = NULL; - g_autofree char *formatted_date_time = NULL; - gint64 timestamp; - gint64 exp_timestamp; - const char *fingerprint; - const char *pubkey_algo; - const char *user_name; - const char *user_email; - const char *key_id; - gboolean valid; - gboolean sig_expired; - gboolean key_missing; - gsize len; - - /* This function roughly mimics the verify output generated by - * check_sig_and_print() in gnupg/g10/mainproc.c, though obviously - * greatly simplified. */ - - variant = ostree_gpg_verify_result_get_all (result, signature_index); - - g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_VALID, - "b", &valid); - g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_SIG_EXPIRED, - "b", &sig_expired); - g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING, - "b", &key_missing); - g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT, - "&s", &fingerprint); - g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_TIMESTAMP, - "x", ×tamp); - g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_EXP_TIMESTAMP, - "x", &exp_timestamp); - g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_PUBKEY_ALGO_NAME, - "&s", &pubkey_algo); - g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_USER_NAME, - "&s", &user_name); - g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL, - "&s", &user_email); - - len = strlen (fingerprint); - key_id = (len > 16) ? fingerprint + len - 16 : fingerprint; - - date_time_utc = g_date_time_new_from_unix_utc (timestamp); - date_time_local = g_date_time_to_local (date_time_utc); - formatted_date_time = g_date_time_format (date_time_local, "%c"); - - g_print (" Signature made %s using %s key ID %s\n", - formatted_date_time, pubkey_algo, key_id); - - g_clear_pointer (&date_time_utc, g_date_time_unref); - g_clear_pointer (&date_time_local, g_date_time_unref); - g_clear_pointer (&formatted_date_time, g_free); - - if (key_missing) - g_print (" Can't check signature: public key not found\n"); - else if (valid) - g_print (" Good signature from \"%s <%s>\"\n", user_name, user_email); - else if (sig_expired) - g_print (" Expired signature from \"%s <%s>\"\n", user_name, user_email); - else - g_print (" BAD signature from \"%s <%s>\"\n", user_name, user_email); - - if (exp_timestamp > 0) - { - date_time_utc = g_date_time_new_from_unix_utc (exp_timestamp); - date_time_local = g_date_time_to_local (date_time_utc); - formatted_date_time = g_date_time_format (date_time_local, "%c"); - - if (sig_expired) - g_print (" Signature expired %s\n", formatted_date_time); - else - g_print (" Signature expires %s\n", formatted_date_time); - } -} - static gboolean print_object (OstreeRepo *repo, OstreeObjectType objtype, @@ -266,16 +185,23 @@ print_object (OstreeRepo *repo, } else { + GString *buffer; guint n_sigs, ii; n_sigs = ostree_gpg_verify_result_count_all (result); g_print ("Found %u signature%s:\n", n_sigs, n_sigs == 1 ? "" : "s"); + buffer = g_string_sized_new (256); + for (ii = 0; ii < n_sigs; ii++) { - g_print ("\n"); - print_signature (result, ii); + g_string_append_c (buffer, '\n'); + ostree_gpg_verify_result_describe (result, ii, buffer, " ", + OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT); } + + g_print ("%s", buffer->str); + g_string_free (buffer, TRUE); } }