JDK-8234271 : Specify the exceptions that can be thrown by the javax.crypto.Cipher constructor
  • Type: CSR
  • Component: security-libs
  • Sub-Component: javax.crypto
  • Priority: P3
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 14
  • Submitted: 2019-11-15
  • Updated: 2019-12-04
  • Resolved: 2019-12-04
Related Reports
CSR :  
Description
Summary
-------
The protected constructor of javax.crypto.Cipher class throws an undocumented NullPointerException.

Problem
-------
javax.crypto.Cipher class has a protected constructor for JCE providers to wrap their implementation class into a Cipher object. This constructor throws NullPointerException when provider argument is null. It also throws NullPointerException when provider argument is not null but cannot be verified or used for this Cipher object construction. This may be unexpected as NullPointerException is often thrown as a result of illegal uses of null values.

Solution
--------
Change the constructor to throw IllegalArgumentException instead of NullPointerException when provider argument is not null but invalid. Document the javadoc of the protected constructor with both IllegalArgumentExceptionexception and NullPointerException (i.e. when provider argument is null).

Specification
-------------
Updating the javadoc for Cipher(CipherSpi, Provider, String) constructor with following changes:

        @@ -266,19 +266,22 @@
          * Creates a Cipher object.
          *
          * @param cipherSpi the delegate
          * @param provider the provider
          * @param transformation the transformation
    +     * @throws NullPointerException if {@code provider} is null
    +     * @throws IllegalArgumentException if the supplied arguments
    +     *         are deemed invalid for constructing the Cipher object
          */
         protected Cipher(CipherSpi cipherSpi,
                          Provider provider,
                          String transformation) {
             // See bug 4341369 & 4334690 for more info.
             // If the caller is trusted, then okay.
    -        // Otherwise throw a NullPointerException.
    +        // Otherwise throw an IllegalArgumentException.
             if (!JceSecurityManager.INSTANCE.isCallerTrusted(provider)) {
    -            throw new NullPointerException();
    +            throw new IllegalArgumentException("Cannot construct cipher");
             }
             this.spi = cipherSpi;
             this.provider = provider;
             this.transformation = transformation;
             this.cryptoPerm = CryptoAllPermission.INSTANCE;


Comments
Moving to Approved.
04-12-2019

Thanks for the comment, Joe, I have added a release note for this.
03-12-2019

[~mullan], if the javadoc tags are correct javax.crypto.Cipher and the constructor in question have been around since 1.4: https://docs.oracle.com/en/java/javase/13/docs/api/java.base/javax/crypto/Cipher.html#%3Cinit%3E(javax.crypto.CipherSpi,java.security.Provider,java.lang.String) I don't have a good sense abouthow significant behavioral compatibility impact, if any in practice, of changing the exception behavior in this case. I believe at least a release note is warranted.
20-11-2019

Joe, in this case the implementation is throwing a NullPointerException when the provider argument is *not null*. It is clearly the wrong exception. We have one chance to fix this in the impl and spec for what should be a very rare case in practice. Also, both IAE and NPE are RuntimeExceptions, so I would think the compatibility risk of changing NPE to IAE is pretty low.
19-11-2019

Documenting existing behavior is my initial thought as well. The concern from my peer is that such behavior does not seem the best fit for the definition of NPE as none of the arguments are null. Is this a strong enough reason? Considering that this is a rare corner case, we feel that changing to throw IllegalArgumentException should not break existing apps and fits the scenario better. I'll bring your feedback to my peers and see what they think.
18-11-2019

The default resolution of a case like this is to document the existing behavior, throwing a NPE. Is there a strong reason that course is not being followed here? Moving to Provisional while the discussion over which exception to document and throw plays out.
18-11-2019