What are Verified Commits on GitHub?

If you've been on GitHub in the last few months, you might have noticed and increasing number of commits have a little 'Verified' badge next to it.

And when you click on it, it says that 'This commit was signed with a verified signature'.

What are Verified Commits and how can you verify your own commits?

The Case of Stolen Identity

When you create a new commit in Git, Git will keep several pieces of information, including the time and author of the commit. The information about the author are usually read from the Git configuration files, which the committer sets him/herself.

However, this also means anyone can set their user configuration to masquerade as someone else. For example, a malicious party can introduce an insecurity into an open-source library that I contribute to, and commit it using my name and email. The maintainers of the project, seeing that the commit came from me, may merge it into the master branch.

To prevent this sort of scenarios, GitHub allows you to sign your commits using a GNU Privacy Guard (GPG) key.

How GPG Verification Works?

You'd first generate a GPG key pair, which consists of a private and public key. You'd sign your commits using the private key, and associate the public key with GitHub. When GitHub sees a commit signed using a GPG key, it'll use the public key you provided to decrypt the data; if the data makes sense, then GitHub verifies the committer as you. Since no one knows your GPG private key, they can't sign the commit with it.

Getting a GPG Key

First, we need to have a GPG key.

Checking for Existing GPG Key

If you've used other services like keybase.io, you may already have a GPG key configured.

Run gpg --list-secret-keys --keyid-format LONG to find out if you have an existing key. If you do, you can skip ahead to the 'Associating GPG Key with GitHub' section, or continue on to create a new key pair specifically for GitHub.

$ gpg --list-secret-keys --keyid-format LONG
~/.gnupg/pubring.kbx
----------------------------
sec   rsa4096/EF34CDD9A458D8AF 2017-10-02 [SC]  
uid                 [ultimate] Daniel Li <dan@danyll.com>  
ssb   rsa4096/54118D71AE1DB6FB 2017-10-02 [E]  

Generating a New GPG Key

Run gpg --full-gen-key and follow the wizard to generate your key. We are going to use the RSA algorithm with key size of 4096 (the longer the key, the less susceptible it is to brute-force attacks).

$ gpg --full-gen-key

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)
Your selection? 1

RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits

Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all

Is this correct? (y/N) y

After this, gpg will ask you to enter a passphrase; this is extra security - if someone wants to masquerade as you, they'll need both the key and your passphrase.

You need a user ID to identify your key; the software constructs the user ID from the Real Name, Comment and Email Address in this form:
    "Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"

Real name: Daniel Li
E-mail address: dan@danyll.com
Comment: [--leave blank--]
You selected this USER-ID:
    "Daniel Li <dan@danyll.com>"

Change (N)ame, (C)omment, (E)-mail or (O)kay/(Q)uit? o

gpg: key 2B6133C585E1799A marked as ultimately trusted
gpg: revocation certificate stored as '~/.gnupg/openpgp-revocs.d/AC96C56725A245695510A804EF34CDD9A458D8AF.rev'
public and secret key created and signed.

sec   rsa4096 2017-10-02 [SC]
      AC96C56725A245695510A804EF34CDD9A458D8AF
uid           [ultimate] Daniel Li <dan@danyll.com>
ssb   rsa4096 2017-10-02 [E]

Associating GPG Key with GitHub

Run gpg --list-secret-keys --keyid-format LONG to get a list of GPG keys.

$ gpg --list-secret-keys --keyid-format LONG
~/.gnupg/pubring.kbx
----------------------------
sec   rsa4096/EF34CDD9A458D8AF 2017-10-02 [SC]  
uid                 [ultimate] Daniel Li <dan@danyll.com>  
ssb   rsa4096/54118D71AE1DB6FB 2017-10-02 [E]  

sec stands for 'secret key', and ssb stands for 'secret subkey'. And the string of letters after rsa4096/ are the keys' ID. This ID is the same for both the private and public keys.

Copy the ID and run the following command to copy the the public key (in armor format) onto your clipboard.

$ gpg --armor --export EF34CDD9A458D8AF | xclip -selection clipboard

Now, go to github.com/settings/keys and click on the 'New GPG key' button.

Paste the public key into the textarea and click 'Add GPG key'.

You'll now see your GPG key on your GitHub account.

Signing Your Commits with your GPG key

Next, we need to tell Git to use our key to sign our commit. We can do that through the --gpg-sign option.

$ git commit --gpg-sign=EF34CDD9A458D8AF

However, signing commits individually is tedious. An easier way it to set your key as a global Git configuration, and tell Git to use that key to sign every commit under this user account.

$ git config --global user.signingkey EF34CDD9A458D8AF
$ git config --global commit.gpgsign true

Now, all your commits will be automatically signed by Git!

Daniel Li

Full-stack Web Developer in Hong Kong. Founder of Brew.

Hong Kong http://danyll.com