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 14:15:56 CEST 2020


Hi Werner,

Thanks for responding

> this is a requirement for OpenPGP because OpenPGP allows to embed a signature
> in encrypted data (combined method in contrast to the rarely used MIME
> containers).  Thus when calling the decrypt function you can't know in
> advance whether there will be a signature - not returning an error if there
> is no signature is proper behaviour.

I'm not referring to any decrypt function. I'm only referring to:

* gpgme_op_verify()
* gpgme_op_verify_result()

I do understand that a PGP message can be both encrypted and signed.

Taking tests/run-verify.c as an example (I only just found it) it seems as
though gpgme_op_verify() doesn't handle encrypted data at all, and the
behaviour I identified is somewhat novel.

```
% ./run-verify <(echo hello | gpg --detach-sign) <(echo hello)
Original file name .: [none]
MIME flag ..........: no
Signature ...: 0
  status ....: Success
  summary ...: valid green
  fingerprint: F7DFBCA15A8D731FB0E7323A8719360278F979DD
  created ...: 1592217969
  expires ...: 0
  validity ..: full
  val.reason : Success
  pubkey algo: 1 (RSA)
  digest algo: 10 (SHA512)
  pka address: [none]
  pka trust .: n/a
  other flags: de-vs
```

Above is expected behaviour

```
% ./run-verify <(echo hello | gpg --sign)
Original file name .: [none]
MIME flag ..........: no
Signature ...: 0
  status ....: Success
  summary ...: valid green
  fingerprint: F7DFBCA15A8D731FB0E7323A8719360278F979DD
  created ...: 1592218246
  expires ...: 0
  validity ..: full
  val.reason : Success
  pubkey algo: 1 (RSA)
  digest algo: 10 (SHA512)
  pka address: [none]
  pka trust .: n/a
  other flags: de-vs
```

Also expected behaviour

```
% ./run-verify <(echo hello | gpg --sign) <(echo hello)
Original file name .: [none]
MIME flag ..........: no
```

Above is the surprising behaviour I'm writing about (No error; no signatures)

```
% ./run-verify <(echo hello | gpg --encrypt -r 'Test Key') <(echo hello)
Original file name .: [none]
MIME flag ..........: no
run-verify: verify failed: General error
```

Above is trying to verify an encrypted message as though it's a detached
signature. General error is expected (There's no signature to verify)

```
% ./run-verify <(echo hello | gpg --encrypt -r 'Test Key')
Original file name .: [none]
MIME flag ..........: no
run-verify: verify failed: General error
```

Above is trying to verify an encrypted message as though it's a regular
signature. General error is expected (There's no signature to verify)

```
% ./run-verify <(echo hello | gpg --sign --encrypt -r 'Test Key') <(echo hello)
Original file name .: [none]
MIME flag ..........: no
run-verify: verify failed: General error
```

Above is trying to verify an encrypted signed message as though it's a detached
signature. General error is probably expected behaviour (I don't know if it
could possibly make sense to ever verify an encrypted message with a detached
signature)

```
% ./run-verify <(echo hello | gpg --sign --encrypt -r 'Test Key')
Original file name .: [none]
MIME flag ..........: no
run-verify: verify failed: General error
```

Above is trying to verify an encrypted signed message as though it's a regular
signature. General error might be unexpected - if gpgme_op_verify() can be used
to check signatures on an encrypted message, is this a functional bug?


(Please do forgive my unfamiliarity with libgpgme. If gpgme_op_verify() can be
used to verify signatures on encrypted messages, do you know where I could find
an example?)


> More important: Checking the signature is one thing; its result is basically
> whether the data is corrupted.  The more important step is to check whether
> you can trust the key used to generate a signature; this is basic crypto
> knowledge which can't be ignored even if you use "GnuPG Made Easy".  GPGME
> has mechanisms to do this in a not too complicated way and of course it
> requires to loop over all signatures.

I don't disagree at all.

For what it's worth, I'm not trying to shift blame from fwupd to libgpgme. I
believe that fwupd can be (and indeed was) vulnerable; and at the same time,
libgpgme is exhibiting surprising behaviour. In my mind, if libgpgme can be
made to behave more predictably, it's not necessarily taking responsibility for
fwupd's bug. It's an outcome that would serve the greater good.

That is, unless there's a reason why libgpgme's behaviour is actually
functionally required - which I know you're trying to explain, I just can't
think of a concrete example as it relates to gpgme_op_verify(). If you have one
I'd greatly appreciate it.

One last thing, https://www.gnupg.org/documentation/manuals/gpgme/Verify.html
says:

> The function gpgme_op_verify verifies that the signature in the data object
> sig is a valid signature [...] The function returns the error code
> GPG_ERR_NO_ERROR if the operation could be completed successfully, [...]
> GPG_ERR_NO_DATA if sig does not contain any data to verify, and passes
> through any errors that are reported by the crypto engine support routines.

Based on this description, I can't understand how it makes sense for
gpgme_op_verify() to return GPG_ERR_NO_ERROR ("the operation could be completed
successfully") if:

* gpgme_op_verify_result() is going to return zero signatures; and
* gpg would print an error and exit with a non-zero status in a similar case

There is even a GPG_ERR_NO_DATA result that could be returned instead.

Justin



More information about the Gnupg-users mailing list