From 5c6cef6711c47e26cd2aec397d0a49c2b32dbd42 Mon Sep 17 00:00:00 2001 From: Alexander Scheel Date: Tue, 23 Jun 2020 14:29:45 -0400 Subject: [PATCH] Fix loading of CryptoManager in JSSLoader scenario When using JSSLoader to initialize JSSProvider from the java.security list, sometimes CryptoManager.getInstance() will fail. Usually this is because instance is still null, even though Security.getProvider("Mozilla-JSS") != null The error message will usually be something like: FINE: CryptoManager: loading JSS library FINE: CryptoManager: loaded JSS library from java.library.path Exception in thread "main" org.mozilla.jss.NotInitializedException at org.mozilla.jss.CryptoManager.getInstance(CryptoManager.java:365) at org.mozilla.jss.tests.SigTest.main(SigTest.java:52) Allow JSSLoader to return the new CryptoManager object, let JSSProvider store it, so that in this case, CryptoManager.getInstance() will return an initialized instance. Signed-off-by: Alexander Scheel --- org/mozilla/jss/CryptoManager.java | 63 ++++++++++++++++++++---------- org/mozilla/jss/JSSLoader.java | 11 +++--- org/mozilla/jss/JSSProvider.java | 18 ++++++++- tools/jss.cfg.in | 1 - 4 files changed, 65 insertions(+), 28 deletions(-) diff --git a/org/mozilla/jss/CryptoManager.java b/org/mozilla/jss/CryptoManager.java index 1def077e4..20d5269ea 100644 --- a/org/mozilla/jss/CryptoManager.java +++ b/org/mozilla/jss/CryptoManager.java @@ -340,31 +340,54 @@ protected CryptoManager() { * called. * @return CryptoManager instance. */ - public synchronized static CryptoManager getInstance() + public static CryptoManager getInstance() throws NotInitializedException { - if (instance == null) { - /* Java has lazy-loading Security providers; until a provider - * is requested, it won't be loaded. This means we could've - * initialized the CryptoManager via the JSSLoader but we won't - * know about it until it is explicitly requested. - * - * This breaks tests looking to configure a file-based password - * handler: if the very first call is to getInstance(...) instead - * of a Provider call, we'd fail. - * - * Try to get the Mozilla-JSS provider by name before reporting - * that we're not initialized. - */ - if (Security.getProvider("Mozilla-JSS") != null) { - if (instance != null) { - return instance; - } + synchronized (CryptoManager.class) { + if (instance != null) { + return instance; } + } + + /* Java has lazy-loading Security providers; until a provider + * is requested, it won't be loaded. This means we could've + * initialized the CryptoManager via the JSSLoader but we won't + * know about it until it is explicitly requested. + * + * This breaks tests looking to configure a file-based password + * handler: if the very first call is to getInstance(...) instead + * of a Provider call, we'd fail. + * + * Try to get the Mozilla-JSS provider by name before reporting + * that we're not initialized. + * + * However, in order for the JSSProvider to load, we need to + * release our lock on CryptoManager (and in particular, on + * CryptoManager.instance). + */ + java.security.Provider p = Security.getProvider("Mozilla-JSS"); + + synchronized (CryptoManager.class) { + // When instance is properly configured, use that. + if (instance != null) { + return instance; + } + + // Otherwise, work around this by looking at what JSSProvider + // created. + if (p instanceof JSSProvider) { + JSSProvider jssProvider = (JSSProvider) p; + assert jssProvider.getCryptoManager() != null; - throw new NotInitializedException(); + if (instance == null) { + instance = jssProvider.getCryptoManager(); + } + + return instance; + } } - return instance; + + throw new NotInitializedException(); } /** diff --git a/org/mozilla/jss/JSSLoader.java b/org/mozilla/jss/JSSLoader.java index bc526ee7d..c102dad42 100644 --- a/org/mozilla/jss/JSSLoader.java +++ b/org/mozilla/jss/JSSLoader.java @@ -92,7 +92,7 @@ public static boolean loaded() { /** * Initialize JSS from the specified path to a configuration file. */ - public static void init(String config_path) throws Exception { + public static CryptoManager init(String config_path) throws Exception { if (config_path == null) { String msg = "Please specify the path to the JSS configuration "; msg += "file in the java.security provider list."; @@ -100,17 +100,16 @@ public static void init(String config_path) throws Exception { } try (FileInputStream fistream = new FileInputStream(config_path)) { - init(fistream); - return; + return init(fistream); } } /** * Initialize JSS from an InputStream. */ - public static void init(InputStream istream) throws Exception { + public static CryptoManager init(InputStream istream) throws Exception { if (loaded()) { - return; + return CryptoManager.getInstance(); } if (istream == null) { @@ -137,6 +136,8 @@ public static void init(InputStream istream) throws Exception { parsePasswords(config, cm); parseExperimental(config); + + return cm; } /** diff --git a/org/mozilla/jss/JSSProvider.java b/org/mozilla/jss/JSSProvider.java index 8b9637bfd..eb2c76b8a 100644 --- a/org/mozilla/jss/JSSProvider.java +++ b/org/mozilla/jss/JSSProvider.java @@ -26,6 +26,8 @@ public final class JSSProvider extends java.security.Provider { private static JSSLoader loader = new JSSLoader(); + private static CryptoManager cm; + public JSSProvider() { this(loader.loaded()); } @@ -48,7 +50,7 @@ public JSSProvider(String config_path) throws Exception { public JSSProvider(InputStream config) throws Exception { this(false); - loader.init(config); + cm = loader.init(config); initializeProvider(); } @@ -63,7 +65,7 @@ public JSSProvider(InputStream config) throws Exception { */ public Provider configure(String arg) { try { - loader.init(arg); + cm = loader.init(arg); } catch (NullPointerException npe) { throw npe; } catch (Exception e) { @@ -75,6 +77,18 @@ public Provider configure(String arg) { return this; } + /** + * Return the CryptoManager this instance was initialized with. + */ + public CryptoManager getCryptoManager() { + if (cm == null) { + try { + cm = CryptoManager.getInstance(); + } catch (NotInitializedException nie) {} + } + return cm; + } + protected void initializeProvider() { ///////////////////////////////////////////////////////////// // Signature diff --git a/tools/jss.cfg.in b/tools/jss.cfg.in index dac8b3600..64d375adb 100644 --- a/tools/jss.cfg.in +++ b/tools/jss.cfg.in @@ -1,4 +1,3 @@ nss.config_dir=${NSS_DB_PATH} -nss.cooperate=true jss.password=${DB_PWD} jss.experimental.sslengine=true