The main TLS toolkit for Fedora comprises GnuTLS, OpenSSL, and Network Security Services (NSS).
For GnuTLS, the main end-user command is certtool. Package gnutls-utils provides this along with a few other utilities:
=> rpm --query --list gnutls-utils | grep bin /usr/bin/certtool /usr/bin/danetool /usr/bin/gnutls-cli /usr/bin/gnutls-cli-debug /usr/bin/gnutls-serv /usr/bin/ocsptool /usr/bin/p11tool /usr/bin/psktool /usr/bin/srptool /usr/bin/tpmtool
Command gnutls-cli and p11tool are handy from time-to-time, too. There is a dedicated man page for each of these.
For OpenSSL, the end-user command is openssl (synonymous package). This is a container command that hands off the real work to sub-commands, like genpkey, verify, etc. There is a dedicated man page for each of these.
OpenJDK (package java-1.8.0-openjdk-headless) provides keytool for managing keys and certificates. These notes do not use keytool, however.
You can download a server's certificate or certificate chain if you have a notion to have a look.
Here's how to retrieve this website's certificate into file acert.pem, for example:
-> gnutls-cli --save-cert=acert.pem raysnotebook.info Processed 154 CA certificate(s). Resolving 'raysnotebook.info:443'... ⋮ - Simple Client Mode: Type ^D to exit. DONE
By default, gnutls-cli connects on port 443 for HTTPS, but you can use option --port to fetch a certificate for a different service, such as port 465 for SMTPS or port 585 for IMAPS. You'll need to specify STARTTLS for SMTP on port 587 or IMAP on port 993; for example:
-> gnutls-cli --save-cert acert.pem --port 587 --starttls-proto smtp smtp.gmail.com ⋮
This command grabs the certificate chain—signers' certificates in addition to the server's certificate:
-> grep "BEGIN CERTIFICATE" acert.pem | wc --lines 3
The s_client command of OpenSSL returns the server's certificate to stdout. For example:
-> openssl s_client -connect raysnotebook.info:443 CONNECTED(00000003) ⋮ -----BEGIN CERTIFICATE----- base64-encoded certificate data -----END CERTIFICATE----- ⋮
(Note that you must append the port to the hostname.) Just copy this PEM block and paste it into a file. By default, s_client shows only the server's certificate. You can add option -showcerts to see the signers' certificates, too.
You'll need to coach s_client on STARTTLS, too:
-> openssl s_client -connect smtp.gmail.com:587 -starttls smtp ⋮
The s_client man page lists additional protocols offered.
If you want to retrieve a self-signed certificate from, say, your development rig on localhost, tell gnutls-cli not to worry about verification:
-> gnutls-cli --save-cert acert.pem --no-ca-verification --insecure --port 465 localhost ⋮
But s_client has no such qualms about ignoring failed verification; proceed with due caution. (Its man page suggests option -verify_return_error, but this does not seem to do the trick.)
Your web browser may offer to export a website's certificate with a few clicks. In Firefox, for example: From themenu, select . From the page-info window that opens, select the tab and then the subsequent button. In the certificate-viewer window that opens, select the tab and then the subsequent button. The file picker that opens gives you several choices for the content and format to export, in lower right-hand corner.
You can easily view a certificate in a file, say acert.pem, to see what's inside:
-> certtool --infile acert.pem --certificate-info ⋮ -> openssl x509 -in acert.pem -text -noout ⋮
This reports the X.509 certificate information: the version of X.509 in use; the certificate's serial number and validity dates; the subject's identification and public key; the issuer's identification and signature; the algorithms used for the public key and the signature; and any v3 extensions. Other information may be added. For example, certtool shows the certificate's fingerprints and the public key's ID and random art. openssl displays the PEM block (unless you suppress that with option --noout).
OpenSSL's x509 command lets you pick what components you'd like to see; for example:
-> openssl x509 -in acert.pem -noout -subject -issuer -serial -fingerprint subject=C = US, ST = California, L = Mountain View, O = Google Inc, CN = smtp.gmail.com issuer=C = US, O = Google Trust Services, CN = Google Internet Authority G3 serial=6362472E5418FE13 SHA1 Fingerprint=87:F4:C9:7A:D1:A4:C0:54:6A:24:D6:7A:A6:E9:4C:D1:25:A1:1C:36
See section Display Options of the X509 man page for the full list.
Viewing options under certtool are limited: --fingerprint, --key-id, --pubkey-info, --certificate-pubkey. For example:
-> certtool --infile acert.pem --fingerprint 87f4c97ad1a4c0546a24d67aa6e94cd125a11c36
You can use only one such option at a time.
certtool kindly reads all certificates in a bundle, but openssl stops after the first:
-> certtool --certificate-info --infile pem/tls-ca-bundle.pem | grep Issuer: | wc --lines 138 -> openssl x509 -in pem/tls-ca-bundle.pem -issuer -noout | wc --lines 1
But certtool can't interpret OpenSSL's "TRUSTED CERTIFICATE" blocks:
-> certtool --certificate-info --infile openssl/ca-bundle.trust.crt import error: No certificate was found.
A PEM file (.pem) takes an X509 certificate's binary data stream, encodes that into base64 (ASCII armor), and sandwiches the result between a header and footer:
-> cat acert.pem -----BEGIN CERTIFICATE----- text/base64 rendition of certificate's binary data stream goes here -----END CERTIFICATE-----
The delimiters allow two conveniences. The program generating the certificate may include a readable version of the data stream outside of the delimiters; certtool does this. And multiple PEM blocks may be concatenated into a single file, called a certificate bundle. You can view a PEM block with any text editor or browser, but it's ASCII noise between delimiters.
By origin, "PEM" refers to "Privacy-enhanced Electronic Mail", which was an IETF proposal that failed to launch. In practice, "PEM" simply indicates this format for incorporating keys and certificates in text files.
Under the hood, X.509 uses Abstract Syntax Notation One, or ASN.1, to structure a certificate's public key and metadata. It then encodes this ASN.1 representation into a binary data stream according to Distinguished Encoding Rules, or DER, to facilitate data exchange. A PEM block subsequently encodes the latter stream into a base64 stream in deference to applications that can't handle binary data.
You can see what ASN.1 looks like:
-> openssl asn1parse -in acert.pm 0:d=0 hl=4 l=1458 cons: SEQUENCE 4:d=1 hl=4 l=1178 cons: SEQUENCE 8:d=2 hl=2 l= 3 cons: cont [ 0 ] 10:d=3 hl=2 l= 1 prim: INTEGER :02 13:d=2 hl=2 l= 17 prim: INTEGER :D33C081C650F6C4EC4EB3C3B59A6CA43 ⋮ 1188:d=2 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption 1199:d=2 hl=2 l= 0 prim: NULL 1201:d=1 hl=4 l= 257 prim: BIT STRING
See man page asn1parse for more examples and options. It notes: "Some knowledge of the ASN.1 structure is needed to interpret the output."
Going just a little deeper: DER is a restricted variant of Basic Encoding Rules, or BER. DER removes some of the flexibility that BER supports in order to gain specificity required for cryptography. The X.509 standard for rendering abstract information from ASN.1 into a concrete data stream for transfer comprises encoding formats BER, DER, and a third variant CER (Canononical Encoding Rules).
A certificate's fingerprint is a digest of its DER data stream. Conceptually, start with the PEM block, remove its envelope, and decode the remaining, base64 innards. What you get is the DER stream. This is the idea:
-> grep -v -P "\-----(BEGIN|END) CERTIFICATE-----" acert.pem | base64 --decode > acert.der
But just delegate this chore to openssl:
-> openssl x509 -in acert.pem -outform der -out acert.der
Now compute a digest of acert.der explicitly and compare the result to what openssl reports. With SHA1, for example:
-> sha1sum --tag acert.der SHA1 (acert.der) = 9dd2e2eacfbee08dc61956933601a489e2edd39d -> openssl x509 -in acert.pem -fingerprint -sha1 -noout SHA1 Fingerprint=9D:D2:E2:EA:CF:BE:E0:8D:C6:19:56:93:36:01:A4:89:E2:ED:D3:9D
Incidentally, OpenSSL offers a digest command, dgst, which offers multiple algorithms:
-> openssl list --digest-commands blake2b512 blake2s256 gost md2 md4 md5 rmd160 sha1 sha224 sha256 sha384 sha512
Specify the algorithm by prefixing a hyphen to the name:
-> openssl dgst -sha1 -c acert.der SHA1 (acert.der) = 9dd2e2eacfbee08dc61956933601a489e2edd39d -> openssl dgst -md5 -c acert.der MD5(acert.der)= a9:90:03:9e:f8:2a:32:4b:7e:ae:9f:a3:f9:99:83:53
Option -c tells dgst to infix those colons. The dgst command hashes any file, related to PKI or not.
-> certtool --infile rnb.pem --verify Loaded system trust (154 CAs available) Loaded 3 certificates, 154 CAs and 0 CRLs ⋮ Chain verification output: Verified. The certificate is trusted.
-> certtool --infile rnb.pem --verify --load-ca-certificate cacert-curl.pem Loaded 3 certificates, 138 CAs and 0 CRLs ⋮ Chain verification output: Verified. The certificate is trusted.