• TokenSoft

Securing the Software Supply Chain

Updated: Mar 4

Signing Git Commits with Yubikey


by Chris Walker, TokenSoft Developer

Thieves are compromising software with malicious code that steals cryptocurrencies. If you build software, you need to protect your clients from these attackers. At TokenSoft, we take this threat seriously and we practice what we preach. This piece outlines one aspect of our best practices.


So far there have been several attempts to compromise software hosted by NPM, a popular package manager for the Javascript community. Attackers gain control of a commonly used software package with an innocent name like event-stream or electron-native-notify and then push malicious updates to NPM. 


These compromised packages are then automatically pulled into your own software projects during the build process and eventually distributed to unsuspecting users. The NPM team has foiled some of these attacks, but attackers can also target your project’s source code directly.

The first obvious step is to host your code on a reputable platform like Github and require all code contributors to use multi-factor authentication. But what if that’s not good enough? The next step is securing your git repository with signed commits, ensuring that all code can be traced to a specific authorized developer.


How To


To start, we’ll assume you have a Yubikey 4 and an Apple computer and are committing code to a git repository stored on Github.


Prepare to roll up your sleeves: this will take some time.



Check Yubikey Firmware


First, plug in your Yubikey and look it up in System Report.

Apple → About this Mac → System Report → Hardware → USB

Verify that the Yubikey version is at least 3.1.8. This guide will assume you have a Yubikey 4. The instructions are not compatible with the older Yubikey FIDO U2F Security Key.



Set Yubikey Mode 


Switch Yubikey to OTP/U2F/CCID mode (the Yubikey is probably already in this mode as a factory default, so this may only be necessary if it has been configured previously).

$ brew install yubikey-personalization
$ ykpersonalize -m6
Firmware version 4.2.6 Touch level 516 Program sequence 1
The USB mode will be set to: 0x6
Commit? (y/n) [n]: y



Enable Yubikey Touch Feature


This setting causes the Yubikey to flash when a signature is requested and only sign the message once the user touches the Yubikey.


Because we haven’t set up any custom PINs yet, the default Yubikey PIN (123456) and admin PIN(12345678) still work. 

$ brew install ykman
$ ykman openpgp touch sig on
Current touch policy of AUTHENTICATE key is OFF.
Set touch policy of AUTHENTICATE key to ON? [y/N]: y
Enter admin PIN: 12345678
Touch policy successfully set.


Install GPG tools and Create GPG Key


Install GPG tools (and install Brew if you don’t have it already).

$ brew cask install gpg-suite

Use gpg2 to configure your Yubikey “card” for a 4096 bit RSA key.

$ gpg2 --card-edit
Reader ...........: Yubico Yubikey 4 OTP U2F CCID
Application ID ...: E1881231250102010005075345670000
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 09421669
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
gpg/card> admin
Admin commands are allowed
gpg/card> key-attr
Changing card key attribute for: Signature key
Please select what kind of key you want:
(1) RSA
(2) ECC
Your selection? 1
What keysize do you want? (2048) 4096
The card will now be re-configured to generate a key of 4096 bits
Changing card key attribute for: Encryption key
Please select what kind of key you want:
(1) RSA
(2) ECC
Your selection? 1
What keysize do you want? (2048) 4096
The card will now be re-configured to generate a key of 4096 bits
Changing card key attribute for: Authentication key
Please select what kind of key you want:
(1) RSA
(2) ECC
Your selection? 1
What keysize do you want? (2048) 4096

Generate the new RSA private and public key on the Yubikey (do not store the key locally). Note that the email address you will provide below in the next command must match your Github account email address if you configure Github to accept only verified git commits.

This command takes a long time (several minutes) to generate keys.

$ gpg2 --card-edit
Reader ...........: Yubico Yubikey 4 OTP U2F CCID
Application ID ...: E1881231250102010005075345670000
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 09421669
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: rsa4096 rsa4096 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
gpg/card> admin
Admin commands are allowed
gpg/card> generate
Make off-card backup of encryption key? (Y/n) n
Please note that the factory settings of the PINs are
PIN = '123456'     Admin PIN = '12345678'
You should change them using the command --change-pin
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)
Key does not expire at all
Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.
Real name: Chris Walker
Email address: <email address for github account>
Comment: tokensoft
You selected this USER-ID:
"Chris Walker (tokensoft) <email address for github account>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O

The Yubikey device lights should flicker while the keys are being generated.


Change Card PINs


The Yubikey PIN and Admin PIN should be changed from their factory defaults: make sure to save these PINs safely.


The PIN must be 6 digits and the Admin PIN must be 8 digits: this command will fail without a helpful error message if the PINs are not the correct length.

$ gpg2 --card-edit 
gpg/card> admin
Admin commands are allowed
gpg/card> passwd
gpg: OpenPGP card no. E1881231250102010005075345670000 detected
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
Your selection? 1
(enter the default PIN 123456)
(enter the new pin)
PIN changed.
Your selection? 3
(enter the default Admin PIN 12345678)
(enter the new Admin PIN)
PIN changed.
Your selection? q
gpg/card> q



Back It Up and Do It Again


That’s right! You weren’t planning on using a single Yubikey, were you?

Securing crypto assets and software supply chains both require forethought and personal responsibility. Losing a single Yubikey must not shut down your software development process, so repeat the entire process above for two or more Yubikeys.


Get RSA Key IDs


Next, we need to list all keys held on Yubikey devices so that we can tell git to use the correct key for signing commits.

$ gpg2 --list-public-keys --keyid-format LONG
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
gpg: next trustdb check due at 2021-04-01
/Users/cw/.gnupg/pubring.kbx
----------------------------
pub   dsa2048/76D78F4567D026C4 2010-08-19 [SC] [expires: 2020-06-15]
      85E38F69046B44C1FBFBFB07B76D78F4567D026C4
uid                 [ unknown] GPGTools Team <team@gpgtools.org>
sub   elg2048/07EFF49ADBCBE671 2010-08-19 [E] [expires: 2020-06-15]
sub   rsa4096/E8A678480D9E43F5 2014-04-08 [S] [expires: 2024-01-02]
pub   rsa2048/5F5F11700099D0E6 2019-04-02 [SC] [expires: 2021-04-01]
      289FDB94C4BAFD1F9BE5555C5F5F11700099D0E6
uid                 [ultimate] chris <email address>
sub   rsa2048/2EF25E8DF1C5F49D 2019-04-02 [E] [expires: 2021-04-01]
pub   rsa4096/8614429225103F77 2019-04-02 [SC]@
      5ECB4A51E85D1695CD3A714D8614429225103F77
uid                 [ultimate] Chris Walker (tokensoft) <email address>
sub   rsa2048/37CFFB1842DCC41E 2019-04-02 [A]
sub   rsa4096/A2A37EF4F95B689D 2019-04-02 [E]
pub   rsa4096/4012AA0013C6724A 2019-04-02 [SC]
      C5F64E5B7494A0A5233D83E74012AA0013C6724A
uid                 [ultimate] Chris Walker (tokensoft) <email address>
sub   rsa4096/78A3D72DB3F8F0F0 2019-04-02 [A]
sub   rsa4096/1D5F782EBBF2EF81 2019-04-02 [E]

Find the key IDs for the keys with these characteristics:

  • RSA 4096 used for public key

  • The key is used for signatures / certs (SC)

  • The key was generated today

  • UID matches the description you provided when generating the key.


In this case, my public keys from two Yubikeys are 8614429225103F77 and 4012AA0013C6724A.



Connecting Git to Yubikey


Tell git to use the key ID from the Yubikey, automatically sign each git commit, and use the gpg2 program for signing. Unfortunately, I don’t know of a way to configure git to accept multiple signing keys, so this configuration must be updated if you switch between the Yubikeys that were set up earlier.

$ git config --global user.signingkey 8614429225103F77 
$ git config --global commit.gpgsign true
$ git config --global gpg.program gpg2

Your git config should now look something like this.

$ cat ~/.gitconfig
[user]
      email = <an email>
      name = Chris Walker
      signingkey = 8614429225103F77
[core]
      editor = nano
[gpg]
      program = gpg2
[commit]
      gpgsign = true


Verifying Functionality


Make some changes to a git repo and then try to commit them, e.g.

$ git commit -am 'testing gpg'

If you haven’t already entered the PIN recently to unlock the Yubikey, a modal dialog should pop up asking you to enter the PIN.

Once this is done, the Yubikey will flash. Press the Yubikey button to sign the commit. Because it’s easy to forget the signing step and wonder why the git commit is hanging, I added a precommit hook to notify the user that their signature is required after passing typical linting and tests.

$ git commit -am 'testing yubikey'
husky > npm run -s precommit (node v10.20.1)
lerna info version 2.16.0
lerna success run Ran npm script 'precommit' in packages:
lerna success - foo
lerna success - bar
WAITING FOR GIT SIGNATURE
[e372dfc9] testing yubikey
1 file changed, 2 insertions(+), 1 deletion(-)

The git log command can check the RSA signatures on git commits for validity.


$ git log --show-signature
commit 5d954a6371a63003756591a6c7f07a80efd497ea (HEAD -> master)
gpg: Signature made Tue Apr  2 12:42:53 2019 PDT
gpg:                using RSA key 6ACB4A51E85D1695CD3A714D8614429225103F77
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   2  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 2u
gpg: next trustdb check due at 2021-04-01
gpg: Good signature from "Chris Walker (tokensoft) <email address>" [ultimate]
Author: Chris Walker <email address>
Date:   Tue Apr 2 12:42:53 2019 -0700
...


Configuring Your Personal Github Account


Export the correct public key from each configured Yubikey.

gpg2 --armor --export 4012AA0013C6724A
-----BEGIN PGP PUBLIC KEY BLOCK-----
mRQ3KLdsT...
...
...
...
...
=eFKq
-----END PGP PUBLIC KEY BLOCK-----

Navigate to your settings: Github → Settings → SSH and GPG Keys


Click the “New GPG Key” button


Paste the exported public key. After setting up both keys the GPG key section should look like the image below.

Configuring Your Project Github Account


To lock down your software supply chain further, configure protected branches to require verified commits.


It Works!


This process may be complex, but the assurance it provides to your software team is worthwhile, especially in the cryptocurrency industry where clients depend on your software to secure their business and finances.


Fixes (You Will Mess This Up)


During this process, I misconfigured or locked myself out of Yubikeys several times.


Resetting Yubikey Applet


If you enter the incorrect PIN or admin PIN too many times the Yubikey locks you out. This is easy to fix but you will lose all saved keys.


Install the Yubikey manager.


$ brew install ykman

Reset the applet.


$ ykman openpgp reset
WARNING! This will delete all stored OpenPGP keys and data and restore factory settings? [y/N]: y
Resetting OpenPGP data, don't remove your YubiKey...
Success! All data has been cleared and default PINs are set.
PIN:         123456
Reset code:  NOT SET
Admin PIN:   12345678

After resetting the applet you will need to go through this setup process again.



Deleting unused GPG keys


During the setup process, you may create incorrectly configured keys. These can be deleted from your gpg key ring by first deleting the secret key and then the public key as follows (do ensure the key being deleted is not necessary).

$ gpg2 --delete-secret-keys 5F5F11700099D0E6
gpg (GnuPG/MacGPG2) 2.2.10; Copyright (C) 2018 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.
sec  rsa2048/5F5F1170009D0E6 2019-04-02 chris <email>
Delete this key from the keyring? (y/N) y
This is a secret key! - really delete? (y/N) y
$  gpg2 --delete-key 5F5F11700099D0E6
gpg (GnuPG/MacGPG2) 2.2.10; Copyright (C) 2018 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.
pub  rsa2048/5F5F11700099D0E6 2019-04-02 chris <email>
Delete this key from the keyring? (y/N) y


Further References


The first article below describes the minimum viable security practices. If you haven’t read this article yet and aren’t sure if you are following good practices, stop what you are doing, read the article, and implement everything on it right now.


Minimum Viable Security

The least you can do to frustrate would-be hackers.

The following articles were helpful source material for figuring out how to set up these Yubikeys.


  • medium
  • White Twitter Icon
  • White LinkedIn Icon

Join our mailing list

THIS WEBSITE IS OWNED AND OPERATED BY TOKENSOFT, INC. (“TOKENSOFT”), A TECHNOLOGY COMPANY PROVIDING COMPLIANCE AND BLOCKCHAIN-BASED SERVICES FOR ISSUERS OF SECURITIES OR OTHER DIGITAL ASSETS.  TOKENSOFT IS NOT A BROKER-DEALER, INVESTMENT ADVISER, OR FINANCIAL ADVISOR.  TOKENSOFT IS NOT REGISTERED WITH THE U.S. SECURITIES & EXCHANGE COMMISSION (SEC) NOR ANY OTHER REGULATORY AGENCY OR BODY IN THE UNITED STATES OR INTERNATIONALLY.  TOKENSOFT DOES NOT GIVE INVESTMENT OR LEGAL ADVICE, ENDORSEMENTS, ANALYSIS, OR RECOMMENDATIONS WITH RESPECT TO ANY SECURITIES OR OTHER DIGITAL ASSETS. NOTHING ON THIS WEBSITE SHALL CONSTITUTE OR BE CONSTRUED AS AN OFFERING OF SECURITIES OR AS INVESTMENT ADVICE OR INVESTMENT RECOMMENDATIONS BY TOKENSOFT OR ANY OF ITS AFFILIATES OR A RECOMMENDATION AS TO AN INVESTMENT. ALL THIRD PARTY SECURITIES OFFERINGS AND DIGITAL ASSETS POWERED BY TOKENSOFT’S TECHNOLOGY ARE OFFERED BY, AND ALL INFORMATION RELATED THERETO IS THE RESPONSIBILITY OF, THE APPLICABLE ISSUER OF SUCH SECURITIES OR DIGITAL ASSETS. TOKENSOFT DOES NOT CUSTODY ANY DIGITAL SECURITIES OR DIGITAL ASSETS ON BEHALF OF ANY OF ITS CUSTOMERS OR USERS OF OUR WEBSITE SERVICES.


For information relating to Tokensoft Global Markets, our affiliate broker-dealer, please visit https://www.tokensoftmarkets.com.