Recently I finally got around to reading the excellent OpenSSL Cookbook from Ivan Risti? – you can grab a free copy via https://www.openssl.org/docs/ – and the first question in my mind was “what version of OpenSSL is already installed on my Mac”. A quick check showed it’s there pre-built in HighSierra in /usr/bin
:
[code lang=text] $ /usr/bin/openssl version LibreSSL 2.2.7 [/code]
Hmm. Wikipedia tells me that this is a (somewhat controversial) OpenBSD fork from around April 2014, so not necessarily in synch with the “official” OpenSSL code.
I elected to download and build from the OpenSSL code instead, partly so that it would be easier for me to keep it updated. The instructions for obtaining and building it are quite clear, although you have a clear choice to make – pull the code from GitHub, or download it as a tarball. I opted for the latter. The build assumes you have XCode and all the other bits and pieces installed, but then again you would be unlikely to be doing this if you didn’t. The build went just as it said on the box:
[code lang=text] ./Configure darwin64-x86_64-cc shared enable-ec_nistp_64_gcc_128 no-ssl3 no-comp --openssldir=/usr/local/ssl make depend sudo make install [/code]
after which we can verify success:
[code lang=text] $ openssl version -a OpenSSL 1.1.0h 27 Mar 2018 built on: reproducible build, date unspecified platform: darwin64-x86_64-cc options: bn(64,64) rc4(16x,int) des(int) idea(int) blowfish(ptr) compiler: cc -DDSO_DLFCN -DHAVE_DLFCN_H -DNDEBUG -DOPENSSL_THREADS -DOPENSSL_NO_STATIC_ENGINE -DOPENSSL_PIC -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DRC4_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DPADLOCK_ASM -DPOLY1305_ASM -DOPENSSLDIR="\"/usr/local/ssl\"" -DENGINESDIR="\"/usr/local/lib/engines-1.1\"" OPENSSLDIR: "/usr/local/ssl" ENGINESDIR: "/usr/local/lib/engines-1.1" [/code]
“But wait!” you say, “haven’t we just overwritten the LibreSSL installation”.
Fortunately not – unless we tell it otherwise, the build drops the binaries in /usr/local/bin
rather than /usr/bin
where the MacOS original install is. As long as your $PATH
specifies /usr/local/bin
before /usr/bin
you will get the expected one:
[code lang=text] $ openssl version OpenSSL 1.1.0h 27 Mar 2018 $ /usr/bin/openssl version LibreSSL 2.2.7 [/code]
There’s one more thing that you should do for convenience. The SSL directory created contains an empty folder /usr/local/ssl/certs
– the intention is that well known trusted root certificates can be placed there, which is a slightly opaque task.
What I did was grab the set of root certificates maintained by Mozilla:
https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt
but that then needs to be converted from the format they use to a standard PEM format. There’s a number of projects to help with this, the one I selected was from agl/extract-nss-root-certs. The only pre-requisite was to install Go, then the tool Just Worked and I dropped the resulting PEM in /usr/local/ssl/certs
If you’re not familiar with OpenSSL, it’s worth having a look at. It’s an absolute Swiss-Army-Chainsaw of a tool, able to do do everything from generating keys to checking site security to running as a server – Ristić’s book covers all of the usual things you might want to do, and some unusal ones, and helps demystify what is generally well thought of as a user interface from hell.
An example of what you can do? Well, here’s creation of a self-signed certificate:
[code lang=text] # build RSA private key openssl genrsa -aes256 -out fd.key 2048 openssl rsa -text -in fd.key -noout # extract public key openssl rsa -in fd.key -pubout -out fd-public.key # create CSR with prebuilt config file openssl req -new -config fd.cnf -key fd.key -out fd.csr openssl req -text -in fd.csr -noout # create self-signed certificate openssl x509 -req -days 365 -in fd.csr -signkey fd.key -out fd.crt -extfile fd.ext openssl x509 -text -in fd.crt -noout [/code]
the fd.cnf
was:
[code lang=text] [req] prompt = no distinguished_name = dn req_extensions = ext input_passphrase = letmein [dn] CN = example.net emailAddress = admin@example.net O = Example Co L = London C = GB [/code]
and fd.ext
was
[code lang=text] subjectAltName = DNS:example.net;DNS:*.example.net [/code]
Addendum
The talented John Slee points to some background on the LibreSSL fork that is worth having a look at:
The OpenBSD folks have maintained OpenSSL 1.0.x API compatibility and AFAIK are currently working on 1.1.x APIs too. They have also created their own TLS API that is much, much more resistant to incorrect/insecure use, named “libtls”. The changes they made vs. where OpenSSL was at the time of the fork are worth a look, I think — an object lesson in secure C coding
See:
– https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.7.2-relnotes.txt
– https://man.openbsd.org/tls_init.3