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 <secur...@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 _______________________________________________ Gnupg-users mailing list Gnupg-users@gnupg.org http://lists.gnupg.org/mailman/listinfo/gnupg-users