> The difference between signed tags and signed commits is minimal — in the case of commit signing, the signature goes into the commit object itself. It is generally a good practice to PGP-sign commits
One of the most important reasons it doesn't make sense to sign commits is that keys expire so when you sign something you implicitly say it is valid at most until the key is valid; nothing can be guaranteed after that. It is easy enough to re-sign a tag (even automatically) but you can't re-sign a commit without changing its identity and that defeats the whole purpose of git.
The only reason you'd want to sign commits is to defend from malicious maintainers ie if your patch is changed before being merged, or your authorship is removed, or a patch impersonating you is merged. It's probably better to sign your patches (ie the temporary moment where you interact) in that case: I see there was some work in that direction (https://lwn.net/Articles/813646/) but apparently it hasn't caught up (https://lore.kernel.org/signatures/ shows last signatures end of 2020)
The trick is to consider the key invalid for use in signing after it expires, but still valid for verification after that time. Signatures produced by that key can be considered valid well after the key itself has expired. For that to work, you need to have some confidence that the signature was produced at a given time, which is what third-party time stamping authorities (TSA) do. You send your signature to a TSA, which validates the signature, and that the key is valid at the current time, and the TSA counter signs.
For a large project with multiple contributors I wouldn't want to sign the whole tree at a particular point in time (which seems like the natural interpretation of a signed tag) unless I'd actually reviewed it all personally (which, sure, maybe some maintainers do). The commit is the part that I made, so that's the part that I want to sign (and of course it contains a secure reference to a parent commit, but a reader would naturally understand that I'm not vouching for the whole repo history). And I'd far rather publish my contributions as commits on my branches (that then become a PR) than email patches around and worry about how to archive that, personally.
I'm casually learning about this stuff, so please forgive my noob questions. My end-goal is to enable laypersons like me to verify the authenticity and provenance of digital communication.
I see that Ryabitsev also announced a git transparency log for the kernel:
I don't follow. Do you mean while the key is valid?
I think the scenario you're describing is:
a) I'm issued a cert.
b) I create (and register) my PGP key.
c) I sign a commit with my key.
d) My cert is revoked.
e) Somehow my key is expired.
f) Somehow my commits are now flagged.
Would your concern be addressed by having transparency logs for both the certs and keys?
Huh? Replace one convoluted process for another convoluted and less capable one? Seems like not invented here syndrome. Not surprised it's not used. If you're using email for critical, sensitive work, spend the 15 minutes to learn how PGP works and another to set it up. You can even sign your git commits and tags with them!
I'm thinking more like the recent PHP repository compromise. I was thinking at some point that I may want to host my own git public repos, but they might not be safe. My solution could be to ask people to check my signatures.
Totally though this was going to be some snarky article claiming they're worthless. Refreshing to see the article just ernestly answers the headline.
> To my knowledge, there are no effective attacks against sha1 as used by git
Perhaps im missing something, but wouldn't a chosen prefix collision be relavent here? I imagine the real reason is that cost to pull it off for sha1 is somewhere in the $10,000-$100,000 range (but getting cheaper every year) which is lots of $$$ to attack something without an obvious attack scenario that can justify it.
So the big problem with Git and SHA1 is that in many cases you are giving full control to an untrusted third party over the sha1 hash of something. For example, if you merge a binary file, it'd be quite easy for them to generate two different versions of the same file, with the same SHA1 digest, and then use the second version to cause problems in the future. You may also be able to modify a text file in the same way without getting noticed in review (I'm not up to speed on how advanced sha1 collision techniques are now).
Similarly, the git commits you merge themselves could have that done - the actual git commit serialization gives you a fair bit of ability to append stuff to it that isn't shown in the UI. That wouldn't affect the signed git commits. But it's still dubious to have the ability to change old history in a checkout.
Anyway, Git is apparently moving towards SHA256 support, so hopefully this problem will be fixed soon: https://lwn.net/Articles/823352/
> If we cared to, we could walk each commit all the way back to the beginning of Linux git history, but we don't need to do that — verifying the checksum of the latest commit is sufficient to provide us all the necessary assurances about the entire history of that tree.
Doesn't this imply a tremendous amount of trust in the signer? It sounds like it's only a guarantee about history if every commit was signed.
It's not a matter of trusting the signer. Every commit includes the hash of its parent, and thus the combined hashes of all its ancestors. Signing just the last commits signs the entire chain.
SHA1 wasn’t meant to be a security measure but as far as I know no one has been able to generate a collision that could fool a code review.
> Just replacing an object in a repository is not enough; the attacker would have to find a way to distribute that object to other repositories around the world, which is not an easy task. The colliding object would have to function as C source (if the kernel were the target of attack here), and would have to stand up to a casual inspection — it would have to look like proper kernel source.
https://lwn.net/Articles/715716/
Regardless of whether or not SHA1 was meant to be a security measure, it should have been. Linus's original thinking re: git security is much less useful than just having a secure hash function that you can rely on.
There's a cautionary note at the end of the article reminding the reader that git still relies on sha1 (with mitigations). Recall that $10k worth of GTX1060's produced a sha1 collision in late 2019.
tl;dr: it proves data existed in the past. In the case of a PGP signature on a Git commit, that can prove the signature (and the repo contents) were created prior to the key being compromised.
1) Mostly, because sometimes you don't know when the key was compromised.
We have a similar approach planned in sigstore, but with a slightly different approach to the timestamps by using Transparency Logs. We have some demos here on how to sign git commits: https://github.com/sigstore/cosign/blob/main/FUN.md
The idea is that you can use short-lived keys, bound to certificates via an ACME-style challenge, but based on an email address. The signature goes into a Transparency log to prove it happened while the cert was valid. Then revocation is no longer an issue.
Peter, OpenTimestamps are great. Is there a plan to get the raw ots file for embedding in OpenPGP signatures (as notation data) so that I could be sure that the signature was made at given time? (Just like RFC 3161 - style timestamping data).
Something that is not discussed: to verify the signature you need a copy of Linus's public key, but how do you know you have his actual public key? If you downloaded the key from some server somewhere, and that server was compromised, it could fool you into thinking the signature is valid, which undermines the whole thing.
One way to know the key is valid is if you meet Linus himself and verify it first hand (like when you verify Whatsapp keys, which you do, right?). But not everyone can do that. PGP implements a "web of trust" security model. That means if someone you trust has signed Linus's key, you can verify his key via their signature. This extends beyond one hop; it's up to you how much you trust it based on its signatures.
This is in contrast to centralised systems like SSL/TLS where you have no choice but to trust entities like Microsoft, Google, Verisign etc.
> Kernel.org web of trust
PGP keys used by members of kernel.org are cross-signed by other members of the Linux kernel development community (and, frequently, by many other people). If you wanted to verify the validity of any key belonging to a member of kernel.org, you could review the list of signatures on their public key and then make a decision whether you trust that key or not. See the Wikipedia article on the subject of the Web of Trust.
In practice, most people don't care if they have a copy of Linus's public key. They only care if they have a copy that is sufficiently likely to be Linus's public key.
This is the reason why the web of trust has, by and large, failed to reach any noteworthy amount of adoption. The web/operating system PKI is good enough for most purposes. Unless your usage scenario involves a massively critical government agency with good reason to be actually paranoid, "good enough" for the web means "good enough" to deliver a public key for the Linux kernel. Or more likely, "good enough" to deliver an installation image for the distribution of your choice that is theoretically signed with PGP/something actually reasonable, but whose signature you won't check anyway because the web PKI is, in fact, good enough.
The distribution of your choice may then possibly have verified the source of the public key, but that's so far upstream of you that, quite honestly, you have no way of checking anyway. Even if you bothered checking this being checked upstream, there are tons of other critical system components for which you would have to repeat this.
> With git, a cryptographic signature on a commit provides strong integrity guarantees of the entire history of that branch going backwards, including all metadata and all contents of the repository, all the way back to the initial commit.
The purpose of a signature is to add authenticity assurances on top of integrity guarantees (which are necessary to authenticity, but independent). A document is signed by producing a digest of it, and that digest provides an integrity guarantee. The signature of the digest is then an additional authenticity guarantee.
"Integrity guarantees" means that it is vanishingly unlikely that someone can make a maliciously altered clone of that repository, including its history, all the way to the initial commit, including that signature.
The git hashes already provide pretty strong integrity guarantees of this sort. We can be confident that someone re-creating a fake history cannot end up at the same baseline at the HEAD, with the same commit hash. The strength of that confidence could be increased simply by adding additional, stronger hashes as part of a commit's content.
In terms of authenticity, the signature provides confidence (not a "guarantee") that whoever signed that commit held some beliefs about the repository, sufficient to want to put their signature to it
Someone could be duped into signing a corrupted repository, believing it to be genuine, in which case their beliefs were wrong. (And do not necessarily match their present beliefs!)
Someone could be coerced into signing corrupted repository, in which case their beliefs at the time of signing are that the repository is malicious, and that that they will be harmed if they don't comply.
Someone's private key could be compromised, so that an unauthorized agent perpetrates their signature without their knowledge or consent.
An authenticity assurance is not as easily quantifiable as an integrity guarantee. The integrity guarantee rests in the digest algorithm (how difficult is it to produce a document matching a given digest), but authencity assurances involve people problems.
I think the most valuable aspect of signed commits is that of also signing the contributor license agreement with the same key. This is the Apache Source Foundation's policy.
> Obligatory note: sha1 is not considered sufficiently strong for hashing purposes these days, and this is widely acknowledged by the git development community. Significant efforts are under way to migrate git to stronger cryptographic hashes
[+] [-] rakoo|5 years ago|reply
Note: Linus says otherwise, the two are very different: http://git.661346.n2.nabble.com/GPG-signing-for-git-commit-t...
One of the most important reasons it doesn't make sense to sign commits is that keys expire so when you sign something you implicitly say it is valid at most until the key is valid; nothing can be guaranteed after that. It is easy enough to re-sign a tag (even automatically) but you can't re-sign a commit without changing its identity and that defeats the whole purpose of git.
The only reason you'd want to sign commits is to defend from malicious maintainers ie if your patch is changed before being merged, or your authorship is removed, or a patch impersonating you is merged. It's probably better to sign your patches (ie the temporary moment where you interact) in that case: I see there was some work in that direction (https://lwn.net/Articles/813646/) but apparently it hasn't caught up (https://lore.kernel.org/signatures/ shows last signatures end of 2020)
[+] [-] pipingdog|5 years ago|reply
[+] [-] lmm|5 years ago|reply
[+] [-] specialist|5 years ago|reply
I see that Ryabitsev also announced a git transparency log for the kernel:
https://people.kernel.org/monsieuricon/introducing-the-kerne...
This is very cool.
You wrote:
> ...it is valid at most until the key is valid
I don't follow. Do you mean while the key is valid?
I think the scenario you're describing is:
Would your concern be addressed by having transparency logs for both the certs and keys?[+] [-] waynesonfire|5 years ago|reply
> https://lwn.net/Articles/813646/
Huh? Replace one convoluted process for another convoluted and less capable one? Seems like not invented here syndrome. Not surprised it's not used. If you're using email for critical, sensitive work, spend the 15 minutes to learn how PGP works and another to set it up. You can even sign your git commits and tags with them!
Also, get some yubikeys, they work well with pgp.
[+] [-] orblivion|5 years ago|reply
[+] [-] viraptor|5 years ago|reply
Only if you want them to expire. They don't have to.
[+] [-] bawolff|5 years ago|reply
> To my knowledge, there are no effective attacks against sha1 as used by git
Perhaps im missing something, but wouldn't a chosen prefix collision be relavent here? I imagine the real reason is that cost to pull it off for sha1 is somewhere in the $10,000-$100,000 range (but getting cheaper every year) which is lots of $$$ to attack something without an obvious attack scenario that can justify it.
[+] [-] petertodd|5 years ago|reply
Similarly, the git commits you merge themselves could have that done - the actual git commit serialization gives you a fair bit of ability to append stuff to it that isn't shown in the UI. That wouldn't affect the signed git commits. But it's still dubious to have the ability to change old history in a checkout.
Anyway, Git is apparently moving towards SHA256 support, so hopefully this problem will be fixed soon: https://lwn.net/Articles/823352/
[+] [-] slavik81|5 years ago|reply
[+] [-] nerdponx|5 years ago|reply
Doesn't this imply a tremendous amount of trust in the signer? It sounds like it's only a guarantee about history if every commit was signed.
[+] [-] goerz|5 years ago|reply
[+] [-] gavindean90|5 years ago|reply
> Just replacing an object in a repository is not enough; the attacker would have to find a way to distribute that object to other repositories around the world, which is not an easy task. The colliding object would have to function as C source (if the kernel were the target of attack here), and would have to stand up to a casual inspection — it would have to look like proper kernel source. https://lwn.net/Articles/715716/
[+] [-] petertodd|5 years ago|reply
[+] [-] ganafagol|5 years ago|reply
It literally stands for Secure Hashing Algorithm.
[+] [-] nuisance-bear|5 years ago|reply
https://www.usenix.org/conference/usenixsecurity20/presentat...
[+] [-] unknown|5 years ago|reply
[deleted]
[+] [-] petertodd|5 years ago|reply
tl;dr: it proves data existed in the past. In the case of a PGP signature on a Git commit, that can prove the signature (and the repo contents) were created prior to the key being compromised.
1) Mostly, because sometimes you don't know when the key was compromised.
[+] [-] dlor|5 years ago|reply
The idea is that you can use short-lived keys, bound to certificates via an ACME-style challenge, but based on an email address. The signature goes into a Transparency log to prove it happened while the cert was valid. Then revocation is no longer an issue.
[+] [-] Woung1938|5 years ago|reply
[+] [-] bawolff|5 years ago|reply
[+] [-] globular-toast|5 years ago|reply
One way to know the key is valid is if you meet Linus himself and verify it first hand (like when you verify Whatsapp keys, which you do, right?). But not everyone can do that. PGP implements a "web of trust" security model. That means if someone you trust has signed Linus's key, you can verify his key via their signature. This extends beyond one hop; it's up to you how much you trust it based on its signatures.
This is in contrast to centralised systems like SSL/TLS where you have no choice but to trust entities like Microsoft, Google, Verisign etc.
[+] [-] waynesonfire|5 years ago|reply
https://www.kernel.org/signature.html
Looks like the kernel.org folks actually use the web of trust model.
[+] [-] rdpintqogeogsaa|5 years ago|reply
This is the reason why the web of trust has, by and large, failed to reach any noteworthy amount of adoption. The web/operating system PKI is good enough for most purposes. Unless your usage scenario involves a massively critical government agency with good reason to be actually paranoid, "good enough" for the web means "good enough" to deliver a public key for the Linux kernel. Or more likely, "good enough" to deliver an installation image for the distribution of your choice that is theoretically signed with PGP/something actually reasonable, but whose signature you won't check anyway because the web PKI is, in fact, good enough.
The distribution of your choice may then possibly have verified the source of the public key, but that's so far upstream of you that, quite honestly, you have no way of checking anyway. Even if you bothered checking this being checked upstream, there are tons of other critical system components for which you would have to repeat this.
[+] [-] kazinator|5 years ago|reply
The purpose of a signature is to add authenticity assurances on top of integrity guarantees (which are necessary to authenticity, but independent). A document is signed by producing a digest of it, and that digest provides an integrity guarantee. The signature of the digest is then an additional authenticity guarantee.
"Integrity guarantees" means that it is vanishingly unlikely that someone can make a maliciously altered clone of that repository, including its history, all the way to the initial commit, including that signature.
The git hashes already provide pretty strong integrity guarantees of this sort. We can be confident that someone re-creating a fake history cannot end up at the same baseline at the HEAD, with the same commit hash. The strength of that confidence could be increased simply by adding additional, stronger hashes as part of a commit's content.
In terms of authenticity, the signature provides confidence (not a "guarantee") that whoever signed that commit held some beliefs about the repository, sufficient to want to put their signature to it
Someone could be duped into signing a corrupted repository, believing it to be genuine, in which case their beliefs were wrong. (And do not necessarily match their present beliefs!)
Someone could be coerced into signing corrupted repository, in which case their beliefs at the time of signing are that the repository is malicious, and that that they will be harmed if they don't comply.
Someone's private key could be compromised, so that an unauthorized agent perpetrates their signature without their knowledge or consent.
An authenticity assurance is not as easily quantifiable as an integrity guarantee. The integrity guarantee rests in the digest algorithm (how difficult is it to produce a document matching a given digest), but authencity assurances involve people problems.
[+] [-] unknown|5 years ago|reply
[deleted]
[+] [-] exabrial|5 years ago|reply
[+] [-] numbsafari|5 years ago|reply
[+] [-] upofadown|5 years ago|reply
Also, OpenPGP is an open published standard with an extensive infrastructure of implementations. It's hard to overcome that with a new proposal.
[+] [-] phs318u|5 years ago|reply
[+] [-] shawabawa3|5 years ago|reply
Gpg signature's are the only way of having any verification at all on who wrote a commit
[+] [-] bawolff|5 years ago|reply
[+] [-] asguy|5 years ago|reply
[+] [-] phs318u|5 years ago|reply
My initial comment was dumb and deserved downvotes, but all git usage isn't the git usage you know of.
[+] [-] waynesonfire|5 years ago|reply
Ops, forgot to add a tag to your hash algorithm?