GitHub has announced that they'll start marking commits and tags signed with GPG (GnuGP) signatures with a
Verified tag. Excited about the thought of verifying my identity as to adds and updates, I went straightforward to set this up!
Note: a Mac binary (DMG) exists for setting up a suite of GnuGP tools:
GPGTools
Also, a Mac binary exists for the "modern" version (meaning the up and coming, not yet stable version):
GnuGP for OSX
I recommend one of these if you want a quick, easy setup on your Mac. However, I have to do things the hard way (mocking grin here ;)
Seriously,
- I only wanted the encryption/signing capability, as opposed to the whole email thing (GPGTools), and
- the GPGTools site was last updated in November of 2015 and indicated their El Capitan version was still in beta, while the GnuGP for OSX was the newest, not-"stable" version, and
- REALLY, I like to learn new things and understand how the underpinnings work. This was a chance for me to try "make"ing something from source on my Mac beyond simple C programs. I've generally used various tools that handle that stuff under the hood, so I thought this should be interesting.
Following the instructions
here, then, I began the install process.
Long story short, including lessons learned:
- Download the following from the GnuPG Download page:
- GnuPG stable
- Libgpg-error
- Libgcrypt
- Libksba
- Libassuan
- Pinentry
- Download Gnu Portable Threads (Gnu pth). (Note: there may be newer versions of this or alternate configurations. I used v2.0.7 as linked on the page.)
- Verify each package's authenticity (please, no discussions of trust here! It is what it is.)
- For Mac, use 'openssl sha1' to verify that the signatures match.
- Text signatures for the GnuPG-listed packages are on at: GnuPG Integrity Check.
- Gnu pth provides a .sig file for verification. To use this, you must already have a prior version of GnuPG installed. Alternatively, I found a matching SHA1 hash at the Free Software Foundation's membercard page for pth-2.0.7-14: 9a71915c89ff2414de69fe104ae1016d513afeee
- Uncompress all of the packages.
- Saving GnuPG itself for last, run these commands in Terminal from each package's own folder:
- ./configure
- make
- sudo make install
Following these steps, the error you're most likely to find on a Mac has to do with unknown type names (intmax_t and uintmax_t). This error and the fix I chose, for right or wrong, is described in the long story below.
Once installed, follow the steps at
GitHub Help for GPG to set up your account to use verification.
Setting up for GitHub, I discovered a few more things to note:
- If you're using a private email for GitHub, set up your GPG key with that email, not your "real" one.
- If your GPG installation uses the 'gpg2' command instead of just 'gpg', see the fix described in Edit 1, below.
- If your 'pinentry-agent' gives you grief about an 'inappropriate ioctrl', see the fix in Edit 2, below.
The long story:
I started by downloading GnuPG stable and verifying its authenticity:
- run the following command in Terminal to verify the signature:
openssl sha1 path/to/downloaded/file
- then compare the text signature from the
GnuPG Integrity Check page with the result.
I then double-clicked the compressed file to break out the enclosed folder,
In Terminal, I cd'd (is that a word?) to the folder (gnupg-2.0.30 in my case) and typed the command ./configure (note: this is dot slash configure). The end output was a list of four dependencies I needed to install: libgpg-error, libgcrypt, libassuan, and gnu-pth.
Starting with Gnu Portable Threads (pth) (the messages said to install that one first!), I followed these steps for each dependency:
- Download the compressed file
- Locate and match a text version of the appropriate signature (using openssl as above)
- Uncompress the file (double-click in Finder)
- cd to the resulting folder, and
- run the following commands:
- ./configure
- make
- sudo make install
Note: no dependencies for 'libkbsa' or 'pinentry' showed up on the original ./configure list. However, I recommend you install those here as well in order to avoid pain later on ;)
Everything went smoothly, until I was ready to continue with GPG. I ran './configure' again, which appeared to complete with no problems. When I ran 'make', though... a bunch of errors came up having to do with 'intmax_t' and 'uintmax_t'.
intmax_t/uintmax_t errors:
The error messages looked like this, with a few pointing to 'uintmax_t' as well:
/usr/include/inttypes.h:235:8: error: unknown type name 'intmax_t'
extern intmax_t
^
So, I went a'hunting. I found several resources which helped me locate and fix the problem, enabling me to complete the installation.
If you've worked with C, Objective-C, or C++, you know that you have to "include" header files for various reasons. Of course, you don't want to duplicate header file inclusions - and, you don't generally need to do so. Once you have included a header in one file, if you include that file in another file, the original header comes along for the ride.
Well, the problem here is that GnuPG has files designed to work on multiple systems, without knowing exactly what those systems will look like. And, apparently, the GnuPG developers generally work with Linux - not Mac. So, they do their best to code stuff that'll work on the Mac, but... well, there's reason they point you to the Mac-related GPG sites listed at the beginning of this article.
Getting to the point, a Mac with Xcode installed has two 'stdint.h' files and two 'inttypes.h' files. To further the complication, GnuPG has some 'stdint.h' files of its own.
Xcode's package contents contain a 'stdint.h' file. This file uses a typedef statement to define the constants 'intmax_t' and 'uintmax_t'.
Xcode's package contents also contain an 'inttypes.h' file. This file has no reference to either 'stdint.h' or 'intmax_t'/'uintmax_t'. However, it does have a reference to another 'inttypes.h' file, via a #include_next statement.
Now, #include_next means that the next file of the specified name found in the header search path should be included. Yike! Who knows where that could be (from strictly a file perspective, anyway) if someone might've changed up the search path?! Wow!
In this case, it appears that the next 'inttypes.h' file is in the /usr/include/ directory. At least, that's the file that's giving us those "unknown type name" errors.
The weird thing is that the /usr/include/inttypes.h file does #include a 'stdint.h' header. Theoretically, that header should contain the 'intmax_t' and 'uintmax_t' definitions.
We know that Xcode's package contents version has a typedef statement to handle that, so I checked the /usr/include/stdint.h: it has a #include <_types/_intmax_t> statement, as well as a corresponding statement for 'uintmax_t'. So, that 'stdint.h' should work, too. However, the /usr/include/inttypes.h file doesn't seem to be using either of those 'stdint.h' files. So, what 'stdint.h' is actually getting included?
It turns out that GnuPG has a 'stdint.h' file in the 'gl' directory that is causing - or related to, anyway - the problem. To fix the issue, locate that gl/stdint.h file under your GnuPG stable's folder.
Open the gl/stdint.h file in an editor (I suggest making a backup copy first, of course!), and look for this line:
# include "///Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/7.3.0/include/stdint.h"
Remark out that line (put /* */ type comment marks around it) or delete it, and replace it with:
# include "///usr/include/stdint.h"
Now, try your 'make' command again. This time, assuming no missing files (such as libkbsa or pinentry), everything should work!
Continue with the 'sudo make install' command, and
you should be ready to go!
Note: most of the GnuPG documentation uses the command as 'gpg'. For the version I used (2.0.7), the command is actually 'gpg2'. In this case, you may need to make various tweaks to get the GPG to run correctly with whatever application you're using. I'll leave that research up to you.
Enjoy your new certificate/key signing capabilities!
Edit 1:
When I tried to use my GnuPG (v2.0.7) with Git, I found Git didn't like the 'gpg2' command. Per a
Stack Overflow answer provided by Jens Erat, I was able to use the following command to fix this issue:
git config --global gpg.program gpg2
Edit 2:
When I tried to perform a secure commit in Git, I got an error from the
gpg-agent:
inappropriate ioctl for device. Pinentry needs access to the Terminal window in order to allow you to enter the passphrase for your commit key. This error means that pinentry can't access the Terminal window correctly.
To fix this, create a .bash_profile file under your user's home (~) folder. (Note that the filename starts with a dot.) Add two lines to this file:
export GPG_TTY=$(tty)
export PINENTRY_USER_DATA="USE_CURSES=1"
Save the file, then restart your Terminal session.
To check if the change is in effect, run the 'set' command at the Terminal prompt. In the list of environment variables this command returns, look for entries for GPG_TTY and PINENTRY_USER_DATA. Ensure their values appear correct: the 'tty' value from the profile will be replaced by a default Mac value, while the pinentry value will show as expected.
Now, you'll be prompted for the passphrase so your commit will be signed properly.
Again, I am using OS X 10.11 El Capitan. This, or some similar setup, may work in other versions of OS X and on Linux, based on my research, but tread on at your own risk. Also, I'm using the default Bash shell.