Under older JSS versions, it is possible to do the following:
In java.security:
...
security.provider.n = org.mozilla.jss.JSSProvider
...for some n. Other providers may be on either side.
Then, in the code before anything else is done:
public static void main(String[] args) {
InitializationValues ivs = new InitializationValues(args[0]);
ivs.installJSSProvider = false;
CryptoManager.initialize(ivs);
// Rest of the application ...
}Because CryptoManager.initialize(...) doesn't use any Security methods,
loading will be successful. It also means there's exactly one Mozilla-JSS
provider loaded in the correct spot.
However, CryptoManager.initialize(...) must be called, otherwise Java will
crash. This is the behavior exhibited by Candlepin (using netscape.security
without calling CryptoManager.initialize(...).
Under new code, there's two ways to load JSS:
- Directly via
CryptoManager.initialize(...)which ignoresjava.security, or - From
java.security, passing a config file option, which calls the above.
In particular, the pull request
allows a CryptoManager.getInstance(...) call to return a CryptoManager
instance from the java.security loader, if CryptoManager.initialize(...)
hasn't yet been called.
It also introduces a new initialize method which takes two parameters, the
InitializationValues and whether or not to prefer the global JDK
configuration.
In certain tests, we know we want to ignore the global JDK configuration, so
we set this boolean to false.
For backwards compatibility, we've set this value to false for the time
being, however, we could change this to true at a later point, when use
via java.security becomes more widespread.
More documentation is going to land in a separate pull request.
Because java.security is, by default, only a file admins can write changes
to, system-wide (and a file passed by -Djava.security=/some/path complements
it, with == providing a strict override), this means that admins can
upgrade JSS seamlessly, with the application being unaware that they're using
JSS. However, if the application was written for an older version of JSS
(implying the users running the app weren't aware of the upgrade or
restrictions placed by their administrators -- as would be the case if JSS
were shipped as the default FIPS compliant crypto implementation somewhere),
this could cause breakage.
There's three scenarios we want to support:
Trivial; given the options above, choose one.
Trivial; continues working.
This is the harder case. Assuming the new JSS version doesn't break any APIs from the previous target version (e.g., a v4.6.3 -> v4.6.4 change even!), the new JSS should continue to function. This is a reasonable assumption, IMO: we try to break as little as necessary and only add new features / fix bugs.
There's two cases here:
- No
java.security; trivial; depends on what the app uses. java.security: complicated.
In particular, for 2, we have the question of what does the following code do?
In java.security:
security.provider.n = org.mozilla.jss.JSSProviderIn the code:
public static void main(String[] args) {
CryptoManager.initialize("/path/to/nssdb");
// Rest of the application ...
}My view is that, since JSS is new enough, we should load JSS out of the
java.security file instead of the CryptoManager.initialize(...) call.
However, since it is a technically a breaking change, to give applications
a chance to upgrade, we've defaulted to the false form, i.e., prefer local
configuration instead.
This should behave as if JSS was loaded from CryptoManager.initialize(...).
Detection logic is given below if the application wishes to prefer
java.security and maintain fallback code.
There are thus two paths to upgrade a legacy code base to use a newer JSS version:
-
Continue using
CryptoManager.initialize(...)as before. This gives the local application dynamic control over the NSS DB path. -
Switch to using
java.security-based configuration (either via local policy with-Djava.security.properties=/pathor via system-wide policy with modifying$JAVA_HOME/conf/security/java.security) and remove the call toCryptoManager.initialize(...). If this call is necessary for backwards-compatibility reasons (to support multiple JSS versions), it would be sufficient to check the value ofCryptoManager.getInstance(...)before excuting configuration:try { cm = CryptoManager.getInstance(); } catch (NotInitializedException nie) { CryptoManager.initialize(...); cm = CryptoManager.getInstance(); }
This gives the user control over NSS DB path via modifying either of those two configuration files (or by providing a local override).