BCFIPS Cipher exception in Java 8, but not 9+

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

BCFIPS Cipher exception in Java 8, but not 9+

Phil Edwards
(Resending after the "gmail bounce auto-unsub" bit me.  The web
archives don't show anything past March of this year; forgive me if
this actually went through the first time.)


We're using BCFIPS 1.0.1 as a drop-in replacement JCE provider, and
after some initial hiccups, we've had pretty good results.  We've just
hit a snag that I'm at a loss to unravel.  For context, we create the
BCFIPS instance via the moral equivalent of

   Provider bc = new
BouncyCastleFipsProvider("C:DEFRND[HMACSHA512];ENABLE{ALL};");

There's actually some reflection involved, etc, but that's what it
boils down to.

123456789012345678901234567890123456789012345678901234567890
The situation is wrapping an asymmetric public key.  For backwards
compatibility, the wrapping transform spec is
"RSA/ECB/PKCS1Padding", but I'm aware that for key wrapping the
"ECB" is a misnomer.  (I've been pushing for us to switch to all-OAEP
rather than PKCS1Padding for these situations, but there's a lot of
organizational inertia involved, and the organization involved is large.
We also have to work with other JCE providers, so it's a "least common
denominator" codebase in many places.  And the use case here is not
one in which we're too worried about PKCS#1 padding oracles.)

   Key key = ... an instance of PublicKey to do the wrapping ...

   Cipher cipher = Cipher.getInstance ("RSA/ECB/PKCS1Padding", bc);
   cipher.init (Cipher.WRAP_MODE, key);

Under Java 8, that call to init() throws InvalidParameterSpecException with
"OAEPParameterSpec required to initialise an OAEP AlgorithmParameters
object".  The stack looks like this:

org.bouncycastle.jcajce.provider.ProvRSA$OAEPAlgorithmParameters.engineInit(ProvRSA.java:1407)
java.security.AlgorithmParameters.init(AlgorithmParameters.java:275)
org.bouncycastle.jcajce.provider.BaseSingleBlockCipher.engineGetParameters(BaseSingleBlockCipher.java:282)
javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1020)
javax.crypto.Cipher.init(Cipher.java:1245)
javax.crypto.Cipher.init(Cipher.java:1186)

Very briefly, the JCE Cipher does (sorry about the formatting):
   Cipher.init --> Cipher.checkCryptoPerm -> bc.engineGetParameters
               |-> bc.engineInit   // never reached

In the call to engineGetParameters, the instance members are still
null, so it tries to build a default using

   // BaseSingleBlockCipher.java line 281:
   engineParams = AlgorithmParameters.getInstance("OAEP", fipsProvider);
   engineParams.init(paramSpec);   // throws

But because BaseSingleBlockCipher's engineInit still hasn't been
called, paramSpec is still null.  (There's also a path from
Cipher.getInstance -> private Cipher.Transform stuff ->
engineSetPadding, but "PKCS1Padding" in that routine doesn't result
in a call to initFromSpec, which would have also set paramSpec.)


Under Java 9, everything works.  The users in this case won't be able
to move past 8 for a while, but I'm hoping we'll be allowed to use jlink
to avoid those problems.  So in the meantime I'd like to figure out a
solution for 8, and I thought figuring out why it works under 9+ might
be a good place to start.  However, looking at the source for
javax.crypto.Cipher, the changes are largely in javadoc markup and
some cosmetic code diffs.  Presumably there's some call somewhere
in the stack that's examining previously-set state, and the difference
from 8 to 9 alters that state, but I've not found what that might be, and
am not sure where to look.

For most of our BCFIPS configurations, we set
"org.bouncycastle.fips.approved_only" to true so that
CryptoServicesRegistrar will properly elide the non-FIPS algorithms,
but in a fit of paranoia I've tried these steps with and without that
override property, and verified that it makes no difference to this
particular case.