If you're running your own server, you're probably not shelling out $400 to get an “official” Certificate Authority (CA) to sign your key. Here's a quick note to myself about how to create, sign, and install your own CA and key. Depending on your application, you can use either the GnuTLS or OpenSSL toolchain.
GnuTLS
Following the GnuTLS manual, create a certificate
authority with certtool, adjusting the cn
as you see fit:
$ certtool --generate-privkey > x509-ca-key.pem
$ echo 'cn = GnuTLS test CA' > ca.tmpl
$ echo 'ca' >> ca.tmpl
$ echo 'cert_signing_key' >> ca.tmpl
$ certtool --generate-self-signed --load-privkey x509-ca-key.pem \
--template ca.tmpl --outfile x509-ca.pem
Now generate the unencrypted server key.
$ certtool --generate-privkey > x509-server-key.pem
And sign the key with your CA, adjusting the cn
as you see fit, and
changing dns_name
to match your fully qualified host name.
$ echo 'organization = GnuTLS test server' > server.tmpl
$ echo 'cn = test.gnutls.org' >> server.tmpl
$ echo 'tls_www_server' >> server.tmpl
$ echo 'encryption_key' >> server.tmpl
$ echo 'signing_key' >> server.tmpl
$ echo 'dns_name = test.gnutls.org' >> server.tmpl
$ certtool --generate-certificate --load-privkey x509-server-key.pem \
--load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem \
--template server.tmpl --outfile x509-server.pem
You can also print certificates with certtool.
$ certtool --infile x509-server.pem --certificate-info
You can add alternate hostnames using subject alternative
names. Just add more dns_name
entries to your template:
$ echo 'dns_name = other.gnutls.org' >> server.tmpl
$ certtool --generate-certificate …
You can verify a certificate if you can supply the whole certificate chain.
$ certtool --verify-chain --infile x509-server.pem --infile x509-ca.pem
With versions of GnuTLS since 2.99.0 (released 2011-04-09), you can verify against the global list of trusted CAs.
$ certtool --verify --load-ca-certificate /etc/ssl/certs/ca-certificates.crt --infile x509-server.pem
OpenSSL
Use openssl's genpkey to generate an unencrypted key.
$ openssl genpkey -algorithm RSA -out key.pem
An unencrypted key is less secure, but it allows the web server to be
restarted (e.g. after rebooting) without you being there to enter the
decryption key. Make sure key.pem
is only readable by root
.
Use req to generate certificate signing request.
$ openssl req -new -key key.pem -out req.pem
-new
prompts you for new relevant field values. You can also
specify the values on the command line or in an configuration file
(override the default with -config filename
).
Use x509 to sign the certificate.
$ openssl x509 -req -days 365 -in req.pem -signkey key.pem -out cert.pem
You should keep your certificate signing request around so you can re-sign your key later on (since your initial signature will eventually expire).
You can add subject alternative names to the request using
the openssl.cnf
config file:
$ cp /etc/ssl/openssl.cnf openssl.cnf
$ emacs openssl.cnf
$ cat openssl.cnf
…
[ req ]
…
req_extensions = v3_req
…
[ v3_req ]
…
subjectAltName = DNS:test.gnutls.org,DNS:other.gnutls.org
…
$ openssl req -new -config openssl.cnf -key key.pem -out req.pem
You can also print certificates with x509.
$ openssl x509 -in cert.pem -noout -text
You can verify a certificate if you can supply the whole certificate chain with verify.
$ openssl verify cert.pem
PEM
We've been throwing around a lot of files with a .pem extension.
These files contain Base64 encoded DER certificates enclosed
between -----BEGIN CERTIFICATE-----
and -----END CERTIFICATE-----
.
The .crt
files requested by update-ca-certificates
(discussed
below) are generally binary DER files, but can also be base64 encoded.
Downloading certificates
You can download certificates from remote servers using OpenSSL's simple client:
$ openssl s_client -showcerts -connect host:port
The PEM certificates will be printed to your terminal.
System wide certificates
The situation is confusing because there is currently no standardized way to track trusted certificates. Here are some things to keep in mind:
ca-certificates
Gentoo uses Debian's ca-certificates package to manage
trusted CAs. The certificates are stored under /etc/ssl/certs
in
three forms:
- As a
<filename>.pem
symlink to the external certificate (if it was already base64 encoded) or an encoded version (if the external certificate is binary). - As a symlink to 1 named with the certificate's hashed subject name, key identifier (if present), and serial number.
- As an entry in
ca-certificates.crt
, which is a concatenated list of all the trusted certificates.
You can update these system certificates using
update-ca-certificates
, from the the ca-certificates
package:
# update-ca-certificates
On Fedora-based systems, update-ca-certificates
also updates the
system NSS storage at /etc/pki/nssdb
(more on NSS in a
second).
update-ca-certificates
looks in a number of places to find trusted
CAs. To add a new CA, place the certificate in
/usr/local/share/ca-certificates/
as a single file ending in .crt
and run update-ca-certificates
.
GnuTLS
In GnuTLS, you set the list of trusted CAs using
gnutls_certificate_set_x509_trust_file. By convention this
function is pointed to the /etc/ssl/certs/ca-certificates.crt
file
mentioned above.
OpenSSL
OpenSSL loads trusted CAs with SSL_CTX_load_verify_locations,
which loads certificates from a file (like
gnutls_certificate_set_x509_trust_file
) or from a directory (usually
/etc/ssl/certs/
). For efficiency, many applications prefer the
directory approach, as certificates can then be loaded on an as-needed
basis using their hashed subject name, key identifier (if present),
and serial number. If you place a new CA this directoy, you'll want
to run c_rehash
to generate the hashed symlinks:
# c_rehash /etc/ssl/certs
OpenSSL doesn't currently provide a man page for c_rehash
, but
there's one attached to Debian bug 215618.
update-ca-certificates
(mentioned above) uses c_rehash
internally
to generate hashed symlinks for OpenSSL.
NSS
NSS is the crypto library used by Firefox and Chromium
that doesn't use the /etc/ssl/certs
framework discussed above. It
looks in a number of places depending on the package
type, but the system-wide sql:/etc/pki/nssdb
. User applications
will also look in sql:~/.pki/nssdb
. You manage the databases with
certutil. You can install certutil
on Gentoo by emerging
dev-libs/nss
with the utils
USE
flag enabled. Add your
certificate with something like:
$ certutil -A -n jdoe -t "C,," -d "sql:${HOME}/.pki/nssdb" -i /etc/ssl/certs/cacert.org.pem
This adds a certicate (-A
) to the sql:${HOME}/.pki/nssdb
database
(-d
). The certificate is named jdoe
(-n
), and you can use this
name to manage the certificate later (e.g. to delete it). -t "C,,"
sets SSL trust to C
, but does not grant email or object signing
trust. C
means you trust this certificate to issue SSL server
certificates (but not client certificates, which would be T
), and
that you don't trust it for direct SSL authentication or email signing
(which would be u
).
Unfortunately, many applications using NSS have a compiled-in list of trusted CAs, so you don't have complete control from a sysadmin perspective unless you tweak that file at compile time.