lib/gpg: Add more specific OstreeGpgError codes

Currently `ostree_gpg_verify_result_require_valid_signature` always
returns an error that the key used for the signature is missing from the
keyring. However, all that's been determined is that there are no valid
signatures. The error could also be from an expired signature, an
expired key, a revoked key or an invalid signature.

Provide values for these missing errors and return them from
`ostree_gpg_verify_result_require_valid_signature`. The description of
each result is appended to the error message, but since the result can
contain more than one signature but only a single error can be returned,
the status of the last signature is used for the error code. See the
comment for rationale.

Related: flatpak/flatpak#1450
This commit is contained in:
Dan Nicholson 2019-06-15 09:56:44 -05:00
parent 2c24f28ce4
commit 0fbfc0b207
4 changed files with 64 additions and 6 deletions

View File

@ -769,8 +769,58 @@ ostree_gpg_verify_result_require_valid_signature (OstreeGpgVerifyResult *result,
if (ostree_gpg_verify_result_count_valid (result) == 0)
{
g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_MISSING_KEY,
"GPG signatures found, but none are in trusted keyring");
/*
* Join the description of each failed signature for the error message.
* Only one error code can be returned, so if there was more than one
* signature, use the error of the last one under the assumption that
* it's the most recent and hopefully most likely to be made with a
* valid key.
*/
gint code = OSTREE_GPG_ERROR_NO_SIGNATURE;
g_autoptr(GString) buffer = g_string_sized_new (256);
guint nsigs = ostree_gpg_verify_result_count_all (result);
if (nsigs == 0)
/* In case an empty result was passed in */
g_string_append (buffer, "No GPG signatures found");
else
{
for (int i = nsigs - 1; i >= 0; i--)
{
g_autoptr(GVariant) info = ostree_gpg_verify_result_get_all (result, i);
ostree_gpg_verify_result_describe_variant (info, buffer, "",
OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT);
if (i == nsigs - 1)
{
gboolean key_missing, key_revoked, key_expired, sig_expired;
g_variant_get_child (info, OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING,
"b", &key_missing);
g_variant_get_child (info, OSTREE_GPG_SIGNATURE_ATTR_KEY_REVOKED,
"b", &key_revoked);
g_variant_get_child (info, OSTREE_GPG_SIGNATURE_ATTR_KEY_EXPIRED,
"b", &key_expired);
g_variant_get_child (info, OSTREE_GPG_SIGNATURE_ATTR_SIG_EXPIRED,
"b", &sig_expired);
if (key_missing)
code = OSTREE_GPG_ERROR_MISSING_KEY;
else if (key_revoked)
code = OSTREE_GPG_ERROR_REVOKED_KEY;
else if (key_expired)
code = OSTREE_GPG_ERROR_EXPIRED_KEY;
else if (sig_expired)
code = OSTREE_GPG_ERROR_EXPIRED_SIGNATURE;
else
/* Assume any other issue is a bad signature */
code = OSTREE_GPG_ERROR_INVALID_SIGNATURE;
}
}
}
/* Strip any trailing newlines */
g_strchomp (buffer->str);
g_set_error_literal (error, OSTREE_GPG_ERROR, code, buffer->str);
return FALSE;
}

View File

@ -159,6 +159,11 @@ gboolean ostree_gpg_verify_result_require_valid_signature (OstreeGpgVerifyResult
* @OSTREE_GPG_ERROR_NO_SIGNATURE: A signature was expected, but not found.
* @OSTREE_GPG_ERROR_INVALID_SIGNATURE: A signature was malformed.
* @OSTREE_GPG_ERROR_MISSING_KEY: A signature was found, but was created with a key not in the configured keyrings.
* @OSTREE_GPG_ERROR_EXPIRED_SIGNATURE: A signature was expired. Since: 2019.7.
* @OSTREE_GPG_ERROR_EXPIRED_KEY: A signature was found, but the key used to
* sign it has expired. Since: 2019.7.
* @OSTREE_GPG_ERROR_REVOKED_KEY: A signature was found, but the key used to
* sign it has been revoked. Since: 2019.7.
*
* Errors returned by signature creation and verification operations in OSTree.
* These may be returned by any API which creates or verifies signatures.
@ -169,6 +174,9 @@ typedef enum {
OSTREE_GPG_ERROR_NO_SIGNATURE = 0,
OSTREE_GPG_ERROR_INVALID_SIGNATURE,
OSTREE_GPG_ERROR_MISSING_KEY,
OSTREE_GPG_ERROR_EXPIRED_SIGNATURE,
OSTREE_GPG_ERROR_EXPIRED_KEY,
OSTREE_GPG_ERROR_REVOKED_KEY,
} OstreeGpgError;
/**

View File

@ -189,7 +189,7 @@ cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.2,}
if ${OSTREE} --repo=repo pull origin main 2>err.txt; then
assert_not_reached "Successful pull with old summary"
fi
assert_file_has_content err.txt "none are in trusted keyring"
assert_file_has_content err.txt "BAD signature"
assert_has_file repo/tmp/cache/summaries/origin
assert_has_file repo/tmp/cache/summaries/origin.sig
cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2

View File

@ -163,7 +163,7 @@ ${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/key1.asc,${test_tmp
if ${OSTREE} pull R8:main 2>err.txt; then
assert_not_reached "Unexpectedly succeeded at pulling with different key"
fi
assert_file_has_content err.txt "GPG signatures found, but none are in trusted keyring"
assert_file_has_content err.txt "public key not found"
# Test gpgkeypath success with directory containing a valid key
${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/ R9 $(cat httpd-address)/ostree/gnomerepo
@ -243,7 +243,7 @@ ${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/key2.asc R6 $(cat h
if ${OSTREE} pull R6:main 2>err.txt; then
assert_not_reached "Unexpectedly succeeded at pulling with different key"
fi
assert_file_has_content err.txt "GPG signatures found, but none are in trusted keyring"
assert_file_has_content err.txt "public key not found"
echo "ok"
@ -269,7 +269,7 @@ newrev=$(${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo rev-par
if ${OSTREE} pull --require-static-deltas R1:main 2>err.txt; then
assert_not_reached "Unexpectedly succeeded at pulling commit signed with untrusted key"
fi
assert_file_has_content err.txt "GPG signatures found, but none are in trusted keyring"
assert_file_has_content err.txt "public key not found"
echo "ok gpg untrusted signed commit for delta upgrades"