September 12, 2019

Reading NSS DB from Java 8 with SunPKCS11

Introduction

"Network Security Services (NSS) is a set of libraries designed to support cross-platform development of security-enabled client and server applications. Applications built with NSS can support SSL v3, TLS, PKCS #5, PKCS #7, PKCS #11, PKCS #12, S/MIME, X.509 v3 certificates, and other security standards." [https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS]

And NSS DB is a binary storage for certificates and keys on disk. In this blog I will show you how to read that NSS DB from Java with SunPKCS11

Prerequisite

Install nss-tools on Fedora, RHEL, CentOS.


$ sudo yum install -y nss-tools

NSS DB Format

NSS DB has two types of databases:

  • "The legacy security databases (cert8.db, key3.db, and secmod.db)"
  • "And new SQLite databases (cert9.db, key4.db, and pkcs11.txt)"

Reference:https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Reference/NSS_tools_:_certutil

Java according to official SunPKCS11 only supports the legacy database, but as we will see later, it does supports the new SQLite database.

"nssSecmodDirectory directory containing the NSS DB files The full pathname of the directory containing the NSS configuration and key information (secmod.db, key3.db, and cert8.db). This directive must be specified unless NSS has already been initialized by another component (see above) or NSS is used without database files as described below." [https://docs.oracle.com/javase/8/docs/technotes/guides/security/p11guide.html#NSS]

The Legacy NSS DB

Lets create a new legacy NSS DB. Note that we explicitly use the prefix dbm: when we create the DB.


$ mkdir nssdb_dbm
$ echo "redhat123" > password.txt
$ certutil -N -d dbm:nssdb_dbm -f password.txt

Now lets add a self-signed certificate and a matching private key in our legacy NSS DB.


$ certutil -S -n mkk -s 'CN=MKK, O=MKK Consultancy, C=SE' -t ',,' -k rsa -g 2048 -x -v 24 -f password.txt -d dbm:nssdb_dbm -Z SHA256

Then verify the certificate, keys and the legacy NSS DB files.


$ certutil -L -d dbm:nssdb_dbm 

Certificate Nickname                                         Trust Attributes
                                                             SSL,S/MIME,JAR/XPI

mkk                                                          u,u,u

$ certutil -K -d dbm:nssdb_dbm -f password.txt 
certutil: Checking token "NSS Certificate DB" in slot "NSS User Private Key and Certificate Services"
< 0> rsa      bc4e3491a87df6cd843f551a3f2bb714ecfa2bf7   NSS Certificate DB:mkk

$ ll nssdb_dbm/
total 80
-rw-------. 1 magnuskkarlsson magnuskkarlsson 65536 Sep 12 22:59 cert8.db
-rw-------. 1 magnuskkarlsson magnuskkarlsson 16384 Sep 12 22:59 key3.db
-rw-------. 1 magnuskkarlsson magnuskkarlsson 16384 Sep 12 22:58 secmod.db

Now lets write our Java program


package se.magnuskkarlsson.example.nssdb;

import java.security.Key;
import java.security.KeyStore;
import java.security.Provider;
import java.security.Security;
import java.security.cert.X509Certificate;

import java.util.Enumeration;

// https://docs.oracle.com/javase/8/docs/technotes/guides/security/p11guide.html#NSS
// https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Reference/NSS_tools_:_certutil
/*
          certutil supports two types of databases: the legacy
          security databases (cert8.db, key3.db, and secmod.db)
          and new SQLite databases (cert9.db, key4.db, and
          pkcs11.txt).
 */
public class NSSTool {

    public static char[] password = "redhat123".toCharArray();

    public static void main(String[] args) throws Exception {
        String configName = "/home/magnuskkarlsson/NetBeansProjects/example-nssdb/pkcs11.cfg";
        Provider p = new sun.security.pkcs11.SunPKCS11(configName);
        Security.addProvider(p);
        KeyStore ks = KeyStore.getInstance("PKCS11", p); //p is the provider created above
        ks.load(null, password);
        System.out.println("Successfully loaded NSS DB.");
        for (Enumeration aliases = ks.aliases(); aliases.hasMoreElements();) {
            String alias = aliases.nextElement();
            X509Certificate cert = (X509Certificate) ks.getCertificate(alias);
            Key key = ks.getKey(alias, password);
            System.out.println(key);
            System.out.println(cert);
            System.out.println("------------------------------");
        }
    }
}

name = NSScrypto
# nssLibraryDirectory = 
nssSecmodDirectory = /home/magnuskkarlsson/NetBeansProjects/example-nssdb/nssdb_dbm
nssDbMode = readWrite
nssModule = keystore

The New SQLite NSS DB

Though the official Java documentation does state that it does not support the new format, it can read the new format, but with one hack and that is you need to create an empty secmod.db file.

But first lets create a new NSS DB with the new SQLite format, we explicitly use the prefix sql: when creating the new NSS DB.


$ mkdir nssdb_sql
$ echo "redhat123" > password.txt
$ certutil -N -d sql:nssdb_sql -f password.txt

And then the fix.


$ touch nssdb_sql/secmod.db

And finally lets create a self-signed certificate, so we have something to read.


$ certutil -S -n mkk -s 'CN=MKK, O=MKK Consultancy, C=SE' -t ',,' -k rsa -g 2048 -x -v 24 -f password.txt -d sql:nssdb_sql -Z SHA256

We now have the following files.


$ ll nssdb_sql/
total 68
-rw-------. 1 magnuskkarlsson magnuskkarlsson 28672 Sep 12 23:03 cert9.db
-rw-------. 1 magnuskkarlsson magnuskkarlsson 36864 Sep 12 23:03 key4.db
-rw-------. 1 magnuskkarlsson magnuskkarlsson   420 Sep 12 23:02 pkcs11.txt
-rw-rw-r--. 1 magnuskkarlsson magnuskkarlsson     0 Sep 12 23:04 secmod.db

The Java code stays the same, but we need to update the pkcs11.cfg with our new path


name = NSScrypto
# nssLibraryDirectory = 
nssSecmodDirectory = /home/magnuskkarlsson/NetBeansProjects/example-nssdb/nssdb_sql
nssDbMode = readWrite
nssModule = keystore

No comments: