Open soullivaneuh opened 6 years ago
Great question. I'm walking this exact same process right now.. in terms of revoking a master
gpg key in favor of using a new subkey
.
I was referencing these docs which say:
Your previous commits and tags will show as verified, as long as the key meets all other verification requirements.
But, @Soullivaneuh experience seems to indicate otherwise. I suppose what I'll do for now, is leave the master
gpg key on my GitHub account and just add the subkey
. Once I understand better what is happening I'll look at removing the revoked master
key.
I messed around with this some today and appear to have things working. I didn't revoke the master key, no need to really since it hasn't been compromised.
gpg2 --edit-key <master-key-id-short>
gpg2 --armor --export <subkey-id-long> | pbcopy
.git/config
has signingkey
set to the old short key ID and the new subkey's short key IDBetween steps 3 and 4 I checked my old commits and they were marked as Unverified
briefly. This changed to Verified
once I executed step 4. When you click the Verified
bit on a commit a dialog displays showing the long format GPG key ID
used in the commit. While this has changed - it's now showing the long format of the new subkey I created versus the master key ID - both the old and new commits show as verified given the relationship between the keys.
@aaronwest I don't see any subkey revocation on you process. Am I wrong?
@Soullivaneuh correct, I did not revoke any subkeys. I was signing my Git commits with my master
key and after making the outlined changes I'm signing commits with a subkey. So the subkey is new.
@aaronwest Yeah, but this is not relevant to my use case.
Try to revoke the subkey and add an another one for signing and then re-upload the GPG signature. You will see your older commit unsigned.
I just deleted my gpg and all my out commits had been unverified
So, AFAIK, the commits and tags signed before the revocation date should stay with a verified status.
The problem is that timestamp and date are not easy provable. The attacker can use the compromised keys sign a commit with mocking author/commit/signing dates.
Maybe you need to add the master key to github?
Ah nvm, the master is included in the export.
So, AFAIK, the commits and tags signed before the revocation date should stay with a verified status.
The problem is that timestamp and date are not easy provable. The attacker can use the compromised keys sign a commit with mocking author/commit/signing dates.
@gzm55 You are right. But git log --show-signature
shows the commit has a good signature (underlined in white in the snapshot below). Okay, it's revoked, but still good.
GitHub shows nothing about the signature verification and the revocation of the key:
The problem is that timestamp and date are not easy provable. The attacker can use the compromised keys sign a commit with mocking author/commit/signing dates.
@gzm55 You are right. But
git log --show-signature
shows the commit has a good signature (underlined in white in the snapshot below). Okay, it's revoked, but still good.GitHub shows nothing about the signature verification and the revocation of the key:
git log
checks the signature on the fly with the updated keys, and give 'GOOD with WARNING', so the user should have to evaluate the risk himself. The result from github may be a cache before the revoking.
When using the git, we have more information to prove the timestamp of signature by the relationship between the commits. That is, if a commit C sign by key A has a descendant commit D with a really GOOD signature and the timestamp of that descendant is older than the revoked timestamp of A, then the commit C could be treated as GOOD, since C < D < revoking-A
.
Just for the record, this behavior is documented here:
If your signing key is revoked or expired, GitHub cannot verify your signatures. If your key is revoked, use the primary key or another key that is not revoked to sign your commits.
The underlying issue is actually very interesting. Do old commits signed with a compromised (and revoked) key introduce an attack vector in a project? Started a discussion over at HN: https://news.ycombinator.com/item?id=25856812 . What should happen to code that is signed by a compromised key?
@isaacs What is your stand on this issue?
GPG has a build in mechanism to manage this. When you revoke the subkey, you have to choose a reason for this action. Some of them explicitly state, that subkey has not been compromised. IMHO, subkeys, revoked in this way should remain verified. In contrast, keys, revoked due to leaks, should be displayed as unverified, of even show a warning that the subkey was compromised.
This can probably be argued until the end of time about validity of a key after it has been revoked.
The point of the original post, I believe, is that IF they key was valid at the time of the commit/signature, if it later expires you can't say that is is now invalid because it WAS perfectly valid. So time isn't being considered when showing the badge.
When you talk about a revoked key you have to say the signatures are no longer valid because there just isn't enough detail to know the timing and why. Was it compromised AFTER the commit/signature was made (in which case the signature should be valid)? Or was it BEFORE in which case it is clearly suspicious.
So really I think the handling of this needs to be split between how expired keys and revoked keys are handled. So how about this:
UNVERIFIED
or even REVOKED
(in red)?VERIFIED
else UNVERIFIED
I believe only that expired case is what causes people to do a double take at all in github -- it was valid and now it isn't? ¯\_(ツ)_/¯
.
I'm not speaking to how GPG handles this in general at the command line. I'm sure if you posted over on the main project there would be no shortage of opinions. But here we are just talking about a UI treatment on GitHub.
GitHub should add an "Archive" option for old keys. Don't trust the key for new commits but keep the cached "verified" status on any existing commits.
It would make sense to mark any signature made with a revoked key as "REVOKED" That way if any fraudulent signatures were possible they can be marked as such.
But the nature of git is such that any new commit is a descendant of an older commit. So if you sign a new commit and it verifies you are vouching for the state of the repository then.
But the nature of git is such that any new commit is a descendant of an older commit. So if you sign a new commit and it verifies you are vouching for the state of the repository then.
Yes, but given the nature of human trust etc, I might "vouch for" a state of the repository, because I trust my colleague who I believe has vouched for the state just prior to mine, and only later do we find out that it was a malicious use of my colleague's key.
There is a world of difference between "expired" and "revoked due to compromise".
It sounds like everyone pretty much agrees with the basic principle here though. If a key expires naturally, or is "archived" in some way to indicate that it was not known to be leaked or compromised, then commits made with that key during its valid time should continue to be treated as valid.
If a key is revoked as compromised, imo, the safest thing is to assume that it was always suspect, unless the time of compromise can be verified in some way. Perhaps the best solution here would be a way to archive keys, and indicate whether it was:
And when a key expires naturally, just move it into that third state.
There is a world of difference between "expired" and "revoked due to compromise".
Agreed. I wish git log --show-signature
understood this. It highlights a commit in red regardless of if the subkey was since expired or compromised. So it would be nice to see GitHub providing a better user experience.
You can forge time though so I would say you could reduce the options to just compromised or not compromised (expired).
As a few people have pointed out over this thread, timestamps in commits can be basically arbitrarily set, but is there some way to mark commits that had been pushed (ie, that GitHub has seen) before expiration as "good but expired?" Imagine the overhead on keeping track of this would be non-negligible, but seems like a potential middle ground.
Hi all, I'm changing my GPG key because I'm pretty sure I lost my private key. But I'm still unsure whether removing my old GPG key on GitHub will make my previous commits became unverified, due to the vague words used in this documentation.
Is there any way to add my new GPG key while still maintaining the verification badge on my previous commits? Thanks.
@SimpleXtra If you delete your old GPG key from the github dashboard, all your previous commit will be shown Unverified
.
You can add your new GPG Public Key along side with the previous one, that will preserve the verification badge for your old commits.
@RafikFarhad thanks for the reply. However, I'm still wondering whether keeping my old GPG Public Key on GitHub would pose any security concerns. From what I've learned, if you lose access to your private key, you should somehow remove the public key or at least tell everyone who uses the public key that this particular key is no longer in use.
@SimpleXtra I was searching answer for the exact same question and I landed here. Unfortunately I did not find any answer for this question yet. I want to delete one of my GPG key from github account, but I am unsure about the status of my commits with that key. 🙁
@SimpleXtra the validity of a key has nothing to do with if it is on github or not. If I have a clone and pull your public key from the keyserver, the validity of it is based on 1) is it expired and 2) is it revoked. So removing an old/unused key from github does not make it valid or invalid - it simply associated the public key with your github userid. If you feel that your private key is compromised, then you should revoke that key saying "this is bad, don't trust".
The point of this issue centers more around a key the user feels is NOT compromised, but simply expired. Since commits in the past were valid when signed, and if the key has NOT been revoked as bad, then some feel that github should not flip from valid to invalid simply because time has passed. The tricky part here is that time in a git commit can be set to whatever you want (like the way phone spammers set the callerid to whatever they want). So if a key has expired and you push a commit signed with the expired key BUT the commit date is < expiration date, can that be trusted? Can github even tell the difference? This is the grey area that this thread is trying to figure out. Can an expired key still be trusted after expiration (assuming it isn't revoked)? I don't think anybody here knows enough of the internal workings of github to say if they can even tell between a commit signed and pushed prior to the expiration date or after.
Some have suggested an additional badge(s) for these cases since there are currently only 2 - valid and not valid. It seems like you need:
This thread will continue on and on forever while people debate how to bucket 5 things into 2 so let's just make 5 badges?
~Is this also an issue if you register the GPG „master“ key on GitHub to confirm your identity, but then sign commits with subkeys that you later revoke?~
~To me it seems in the initial example, the identity added in GitHub was the subkey that was later revoked?~
In order to have a new subkey show as "verified", you need to gpg --export --armor [yourkeyid]
and update GitHub account settings with this new key export. The key export contains the master key as well as all subkeys, newly added and revoked ones.
So, my initial assumption that you can register your public master key only, and that all commits signed with a subkey of it (however that link could be made...) will show as valid was wrong. You need to update your GPG settings in GitHub with an export containing the master and all subkeys, and expired or revoked subkeys will show as "unverified" just as the OP described.
I just learned that git log
has the %G?
format placeholder to show GPG signature statuses. From the man page:
"G" for a good (valid) signature, "B" for a bad signature, "U" for a good signature with unknown validity, "X" for a good signature that has expired, "Y" for a good signature made by an expired key, "R" for a good signature made by a revoked key, "E" if the signature cannot be checked (e.g. missing key) and "N" for no signature.
Do commits really have to be marked as unverified
, when I remove my GPG key from my account? Even if the key remains valid, and not expired?
Just faced an issue, when my commits were marked as unverified. It's pretty confusing, since the setting state that they won't be.
It would be much better to have "expired" instead of "unverified"
Faced this issue as well. I keep my primary key on a PGP Smartcard, and generate sign-only subkeys for machines I do a lot of development on. This introduces an issue in which all commits that I signed using a machine-specific subkey become unverified once I revoke the key due to no longer using that device. That's a problem since the underlying primary key is still valid, and all commits still have GOODSIG, just with a revoked subkey.
I'm not sure it's an issue or a bad manipulation from me, but I don't how to do it with another way.
In order to keep my master key secure and valid, I'm trying to do what is explain on this article.
I'll first explain what I did to test, step by step.
First, I create the main key with certificate role only (
C
).GPG main key creation:
``` $ gpg --full-gen-key --expert gpg (GnuPG) 2.1.15; Copyright (C) 2016 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Please select what kind of key you want: (1) RSA and RSA (default) (2) DSA and Elgamal (3) DSA (sign only) (4) RSA (sign only) (7) DSA (set your own capabilities) (8) RSA (set your own capabilities) (9) ECC and ECC (10) ECC (sign only) (11) ECC (set your own capabilities) Your selection? 8 Possible actions for a RSA key: Sign Certify Encrypt Authenticate Current allowed actions: Sign Certify Encrypt (S) Toggle the sign capability (E) Toggle the encrypt capability (A) Toggle the authenticate capability (Q) Finished Your selection? s Possible actions for a RSA key: Sign Certify Encrypt Authenticate Current allowed actions: Certify Encrypt (S) Toggle the sign capability (E) Toggle the encrypt capability (A) Toggle the authenticate capability (Q) Finished Your selection? e Possible actions for a RSA key: Sign Certify Encrypt Authenticate Current allowed actions: Certify (S) Toggle the sign capability (E) Toggle the encrypt capability (A) Toggle the authenticate capability (Q) Finished Your selection? q RSA keys may be between 1024 and 4096 bits long. What keysize do you want? (2048) Requested keysize is 2048 bits Please specify how long the key should be valid. 0 = key does not expireThen, I add a signin (
S
) subkey.GPG signing subkey creation:
``` $ gpg --edit-key 9E0BCC27843CF75E7604AFFD2886875B5AF6449D gpg (GnuPG) 2.1.15; Copyright (C) 2016 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Secret key is available. gpg: checking the trustdb gpg: marginals needed: 3 completes needed: 1 trust model: pgp gpg: depth: 0 valid: 3 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 3u sec rsa2048/2886875B5AF6449D created: 2017-10-21 expires: never usage: C trust: ultimate validity: ultimate [ultimate] (1). Sullivan SenechalThen I export all the part and secure my key by re-importing only the subkeys:
Then I add the pub key here: https://github.com/settings/keys
I edit my
.gitconfig
to tell git to use my GPG key, with the main ID:And I push a test commit, signed with the key. Yay! It's verified and signed with the subkey.
Well. Now imagine the fact my computer was stolen and my subkey is compromised. So I have to revoke it and create a new one. Let's go.
GPG subkey revokation and add:
``` $ gpg --import key.priv gpg: key 2886875B5AF6449D: "Sullivan SenechalI now have my revoked key and my fancy new one.
I remove the old GPG key from my GitHub account and replace it by the new one:
And there is the issue. The old subkey is not here anymore and the old commit is not verified at all:
But, according to
pgpdump
, the concerned subkey is still here and marked as revoked with the accurate date and time.Dump of the final GPG pubkey:
``` Old: Public Key Packet(tag 6)(269 bytes) Ver 4 - new Public key creation time - Sat Oct 21 10:43:12 CEST 2017 Pub alg - RSA Encrypt or Sign(pub 1) RSA n(2048 bits) - ... RSA e(17 bits) - ... Old: User ID Packet(tag 13)(42 bytes) User ID - Sullivan SenechalSo, AFAIK, the commits and tags signed before the revocation date should stay with a verified status.
If not, what is the goal of making subkey if, in any case, all your commits and tags will be unverified as soon as the subkey is revoked? I don't get it. In this case, I'm sure lots of people are continuing using the key even if it is compromised. :pensive: :thinking:
BTW, I have another question related to this issue. I have a current GPG key signing my commit. It was created while I was a truly beginner and it use master keys. I would like to revoke it to no be able to use it at all but without losing my old tag and commit signature verification. Is that even possible?
Regards.