Crypto, Certs, Digests, & All That

Generate Private Keys

You can use openssl and certtool to generate a private key. Both support RSA, DSA or ECC (ECDSA) for the algorithm underlying the key. And they optionally encrypt a key with a passphrase. For clarity and consistency, the examples below adopt filenames mysite-clear.pem and mysite-crypt.pem for their plaintext and encrypted keys, respectively.

You'll want to secure a real-world key. Taking cues from the ArchLinux Wiki, these notes put mysite-clear.pem and mysite-crypt.pem in directory private like so:

-> mkdir --mode 0700 private
-> cd private
-> touch mysite-clear.pem mysite-crypt.pem
-> chmod 0600 mysite-clear.pem mysite-crypt.pem
-> ls -og mysite-clear.pem mysite-crypt.pem
-rw-------. 1 0 Sep 11 12:08 mysite-crypt.pem
-rw-------. 1 0 Sep 11 12:08 mysite-clear.pem

The commands generating the actual private keys will overwrite the files but retain the permissions. You'll need to determine what's right for your security needs, of course.

Here's how to generate an RSA private key using OpenSSL's genpkey command:

-> openssl genpkey -out mysite-clear.pem -algorithm rsa -pkeyopt rsa_keygen_bits:2048

The final argument specifies the size of the key, which for RSA is the number of bits in the modulus. The command prints an esoteric progress report in periods, plus symbols, and new lines. You can direct stderr to /dev/null if you've no interest in that.

The private key is not itself encrypted and thus potentially exposed. You can tell genpkey to encrypt the key with a passphrase of your choosing:

-> openssl genpkey -out mysite-crypt.pem -aes128 -algorithm rsa -pkeyopt rsa_keygen_bits:2048 2> /dev/null
Enter PEM pass phrase: not echoed
Verifying - Enter PEM pass phrase:  not echoed

Here option -aes128 orders encryption using AES with 128 bits. OpenSSL offers several other encryption algorithms and a few other ways to enter the password. For example, this command uses AES-256 with password 'demo':

-> openssl genpkey -out mysite-crypt.pem -aes256 -pass pass:demo -algorithm rsa -pkeyopt rsa_keygen_bits:2048 2> /dev/null

The file created by genpkey consists of a PEM block encoding and optionally encrypting the private key. For a plaintext key:

-> cat mysite-clear.pem 
base64 rendition of key's binary data stream goes here

For an encrypted key:

 -> cat mysite-crypt.pem 
 base64 rendition of key's encrypted data stream goes here

If you include option -text, genpkey reports readable values of the modulus, exponents, prime numbers, and coefficients constituting the private key and its public partner. It writes these after the key's PEM block. This information always appears in plaintext—regardless encryption for the PEM block—and thus exposes the private key to anyone who can read the file.

See man page genpkey for more details and options.

You can alternatively use OpenSSL's command genrsa to generate an RSA private key:

-> openssl genrsa -out mysite-clear.pem 2048
Generating RSA private key, 2048 bit long modulus
e is 65537 (0x10001)

You can encrypt the key, too:

-> openssl genrsa -out mysite-crypt.pem -aes128 2048 2> /dev/null

Man page openssl says that genpkey supersedes genrsa and a few analogous commands for other encryption algorithms. Man page genpkey elaborates, a little, by noting that genpkey offers additional options.

Here's how to create an RSA private key using certtool:

-> certtool --generate-privkey --outfile mysite-clear.pem
Generating a 2048 bit RSA private key...

The key is not encrypted. This allows certtool to prepend information about the private key and its matching public key to the PEM block encoding the private key. You can thus view mysite-clear.pem with cat, less, or any text editor to get an idea of the components (modulus, exponents, primes) of the keys.

You can adjust the key's level of security with option --sec-params:

-> certtool --generate-privkey --sec-param low --outfile mysite-clear.pem
Generating a 1024 bit RSA private key...
-> certtool --generate-privkey --sec-param medium --outfile mysite-clear.pem
Generating a 2048 bit RSA private key...
-> certtool --generate-privkey --sec-param high --outfile mysite-clear.pem
Generating a 3072 bit RSA private key...

You can instead use option --bits, but then certtool will urge you to use --sec-params anyway.

You can create an encrypted private key by specifying PKCS #8 format:

-> certtool --generate-privkey --pkcs8 --outfile mysite-crypt.pem
Generating a 2048 bit RSA private key...
Enter password: 

Because the key is encrypted, certtool does not prepend information to the PEM block, as it does for unencrypted keys. Tools like cat and less find only the that chunk of junk to display. You can use option --pkcs-cipher to select a different cipher.

You can alternatively create a DSA or an ECC (ECDSA) key with option --dsa or --ecc, respectively:

-> certtool --generate-privkey --dsa --sec-param low  --outfile mysite-clear.pem
Generating a 1024 bit DSA private key...
-> certtool --generate-privkey --ecc --sec-param high --outfile mysite-clear.pem
Generating a 256 bit EC private key...

Note the difference in the number of bits. For ECC, a 256-bit key is considered high security. For RSA and DSA, a 1024-bit key is considered low security.

Examine Private Keys

The PEM block of a private key encodes the mathematical components of both the key and its public counterpart. You can use OpenSSL's pkey command or GnuTLS's certtool command to decode the PEM block and report these components in a simple, readable format. Even so, what you get is a lot of hex numbers for the bit strings representing these components.

Your key file may aready report the mathematical components outside of the PEM block—depending on how you generated the file. This is the case if you ran genpkey with option -text or if you ran certtool without encryption. Just open the file in a text browser or editor. If you generated your private key using certtool with encryption, however, the key file does not reveal these components.

Here's how to list the components of the private and public keys encoded in file mysite-clear.pem, for example.

Using pkey:

-> openssl pkey -in mysite-clear.pem -text -noout

Private-Key: (2048 bit)
publicExponent: 65537 (0x10001)

Option -noout stops pkey from showing the PEM block.

Or using certtool:

-> certtool --infile mysite-clear.pem --key-info

The report additionally prints the ID and ASCII art for the public key, and it includes the private key's PEM block.

If your private key is encrypted, both commands prompt for the password. Or you can invoke either command with the password included:

-> openssl pkey -in mysite-crypt.pem -text -noout -passin pass:demo

-> certtool --load-privkey mysite-crypt.pem --pubkey-info --password demo

But you expose the password this way.

If you are just interested in the modulus and exponent forming the public key, use option -text_pub instead of -text with pkey:

-> openssl pkey -in mysite-clear.pem -text_pub -noout
Public-Key: (2048 bit)
Exponent: 65537 (0x10001)

Or with certtool use option --pubkey-info instead of --key-info

-> certtool --load-privkey mysite-clear.pem --pubkey-info

In addition to the modulus and exponent, certtool reports the algorithm (e.g., RSA, DSA, etc), usage, ID, and PEM block for the public key.

Extract & Examine Public Keys

A private-key file also holds the components for its public-key partner. You can use OpenSSL's pkey command or GnuTLS's certtool command to extract the public key for distribution or review.

Here's how to extract the public key from the private key in file mysite-clear.pem, for example.

Using pkey:

-> openssl pkey -in private/mysite-clear.pem -pubout -out mysite.pem
-> cat mysite.pem 
base64 rendition of public key's binary data stream goes here
-----END PUBLIC KEY-----

Option -pubout tells pkey to extract the public key only. If you add option -text_pub, then pkey appends a report of the key's components. Do not use option -text because the appended report would include the components of the private key.

Or use certtool:

-> certtool --load-privkey private/mysite-clear.pem --pubkey-info --outfile mysite.pem

The output file includes a report of the key's components, in addition to the key's PEM block.

If the private key is encrypted, you'll be prompted for its passphrase whatever command you choose. The data stream of a public key is not encrypted.

Here's how to list the components of the public key encoded in file mysite.pem, for example.

Using pkey:

-> openssl pkey -in mysite.pem -pubin -text -noout
Public-Key: (2048 bit)
Exponent: 65537 (0x10001)

Option -pubin lets pkey know that it's looking at a public key. Options -text and -text_pub are interchangeable for a public key.

Or using certtool:

-> certtool --load-pubkey mysite.pem --pubkey-info

The report additionally prints the ID and ASCII art for the public key, and it includes the private key's PEM block.

If you extracted your public key with certtool, the output file already includes the key's components in a readable format outside of the PEM block.

Examine Certificates

You can use certtool or openssl too view a certificate saved in a file, say acert.pem:

-> certtool --certificate-info --infile acert.pem

-> 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).

A PEM file (.pem) takes a certificate's binary X.509 data stream, encodes that into base64 (ASCII), and sandwiches the result between a header and footer:

-> cat acert.pem 
text/base64 rendition of certificate's binary data stream goes here

You can view a PEM block with any text editor or browser, but it's ASCII noise as far as the eye can see. 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.

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.

Under the hood, X.509 uses Abstract Syntax Notation One, or ASN.1, to represent a certificate's data. It then encodes this 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. 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).

There are three versions of X.509 certificates. Version 3 allows extensions, which can narrow the valid uses for the certificate. For example, a CA may bind a public key to an IP address but stipulate validity only for SSL transactions. It looks like version 2 never got much play.

A certificate's fingerprint is a digest of its DER data stream. Conceptually, start with the PEM block, strip its envelope, and decode the base64 innards. What you get is the DER stream. You can delegate this chore to openssl:

-> openssl x509 -in acert.pem -outform DER -out acert.der

Now compute the SHA1 digest of acert.der explicitly and compare the result to what openssl reports:

-> sha1sum --tag acert.der 
SHA1 (acert.der) = eadf929ccb1fcbd05c78a1f5bdb3401f76395bd8
-> openssl x509 -in acert.pem -fingerprint -sha1 -noout
SHA1 Fingerprint=EA:DF:92:9C:CB:1F:CB:D0:5C:78:A1:F5:BD:B3:40:1F:76:39:5B:D8

Of course, other digests will do as long as all parties hash alike. openssl also offers SHA256 and MD5 fingerprints (via options -sha256 and -md5). certtool reports SHA1 and SHA256 fingerprints.

You can use openssl to retrieve a server's certificate if you're keen to have a look at it. For example:

-> openssl s_client -connect

Server certificate
Several of lines base64 text

Or for an SMTP server on a TLS/SSL port:

-> openssl s_client -connect

For an SMTP server on port 587, tell openssl to issue a starttls command on connection:

-> openssl s_client -connect -starttls smtp

The session stays open until you enter Ctrl-D or a protocol-specific command (e.g., quit for SMTP).

Simply copy and paste the PEM block into a file, say server-cert.pem, and use certtool or openssl to examine it.

-> openssl x509 -in server-cert.pem -noout -subject -issuer
subject= /C=US/ST=California/L=Mountain View/O=Google Inc/
issuer= /C=US/O=Google Inc/CN=Google Internet Authority G2

Left to its own inclinations, s_client accepts any certificate chain in the interest of continued testing. Thus you should be wary of blindly exchanging sensitive data without first vetting the certificate chain. You can add option -showcerts if you'd like to see the links of the chain.

Certificate Authorities

Fedora's store of trusted CA certificates derives from the Mozilla CA Certificate Store. Package ca-certificates installs these certificates under /etc/pki/ca-trust/extracted, primarily, along with other directories. For example:

-> grep 'BEGIN TRUSTED CERTIFICATE' /etc/pki/ca-trust/extracted/openssl/ | wc --lines

The man page update-ca-trust has details.

To address legacy issues with GnuTLS and OpenSSL, Fedora's trust store retains a handful of CA certificates that have been removed from the Mozilla store. These are listed on the project's home page. You can use command ca-legacy (as root) to enable or disable trust in these certificates.

-> ca-legacy check
Legacy CAs are set to ENABLED in file /etc/pki/ca-trust/ca-legacy.conf (affects install/upgrade)
Status of symbolic link /etc/pki/ca-trust/source/ca-bundle.legacy.crt:
-> grep 'BEGIN TRUSTED CERTIFICATE' /usr/share/pki/ca-trust-legacy/ca-bundle.legacy.enable.crt | wc --lines
-> ca-legacy disable
-> ca-legacy check
Legacy CAs are set to DISABLED in file /etc/pki/ca-trust/ca-legacy.conf (affects install/upgrade)
Status of symbolic link /etc/pki/ca-trust/source/ca-bundle.legacy.crt:
-> grep 'BEGIN TRUSTED CERTIFICATE' /usr/share/pki/ca-trust-legacy/ca-bundle.legacy.disable.crt | wc --lines 

Package openssl creates /etc/pki/CA and also populates /etc/pki/tls. Package nss creates /etc/pki/nssdb.

Automatically converted CA Certs from

A PEM file may bundle multiple certificates by simply concatenating PEM blocks. For example, package ca-certificates puts its TLS certificates into a single file:

 -> grep 'BEGIN CERTIFICATE' /etc/pki/tls/cert.pem | wc --lines

certtool kindly reads all certificates in a bundle, but openssl stops after the first:

-> certtool --certificate-info --infile /etc/pki/tls/cert.pem | grep 'Issuer:' | wc --lines
-> openssl x509 -in /etc/pki/tls/cert.pem -issuer -noout | wc --lines

Mozilla Firefox and Thunderbird, Google Chrome, and other applications use Network Security Services (NSS) to manage the store of trusted CA certificates. NSS keeps this collection in a database comprising three files. It favors SQLite for the database engine but retains support for legacy Berkeley DB. With SQLite, a database comprises files cert9.db, key4.db, and pkcs11.txt. With Berkeley DB, a database comprises cert8.db, key3.db, and secmod.db. Separate databases are supported simply by separate directories holding the pertinent files. And a directory can host both SQLite and DB formats since the filenames are distinct.

My Firefox profile, for example, uses legacy DB:

-> cd ~/.mozilla/firefox/hiqa0bo9.default
-> file *.db
cert8.db:  Berkeley DB 1.85 (Hash, version 2, native byte-order)
key3.db:   Berkeley DB 1.85 (Hash, version 2, native byte-order)
secmod.db: Berkeley DB 1.85 (Hash, version 2, native byte-order)

Your Firefox profile will have a different name than that found here.

You can use certutil (package nss-tools) to have a look at your application's CAs:

-> cd ~/.mozilla/firefox/hiqa0bo9.default
-> certutil -L -d . | tail --lines +5 | sort
AlphaSSL CA - SHA256 - G2                                    ,,   

Verizon Akamai SureServer CA G14-SHA2                        ,,   
-> certutil -L -d . | tail --lines +5 | wc --lines

Option -L tells certutil to list the CAs it finds in the database directory that -d locates. The tail pipe trims the initial five header lines, which are not informative here.

When listing certificates, certutil checks environment variable NSS_DEFAULT_DB_TYPE for the database type, given as "sql" or "dbm". In the absence of the latter guidance, it goes with DB. It balks when it tries the wrong format:

-> NSS_DEFAULT_DB_TYPE=dbm certutil -L -d $HOME/.pki/nssdb
certutil: function failed: SEC_ERROR_LEGACY_DATABASE: The certificate/key database is in an old, unsupported format.

You can easily lend a hand by prepending "sql:" or "dbm:" to the directory name:

-> certutil -L -d sql:$HOME/.pki/nssdb

Message Digests

The simple string "abc" (without enclosing quotation marks) is a convenient input to informally compare digest utilities (cf. NSRL Test Data):

-> echo -n abc > abc.txt
-> wc --bytes abc.txt 
3 abc.txt

Be careful to use option -n so that echo excludes a trailing newline, which it would append by default:

-> echo abc | wc --bytes

You can use shasum (package perl-Digest-SHA) to compute SHA digests of a file or input stream, or Secure Hash Algorithm digests. It offers SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA-512224, and SHA-512256. For example:

-> shasum abc.txt 
a9993e364706816aba3e25717850c26c9cd0d89d  abc.txt
-> shasum --algorithm 1 abc.txt 
a9993e364706816aba3e25717850c26c9cd0d89d  abc.txt
-> shasum --algorithm 256 abc.txt 
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad  abc.txt

You can similarly use GNU's sh1sum, sh224sum, sh256sum, sh384sum, and sh512 (package coreutils) instead:

-> sha1sum abc.txt 
a9993e364706816aba3e25717850c26c9cd0d89d  abc.txt
-> sha256sum abc.txt 
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad  abc.txt

You can typically use these tool kits interchangeably because they produce the same output format when computing digests and expect the same input format when checking digests. For example:

-> shasum -a 512 abc.txt xyz.txt > abc-xyz.sha512
-> sha512sum --check abc-xyz.sha512 
abc.txt: OK
xyz.txt: OK

There are potential subtleties to be aware of, however. shasum offers a Universal Newlines mode and a BITS mode, but the GNU commands do not support these modes. And the GNU commands can optionally write and check the BSD-style formats, which shasum spurns.

You can use md5sum (package coreutils) to compute or check the MD5 digest of a file's contents:

-> md5sum abc.txt 
900150983cd24fb0d6963f7d28e17f72  abc.txt
-> md5sum abc.txt > abc.md5
-> md5sum --check abc.md5 
abc.txt: OK

Wikipedia's MD5 article notes that MD5 hashes are no longer secure and should be replaced by SHA-2 hashes.

You can use OpenSSL's command dgst to compute various digests as well:

-> openssl dgst abc.txt
MD5(abc.txt)= 900150983cd24fb0d6963f7d28e17f72
-> openssl dgst -md5 abc.txt
MD5(abc.txt)= 900150983cd24fb0d6963f7d28e17f72
-> openssl dgst -sha1 abc.txt
SHA1(abc.txt)= a9993e364706816aba3e25717850c26c9cd0d89d

See man page dgst for yet more digests. Add option -r to get the output format that the GNU digests write:

-> openssl dgst -sha1 -r abc.txt
a9993e364706816aba3e25717850c26c9cd0d89d *abc.txt

The asterisk indicates binary-mode format, in particular.

GUI GtkHash displays multiple digests for a file; it offers over two-dozen algorithms. Open it with command gtkhash for GTK+2 (package gtkhash) or gtkhash3 for GTK+3 (package gtkhash3). There is no man page. Plugins for Nautilus (package gtkhash-nautilus) and Thunar (gtkhash-thunar) add a Digests tab to a file's Properties dialog.


gnutls-utils for certtool

You can generate a self-signed certificate from a private key file server-key.pem.

-> cat
-> certtool --generate-self-signed --load-privkey server-key.pem --template ss-gnutls.cfg --outfile my.cert.pem

To view contents of a certificate-signing request smtp-csr.pem:

-> certtool --crq --infile smtp-csr.pem

GNU Privacy Guard

In Fedora, Gnu Privacy Guard comes in two flavors: GnuPG2 (command gpg2, package gnupg2) and GnuPG (command gpg, package gnupg). GnuPG2 is the "modern" branch of GNU Privacy Guard, and GnuPG is the "classic" branch:

-> gpg2 --version | head -2
gpg (GnuPG) 2.1.7
libgcrypt 1.6.3
-> gpg --version | head -1
gpg (GnuPG) 1.4.19

The main additions to GnuPG2 include support for S/MIME and smart cards, gpg-agent, and a modular build. The two flavors look to be otherwise interchangeable with respect to invocation.

To list the public keys in your keyring:

-> gpg --list-keys
pub   4096R/57BBCCBA 2009-07-29
uid                  Fedora (12) <>

pub   4096R/E8E40FDE 2010-01-19
uid                  Fedora (13) &>

To delete a public key:

-> gpg --delete-key E8E40FDE
pub  4096R/E8E40FDE 2010-01-19 Fedora (13) <>

Delete this key from the keyring? (y/N) y

You can omit the interactive confirmation like so:

-> gpg --batch --yes --delete-key "Fedora (12) <>"

To change the passphrase protecting your private key, use the passwd command from within the key editor:

gpg --edit-key Test
Secret key is available.

pub  2048R/4549D949  created: 2011-12-13  expires: never       usage: SC  
                     trust: ultimate      validity: ultimate
sub  2048R/4B121B1A  created: 2011-12-13  expires: never       usage: E   
[ultimate] (1). Test Key (A key for testing and trying GnuPG.)

gpg> passwd
Key is protected.

You need a passphrase to unlock the secret key for ...
Enter the new passphrase for this secret key.
gpg> quit
Save changes? (y/N) y

GPG Agent

GnuPG2's gpg-agent, a daemon, remembers a private key's passphrase during a login session. When gpg2 first needs a private key, gpg-agent prompts for the key. If another gpg2 process subsequently needs this key, gpg-agent quietly supplies the passphrase without additional prompting. For symmetric encryption, gpg-agent also handles prompting the user for a passphrase, but it does not record the passphrase.

gpg-agent's configuration file is ~/.gnupg/gpg-agent.conf.

GnuPG2's gpg2 assumes that its helper program gpg-agent is running. It will complain mildly if not, but then it starts gpg-agent just the same. For example:

-> pidof gpg-agent
-> gpg2 --sign file.txt
gpg: can't connect to the agent - trying fall back
-> pidof gpg-agent
-> gpg2 --sign file2.txt
[no complaint]


To see where OpenSSL looks for its run-time files, including CA certificates:

-> openssl version -d
OPENSSLDIR: "/etc/pki/tls"

What certificate authorities does OpenSSL recognize?

To view a certificate in file acert.pem:

-> openssl x509 -in acert.pem -text
... [the whole shebang]

To view particular items, replace -text above with one or more of -subject, -issuer, -dates, -fingerprint, etc. Perhaps add -noout as well. The manual for the x509 command has all the details. For example:

-> openssl x509 -in acert.pem -noout -subject
subject= /C=US/ST=State/L=City/CN=computer.home/O=My Private Network

Here's how to generate a self-signed certificate ca.cert.pem along with its private key ca.key.pem using the settings in configuration file openssl.cnf:

-> openssl req -config ./openssl.cnf -new -x509 -extensions v3_ca -days 3650 -out ca.cert.pem -keyout ca.key.pem

Organization Name (company) [My Home Network]:
Organizational Unit Name (SMTP, Web, etc) []:Certificate Authority
Common Name (hostname, IP, or your name) []:.

Here, the option -extensions v3_ca activates the following section in the configuration file:

[ v3_ca ]
basicConstraints	= CA:TRUE
subjectKeyIdentifier	= hash
authorityKeyIdentifier	= keyid:always,issuer:always

Use OpenSSL command x509 to examine the certificate. For example:

-> openssl x509 -in ca.cert.pem -subject -dates -noout
subject= /O=My Home Network/OU=Certificate Authority
notBefore=Mar 24 17:33:50 2015 GMT
notAfter=Mar 21 17:33:50 2025 GMT

Option -noout suppresses output of the encoded certificate, which amounts to a blob of ASCII noise as far as the eye can see.

To sign a (single) certificate request smtp-req.pem:

-> openssl ca -config ./openssl.cnf -cert ca.cert.pem -keyfile ca.key.pem -in smtp-req.pem -outdir . -out smtp-cert.pem

Generate a request certificate smtp-req.pem with an unencrypted (-nodes) private key smtp-key.pem for a test email server:

-> openssl req -config ./openssl.cnf -new -nodes -keyout smtp-key.pem -out smtp-req.pem

Organization Name (company) [My Home Network]:
Organizational Unit Name (SMTP, Web, etc) []:Test SMTP Server
Common Name (hostname, IP, or your name) []:

GNOME Keyring Agent

There are several related auto-start files (.desktop) in /etc/xdg/autostart with prefix "gnome-keyring-"; e.g., gnome-keyring-ssh.desktop.