Hacker News new | past | comments | ask | show | jobs | submit login
SSH commit verification now supported (github.blog)
227 points by rainworld on Aug 23, 2022 | hide | past | favorite | 110 comments



Neat, I didn't even know you can sign git commits with SSH!

Seems to be a pretty new feature too; [1] claims it's from November 2021.

[1] https://calebhearth.com/sign-git-with-ssh


Shameless plug for the gitsign project in sigstore: https://github.com/sigstore/gitsign

This isn't supported by GitHub yet but we're hopefully working towards that too.


Is there any other Git host/platform that supports it? Gitea/GitLab?



What about Sigstore, is there any plan on supporting it?


You can find the feature request for supporting keyless sigstore/gitsign at https://gitlab.com/gitlab-org/gitlab/-/issues/364428


Sorry, I missed the context your original question was about Sigstore. Someone answered in https://news.ycombinator.com/item?id=32569872


Worth calling out that gitsign works with any Git host for the commit signatures / verification!

The main piece that's platform specific is the Verified badges that you see in the UI + any CI checks.


I think github support came out a year and half after the feature was available in git (nov 2021), so that may going to be a while :(


I just looked through the website and I’m struggling to understand exactly how it works - how do you have signing / verification without the risk of key compromise?


The same way LetsEncrypt makes compromised TLS certificates (almost) useless; short-lived certificats.

What the sigstore project does is having an oauth portal which can authenticate one of your online identities. It uses this to sign a temporary certificate for you with it's root CA. This certificate is what you use to sign commits and artifacts with.


+1 to this!

https://docs.sigstore.dev/fulcio/certificate-issuing-overvie... has a good overview of how the certificate issuing works.

With Gitsign, by default a new keypair is generated per signing event (i.e. per commit) and never hits disk. The cert in the commit signature holds the public key, which we can check against Rekor (https://docs.sigstore.dev/rekor/overview) to verify it was valid at the time of signing.

If you have the time, https://www.youtube.com/watch?v=PVhRQFS9Njg is a great deep dive into how Sigstore works in general!


I may be misunderstanding your question, but here is the answer if I understand you correctly.

This is all based on public key cryptography. In public key cryptography, there are actually 2 keys, a public key and a private key. Sites like get hub and the repose can store the public keys, while into while individual users keep their private key's secret. Anyone with the public key can verify a signature, but only an individual with the private key can create the equivalent signature.

The trick is to determine if a given public key corresponds to an individual. There are various methods to try to address that.

I hope that helps!


Super excited and can't wait!


Finally. Github does not recognize GPG signatures for commits where the e-mail field does not match an e-mail address verified with GH. So you'd have to make your e-mail public to have your commits show as green. This seems to fill that gap.

(Using a burner has the problem that a valid-looking mail might have people legitimately try to reach out, which is not nice)


you can use your no-reply email address

https://docs.github.com/en/authentication/managing-commit-si...

`ID+username@users.noreply.github.com`


Oh, I think that's relatively new? Tried to do exactly that a year or two back but wasn't recognized then.


Wow, had no idea this was possible.


You can add and verify an email address without making it public in GitHub. But, the PGP signature is public and contains the email address associated with the signing key, so if you use PGP signatures at all, your email address is public anyway, regardless of the "verified commit" badge.


Well yes but `username-noreply@example.com` should make it immediately clear that no one will be reading e-mail sent there. As noted in a sibling, GH now recognizes using the github noreply addresses since some time a well.


Does anybody know if this only verifies _new_ commits? I've been signing my commits with my SSH key for a while, but older commits still show as unverified in the web UI. They show the hash of the public key the commit was signed with, which matches a public key associated with my account in the account settings, but the commit still says "Unverified".

Example: https://github.com/grncdr/dev-mode/commit/06376070aff042e9d5...


You'll need to re-upload your public SSH key as a signing key for the signatures to be shown as verified. https://calebhearth.com/sign-git-with-ssh#github


This was it, thanks for the pointer!


You need to re-add your SSH key and there's a new key type select box that has "signing" option. The old keys are only good for auth.


This was it, thanks for the pointer!


All my old commits show as verified now


My guess is that they may have forgotten to backfill old data (because probably whether a commit is verified is not computed on the fly), but I don't see why it can't apply retroactively.

Maybe try removing and adding the public key from your account? That might trigger the system to scan all your commits and re-verify.


Nice! It is easier for me to have multiple SSH keys backed by my Yubikey than GPG keys (only 1 GPG key per Yubikey).


I find it weird that GPG/PGP leans so heavily into "one key per person". Why shouldn't I be encouraged to have 2 or 4 or 10 identities if I want to? If my "web of trust" is diluted as a result, then that's on me (and I don't much care).


>I find it weird that GPG/PGP leans so heavily into "one key per person".

It does?

>Why shouldn't I be encouraged to have 2 or 4 or 10 identities if I want to?

What is stopping you?


> It does?

At least the OpenPGP smart card specification kind of does, yes.

It uses a "single private key stored on the card" (ok, actually three keys) model, whereas FIDO (including SSH‘s security key implementation) uses key handles, which theoretically support an unlimited number of keys per authenticator.


A key handle seems to be the real private key encrypted with a static key from the hardware key.

You can achieve that yourself, for example, using Pass. Encrypt theoretically unlimited number of password and secret keys with the master password in the hardware token.


> A key handle seems to be the real private key encrypted with a static key from the hardware key.

It can be, but it‘s essentially just a binary blob. It can also be entropy to deterministically re-derive a private or secret key from an internal root secret, or just a primary key to look up that key or entropy within the token.

> You can achieve that yourself, for example, using Pass.

How? With a hardware token, you can only do what its protocol allows you to in terms of key derivation.

That means that with a standard OpenPGP card, you will not be able to do key handle based key derivation, while with FIDO/CTAP you can.

You could obviously develop your own OpenPGP-compatible hardware token standard, but you‘d only be able to use it with a patched version of GPG, GPG agent etc, but a big advantage of OpenPGP smartcards (and even more so FIDO/CTAP tokens) is that they are widely supported without requiring driver installation.


Beware: Signing commits with SSH or GPG keys removes the "plausible deniability" [1][2].

Of course certain projects (especially if very critical or secure systems) definitely benefit from that but imagine you put your handwritten signature on every single step of your work (hint: you don't do that in the real World). You would never do so for normal internet activity like Google searches, Twitter or Facebook yet you want to sign your git commits with a signature undeniable connected to yourself, probably also connected to your real name.

If you just think that signing is just a "cool feature to have" then you should really educate yourself about implications of having a connected (real name?) identity on the internet.

[1] https://en.wikipedia.org/wiki/Plausible_deniability

[2] https://legaldictionary.net/plausible-deniability/

P.S.: I just wanted to make people think before activating this feature. Most GitHub code and repositories worked perfectly without it. Do you really need it? When yes, why?


There's nothing about this that stops you from having multiple identities. You can generate a unique key for a project or github account, and then only using that key for that purpose. This allows trust that "MarvinTheMartian" the maintainer of the "Q-36 Space Modulator" doesn't have false commits under their name (maybe important for their reputation!), while still giving the plausible deniability that "therealmarv" isn't developing cartoonish WMDs.


This is definitely the way to go. I just wanted to highlight and warn that some people do not think their actions or new features 100% through their mind. Many/Most repos were also useful without the signing feature.


Why wouldn't you want this?

Committing code is not like browsing facebook, or searching on google. Even then, your name is on any posts you're making on twitter or facebook, and i'm sure google knows what you're searching.

As a maintainer, why would you want people to be able to deny making a given commit? or have them come in completely anonymously?


As a creator, it is sometimes advantageous for me to deny some of my own work. I regularly use "fixup" commits and rebase them out of existence. I'd be mildly embarrassed to have all of them sticking around in code forever.

As a user of code published on Github, I sure as heck want there to be clear ownership and authorship of the code I use, and to be able to hold them accountable for malice. And there is lots malicious code on Github, trying to disguise itself as legit; Having a strong public persona isn't guarantee that my github code isn't malicious, but it does raise the stakes.

As a human who has seen what happens when people commit mistakes, we're very emotionally bad at dealing with mistakes. "Who broke the vase?" is a tough question to ask. "Who broke the build" can carry the same weight - Both very little, and very much, depending on when it's asked and how expensive the vase was. I'd like to think that making mistakes will be easier in a merkle-tree structured world; That as a collective, we will learn to do a better job of helping people admit their mistakes, come forward with them, and say "I made that mistake, and have learned from it". The internet has proven that false again and again.

In two important ways - People are unwilling to forgive, and people are unwilling to admit. Past minor mistakes haunt people forever all the time. Look at things like "Has Justine Landed Yet?"[1].

A malicious liar (We'll call them Eve) will deny, refute, and plain old lie in the face of whatever. There can be incredibly convincing evidence (A RSA-Key Verified Git Signature, for example) of... whatever, and it will be written off as "Harassment" by friends of Eve. Further: There's plenty of actual malice that passes itself off as not. Rapists say "She clearly wanted it, she got wet" - Criminals do that at all levels, making up excuses for why their victims deserved it.

Regardless - It is a sea change to be held accountable for your code. I do want it, but I do not believe that SSH key verification will achieve that. I think it will be a significant change when it does happen, though, and one with significant consequences.

[1]https://www.nytimes.com/2015/02/15/magazine/how-one-stupid-t...


GitHub never deletes anything you push. Even if you rebase and force push, that old information is still accessible. Also why would you drag out such an ugly article to make a point?


Because this is a security question. Ugly questions need to be asked - Understanding how actual malice interacts with your security model is the whole point.


Say you’re writing some code that may be illegal (piracy stream, rips off another API with licensed content, etc). I would want to deny that it was me (but then, i wouldn’t connect it to my real-life identity at all).


It's that serious? Wouldn't the offended party just ask for the content/service/repo be removed?


With the digital footprint these days, that might impede employment in the future in certain industries or sectors, especially if it’s tied to your name.


>if it’s tied to your name

How can this be proved? Even with signing, anyone can impersonate anyone.


The entire point of the signature is that it can't be forged. If a commit is signed with your private keys, I can reasonably conclude you authored it.


I know this is a solved problem in certain contexts, but realistically how does a third party prove that your private keys are yours?


Because if you're signing your commits you're probably also the type of person to sign your email with the same key.


Adding a data point to your statistics: I sign commits and packages I maintain (when it applies), not my emails.


Obvious recent case is Tornado Cash.


is it not enough to sign it and burn the keys?

PGP encrypted public messages is common even on the dark web.


> As a maintainer, why would you want people to be able to deny making a given commit? or have them come in completely anonymously?

1. Because you trust code for what it is and are willing to trade attribution surety for a lesser ask of contributors

2. Because you care about certain principles of anonymity and non-repudiation and want to respect them in your own plainly legitimate project.

3. Because your project is or risks becoming illegitimate in some jurisdiction and you want to protect your contributors as best you can.

It'd be nice if we can continue to respect these reasons as valid even while allowing other maintainers to exercise different policies.


I don't see that any of those reasons are relevant, in all honesty.

1. This is not even a moderate ask; using ssh for git transactions is no more or less burdensome than https

2. As has been pointed out, there is no reason or reliable way to verify the identity of a creator's SSH key

3. Real-world example of such a project, or why this matters in the context of (2)?


> there is no ...reliable way to verify the identity of a creator's SSH key

GitHub exposes your public key via it's API. (Why? I have no idea. I call it a privacy violation) So, you need to create new github identity for every SSH identity that you wish to remain anonymous for, otherwise they just get tied together & one aspect of anonymity is lost.


All that does is associate an arbitrary SSH key with a GitHub account. There is still no reliable way to verify the identity of the GitHub account owner, or the SSH key that account holder generated.

How does that expose any more information than you do by pushing a commit with a GitHub account?


It looks like this feature can be used with an pseudonym account that may be the way to go if this is a concern for you.

Having your real name on the GitHub account but not having a commit sig is not really that strong deniability anyway.

If your thinking about some situation where you are being legally hounded because of code (e.g. DMCA, tornado cash situation etc) they will subpoena your hardware and likely find enough evidence that you can't plausibly deny writing the code anyway. GitHub logs may show you the upload was with a SSH key or http auth associated with you anyway.

For non legal situations, I suspect most observers won't really believe that a non-signed upload could have been done by someone else. Especially if it's to a repo only you have upload permission to or something.


> You would never do so for normal internet activity like Google searches, Twitter or Facebook

Websites from Google search result are verified by my browser via HTTPS certs. On twitter or facebook, users usually trust the centralized authnz systems hosted by the platform to verify content ownership. But out of box, git allows you to use whatever name/email on your commit, so that's a problem.

In my whole career, there were 3 times that I got questioned about "why did you introduce this line of code, which caused some production issue?" and turned out to be results of someone junior developer's rebase/amend or whatnot. I pointed out that I always sign my commits and those unsigned ones were not mine. Without signature I really could not tell whether I was the author or not, since some commits are months/years old.

I believe those altered commits were honest mistakes without malicious intention, and our organization has blameless culture. But I still want to let my coworkers know that I am not the one who caused this problem. Signing commits helps a lot in these situations and clears misunderstanding, and I believe more or less impacted my performance review and bonus (my performance would probably not be as good if I had to own those incidents).

CI/CD tools are getting better each day, a commit can mean a lot more than "a snapshot of the code base", like, it could have been a checkpoint of the state of the production environment (IaC, GitOps ... etc). You already have your name on the commit, so why not offer a way for others to verify you are really who you say you are?

And I should probably clarify, that the identity of a git commit does not have to be linked to a human in real life. It's just a way to verify that a commit is really from author X and not Y.


> But out of box, git allows you to use whatever name/email on your commit, so that's a problem.

Systems are typically unsecured until someone starts abusing it. GitHub has obviously foreseen this possibility which is why they have the infrastructure in place to restrict freedom in the interest of security. The day someone starts aggressively misusing that feature, they could take it away just like that.


> but imagine you put your handwritten signature on every single step of your work

In most engineering or engineering adjacent fields you are doing this, btw. Yes, in software too.


Also known as non-repudiation[1] and, as you point out, not something to be used without considering its consequences.

https://en.wikipedia.org/wiki/Non-repudiation


What consequences? Something like "if you push to a repo that gets taken down for DCMA requests, you can't deny in court that you made the commit"?


You can't deny you authored commits even if somebody steals your private key?


What are the advantages of signing with SSH rather than GPG?


For starters, you don't have to manage two keys at minimum. That's already a plus. For another reason, I wasted a lot of time diagnosing problems with gpg not working correctly, from the daemon crashing and needing to be killed periodically to random lockups or failed signatures due to keys not being unlocked. All of that is alleviated with ssh.

Edit: Turns out this still uses gpg? I think?


You can use your GPG key as an SSH key[0], and you'll also only need to manage one key - although that doesn't fix whatever issues you might have with GPG, of course.

[0]: https://wiki.archlinux.org/title/GnuPG#SSH_agent


> Edit: Turns out this still uses gpg? I think?

Nope, it uses your SSH agent. It's super confusing because the git config key is `gpg.format` (which you set to `ssh`), but I promise it works without GPG installed.

I suspect this confusing name is because when support for signing commits was originally added to git it only supported GPG, and a bad choice on the parameter name was made.


My gut feeling is to create a separate key for signing but I’m not sure why. Is there downside to using the same SSH key for both signing and login?


Ordinarily you should not use private keys for more than one purpose because the algorithms may make it possible for bad guys to surprise you with the consequences. e.g. you sign a document vouching for someone to adopt a cat, but it turns out actually when interpreted as a bank sign-in instead of cat adoption document your signature still works.

However, the OpenSSH team were very careful to design their signature feature so that what is signed is always different from any possible SSH login.

Now, of course if you sign a text document which says "I want Bill to have all my stuff" but you meant, you know, Bill at work, can keep my stapler and that cool glow-in-the-dark mug, because I'm leaving next week and I can't be bothered to box it all up and take it, whereas your 2nd cousin William tries to persuade a judge it's a legal Will, and so your untimely death in a car crash should result in him inheriting everything instead of your bereaved wife and six year old daughter - well, that OpenSSH can't do anything about.

But you would be correct to assume it is not safe in general to use keys for unrelated purposes, and only the (documented and justified) choice by OpenSSH reverses that assumption for the SSH tools.


If you wish for a computer to be able to sign commits but not push (or push commits but not sign) that would be impossible.

Anytime you use that public key (for example, to SSH into a server) that session is linked to your identity via git commits (this doesn't actually matter for github, as github exposes all your SSH keys via its API anyways).


In my experience, almost every git user has an SSH key already set up, to push with. Far fewer people have GPG keys set up.


It's a lot simpler to set up. I have forgotten the details on all of this, but basically gpg signing worked fine for a few years until it didn't and then I couldn't fix it in under an hour. I just stopped signing stuff until git added ssh support last year.


I think hardware SSH keys using FIDO2 are a lot more convenient to set up than GPG as well.


So I can upload my public key, and GitHub will associated it with my commits. Do I sign it locally with my private key?

This below doc indicates "no" but if not then, when?

> To set your SSH signing key in Git, paste the text below, substituting the contents of your clipboard [which contains the public key] for the key you'd like to use. Since the key contains spaces, you must wrap it in quotes:

https://docs.github.com/en/authentication/managing-commit-si...

Or am I missing something?


You sign with your private key. You’re using the public key as an identifier to tell your git client which key to use, since git can use the public key to confirm it’s using the right private key.


Ah, thanks!


When you push to git via ssh which uses this key?


I'm still a student, but I enabled commit signing for all of my friends after showing them the Linus Torvalds fake commits.


In most cases I presume this isn't a big deal but is it wise for your auth key and signing key to be the same key pair?


Generally, no; in this particular case (SSH authentication and generic signatures), it seems to be ok: https://www.agwa.name/blog/post/ssh_signatures


If signing commits becomes popular, it would be one of the very first tiny cracks in the stronghold of bigtech over the internet.

So far, we trust GitHub that a certain repo is under control of a certain individual or organization.

We trust Twitter that a tweet was done by Elon Musk and not by Joe Doe. We trust Instagram, that Sue really got a like from that famous influencer and did not fake it. We trust HN, that I wrote this comment.

But if signing these things would become the norm, commits, tweets, likes and posts would become eternal. Independent of any central authorities.

Unfortunately, it will probably not become popular. As there is nothing to gain for the author of a commit by signing it.


> Unfortunately it will not become popular because Twitter will not force celebrities to use SSH keysigning to earn a blue checkmark

I mean, if you heard the horror stories of how a particular ex President's twitter password was incredibly insecure without even two factor auth you'd understand that users just don't care about anything even close to security.

I still long for the old days of tech when you at least had to figure out how a 56K modem worked to use it. You at least had to respect the ancient wizardry or incur the wrath of the Code Gods.

The amount of people using 1Password / Elliptical Curve Encryption / MFA in 2022 is effectively zero because everything has be ultra optimized for ease of use.


GitHub has supported GPG-signed commits since 2016: https://github.blog/2016-04-05-gpg-signature-verification/

AFAICT, the new thing here is that you can use SSH instead of GPG to sign commits, which should hopefully make it easier for people to adopt.


Yeah; GitLab has supported GPG-signed commits for years, too.


> As there is nothing to gain for the author of a commit by signing it.

All of the recent focus on supply chain security could result in signed commits becoming more routine.


Do auditors care? All the ones I've dealt with just want you to log everything and rake your face over the hot pavement for their stamp of approval, actual security be damned. I'm surprised they even require 2FA at all.


Useless security theater at best. They treat all 2FA as the same, including phishable TOTP or RSA SecurID, and (shudder) SMS.


Our auditors were perfectly willing to treat FIDO2 2FA as a specific mitigation against phishable credentials and whatnot. Really depends on your auditor/ the case you make.


My point is the other methods should not be considered acceptable as 2FA because they are phishable. But yes, I'm sure there are competent auditors (as opposed to the ones who are financial auditors from accounting firms and completely out of their depth in matters of security).

The problem is that unless there is a big stick, like a cybersecurity insurance company saying "unless you use U2F keys for 2FA, you are not covered", there is no incentive to change.


It goes further than that. Knowing that leftpad 1.0 was indeed signed by johndoe1234, author of leftpad, does not help you in trusting that leftpad actually left pad strings correctly, that it doesn't do anything malicious, that vulnerabilities get patched, etc. In other words, it does nothing at all for you.

Sure, you might trust Facebook, and so knowing that React 18.0 was indeed signed by Facebook is interesting. But then React depends on leftpad, is-odd, reversearray, ... by random devs. What security do you gain by verifying the random signatures from random devs?

Unless there is a way for Facebook to sign those transitive dependencies, vouching for them in a way that you can check. That would be something. But their authors signing them does nothing.


Commits are still signed with sha1, albeit a version that is resistant to the current attack against sha1. It kinda sucks, I'd be a lot more willing to sign commits (well, I do, but still) if it were at least backed by crypto that doesn't have decades of issues.


Personally I'm still dependent on the platforms, because I use the no-reply email supplied by the git platform.

It helps avoiding spam, as its only used for just confirming the author.


What is the benefit of signing a commit with a SSH key vs. a GPG key? Is it simply being able to use ssh-keygen instead of gpg?


Great! So now you can sign commits on Windows (on GH repos) without installing GPG4Win (or having to use a WSL GPG)



Looks like you can side-step this entire issue by using Windows' own OpenSSH port: https://superuser.com/questions/1695601/use-ssh-key-signing-...


Fixed it locally by installing updated SSH client and forcing git to use it:

git config --global "gpg.ssh.program" "C:/Program Files/OpenSSH/ssh-keygen.exe"


Finally! only reason I've been keeping gpg around has been to sign git commits, so now I can just sign with my ssh key. Wonderful


Is there any reason to use commit signing in a private corporate GH repo?

The only thing I could see it really preventing is a malicious employee making a commit with obviously bad code in someone else's name, but with branch protections enabled, it wouldn't go to prod without someone else catching it.


> malicious employee making a commit with obviously bad code in someone else's name, but with branch protections enabled, it wouldn't go to prod without someone else catching it.

You are massively overconfident about the protections code review provides. But even if you _are_ confident in code reviews, you can push code to someone else's PR under their name, then approve it yourself and ship it yourself.

It also opens up social engineering vectors. Create a PR by CEO/CTO/Senior Security Engineer/whatever, with some critical sounding bug fix impacting $BIG_CLIENT, then you DM someone "hey, $IMPORTANT_PERSON needs this shipped ASAP, can you help us out with a quick +1?"


In both cases, you're leaving a paper trail that you were involved. In the first, you approved bad code. In the second, you asked someone to approve bad code.

Of course, who knows how long that bad code could sit in prod before it gets noticed is a toss-up, and preventing it from happening is going to be infinitely better than just logging it.

Got any other scenarios that commit signing would solve?


Is this backward compatible with clients that do not support SSH signing yet or older versions of git?

i.e What happens if I push a SSH signed commit to a Gitlab or Bitbucket remote or mirror the repository? How do the commits appear to a client that does not understand SSH signatures?


It's just ignored. The signing data is added in the same way as a GPG key, just in a different format. Git commands don't look at signatures by default, and if they do, they will just say "invalid signing format" or some such.

It's always possible some program handles this badly, but I've been signing with ssh pretty much since the day it was added to git (before it was in a release) and never experienced any problems or complaints.


Signing using SSH keys does not work reliably on Windows: https://github.com/git-for-windows/git/issues/3883


Fixed it locally by installing updated SSH client and forcing git to use it:

git config --global "gpg.ssh.program" "C:/Program Files/OpenSSH/ssh-keygen.exe"


Finally, one step closer to the dream of having a dirt-cheap, unphishable, unstealable FIDO2 key for all my security needs. Now all we need is for WebAuthn to catch on.


How do you implement this as unstealable?


You need the physical key plus a password/PIN that deletes the data after N wrong tries.



Need git > 2.34 to make this work. Mac OS git is 2.32 which doesn't work. Had to homebrew install.

EDIT: Interestingly, updating gave me a neat suggestion to use:

    git config --global --add --bool push.autoSetupRemote true
So it's a win in another sense for me too.


Homebrew-installing newer versions than the macOS provided ones is a must in my opinion. I also recommend upgraded the Apple-provided versions of other utilities you use (e.g. less, Ruby, vim, etc.)

I had upgraded git to get `git switch`


If you're used to GNU find and grep, and maybe tar, then getting those from homebrew or macports is a major improvement too.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: