NSS Library Init

From MozillaWiki
Revision as of 21:48, 1 September 2009 by Nelsonb (talk | contribs) (word smithing and seeking some clarifications)
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. An application would initialize NSS early before any libraries that used NSS could run. NSS initialization is idempotent, so system libraries could initialize NSS successfully after the application had already initialized NSS. Then, whether called by the application or by system libraries, NSS would use the application's configuration for certificates and trust. If NSS wasn't initialized by the application before it was initialized by system libraries, NSS would use the configuration files specified by the system libraries. Libraries would typically detect the case where NSS was already initialized before they used it, and would remember that, and would not shut NSS down when they were shut down.

There are several problems with that design:

  1. Like initialization, NSS shutdown is global over the entire application, and is forceful. Consequently, if the library shuts down NSS without the application's knowledge, and the application makes subsequent calls to NSS functions, those calls would experience errors or even crashes. Libraries can reduce this risk by checking to see if NSS is already initialized when they start, and if it was, then do not attempt to shut down NSS later when they are finished. However, this approach still has problems in cases where the library has initialized NSS before the application.
  2. In the same way, if the application shuts NSS down without the library knowing, they library may experience errors or crashes.
  3. If the library needs different databases to do its functions than those that the application opened, the library won't be able to access them.
  4. If the library initializes NSS first, and it chose different databases than the application wants, or it initializes the databases read-only but the application needs read-write access, the application won't be able to access the databases it desires in the desired fashion.
  5. If the application or library have different lists of trusted CA's, the first initializer's list wins.
  6. Multiple libraries may be using NSS, multiplying the problems.

How we initially intended to solve these problems:

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 not in any any one application's specific directory of application configuration files, but would be part of the system. One 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 where the user may want to keep multiple different configurations for testing (Mozilla profiles for example). Finally, some applications only need read-only access to the NSS configuration, but other applications (like Firefox, or Thunderbird) need read-write access. This means if a read/only application initializes first, then a read/write application will not be able to update the database. (what?? --MisterTLS 21:48, 1 September 2009 (UTC) )

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 hold references to NSS objects (such as slots, keys, or certs that NSS has returned to it) in its address space. 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. (Do you mean continue to fail? --MisterTLS 21:48, 1 September 2009 (UTC) )

2) NSS still maintains a single 'trust domain' in which certificates are verified. In a single process, NSS has the ability to process certificates in the context of any one of several independent trust domains, but many of NSS's existing API functions do not allow a trust domain to be explicitly specified.

Support for explicit trust domains has long been on the NSS developers' 'wish list' but has not been implemented because there has been little or no demand from products that use NSS. Many uses of explicit trust domains may be better handled by the use of certificate policies. The primary use case for explicit trust domains currently identified is in virtual hosting services that service 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 struct NSSInitContextStr NSSInitContext; /* opaque */
NSSInitContext *NSS_Library_Init(const char *configdir,
       const char *certPrefix, const char *keyPrefix,
       const char *secmodName, PRUint32 flags);
SECStatus NSS_Library_Shutdown(NSSInitContext *);