Bug? Vulnerability? gpgme_op_verify_result() can be made to return a list of zero signatures
Justin Steven
justin at justinsteven.com
Mon Jun 15 04:36:07 CEST 2020
Hi all,
On 9 June 2020 I disclosed a vulnerability in fwupd. There was a problem with
the way that it used libgpgme to verify the PGP signature of its update
metadata.
I would like to put it forward for wider discussion: is libgpgme is working as
intended, or should this particular behaviour be considered a bug or a
vulnerability in libgpgme?
# How fwupd uses libgpgme
fwupd used gpgme_op_verify() and gpgme_op_verify_result() with a GPG
homedir containing only trusted keys.
If gpgme_op_verify() returned GPG_ERR_NO_ERROR then it looped over the
signatures returned by gpgme_op_verify_result(). If any of those signatures
were "bad" (According to logic implemented by fwupd) then the metadata
signature was deemed "bad". Otherwise, the signature was deemed "good".
This logic is fragile, if not outright incorrect. fwupd is assuming that if it
gets GPG_ERR_NO_ERROR from gpgme_op_verify() then it will get at least one
signature back from gpgme_op_verify_result()
In short, by giving gpgme_op_verify() the following arguments:
* A normal (i.e. NON-DETACHED) signature as 'sig'
* Any data as 'signed_text' (which is a hint to gpgme that 'sig'
should be detached)
* Anything as 'plain'
Then gpgme will attempt to verify the non-detached signature as if it were a
detached signature. I found that this triggers interesting behaviour in
libgpgme, where gpggme_op_verify() will return GPG_ERR_NO_ERROR but
gpgme_op_verify_result() will return a list of zero signatures. This violates
the assumption made by fwupd, which allowed me to bypass its signature
validation.
fwupd fixed this vulnerability on their end by ensuring that libgpgme returned
a non-zero number of signatures. However, I wouldn't be surprised if there were
other software projects making the same assumption, and I think libgpgme could
act more predictably (or indeed "correctly") considering such inputs.
More details on the fwupd vulnerability are available at
https://github.com/justinsteven/advisories/blob/master/2020_fwupd_dangling_s3_bucket_and_CVE-2020-10759_signature_verification_bypass.md
(In particular the section titled "So whose fault was this anyway?")
# Could this be a bug in libgpgme?
During the disclosure process with fwupd I reached out to <security at gnupg.org>.
In short, the developers on duty said that this is expected behaviour from
libgpgme and that fwupd is solely to blame for its insecure use of libgpgme.
The developers on duty made a documentation change cautioning developers of
this behaviour at
<https://dev.gnupg.org/rM88f3202521d422d94bfd79e61bde00707d6f28c9>
I do agree that fwupd was using libgpgme in an unorthodox and very dangerous
way. However, I feel that it is very surprising for gpgme_op_verify() to return
GPG_ERR_NO_ERROR but for gpgme_op_verify_result() to return a list of zero
signatures. This feels like an erroneous condition to me, and with libgpgme
working the way it is, there is the risk of surprising developers and for there
to be verification bypasses in their code.
# Caveat
It is possible that there are many sets of input to gpgme_op_verify() that will
cause it to return zero signatures. I stopped looking for such edge-cases after
I found the one I did.
Justin
More information about the Gnupg-users
mailing list