{"record":{"id":"02dd899354940fbc","repo":"apache/pulsar","slug":"keystore-creation-error","errorCode":null,"errorMessage":"KeyStore creation error","messagePattern":"KeyStore creation error","errorType":"exception","errorClass":"KeyStoreException","httpStatus":null,"severity":"critical","filePath":"pulsar-common/src/main/java/org/apache/pulsar/common/util/KeyStoreHolder.java","lineNumber":76,"sourceCode":"     *                    empty entry password are used, exactly as before)\n     * @throws KeyStoreException if the store cannot be created or the pinned provider supplies no usable type\n     */\n    public KeyStoreHolder(Provider jcaProvider) throws KeyStoreException {\n        // Backward compatibility: only the opt-in pinned-provider path changes the entry password. This class is\n        // public and unrelocated, so callers that still pass \"\".toCharArray() to KeyManagerFactory.init() must\n        // keep working on the default path.\n        this.entryPassword = jcaProvider == null ? new char[0] : JcaKeyStores.newInMemoryPassword();\n        try {\n            String storeType = JcaKeyStores.inMemoryStoreType(jcaProvider, KeyStore.getDefaultType());\n            keyStore = JcaKeyStores.keyStore(storeType, jcaProvider);\n            keyStore.load(null, null);\n        } catch (KeyStoreException e) {\n            // JcaKeyStores raises this with an actionable message naming the pinned provider and the store\n            // types it does register; wrapping it in a generic \"KeyStore creation error\" would bury exactly\n            // the text the operator needs, since only the cause would carry it.\n            throw e;\n        } catch (GeneralSecurityException | IOException e) {\n            throw new KeyStoreException(\"KeyStore creation error\", e);\n        }\n    }\n\n    public KeyStore getKeyStore() {\n        return keyStore;\n    }\n\n    /**\n     * @return the password this holder's key entries are stored under; a {@code KeyManagerFactory} reading\n     *         them must be initialized with it. A fresh copy is returned on each call and is owned by the\n     *         caller, who should zero it once the factory has consumed it (as\n     *         {@code JdkSslContexts.setupKeyManager} does) rather than leaving the plaintext password\n     *         reachable.\n     */\n    public char[] getEntryPassword() {\n        return Arrays.copyOf(entryPassword, entryPassword.length);\n    }\n","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-common/src/main/java/org/apache/pulsar/common/util/KeyStoreHolder.java#L58-L94","documentation":"KeyStoreHolder's constructor creates an in-memory KeyStore via JcaKeyStores and loads it. Any GeneralSecurityException or IOException during creation/load (other than the provider-specific KeyStoreException, which is rethrown unwrapped with an actionable message) is wrapped as KeyStoreException(\"KeyStore creation error\") with the original as cause.","triggerScenarios":"new KeyStoreHolder() or new KeyStoreHolder(provider) throwing during KeyStore.getInstance/store-type resolution or keyStore.load(null, null) — e.g. IOException or a non-KeyStoreException security error while instantiating the store type for the pinned provider.","commonSituations":"JVM misconfiguration where the default keystore type (e.g. PKCS12/JKS) provider is unavailable or broken (tampered java.security file, FIPS-only environment without BCFKS support); pinning a jcaProvider that does not support an in-memory store type.","solutions":["Inspect the cause attached to the KeyStoreException — it holds the real error from the JCA provider.","If pinning a provider, verify it registers an in-memory store type (PKCS12/BCFKS); the provider-specific KeyStoreException is propagated unwrapped with details naming supported types.","Check the JVM's java.security and installed security providers; restore the default JDK configuration if it was modified.","Construct the holder early at startup (fail fast) rather than lazily during TLS handshake setup."],"exampleFix":"// before\nKeyStoreHolder holder = new KeyStoreHolder(pinnedProvider); // \"KeyStore creation error\"\n// after\nif (pinnedProvider != null && Security.getProvider(pinnedProvider.getName()) == null) {\n    throw new IllegalStateException(\"pinned provider not registered: \" + pinnedProvider.getName());\n}\nKeyStoreHolder holder = new KeyStoreHolder(pinnedProvider);","handlingStrategy":"try-catch","validationCode":"static void checkProvidersReady(Provider pinned) {\n    if (pinned != null && Security.getProvider(pinned.getName()) == null) {\n        throw new IllegalStateException(\"pinned JCA provider not registered: \" + pinned.getName());\n    }\n    // sanity: default store type must be creatable\n    try {\n        KeyStore.getInstance(KeyStore.getDefaultType());\n    } catch (KeyStoreException e) {\n        throw new IllegalStateException(\"default KeyStore type unavailable: \" + KeyStore.getDefaultType(), e);\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    KeyStoreHolder holder = new KeyStoreHolder(pinnedProvider);\n} catch (KeyStoreException e) {\n    // cause holds the real JCA/IO error (store type unavailable, provider broken, JVM security config)\n    throw new RuntimeException(\"in-memory keystore init failed: \" + e.getCause(), e);\n}","preventionTips":["Verify java.security providers config is unmodified in production images","Confirm the pinned provider registers an in-memory store type before enabling PIP-478 pinning","Create the holder at startup to fail fast, not during first TLS use","Always log e.getCause() — the wrapper message is generic by design"],"tags":["security","keystore","tls"],"backgroundTag":"keystore-initialization-failed","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}