NSS Library Init: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
Line 59: Line 59:


== FAQ ==
== FAQ ==
1. Shouldn't the NSSInitContext be passed to functions like PK11_GetBestSlot() or CERT_VerfiyCertificate()?
No. First, changing these signatures would not be allowed under the NSS binary compatibility guarantee. Second, the NSSInitContext is only a way to match up NSS_InitContext and NSS_ShutdownContext calls to prevent multiple libraries from prematurely closing NSS on each other.
2. But what if you need to have differently configured trust and certs for different subsystems?
That problem is explicitly not being solved by this proposal. So far I've seen one convincing use of trust domains (that is a single process virtual hosting environment). Most proposed scenarios for using multiple trust domains are really better handled using certificate policy. Using a different root cert for each kind of access tends not to scale well.
That being said, adding trust domain support remains an option in the future. In all these cases, however, it's clear that trust domain support should be separate for NSS_Initialization. If you have multiple trust domains, you will most certainly want to support them in the context of a single NSS_Initialization.
Finally, in most cases, a library using NSS in the context of an application that is already using NSS, should use the configuation of the application anyway. User's don't view the combination as a separate entity, but a single application. When the user configures his certs in thunderbird, he will be surprised if those certs aren't available to his ldap library, for instance.
In short NSSInitContexts are not meant to be replacement for trust domains.
3. What happens if NSS_Init is called more than once?
If NSS_Init is called more than once (without an intervening NSS_Shutdown), the second NSS_Init returns SECSuccess without doing anything, just as it does today. This is to keep current applications which depend on this behavior from breaking.
4. What happens if I only call NSS_InitContext()?
NSS is fully initialized, and will stay initialized at least until you call NSS_ShutdownContext(), or someone calls NSS_Shutdown().
5. Why does NSS_Shutdown() always shutdown, rather than just shutdown the NSS_Init side?
Some applications (at least in the past), call NSS_Shutdown() to 'switch profiles'. In order for this to work, NSS_Shutdown() must try to shutdown NSS completely.
NOTE: If some library attached to this application is actively using NSS at the time (open SSL connection, holding cert, key, or slot references, etc.), NSS_Shutdown() does not completely shutdown today. In light of this fact, it may be better to treat NSS_Shutdown() with the semantics described for NSS_ShutdownContext(NULL). I believe I can be talked into this semantic, but I wrote the proposal for the most conservative position on binary compatibility.
6. What happens if you call a PKCS #11 module which has already been initialized?
When a someone attempts to initialize a PKCS #11 module a second time, the PKCS #11 module will return CKR_LIBRARY_ALREADY_INITIALIZED. At this point one of two things happen:
1) If the PKCS #11 module supports the NSS 'add new slot' protocol, then NSS will add a new slow with the new configuration.
2) For most modules we will move on. The requested module is already initialized and loaded in the trust domain, there is no further work needed to use it.
7. FIPS question [still working on it..]

Revision as of 01:14, 2 September 2009

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 be in 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 library initializes first, then a read/write application will not be able to update the database. (what?? --MisterTLS 21:48, 1 September 2009 (UTC) I've changed application->library. This is a real issue that I believe sun reported. PAM calls pam-ldap which initializes NSS read only. now FF and TB can't get to their databases.)

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) no, I mean continue to work. Applications that call the base NSS_InitXXX expect it to be idempotent. It will continue to be. Applications expect to call NSS_Shutdown() and be able to switch profiles. This will continue to work as well. This last one we can discuss. It may make more sense for NSS_Shutdown to work as NSS_ShutdownContext(NULL) does. )

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_InitContext(). This call would be made by system libraries that use NSS. NSS_InitContext() would take the same parameters as NSS_Init()*, but it will return a context that the library would save. This context would be passed to NSS_ShutdownContext(). The semantics and interaction of these initialization functions are as follows:

1. Multiple NSS_InitContext() calls are allowed. Each call will get it's own context. NSS will keep track of NSS_InitContext() calls. (why? --MisterTLS 22:00, 1 September 2009 (UTC) see NSS_ShutdownContext) If the database referenced by a given NSS library init call has not been opened, NSS_InitContext() 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_InitContext() calls will function just as NSS_InitContext() does with respect opening new databases. In addition, the 'main' database from NSS_Init() will be the database returned by PK11_GetInternalKeySlot().

3. NSS_ShutdownContext() can be called once per context. If NSS_ShutdownContext is called a second time on the same context, an error is returned. NSS_ShutdownContext() will shut down NSS if there are no more active contexts returned by NSS_InitContext() and NSS_Init() has not been called.

4. An application that initialized NSS with NSS_Init() can call NSS_LibraryShutdown() with NULL. This will close out the NSS_Init() call, but will only shutdown NSS if all the active contexts are also closed. (What if NSS_Init has been called multiple times? Clearly spelled out in item 2-- 'as it does today.... calls are idempotent...' I'd be happy to take suggestions on how to wordsmith it better. I started to adjust the current words, but found I couldn't improve on them--MisterTLS 22:00, 1 September 2009 (UTC) )

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_InitContext(const char *configdir,
       const char *certPrefix, const char *keyPrefix,
       const char *secmodName, PRUint32 flags);
SECStatus NSS_ShutdownContext(NSSInitContext *);

FAQ

1. Shouldn't the NSSInitContext be passed to functions like PK11_GetBestSlot() or CERT_VerfiyCertificate()?

No. First, changing these signatures would not be allowed under the NSS binary compatibility guarantee. Second, the NSSInitContext is only a way to match up NSS_InitContext and NSS_ShutdownContext calls to prevent multiple libraries from prematurely closing NSS on each other.

2. But what if you need to have differently configured trust and certs for different subsystems?

That problem is explicitly not being solved by this proposal. So far I've seen one convincing use of trust domains (that is a single process virtual hosting environment). Most proposed scenarios for using multiple trust domains are really better handled using certificate policy. Using a different root cert for each kind of access tends not to scale well.

That being said, adding trust domain support remains an option in the future. In all these cases, however, it's clear that trust domain support should be separate for NSS_Initialization. If you have multiple trust domains, you will most certainly want to support them in the context of a single NSS_Initialization.

Finally, in most cases, a library using NSS in the context of an application that is already using NSS, should use the configuation of the application anyway. User's don't view the combination as a separate entity, but a single application. When the user configures his certs in thunderbird, he will be surprised if those certs aren't available to his ldap library, for instance.

In short NSSInitContexts are not meant to be replacement for trust domains.

3. What happens if NSS_Init is called more than once?

If NSS_Init is called more than once (without an intervening NSS_Shutdown), the second NSS_Init returns SECSuccess without doing anything, just as it does today. This is to keep current applications which depend on this behavior from breaking.

4. What happens if I only call NSS_InitContext()?

NSS is fully initialized, and will stay initialized at least until you call NSS_ShutdownContext(), or someone calls NSS_Shutdown().

5. Why does NSS_Shutdown() always shutdown, rather than just shutdown the NSS_Init side?

Some applications (at least in the past), call NSS_Shutdown() to 'switch profiles'. In order for this to work, NSS_Shutdown() must try to shutdown NSS completely.

NOTE: If some library attached to this application is actively using NSS at the time (open SSL connection, holding cert, key, or slot references, etc.), NSS_Shutdown() does not completely shutdown today. In light of this fact, it may be better to treat NSS_Shutdown() with the semantics described for NSS_ShutdownContext(NULL). I believe I can be talked into this semantic, but I wrote the proposal for the most conservative position on binary compatibility.

6. What happens if you call a PKCS #11 module which has already been initialized?

When a someone attempts to initialize a PKCS #11 module a second time, the PKCS #11 module will return CKR_LIBRARY_ALREADY_INITIALIZED. At this point one of two things happen: 1) If the PKCS #11 module supports the NSS 'add new slot' protocol, then NSS will add a new slow with the new configuration. 2) For most modules we will move on. The requested module is already initialized and loaded in the trust domain, there is no further work needed to use it.

7. FIPS question [still working on it..]