NSS Library Init

From MozillaWiki
Revision as of 23:11, 19 August 2009 by Relyea (talk | contribs) (→‎Problem)
Jump to navigation Jump to search

NSS Library Initialization

Problem

NSS was designed as a library that a single application would use. The application would control how NSS was initialized and configured. Applications would initialize NSS early before any other libraries that used NSS could run. NSS init is idempotent, so stand alone libraries could initialize NSS successfully even if the application had already initialized NSS. These libraries would use the application's configuration for certificates and trust. If NSS wasn't initialized, the libraries would use the configuration the library specifies. Libraries would typically detect the case where the application already initialized NSS and would not shut NSS down.

There are a couple of problems with this set up:

  1. Like initialization, NSS shutdown is global over the entire application. This means if the library calls shutdown while the application has NSS open, the application would experience NSS errors and crashes when it made NSS function calls subsequent to the NSS shutdown. This was partially solved by libraries checking to see if NSS was already initialized and skip the later shutdown if it was. This scheme has problems if either the library initialized NSS before the application, or the application shutdown NSS before the library was ready.
  2. In the same way if the application shuts NSS down without the library knowing, they library will experience crashes.
  3. If the library needs different databases to do its functions from those that the application opened, it won't be able to access them.
  4. If the library initializes NSS first, and it choosed different databases or it needs to access these databases differently (R/W, for instance), it won't be able to function properly since the library's idea of database configuration is.
  5. If the application or library have different lists of trusted CA's, the first list wins.
  6. Multiple libraries may be using NSS multiplying the magnitude of these problem.

How we initially viewed solving this problem:

We intended to go to a single user/machine configuration for most applications and libraries, where all applications open the same set of databases for a particular user and machine. This configuration would eventually be outside the application, and part of the system. The problem with this approach is that not all NSS applications run on systems which will have a 'system configured' NSS. In addition, there are still cases here you may want to keep multiple different configurations for testing (mozilla profiles for example). Finally, many applications only need read/only access to the NSS configuration, but some applications (like firefox, or thunderbird) need read/write access. This means if a read/only user initializes first, then the read/write user will not be able to update the database.

Restrictions on any future solution:

1) NSS must maintain binary compatibility. Applications should not become more broken as a result of linking with this new functionality. This means the existing shutdown should shutdown NSS in the same way that it has in the past.

The existing shutdown will close down all NSS internal references to object and free up internal lists. It is possible that the application may still have NSS objects open in its address space (references to slots, keys, or certs that NSS has returned to it). NSS will shutdown all slots that do not have outstanding object references to them. If NSS cannot shutdown all slots, it will return an error. At this point NSS is 'shutdown', but it will not be able to initialized again until all those outstanding references are freed.

Few applications depend on this behavior, but there are some, usually applications which have some sort of dynamic profile switching code. Even though these apps are few, they must still continue to work.

2) NSS still maintains a single 'trust domain' in which certificates are verified against. Internally NSS has the ability to process on independent trust domains, but the neither the creation of new trust domains, nor the passing of such trust domains to the certificate verification code is currently supported.

This feature has been a long standing 'wish list' for NSS, and has not been implemented since there has been no demand from customers. In general most uses of trust domain is better handled by the use of policies rather then different CA trees. The only use case currently identified is in virtual hosting services which services multiple customers through a single process web server.

Proposal

Provide a new NSS call to initialize NSS: NSS_Library_Init(). This call would be made by system libraries that use NSS. NSS_Library_Init() would take the same parameters as NSS_Init(), but it will return a context the library would save. This context would be passed to NSS_Library_Shutdown(). The semantics and interaction of these initialization functions are as follows:

1. Multiple NSS_Library_Init() calls are allowed. Each call will get it's own context. NSS will keep a count of NSS_Library_Init calls. If the database referenced by a given NSS library init call has not been opened, NSS_Library_Init() will open that database in a new slot.

2. NSS_Init will continue to function as it does today with the following exception: while multple NSS_Init calls are idempotent, NSS_Init() called after one or more NSS_Library_Init() calls will function just as NSS_Library_Init() does with respect opening new databases. In addition, the 'main' database from NSS_Init() will be the database returned by PK11_GetInternalPrivateKeyDB().

3. NSS_Library_Shutdown() can be called once per context. If NSS_Library_Shutdown is called a second time on a context an error is returned. NSS_Library_Shutdown() will shutdown NSS if there are no more active contexts returned by NSS_Library_Init and NSS_Init() has not been called.

4. An application that initialized NSS with NSS_Init() can call NSS_Library_Shutdown() with NULL. This will close out the NSS_Init() call, but will only shutdown NSS if all the active contexts are also closed.

5. NSS_Shutdown() will operate as it does today. NSS will completely shutdown, active contexts will be closed.


Signature for the new functions:

typedef NSSInitContextStr *NSSInitContext; /* opaque */
NSSInitContext *NSS_Library_Init(const char *configdir,
       const char *certPrefix, const char *keyPrefix,
       const char *secmodName, PRUint32 flags);
SECStatus NSS_LibraryShutdown(NSSInitContext *);