{"record":{"id":"b632f15c77543ed0","repo":"Homebrew/homebrew-core","slug":"failed-to-initialize-non-fips-provider","errorCode":null,"errorMessage":"Failed to initialize non-FIPS provider","messagePattern":"Failed to initialize non-FIPS provider","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"Formula/n/nexus.rb","lineNumber":200,"sourceCode":"index dfeb6f0..38e067c 100644\n--- a/public/common/components/nexus-crypto/src/main/java/org/sonatype/nexus/crypto/internal/CryptoHelperImpl.java\n+++ b/public/common/components/nexus-crypto/src/main/java/org/sonatype/nexus/crypto/internal/CryptoHelperImpl.java\n@@ -87,8 +87,25 @@ public class CryptoHelperImpl\n   }\n \n   private static void loadNonFipsProvider() {\n-    // BouncyCastleProvider must be set as the last provider\n-    Security.addProvider(new BouncyCastleProvider());\n+    try {\n+      Class<?> providerClass =\n+          getNonFipsClassLoader().loadClass(\"org.bouncycastle.jce.provider.BouncyCastleProvider\");\n+      Provider provider = (Provider) providerClass.getConstructor().newInstance();\n+      // BouncyCastleProvider must be set as the last provider\n+      Security.addProvider(provider);\n+    }\n+    catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException\n+        | InstantiationException | IllegalAccessException e) {\n+      throw new RuntimeException(\"Failed to initialize non-FIPS provider\", e);\n+    }\n+  }\n+\n+  private static URLClassLoader getNonFipsClassLoader() {\n+    // Load bcprov and bcutil in an isolated classloader to prevent bc-fips classes\n+    // (which share org.bouncycastle.crypto.* package names) from interfering.\n+    URL bcprovUrl = BouncyCastleProvider.class.getProtectionDomain().getCodeSource().getLocation();\n+    URL bcutilUrl = org.bouncycastle.util.Arrays.class.getProtectionDomain().getCodeSource().getLocation();\n+    return new URLClassLoader(new URL[]{bcprovUrl, bcutilUrl}, null);\n   }\n \n   private static void loadFipsProvider() {\ndiff --git a/public/common/components/nexus-scheduling/src/main/java/org/sonatype/nexus/scheduling/internal/NoopRecoveryModeService.java b/public/common/components/nexus-scheduling/src/main/java/org/sonatype/nexus/scheduling/internal/NoopRecoveryModeService.java\nnew file mode 100644\nindex 0000000..9279594\n--- /dev/null\n+++ b/public/common/components/nexus-scheduling/src/main/java/org/sonatype/nexus/scheduling/internal/NoopRecoveryModeService.java\n@@ -0,0 +1,26 @@","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/Homebrew/homebrew-core/blob/c0cb250747358d289b951bffea74f18e4dfeea95/Formula/n/nexus.rb#L182-L218","documentation":"RuntimeException thrown by the patched org.sonatype.nexus.crypto.internal.CryptoHelperImpl.loadNonFipsProvider() (patch hunk carried at Formula/n/nexus.rb:200) when it cannot reflectively load and instantiate org.bouncycastle.jce.provider.BouncyCastleProvider. The provider is deliberately loaded through an isolated URLClassLoader (bcprov + bcutil only, parent=null) so that bc-fips classes, which share the org.bouncycastle.crypto.* package namespace, cannot interfere. The catch clause covers ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException and IllegalAccessException, so any mismatch between the expected class/jar layout and reality aborts crypto initialization.","triggerScenarios":"Calling the static initialization path of CryptoHelperImpl (i.e. Nexus startup / brew install nexus smoke run) when: (a) bcprov or bcutil jar is missing from the classpath so getNonFipsClassLoader() cannot resolve a code-source URL; (b) the BC version's jar split differs (org.bouncycastle.util.Arrays moved between bcprov and bcutil across releases) so the two URLs point at jars that do not contain the expected entries; (c) the provider constructor throws (InvocationTargetException) because it needs a class outside the two-jar, parentless loader; (d) code source getLocation() returns null (module/jrt or custom loader); (e) a bc-fips-only deployment where BouncyCastleProvider (non-FIPS) does not exist at all.","commonSituations":"Upgrading BouncyCastle versions where classes relocate between bcprov/bcutil; mixing bc-fips artifacts with regular bcprov/bcutil on one classpath (the exact interference this patch isolates against); shaded or relocated uber-jars where code-source URLs no longer match the expected jars; trimmed distributions that drop bcutil; running under a JRE/container where the protection domain reports no location. Note a hard NoClassDefFoundError on the BouncyCastleProvider.class reference itself escapes the catch clause and surfaces raw.","solutions":["Read the wrapped cause first: log/inspect getCause() (and the nested cause chain) — ClassNotFoundException points to a missing/wrong jar, InvocationTargetException to a constructor failure inside the isolated loader.","Verify both jars on the runtime classpath actually contain the classes used for code-source discovery: jar tf bcprov-*.jar | grep 'jce/provider/BouncyCastleProvider.class' and jar tf bcutil-*.jar | grep 'util/Arrays.class'; fix the version pair if either is missing.","If the constructor fails because it references classes outside the two jars, extend the URL[] in getNonFipsClassLoader() with the missing jar(s), or pass a suitable parent classloader instead of null.","Ensure non-FIPS bcprov/bcutil are present even when bc-fips is deployed, and that the non-FIPS and FIPS artifact versions are the pair Nexus expects; do not shade/relocate the BouncyCastle jars for this deployment.","Guard getLocation() results for null and fail with an explicit message naming the unresolved class before building the URLClassLoader."],"exampleFix":"// before\nprivate static URLClassLoader getNonFipsClassLoader() {\n  URL bcprovUrl = BouncyCastleProvider.class.getProtectionDomain().getCodeSource().getLocation();\n  URL bcutilUrl = org.bouncycastle.util.Arrays.class.getProtectionDomain().getCodeSource().getLocation();\n  return new URLClassLoader(new URL[]{bcprovUrl, bcutilUrl}, null);\n}\n\n// after\nprivate static URLClassLoader getNonFipsClassLoader() {\n  URL bcprovUrl = requireCodeSource(BouncyCastleProvider.class);\n  URL bcutilUrl = requireCodeSource(org.bouncycastle.util.Arrays.class);\n  return new URLClassLoader(new URL[]{bcprovUrl, bcutilUrl}, null);\n}\n\nprivate static URL requireCodeSource(Class<?> clazz) {\n  URL url = clazz.getProtectionDomain().getCodeSource().getLocation();\n  if (url == null) {\n    throw new IllegalStateException(\"No code source for \" + clazz.getName() + \"; cannot build isolated BC classloader\");\n  }\n  return url;\n}","handlingStrategy":"try-catch","validationCode":"// Run before Nexus/crypto init to confirm the isolated BC load will succeed\nstatic boolean nonFipsProviderLoadable() {\n  URL bcprov = BouncyCastleProvider.class.getProtectionDomain().getCodeSource().getLocation();\n  URL bcutil = org.bouncycastle.util.Arrays.class.getProtectionDomain().getCodeSource().getLocation();\n  if (bcprov == null || bcutil == null) return false;\n  try (URLClassLoader cl = new URLClassLoader(new URL[]{bcprov, bcutil}, null)) {\n    return cl.loadClass(\"org.bouncycastle.jce.provider.BouncyCastleProvider\").getConstructor() != null;\n  } catch (ReflectiveOperationException | RuntimeException e) {\n    return false;\n  }\n}","typeGuard":null,"tryCatchPattern":"// CryptoHelperImpl init runs in a static block, so catch the wrapper AND the static-init error\ntry {\n  // ... trigger crypto helper initialization ...\n} catch (ExceptionInInitializerError e) {\n  Throwable root = unwrap(e.getException()); // walk getCause() chain\n  if (root instanceof ClassNotFoundException) { /* bcprov/bcutil jar missing or version mismatch */ }\n  else if (root instanceof InvocationTargetException && root.getCause() != null) { /* provider constructor failed inside isolated loader */ }\n  throw new IllegalStateException(\"Non-FIPS BC provider init failed: \" + root, root);\n} catch (RuntimeException e) { // if not via static init\n  throw new IllegalStateException(\"Non-FIPS BC provider init failed: \" + unwrap(e), e);\n}","preventionTips":["Pin bcprov and bcutil to a matched version pair in the distribution; never let them drift independently.","Do not deploy bc-fips and non-FIPS bcprov/bcutil on the same classpath without the isolated-classloader isolation this patch implements.","After any BouncyCastle upgrade, verify org.bouncycastle.util.Arrays still lives in the jar your code-source discovery assumes (it has moved between bcprov and bcutil across releases).","Add a startup smoke assertion that Security.getProvider(\"BC\") is non-null after crypto init so silent provider-loss fails loudly.","Never shade or relocate the BouncyCastle jars in a deployment that relies on code-source-based classloader isolation."],"tags":["java","bouncycastle","reflection","urlclassloader","classpath","nexus","homebrew","runtime-exception"],"backgroundTag":"classpath-conflict","analyzedSha":"c0cb250747358d289b951bffea74f18e4dfeea95","analyzedAt":"2026-08-21T14:47:57.847Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}