NSS-OpenSSL Command How to: The complete list.

NSS-OpenSSL Command How to: The complete list.

I am sick and tired of the lack of documentation for how to actually use OpenSSL and NSS to achieve things. Be it missing small important options like "subjectAltNames" in nss commands or openssls cryptic settings. Here is my complete list of everything you would ever want to do with OpenSSL and NSS.

References:

Nss specific

DB creation and basic listing

Create a new certificate database if one doesn't exist (You should see key3.db, secmod.db and cert8.db if one exists). :

certutil -N -d . 

List all certificates in a database :

certutil -L -d .

List all private keys in a database :

certutil -K -d . [-f pwdfile.txt]

I have created a password file, which consists of random data on one line in a plain text file. Something like below would suffice. Alternately you can enter a password when prompted by the certutil commands. If you wish to use this for apache start up, you need to use pin.txt :

echo "Password" > pwdfile.txt
echo "internal:Password" > pin.txt

Importing certificates to NSS

Import the signed certificate into the requesters database.

certutil -A -n "Server-cert" -t ",," -i nss.dev.example.com.crt -d .

Import an openSSL generated key and certificate into an NSS database. :

openssl pkcs12 -export -in server.crt -inkey server.key -out server.p12 -name Test-Server-Cert
pk12util -i server.p12 -d . -k pwdfile.txt

Importing a CA certificate

Import the CA public certificate into the requesters database. :

certutil -A -n "CAcert" -t "C,," -i /etc/pki/CA/nss/ca.crt -d .

Exporting certificates

Export a secret key and certificate from an NSS database for use with openssl. :

pk12util -o server-export.p12 -d . -k pwdfile.txt -n Test-Server-Cert
openssl pkcs12 -in server-export.p12 -out file.pem -nodes

Note that file.pem contains both the CA cert, cert and private key. You can view just the private key with: :

openssl pkcs12 -in server-export.p12 -out file.pem -nocerts -nodes

Or just the cert and CAcert with :

openssl pkcs12 -in server-export.p12 -out file.pem -nokeys -nodes

You can easily make ASCII formatted PEM from here.

Both NSS and OpenSSL

Self signed certificates

Create a self signed certificate.

For nss, note the -n, which creates a "nickname" (And should be unique) and is how applications reference your certificate and key. Also note the -s line, and the CN options. Finally, note the first line has the option -g, which defines the number of bits in the created certificate. :

certutil -S -f pwdfile.txt -d . -t "C,," -x -n "Server-Cert" -g 2048\
-s "CN=nss.dev.example.com,O=Testing,L=example,ST=South Australia,C=AU"

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days

certutil -S -f pwdfile.txt -d . -t "C,," -x -n "Server-Cert2" \
-s "CN=nss2.dev.example.com,O=Testing,L=example,ST=South Australia,C=AU" 

SubjectAltNames

To add subject alternative names, use a comma seperated list with the option -8 IE: :

certutil -S -f pwdfile.txt -d . -t "C,," -x -n "Server-Cert" -g 2048\
-s "CN=nss.dev.example.com,O=Testing,L=example,ST=South Australia,C=AU" \
-8 "nss.dev.example.com,nss-alt.dev.example.com"

For OpenSSL this is harder:

First, you need to create an altnames.cnf :

[req]
req_extensions = v3_req
nsComment = "Certificate"
distinguished_name  = req_distinguished_name

[ req_distinguished_name ]

countryName                     = Country Name (2 letter code)
countryName_default             = AU
countryName_min                 = 2
countryName_max                 = 2

stateOrProvinceName             = State or Province Name (full name)
stateOrProvinceName_default     = South Australia

localityName                    = Locality Name (eg, city)
localityName_default            = example/streetAddress=Level

0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = example

organizationalUnitName          = Organizational Unit Name (eg, section)
organizationalUnitName_default = TS

commonName                      = Common Name (eg, your name or your server\'s hostname)
commonName_max                  = 64

[ v3_req ]

# Extensions to add to a certificate request

basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = server1.yourdomain.tld
DNS.2 = mail.yourdomain.tld
DNS.3 = www.yourdomain.tld
DNS.4 = www.sub.yourdomain.tld
DNS.5 = mx.yourdomain.tld
DNS.6 = support.yourdomain.tld

Now you run a similar command to before with: :

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days -config altnames.cnf
openssl req -key key.pem -out cert.csr -days -config altnames.cnf -new

Check a certificate belongs to a specific key

openssl rsa -noout -modulus -in client.key | openssl sha1
openssl req -noout -modulus -in client.csr | openssl sha1
openssl x509 -noout -modulus -in client.crt | openssl sha1

View a certificate

View the cert :

certutil -L -d . -n Test-Cert

openssl x509 -noout -text -in client.crt

View the cert in ASCII PEM form (This can be redirected to a file for use with openssl)

::

: certutil -L -d . -n Test-Cert -a certutil -L -d . -n Test-Cert -a > cert.pem

Creating a CSR

In a second, seperate database to your CA.

Create a new certificate request. Again, remember -8 for subjectAltName :

certutil -d . -R -o nss.dev.example.com.csr -f pwdfile.txt \
-s "CN=nss.dev.example.com,O=Testing,L=example,ST=South Australia,C=AU"

Using openSSL create a server key, and make a CSR :

openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr

Self signed CA

Create a self signed CA (In a different database from the one used by httpd.) :

certutil -S -n CAissuer -t "C,C,C" -x -f pwdfile.txt -d . \
-s "CN=ca.nss.dev.example.com,O=Testing,L=example,ST=South Australia,C=AU"

OpenSSL is the same as a self signed cert. :

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days

Signing with the CA

Create a certificate in the same database, and sign it with the CAissuer certificate. :

certutil -S -n Test-Cert -t ",," -c CAissuer -f pwdfile.txt -d . \
-s "CN=test.nss.dev.example.com,O=Testing,L=example,ST=South Australia,C=AU"

If from a CSR, review the CSR you have recieved. :

/usr/lib[64]/nss/unsupported-tools/derdump -i /etc/httpd/alias/nss.dev.example.com.csr
openssl req -inform DER -text -in /etc/httpd/alias/nss.dev.example.com.csr  ## if from nss
openssl req -inform PEM -text -in server.csr  ## if from openssl

On the CA, sign the CSR. :

certutil -C -d . -f pwdfile.txt -i /etc/httpd/alias/nss.dev.example.com.csr \
-o /etc/httpd/alias/nss.dev.example.com.crt -c CAissuer

For openssl CSR, note the use of -a that allows an ASCII formatted PEM input, and will create and ASCII PEM certificate output. :

certutil -C -d . -f pwdfile.txt -i server.csr -o server.crt -a -c CAissuer

### Note, you may need a caserial file ... 
openssl x509 -req -days 1024 -in client.csr -CA root.crt -CAkey root.key -out client.crt

Check validity of a certificate

Test the new cert for validity as an SSL server. This assumes the CA cert is in the DB. (Else you need openssl or to import it) :

certutil -V -d . -n Test-Cert -u V

openssl verify -verbose -CAfile ca.crt client.crt

Export the CA certificate

Export the CA public certificate :

certutil -L -d . -n CAissuer -r > ca.crt

NSS sqlite db

Finally, these commands all use the old DBM formatted NSS databases. To use the new "shareable" sqlite formatting, follow the steps found from this blog post.

How to upgrade from cert8.db to cert9.db

You can either use environment variables or use sql: prefix in database directory parameter of certutil:

::

: $export NSS_DEFAULT_DB_TYPE=sql $certutil -K -d /tmp/nss -X

> OR

\$certutil -K -d sql:/tmp/nss -X

When you upgrade these are the files you get

key3.db -> key4.db
cert8.db -> cert9.db
secmod.db -> pkcs11.txt

The contents of the pkcs11.txt files are basically identical to the contents of the old secmod.db, just not in the old Berkeley DB format. If you run the command "$modutil -dbdir DBDIR -rawlist" on an older secmod.db file, you should get output similar to what you see in pkcs11.txt.

What needs to be done in programs / C code

Either add environment variable NSS_DEFAULT_DB_TYPE "sql"

NSS_Initialize call in https://developer.mozilla.org/en/NSS_Initialize takes this "configDir" parameter as shown below.

NSS_Initialize(configDir, "", "", "secmod.db", NSS_INIT_READONLY);

For cert9.db, change this first parameter to "sql:" + configDir (like "sql:/tmp/nss/") i.e. prefix "sql:" in the directory name where these NSS Databases exist. This code will work with cert8.db as well if cert9.db is not present.

https://wiki.mozilla.org/NSS_Shared_DB

Display a human readable certificate from an SSL socket

Note: port 636 is LDAPS, but all SSL sockets are supported. For TLS only a limited set of protocols are supported. Add -starttls to the command. See man 1 s_client.

openssl s_client -connect ldap.example.com:636

[ant@ant-its-example-edu-au ~]$ echo -n | openssl s_client -connect ldap.example.com:636 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | openssl x509 -noout -text

depth=3 C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root
verify return:1
depth=2 C = US, ST = UT, L = Salt Lake City, O = The USERTRUST Network, OU = http://www.usertrust.com, CN = UTN-USERFirst-Hardware
verify return:1
depth=1 C = AU, O = AusCERT, OU = Certificate Services, CN = AusCERT Server CA
verify return:1
depth=0 C = AU, postalCode = 5000, ST = South Australia, L = example, street = Level, street = Place, O =Example, OU = Technology Services, CN = ldap.example.com
verify return:1
DONE
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
    Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=AU, O=AusCERT, OU=Certificate Services, CN=AusCERT Server CA
        Validity
            Not Before: XX
            Not After : XX
        Subject: C=AU/postalCode=5000, ST=South Australia, L=example/street=Level /street=Place, O=Example, OU=Technology Services, CN=ldap.example.com
        Subject Public Key Info:
<snip>
            X509v3 Subject Alternative Name: 
                DNS:ldap.example.com
<snip>

You can use this to display a CA chain if you can't get it from other locations.

openssl s_client -connect ldap.example.com:636 -showcerts

mod_nss

To configure mod_nss, you should have a configuration similar to below - Most of this is the standard nss.conf that comes with mod_nss, but note the changes to NSSNickname, and the modified NSSPassPhraseDialog and NSSRandomSeed values. There is documentation on the NSSCipherSuite that can be found by running "rpm -qd mod_nss". Finally, make sure that apache has read access to the database files and the pin.txt file. If you leave NSSPassPhraseDialog as "builtin", you cannot start httpd from systemctl. You must run apachectl so that you can enter the NSS database password on apache startup.

NOTE: mod_nss DOES NOT support SNI.

LoadModule nss_module modules/libmodnss.so
Listen 8443
NameVirtualHost *:8443
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl    .crl
NSSPassPhraseDialog  file:/etc/httpd/alias/pin.txt
NSSPassPhraseHelper /usr/sbin/nss_pcache
NSSSessionCacheSize 10000
NSSSessionCacheTimeout 100
NSSSession3CacheTimeout 86400
NSSEnforceValidCerts off
NSSRandomSeed startup file:/dev/urandom 512
NSSRenegotiation off
NSSRequireSafeNegotiation off
<VirtualHost *:8443>
ServerName nss.dev.example.com:8443
ServerAlias nss.dev.example.com
ErrorLog /etc/httpd/logs/nss1_error_log
TransferLog /etc/httpd/logs/nss1_access_log
LogLevel warn
NSSEngine on
NSSProtocol TLSv1
NSSNickname Server-cert
NSSCertificateDatabase /etc/httpd/alias
<Files ~ "\.(cgi|shtml|phtml|php3?)$">
    NSSOptions +StdEnvVars
</Files>
<Directory "/var/www/cgi-bin">
    NSSOptions +StdEnvVars
</Directory>
</VirtualHost>