Keep PKCS5S2 usable on a FIPS-restricted JCE, and name the key wrapping property when the runtime has no RSA-OAEP - #1058
Conversation
maximthomas
left a comment
There was a problem hiding this comment.
praise: The fix stays secure and goes where the failures actually happen, without touching the template the way #1054 does.
PKCS5S2PasswordStorageSchemenow takesnew SecureRandom()(:90,:252), as the PBKDF2 family does, and itsInitializationExceptionfinally has a message (:97).supportedKeyWrappingTransformationstill has only an OAEP alternative to fall back to, so #776 holds on a runtime without RSA-OAEP.TestCaseUtils.withoutJceServiceputs the withdrawn providers back at the positions they had (:374), so a later case in the same JVM sees the same provider order.
issue (blocking): Under setup, WARN_CONFIGDS_KEY_WRAPPING_TRANSFORMATION_UNSUPPORTED never reaches the user.
opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureDS.java:1237, opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/Installer.java:1308
Setup runs ConfigureDS.configMain(args, System.out, System.err) in-process (InstallerHelper:117). There, System.err is the Installer's ApplicationPrintStream (Installer:253), and the whole configure step runs inside setNotifyListeners(false) (Installer:1308). ApplicationPrintStream.println reaches the CLI or GUI listeners only if (notifyListeners) (Application:248). Otherwise it only calls logger.info into the setup temp log, and a successful run deletes that log (Installer:311). configMain returns success after the warning. So setup --doNotStart on a SunPKCS11-only runtime still ends silently, as it did before this PR. Only a standalone configure-ds shows the warning. The description ("Setup prints a warning") and the code comment ("has to be told so here rather than by the failed start") both describe the setup road.
Raise the warning from the Installer, after the silenced window:
// Installer.configureServer, after the InvokeThread has finished (notifyListeners is true again)
try
{
ConfigureDS.supportedKeyWrappingTransformation(defaultKeyWrappingTransformation);
}
catch (GeneralSecurityException e)
{
notifyListeners(getFormattedWarning(
WARN_CONFIGDS_KEY_WRAPPING_TRANSFORMATION_UNSUPPORTED.get(defaultKeyWrappingTransformation, e.getMessage())));
}Or, if setup is not meant to warn: drop the setup claim from the description and reword the comment at ConfigureDS.java:1233-1236.
issue (blocking): The FIPS install procedure calls ldifmodify with options it does not have.
opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-install.adoc:826
The only ldifmodify in the distribution is opendj-ldap-toolkit's LDIFModify. It takes trailing arguments source_file [changes_files...] plus -o/--outputLDIF (LDIFModify.java:108, :119). --sourceLDIF, --changesLDIF and --targetLDIF exist nowhere in the tree. An administrator following the one documented way to set key-wrapping-transformation before the first start gets a usage error, and start-ds still refuses to start. (The same stale spelling is in admin-guide/chap-import-export.adoc:230, which predates this PR.)
$ ldifmodify \
-o /path/to/opendj/config/config.ldif.new \
/path/to/opendj/config/config.ldif \
changes.ldifquestion (non-blocking): Should the sentence added to ERR 664 apply only when the transformation itself is refused?
opendj-server-legacy/src/messages/org/opends/messages/core.properties:1197, opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java:424
The try that reports 664 does more than check the cipher. It also computes the instance key ID with MessageDigest "MD5" (:676) and wraps against a hard-coded 1024-bit RSA certificate. A runtime that has RSA-OAEP but lacks MD5, or refuses a 1024-bit wrap, passes ConfigureDS's Cipher.getInstance check without a warning. start-ds then fails with an instruction to change a property that is not the cause. The %s still carries the real exception. I did not run this on an NSS-FIPS or BC-FIPS approved-only JVM. As is, this is a Minor. It becomes a Major if the guide's "with the bundled BC-FIPS provider the default configuration works as it is" is meant to hold in approved-only mode. Splitting the try would give the digest and dummy-certificate failures a message of their own.
suggestion (non-blocking): No test runs the warning road of updateCryptoCipher.
opendj-server-legacy/src/test/java/org/opends/server/tools/ConfigureDSTestCase.java:50
Both cases call only the static supportedKeyWrappingTransformation. Three mutants keep every test green: deleting the printWrappedText(err, WARN_…) line, swapping its two arguments, and dropping the return so that the default gets rewritten. That is how the silencing above got through.
Pin: together with the fix above, run the setup road (or configMain on a test instance) under withoutJceService("Cipher", "RSA", …). Assert that the WARN text reaches the user-visible stream, and that ds-cfg-key-wrapping-transformation still holds the default in config.ldif.
suggestion (non-blocking): The #776 pin cannot see a weaker fallback. Withdrawing Cipher.RSA withdraws RSA/ECB/PKCS1Padding too.
opendj-server-legacy/src/test/java/org/opends/server/tools/ConfigureDSTestCase.java:46
Cipher.getInstance("RSA/ECB/PKCS1Padding") falls back to the Cipher.RSA service, and the fixture has removed it. So a mutant that adds "RSA/ECB/PKCS1Padding" to getAlternativeCipher (ConfigureDS.java:1365) gets null and rethrows, and the test passes against the regression its javadoc names.
withoutJceService("Cipher", "RSA", () ->
{
final Provider weakOnly = new Provider("WeakRsaOnly", "1.0", "PKCS#1 v1.5 only") {};
weakOnly.put("Cipher.RSA/ECB/PKCS1Padding", "com.sun.crypto.provider.RSACipher");
Security.insertProviderAt(weakOnly, 1);
try
{
ConfigureDS.supportedKeyWrappingTransformation(DEFAULT_KEY_WRAPPING_TRANSFORMATION);
fail("a transformation was chosen on a runtime whose only RSA cipher is PKCS#1 v1.5");
}
catch (GeneralSecurityException expected)
{
// the #776 regression returns "RSA/ECB/PKCS1Padding" instead
}
finally
{
Security.removeProvider(weakOnly.getName());
}
return null;
});Or drop "(#776)" from the javadoc.
suggestion (non-blocking): The asserts that the message names the missing algorithm are satisfied by the exception's own text.
opendj-server-legacy/src/test/java/org/opends/server/extensions/PKCS5S2PasswordStorageSchemeTestCase.java:186, opendj-server-legacy/src/test/java/org/opends/server/extensions/PBKDF2PasswordStorageSchemeTestCase.java:98
The second %s of ERR_PWSCHEME_CANNOT_INITIALIZE_MESSAGE_DIGEST is the NoSuchAlgorithmException, whose text is "PBKDF2WithHmacSHA1 SecretKeyFactory not available". So .get(getStorageSchemeName(), e) or .get("", e) in place of the algorithm keeps both cases green.
assertTrue(e.getMessage().contains("for the PBKDF2WithHmacSHA1 algorithm"), e.getMessage());nitpick (non-blocking): testEncodesOfflineWithoutSha1Prng's javadoc names two roads that never reach PKCS5S2PasswordStorageScheme.encodeOffline.
opendj-server-legacy/src/test/java/org/opends/server/extensions/PKCS5S2PasswordStorageSchemeTestCase.java:153
No main code calls it. The initial root password goes through SaltedSHA512PasswordStorageScheme.encodeOffline (ConfigureDS.java:1138), and encode-password goes through the initialized scheme's encodePasswordWithScheme (EncodePassword.java:502). "An offline encoder a tool may call" is accurate. Or drop the clause.
PKCS5S2PasswordStorageScheme asked for SecureRandom "SHA1PRNG" by name, at initialization and again in the offline encoder. A FIPS-restricted JCE (SunPKCS11-NSS-FIPS, BC-FIPS) registers no such algorithm, so the scheme threw a message-less InitializationException and the server refused to start — the failure OpenIdentityPlatform#1054 works around by disabling the scheme in the config template, which would also stop {PKCS5S2} hashes imported from Atlassian products from binding on every new installation. Take the provider's default SecureRandom instead, as the PBKDF2 family already does, and let the InitializationException of both PKCS5S2 and the PBKDF2 schemes name the algorithm that is missing rather than leaving the administrator with no reason for the failed start. The SHA1PRNG constant has no user left and goes. The tests withdraw the providers which register the service — SUN for SHA1PRNG, with BC-FIPS standing in for the digests, SunJCE for PBKDF2WithHmacSHA1 — run the scheme without them, and put them back.
… the runtime has no RSA-OAEP The crypto manager validates its key wrapping transformation when it is created, so a Java runtime whose only RSA cipher is PKCS#1 v1.5 — a SunPKCS11 provider on its own, as on a Linux system in FIPS mode (JDK-6190389 is still open) — cannot start the server with the default, RSA-OAEP. Setup noticed as much in ConfigureDS.updateCryptoCipher and, since OpenIdentityPlatform#776 left it no secure transformation to fall back to, silently kept the default; the failed start which followed named the cipher it could not get and nothing else. Setup now prints a warning naming the transformation, the reason and the property to set before the first start, and the crypto manager's refusal names the property as well. The choice itself stays with the administrator: the install guide gains a procedure for a FIPS 140 runtime which says what the bundled BC-FIPS provider offers, what a SunPKCS11-only runtime does not, and how to set key-wrapping-transformation in config.ldif between setup --doNotStart and start-ds.
…ty only when the transformation is refused Setup runs ConfigureDS in-process with its error stream bound to the installer's ApplicationPrintStream, and silences the progress listeners for the whole configure step, so the warning ConfigureDS printed reached the setup log only, which a successful setup deletes: setup --doNotStart on a runtime without RSA-OAEP still ended silently. ConfigureDS now builds the warning in unsupportedKeyWrappingTransformationWarning(), which the installer calls once the configure step is over, when the listeners are back. A standalone configure-ds still prints it. The check which reports ERR 664 also takes an MD5 digest of the dummy certificate and wraps with its 1024-bit RSA key, so the sentence about key-wrapping-transformation added to that message could point at a property which is not the cause. The transformation is now checked on its own first, and only that refusal (ERR 766) names the property; ERR 664 is back to its original text. The install guide and the admin guide called ldifmodify with --sourceLDIF, --changesLDIF and --targetLDIF, which it does not have: it takes the source and changes files as trailing arguments and the output file with --outputLDIF. The FIPS procedure now says that the default configuration works with the BC-FIPS provider in its default mode, not in approved-only mode. Tests: the setup-time warning, with and without RSA-OAEP, from the installer's entry point and from configure-ds's own step; a runtime whose only RSA cipher is PKCS#1 v1.5 gets no fallback (OpenIdentityPlatform#776), which withdrawing Cipher.RSA alone could not show; a refusal for a cause other than the transformation does not name the property; the scheme initialization failures are asserted on the algorithm argument of the message rather than on the text of the exception it carries.
4ac5363 to
adb4a39
Compare
|
All seven points are taken, in adb4a39 (the branch is rebased onto the current 1. The setup warning (blocking). Confirmed: during the configure step the listeners are off and 2. 3. ERR 664. Split. On approved-only mode, I checked it: with bc-fips 2.1.3 and 4. Warning road untested. 5. #776 pin. Added 6. Message asserts. Both cases now assert 7. Offline encoder javadoc. Now "which a tool may call before any scheme is initialized". Runs (JDK 26, locally): |
Problem
#1054 changes the config template to get a server installed on a FIPS 140-3 Java runtime: it disables the PKCS5S2 password storage scheme and sets
key-wrapping-transformationtoRSA/ECB/PKCS1Padding. The review there explains why neither belongs in the template — PKCS5S2 is PBKDF2-HMAC-SHA1 like thePBKDF2scheme which stays enabled, and PKCS#1 v1.5 is the transformation #776 removed as a CodeQLjava/rsa-without-oaepfinding. What actually fails on such a runtime:PKCS5S2PasswordStorageSchemeasked forSecureRandom"SHA1PRNG" by name, at initialization and in the offline encoder. A FIPS-restricted JCE registers no such algorithm, the scheme threw a message-lessInitializationException, and the server refused to start.SunPKCS11provider on its own, as on a Linux system in FIPS mode; JDK-6190389 is still open — cannot start the server with the RSA-OAEP default. Setup noticed (ConfigureDS.updateCryptoCipher), had no secure fallback left after Fix java/rsa-without-oaep CodeQL alert by dropping the RSA PKCS#1 v1.5 fallback #776, and silently kept the default; the failed start which followed named the cipher it could not get and nothing else.Change
PKCS5S2PasswordStorageSchemetakes the provider's defaultSecureRandom, as the PBKDF2 family does, and itsInitializationException— like the PBKDF2 schemes' — names the algorithm which is missing. TheSHA1PRNGconstant goes. The template keeps the scheme enabled.setupwarns (WARN_CONFIGDS_KEY_WRAPPING_TRANSFORMATION_UNSUPPORTED) with the transformation, the reason and the property to set before the first start. The installer gives the warning itself once the configure step is over, since whatConfigureDSwrites while it runs under setup reaches the setup log only; a standaloneconfigure-dsprints it. At start, a transformation the runtime does not provide is refused withERR_CRYPTOMGR_KEY_WRAPPING_TRANSFORMATION_UNSUPPORTED, which names the property. The rest of that check (MD5 key ID, wrap with the dummy certificate) keepsERR_CRYPTOMGR_CANNOT_GET_PREFERRED_KEY_WRAPPING_CIPHERas it was, since changing the property would not help there. The choice itself stays with the administrator: the install guide gains "To Install OpenDJ Directory Server on a FIPS 140 Java Runtime". With the bundled BC-FIPS provider in its default mode, which offers RSA-OAEP, the default configuration works as it is. A SunPKCS11-only runtime gets thesetup --doNotStart→ldifmodify→start-dsprocedure, with the caveat that PKCS#1 v1.5 is disallowed for key transport by NIST SP 800-131A Rev. 2 and that every replica must use the same transformation. Theldifmodifyexamples of the install and admin guides used options the tool does not have and are corrected.RSA/ECB/NoPadding) is Crypto manager: a FIPS-approved key transport for JVMs whose only RSA cipher is PKCS#1 v1.5 (SunPKCS11) #1056. BC-FIPS in approved-only mode refuses the 1024-bit key of the dummy certificate the start-time check wraps with; that is The start-time key wrapping check wraps with a 1024-bit RSA key, which BC-FIPS refuses in approved-only mode #1081.Testing
The new tests withdraw the JCE providers which register a service, run the code without them, and put the providers back where they were (
TestCaseUtils.withoutJceService):PKCS5S2PasswordStorageSchemeTestCase: the scheme initializes and encodes, online and offline, withoutSHA1PRNG(SUN withdrawn, BC-FIPS standing in for the digests); its initialization failure namesPBKDF2WithHmacSHA1(SunJCE withdrawn). The same failure test forPBKDF2PasswordStorageSchemeTestCase.ConfigureDSTestCase(new): the default transformation stays where the runtime has it. WithoutCipher.RSA, or with a provider offeringRSA/ECB/PKCS1Paddingonly, none is chosen (Fix java/rsa-without-oaep CodeQL alert by dropping the RSA PKCS#1 v1.5 fallback #776). The warning, both as the installer gets it and as configure-ds writes it, names the transformation and the property, and the configuration is not touched.CryptoManagerTestCase: an unsupported transformation is refused with the message that nameskey-wrapping-transformation. A supported one refused for another cause (MD5 withdrawn) is not.Each test was run red before its fix, or against a mutant of it, and green after:
PKCS5S2PasswordStorageSchemeTestCase56/56,PBKDF2PasswordStorageSchemeTestCase40/40,PBKDF2HmacSHA256/512PasswordStorageSchemeTestCase39/39 each,CryptoManagerTestCase32/32,ConfigureDSTestCase5/5. The installer's call is not covered by a test: the setup road does not run in the unit tests.Alternative to #1054. Related: #776, #1056.