S/MIME, our old friend, usually used to sign and encrypt emails. Essentially it’s a standard to ensure the authenticity and security of your communications, especially emails. However, it can also be used to sign regular data. You guessed it, we are going to use it to sign Git commits.

The difference between PGP signatures and S/MIME signatures is that the latter requires a central organization to ensure the certificate is trustworthy, and thus it’s popular among corporations. However, as an individual, we can also utilize that.

An example.

Getting Started

You’ll need an S/MIME certificate (obviously) which can be obtained for free from the previous posts.

GitHub’s own smimesign has been deprecated for a long time and it’s basically impossible to get it working. Thus, we will be using gpgsm to sign our commits.

First you’ll need to import your keys. Please use PKCS#12 bundles to avoid potential errors. You will also need to setup a password to protect it within the GnuPG keyring.

gpgsm --import pkcs12.pfx 
gpgsm: directory '/root/.gnupg' created
gpgsm: keybox '/root/.gnupg/pubring.kbx' created
gpgsm: dirmngr cache-only key lookup failed: No data
gpgsm: total number processed: 4
gpgsm:               imported: 1
gpgsm:              unchanged: 2
gpgsm:       secret keys read: 1
gpgsm:   secret keys imported: 1

After importing the key, we need to check the key fingerprint.

gpgsm --list-secret-keys

The output may look like this.

/root/.gnupg/pubring.kbx
------------------------
           ID: 0xD6D52894 <---- THIS IS YOUR ID
          S/N: 2C0F739B049FB435EA6CFCFA1C1AB81B
        (dec): 58566261026314940740407162240409188379
       Issuer: /CN=Actalis Client Authentication CA G3/O=Actalis S.p.A./L=Ponte San Pietro/ST=Bergamo/C=IT
      Subject: /CN=[email protected]
          aka: [email protected]
     validity: 2024-01-24 11:43:37 through 2025-01-24 11:43:36
     key type: 2048 bit RSA
    key usage: digitalSignature keyEncipherment
ext key usage: clientAuth (suggested), emailProtection (suggested)
     policies: 2.23.140.1.5.1.1:N:
  fingerprint: D5:B9:EE:44:CE:E9:C7:FF:F5:0D:F2:9A:20:51:D4:B9:D6:D5:28:94
     sha2 fpr: 17:FD:90:A9:06:B3:0C:C1:D1:0B:3B:D2:14:DD:69:8D:6D:A9:CD:00:4A:4B:29:20:0F:0A:1C:E2:4B:41:1E:48

Copy your ID and run the following command to tell Git about your key.

git config --global gpg.format x509
git config --global user.signingkey [YOUR ID]
git config --global commit.gpgsign true

Guess what, it’s done. Now try to sign something :)

Cautions

GitHub will do certificate revocation check every time, so if the certificate is revoked, the signature won’t be trusted. Also, if the certificate is expired, the signature may also become Unverified.

It’s also worth noting that self-signed certificate won’t work.

References

S/MIME(X.509) 签名 Git 提交教程 - MBRjun-Blog, archived in Internet Archive on March 2, 2024.