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.JSSProvider
In 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=/path
or 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).