Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Give error message for failed PGP key import #2097

Closed
wants to merge 2 commits into from

Conversation

ffesti
Copy link
Contributor

@ffesti ffesti commented Jun 21, 2022

due to missing SHA1 support. This can happen when old keys are used on
systems that have disabled SHA1 e.g. for FIPS requirements.

See rhbz#2069877

@nwalfield
Copy link
Collaborator

I want SHA-1 to die, but this is a bit too much.

First, for v4 OpenPGP keys (the current version), you have to use SHA1 to compute the Fingerprint and the Key ID. There is no other way. The Fingerprint and Key ID are used everywhere in the OpenPGP specification. For instance, a signature includes an Issuer field, which contains the Key ID of the key that generated the signature. If you can't compute the Key ID, then you can't designate (name) the certificate that generated the signature, but have to try all available signing-capable keys. That's a performance disaster. The good news is that the Key ID is self authenticating: if you verify the signature, then you know that the Key ID is correct.

Second, a hash algorithm provides several security properties. The two most important are collision resistance and second pre-image resistance. SHA1's collision resistance has been broken, but its second pre-image resistance is fine. A second pre-image attack is when an attacker finds a second text that has the same hash as a given text. This type of attack is much harder, because it can't exploit the birthday paradox. Collision resistance is only needed when the attacker can choose both messages. Since an attacker doesn't control the key, self signatures don't need a hash with collision resistance (the attacker doesn't control the key material). And since a fingerprint is basically the hash of a key, it also doesn't need a hash with collision resistance.

In short, yes, data signatures using SHA-1 should be rejected. Yes, it would be nice to have self signatures that don't use SHA-1 since there are alternatives. But, a v4 OpenPGP implementation must be able to compute the fingerprint.

Note: v5 keys will use SHA256. The RFC draft is in working group last call. But even if it is standardized today, it will take years before enough users adopt v5 keys so that we can start rejecting v4 keys.

@pmatilai
Copy link
Member

Yeah... @ffesti , are you sure this is where it's tripping on in the failing case? Like @nwalfield points out above, ability to compute SHA1 is required for v4 keys because it's a part of the RFC itself. So this is different from people "upgrading" their keys to use a stronger hash in the key itself (pardon my caveman terminology) to avoid the issue.

@pmatilai pmatilai added the DONT DO NOT merge, for whatever reason label Jun 27, 2022
@ffesti ffesti removed the DONT DO NOT merge, for whatever reason label Jun 28, 2022
@ffesti
Copy link
Contributor Author

ffesti commented Jun 28, 2022

Ok, looks like my initial test case was broken.
Unfortunately there is no good way to give an error code to the higher level functions. So I just added the warning down in the backend - which is kinda ugly.

This can happen when old keys are used on systems that have disabled SHA1
e.g. for FIPS requirements.

This is less than ideal but there is currently no way to pass a meaningful
error code up to rpmtsImportPubkey. rpmPubkeyNew just returns a valid key
or NULL.

See rhbz#2069877
@pmatilai
Copy link
Member

pmatilai commented Jun 28, 2022

If we add the message to openssl, we'd need to do that for libgcrypt too. I wonder if we could get by with returning ENOTSUP or such from the backend and log something centrally from pgpVerifySignature() instead. In any case, this is a hard error, not a warning.

@ffesti
Copy link
Contributor Author

ffesti commented Jun 28, 2022

Getting libgcrypt to reject the PGP key is somehow less straight forward. While it is not surprising that it won't be affected by update-crypto-policies I didn't have any luck with switching it into FIPS mode according to https://www.gnupg.org/documentation/manuals/gcrypt/Enabling-FIPS-mode.html

@DemiMarie
Copy link
Contributor

Getting libgcrypt to reject the PGP key is somehow less straight forward. While it is not surprising that it won't be affected by update-crypto-policies I didn't have any luck with switching it into FIPS mode according to https://www.gnupg.org/documentation/manuals/gcrypt/Enabling-FIPS-mode.html

I think RPM will need to reject the key/signature itself.

@pmatilai
Copy link
Member

Oh, I didn't even know libgcrypt had a FIPS mode now.

In any case, FIPS is just a side-issue here, the question is whether the underlying crypto library supports that key (algos and all) or not, and somehow communicating it back to the user.

@nwalfield
Copy link
Collaborator

An OpenPGP certificate usually contains several keys. The keys are bound together using binding signatures. It is entirely possible and indeed reasonable for there to be multiple binding signatures for a key, e.g., to extend the expiration time. Thus, if a signature happens to use SHA-1, the whole certificate should not be rejected, just that signature.

@pmatilai
Copy link
Member

pmatilai commented Jun 29, 2022

@nwalfield - I'm sure that's what a proper implementation should and would do, but in rpm world multi-key certificates aren't that common in the first place as they're usually tailored for the very purpose of using in rpm only, so we get by with little less finesse.

@nwalfield
Copy link
Collaborator

Even if subkeys aren't used, there can still be multiple signatures.

Here is 567E 347A D004 4ADE 55BA 8A5F 199E 2F91 FD43 1D51 (Red Hat, Inc. (release key 2) [email protected]):

$ sq keyserver -s hkps://keyserver.ubuntu.com get '567E 347A D004 4ADE 55BA 8A5F 199E 2F91 FD43 1D51' | sq packet dump
Public-Key Packet, new CTB, 525 bytes
    Version: 4
    Creation time: 2009-10-22 11:59:55 UTC
    Pk algo: RSA
    Pk size: 4096 bits
    Fingerprint: 567E347AD0044ADE55BA8A5F199E2F91FD431D51
    KeyID: 199E2F91FD431D51
  
User ID Packet, new CTB, 51 bytes
    Value: Red Hat, Inc. (release key 2) <[email protected]>
  
Signature Packet, new CTB, 589 bytes
    Version: 4
    Type: PositiveCertification
    Pk algo: RSA
    Hash algo: SHA1
    Hashed area:
      Signature creation time: 2009-10-22 11:59:55 UTC
      Key flags: CS
      Symmetric algo preferences: AES256, AES192, AES128, CAST5, TripleDES
      Hash preferences: SHA1, SHA256, RipeMD
      Compression preferences: Zlib, BZip2, Zip
      Features: MDC
      Keyserver preferences: no modify
    Unhashed area:
      Issuer: 199E2F91FD431D51
      Issuer Fingerprint: 567E347AD0044ADE55BA8A5F199E2F91FD431D51
    Digest prefix: 6CE9
    Level: 0 (signature over data)
  
Signature Packet, new CTB, 563 bytes
    Version: 4
    Type: GenericCertification
    Pk algo: RSA
    Hash algo: SHA512
    Hashed area:
      Issuer Fingerprint: E99661DB6683EA305704ED3A4B5C7470051BB332
      Signature creation time: 2022-05-13 07:27:46 UTC
    Unhashed area:
      Issuer: 4B5C7470051BB332
    Digest prefix: B07C
    Level: 0 (signature over data)
  
Signature Packet, new CTB, 156 bytes
    Version: 4
    Type: GenericCertification
    Pk algo: RSA
    Hash algo: SHA1
    Hashed area:
      Signature creation time: 2010-08-10 08:57:09 UTC
    Unhashed area:
      Issuer: EEAD4CFD49A563D9
    Digest prefix: A30F
    Level: 0 (signature over data)

There are three signature packets on the User ID packet, two of them use SHA-1. Note: an OpenPGP certificate is not valid without at least one valid self signature.

ffesti added a commit to ffesti/rpm that referenced this pull request Jul 5, 2022
to set a separate license to the source RPM. This can be useful if the
sources have code under additional licenses that do not end up in the
binary packeges.

Resolves: rpm-software-management#2097
@ffesti
Copy link
Contributor Author

ffesti commented Jul 8, 2022

Not sure if I am really a fan of using errno codes here. But the whole return code handling is a mess and error handling in the crypto backends is very ... ehm ... basic.
Guess this needs a more birds eye look. But the lack of SHA1 is the issue we are running into right now.

@nwalfield
Copy link
Collaborator

error handling in the crypto backends is very ... ehm ... basic.

The crypto API's error reporting is indeed primitive. But, Sequoia has extremely (in my experience) rich error messages. This, of course, is lost at the API boundary. But that's the API's limitation, not the crypto backend's limitation.

@ffesti
Copy link
Contributor Author

ffesti commented Jul 18, 2022

Yeah, issue here is not so much Sequoia but the sum of all crypto libs that are supported there. I'll add a separate ticket to make a plan for that. That's far outside of the scope of this little PR.

@dmnks
Copy link
Contributor

dmnks commented Sep 19, 2022

Why are we even talking about rejecting such keys/signatures in RPM here? Isn't this supposed to be handled by the backend in use? IIUC, verification simply fails in the OpenSSL code if SHA-1 is used in FIPS mode so all we need is make it clear why that is to the user, don't we?

Or is the concern that, as @nwalfield mentioned, some keys (including RH's own) may contain multiple signatures, some of which use SHA-1, for which we'd always print the warning? If that's the case, maybe we could detect we're running in FIPS mode and only print the message there, even though, that already sounds like an ugly hack. But IIRC, there's a similar check in DNF...

@nwalfield
Copy link
Collaborator

Using v4 OpenPGP keys requires the use of SHA-1. SHA-1 is used to compute the fingerprint. This is actually safe as the security of the fingerprint relies on second pre-image resistance (finding a second message with the same hash), not collision resistance (finding two messages with the same hash). SHA-1 second pre-image resistance is still secure, only its collision resistance is broken. Of course, we are not happy to continue to use SHA-1 and the next version of the OpenPGP specification will use SHA-2 256 to compute fingerprints. But, it will take years until all v4 keys have been replaced by v5 keys.

@ffesti
Copy link
Contributor Author

ffesti commented Sep 21, 2022

The discussion here is beside the point of the PR. This is in large parts my fault as the original patch also was beside the point. As it turns out this is unrelated to v4 OpenPGP signatures and their use of SHA-1.

The current patch only returns the error of not supported older SHA-1 based keys/signatures that have been rejected by the openSSL back end due to system wide settings and issues an message to give the user a fighting chance to understand why the key is not working.

@pmatilai
Copy link
Member

pmatilai commented Sep 27, 2022

The patch doesn't do what the PR title says as it only outputs anything on verify.
How do you verify anything with a key that could not be imported in the first place?

@pmatilai
Copy link
Member

pmatilai commented Sep 27, 2022

That, and being specific to a crypto backend which is neither the current or future default are quite show-stoppers to me.

A reasonable compromise could be just outputing signature parameters on failure (rpmPubkeyNew() time basically) without trying to pinpoint what the issue is, but that too runs into the issue of error reporting. OTOH, I'm not sure an rpmlog() call in rpmPubkeyNew() would be any worse than having it in the low-level PGP code.

@nwalfield
Copy link
Collaborator

(FWIW, I believe the internal OpenPGP implementation is still the default for 4.18.)

@pmatilai
Copy link
Member

Yes, but for that the default is libgcrypt whereas this patch only does anything for openssl backend.

@nwalfield
Copy link
Collaborator

Thanks for the clarification.

@pmatilai
Copy link
Member

pmatilai commented Sep 27, 2022

Of course, this all is made even more entertaining by the fact that the internal and Sequoia parsers treat this very differently: Sequoia doesn't verify on import, only on actual use, ie verification. Whereas the internal backend verifies on key import, so this patch doesn't really have a chance to do anything on the backend it targets. Erm. So, I just contradicted myself here: because we verify the self-signatures on import, this does get called on import, when using the internal parser. Sorry.

@pmatilai
Copy link
Member

That tangle could be simplified a bit by ripping the subkey support out of the internal parser as kinda planned past 4.18. It still doesn't fix the error reporting of course. We could add better verify APIs of course to allow returning actual error messages back to callers, but we'd need to pass through multiple layers of historic goo...

@nwalfield
Copy link
Collaborator

As I understand, 4.19 will have an soname bump so it should be possible to rework the API (and remove the old API). Or, if that is not sufficient, what are your concerns?

@pmatilai
Copy link
Member

pmatilai commented Sep 27, 2022

A big part of the old API is already gone (ae7ef1a, 87c4eee etc) and we could certainly add new ones at any time, but as long as the internal parser is there, a significant rework may be painful (because we'd need to implement it in the internal parser too)

@pmatilai
Copy link
Member

Okay, adding an errno abuse hack (which I suggested, yes) to just one of our backends, a backend that will be considered deprecated in 4.19 anyway... it doesn't make sense really.
We'll need something that can apply to all our backends, and that something needs to have a sane means of returning error messages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

5 participants