NSS Shared DB And LINUX
One of the main benefits of consolidating on a single crypto library is doing so create allows consolidation of management of certificates. In order to reap this benefit, however, we not only need to use a common crypto library, but also agree on a common way to use the crypto resources (keys/certs/tokens). This document attempts to explain how applications using NSS as a system library should initialize NSS for maximum effect.
Application Programmer's Summary
The short summary: Except as noted below, all applications should initialize NSS with the following call:
rv = NSS_InitReadWrite(“sql:/etc/pki/nssdb”);
There are 3 classes of Exceptions.
1. The first exception is applications which must set special flags. The two most common flags are NSS_INIT_READONLY == 1 and NSS_INIT_OPTIMIZESPACE == 0. NOTE: applications that used to initialize READONLY because of the old dbm semantics no longer need to do so.
These applications should initialize with:
rv = NSS_Initialize(“sql:/etc/pki/nssdb”, “”, “”, “”, flags);
where flags are 0, NSS_INIT_READONLY, or NSS_INIT_READONLY|NSS_INIT_OPTIMIZESPACE. (Note: flags = NSS_INIT_OPTIMIZESPACE is the same as NSS_InitReadWrite() above. Also NSS_INIT_READONLY|NSS_INIT_OPTIMIZESPACE is the same as NSS_Init().).
2. The second exception is applications which want to perform automatic migration of an old NSS database from an old location to the new system location. These applications should initialize NSS with:
rv = NSS_InitMerge“sql:/etc/pki/nssdb”, “”, “”, “”, oldNSSdirectory, uniqueIDForOldDB, nameOfOldDBForPrompt, flags);
The application should then follow the automatic merge instructions in the shared database documentation.
3. The third exception is applications that must have a separately managed environment. Typically these applications would have a mode (probably default) which would open NSS normally, but could be configured to use their own NSS environment. The options to use the system or private environment should not be hard coded in the application, but should be under user/administrator control. Applications of this class would include Server products or test modes of application products (like Firefox profiles). In this mode the application should initialize NSS with it's traditional Init call, passing in the appropriate private database.
On Linux, the effect of the above initialization (which one?) will be to:
- Open a database in the home directory of the user running. With the flags specified by the application (probably ~/.pki/nssdb).
- Load any User specified PKCS #11 modules.
- Open the system database in /etc/pki/nssdb readonly.
- Load any System specified PKCS #11 modules.
- Load the NSS builtins module.
How this happens will be explained later, but first we discuss where the requirements for the above come from.
Requirements by Package Type
There are 3 typical package types that may use NSS and it's databases:
Type 1: User Application. These are applications like browsers, mail clients, etc. that individual users run. The user expects to be able to access all of his/her certificates from any application. The user also expects that system wide configuration is automatically available, though overridable by the user.
Type 2: System/Service Applications. These include things like web servers, mail servers, etc. These applications may want to share keys and certs with other servers, or they may want to have their own private copies of certs and keys.
Type 3: Libraries. Libraries are a special case. The library may run in any kind of application or services.
Type 1 packages: User applications
User applications should open NSS using a shared database stored in ~/.pki/nssdb in the user's home directory. If the application needs to store new certificates (like a web browser), then it should open this database read/write. User's local preferences would be stored in this database. Changes the application wants to make will occur in this database. Any user specified tokens would also be stored in this database.
In addition, the application should own the system database /etc/pki/nssdb. This database should be opened read only. The user will typically not have permission to modify this database. This database will provide system level defaults for tokens to load and root certs to trust. This gives us hooks form things like IPA to manage and distribute trusted root certs system wide.
Type 2 packages: Services applications
Option 1: Services applications, again, should open both sets of databases. The difference is service applications may actually have read permission on the key database in /etc/pki/nssdb. This means it can use /etc/pki/nssdb to share key material with other system services. Each service could start as it's own user or several services could run as a single user and share keys that way.
Option 2: instead of sharing service level keys in /etc/pki/nssdb, we would specify a different database that services would open for shared key support (call it /etc/pki/services for now). In this case all three would be opened, but there would never be any keys in /etc/pki/nssdb, and User applications would not have access to /etc/pki/services.
Option 3: Either option 1 or option 2 except the 'user' database for the server isn't necessarily stored in ~/.pki/{server_user}, but is configurable for each server.
Type 3 packages: Libraries
Type 3 packages should open ~/.pki/nssdb and /etc/pki/nssdb read only. If the packages are stand alone, this should be sufficient. If the packages are part of a bigger application, then it should follow the needs of that bigger application.
Summary of Requirements
In short, all applications will need to open ~/.pki/nssdb and /etc/pki/nssdb. Now, how can this most easily happen?
How NSS decides what to load
NSS delegates the responsibility for managing the list of PKCS#11 modules in the running process to a shared library, sometimes called the "Module DB library". This shared library has a small API (NOT the PKCS#11 API) with functions to output a list of PKCS#11 modules, add a new PKCS#11 module to the list, and delete a PKCS#11 module from the list. The details of how the Module DB library stores its information about the PKCS#11 modules is entirely up to the Module DB library.
In NSS 3.11 and earlier releases, and in NSS 3.12 (when in dbm compatibility mode), NSS's Module DB library uses a Berkeley database file (commonly named secmod.db) to keep the information about the configured PKCS#11 modules.
In NSS 3.12 (when in sql mode), NSS Module DB library uses a plain text file named pkcs11.txt to store the information about configured PKCS#11 modules. All the information in that file is stored as a plain text string.
In NSS 3.x releases to date, the shared library for the Module DB library is also the shared library for NSS's softoken PKCS#11 module, but that is merely a convention, and is not architecturally required. (RIGHT, BOB?)
During NSS initialization, NSS passes a string of application configuration information to the Module DB library, indicating whether the list is to be managed read-only or read-write, and certain other application preferences, such as whether the PKCS#11 modules should optimize their behavior for maximum speed or minimum memory footprint.
This document proposes to modify the pk11wrap code which loads and invokes the Module DB library. The proposed modification will make it possible for NSS to use a substitute module DB library, different than the one NSS normally uses in the softoken shared library. Such a substitute module DB library will receive the same string that the module DB library in softoken receives, the string which contains the application's NSS preferences. The substitute library can act on this string.
In the simplest case, a Module DB library simply retrieves and outputs a list of PKCS #11 modules and information about them. In the future, a substitute library could utilize some sort of managed database, select PKCS#11 modules according to the appropriate policy, and make system wide decisions on what softoken databases to load. Such decisions could be based on the application's request, the application itself, and the system administrator's policy.
Note: I gather that Bob is about to propose a new substitute Module DB library implementation that will cause softoken to be initialized with multiple slots, one containing the user's own cert and key DBs (e.g. ~/.pki/nssdb) and one containing some "system" DBs, likely containing trusted root CAs (e.g. /etc/pki/nssdb).
Certificate/Key Migration
[[ Most secure applications had an existence before the crypto consolidation effort. If those applications already had ways to store keys and certs, then there needs to be a way to automatically or semi-automatically migrate the keys and certs from those applications to the central NSS database. To assist in this NSS provides some built in primitives. --- work in progress ]]
Issues to be resolved
- 32-bit vs 64-bit packages: Do 32-bit and 64-bit packages both want to use the same directories, ~/.pki/nssdb and /etc/pki/nssdb, or do we want to have 64-bit versions of those directories, such as ~/.pki64/nssdb and /etc/pki64/nssdb or ~/.pki/nssdb64 and /etc/pki/nssdb64, or perhaps yet some other means?
- what about the case of an NFS-mounted home directory that is used from different machines on different OS platforms. Perhaps the path should also attempt to differentiate by architecture more broadly than just 32/64 bits, e.g. linux-x86-32, linux-x86-64, linux-S360, Linux-sparc-v8plus (32), Linux-sparc-v9 (64), Solaris-sparc-v9, etc., etc.
- More work is still needed on the problems faced by libraries.
- How does a library call NSS initialization functions in a way that works well, whether it is the first caller of NSS_Initialize in the process, or is not the first caller.
- How does a library know if it is the first caller of NSS? Does it need to know?
Other comments
- I don't see anything about this proposal that uniquely ties it to Linux. Seems to me that an improved Module DB Library would be useful on all platforms.