JDK-8214096 : sun.security.util.SignatureUtil passes null parameter, so JCE validation fails
  • Type: Bug
  • Component: security-libs
  • Sub-Component: java.security
  • Affected Version: 11
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2018-11-16
  • Updated: 2021-01-12
  • Resolved: 2018-12-19
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 11 JDK 12 JDK 13 JDK 8 Other
11.0.5Fixed 12 b26Fixed 13Fixed 8u251Fixed openjdk8u252Fixed
Related Reports
Relates :  
Description
A DESCRIPTION OF THE PROBLEM :
The class method;

 public static void specialSetParameter(Signature sig, AlgorithmParameters params)

Has a call to sig.setParameter(null) which only catches UnsupportedOperationException. I'll leave the debate as to why it is calling with null to other people, but the catch clause around the call should catch NullPointerException as that would be an acceptable exception for a provider to throw and also InvalidAlgorithmParameterException as it is actually the defined exception for setParameter() if bad AlgorithmParameters are passed.

In the case of third party crypto providers, such as bc-fips-1.0.1.jar this is particularly serious as it leads to a:

JCE cannot authenticate the provider BCFIPS

caused by:

java.util.jar.JarException: file:/tmp/bc-fips-1.0.1.jar is not signed by a trusted signer.

which is the result of the escaping exception generated by sig.setParameters(null).

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Place a third party provider such as BC-FJA 1.0.1 first in the java.security file as in:

security.provider.1=org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider

Compile and run the ProviderTest class:

javac -classpath bc-fips-1.0.1.jar ProviderTest.java
java  -cp .:bc-fips-1.0.1.jar ProviderTest

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
JVM SecurityProvider list:

Provider at position = 1 has name = BCFIPS
Provider at position = 2 has name = SUN
Provider at position = 3 has name = SunRsaSign
Provider at position = 4 has name = SunEC
Provider at position = 5 has name = SunJSSE
Provider at position = 6 has name = SunJCE
Provider at position = 7 has name = SunJGSS
Provider at position = 8 has name = SunSASL
Provider at position = 9 has name = XMLDSig
Provider at position = 10 has name = SunPCSC
Provider at position = 11 has name = JdkLDAP
Provider at position = 12 has name = JdkSASL
Provider at position = 13 has name = SunPKCS11
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$CoreSecureRandom (file:/tmp/java11/bc-fips-1.0.1.jar) to method sun.security.jca.Providers.getSunProvider()
WARNING: Please consider reporting this to the maintainers of org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$CoreSecureRandom
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
ACTUAL -
JVM SecurityProvider list:

Provider at position = 1 has name = BCFIPS
Provider at position = 2 has name = SUN
Provider at position = 3 has name = SunRsaSign
Provider at position = 4 has name = SunEC
Provider at position = 5 has name = SunJSSE
Provider at position = 6 has name = SunJCE
Provider at position = 7 has name = SunJGSS
Provider at position = 8 has name = SunSASL
Provider at position = 9 has name = XMLDSig
Provider at position = 10 has name = SunPCSC
Provider at position = 11 has name = JdkLDAP
Provider at position = 12 has name = JdkSASL
Provider at position = 13 has name = SunPKCS11
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$CoreSecureRandom (file:/tmp/java11/bc-fips-1.0.1.jar) to method sun.security.jca.Providers.getSunProvider()
WARNING: Please consider reporting this to the maintainers of org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$CoreSecureRandom
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
java.lang.SecurityException: JCE cannot authenticate the provider BCFIPS
	at java.base/javax.crypto.Cipher.getInstance(Cipher.java:694)
	at java.base/javax.crypto.Cipher.getInstance(Cipher.java:625)
	at ProviderTest.main(ProviderTest.java:14)
Caused by: java.util.jar.JarException: file:/tmp/java11/bc-fips-1.0.1.jar is not signed by a trusted signer.
	at java.base/javax.crypto.JarVerifier.verifySingleJar(JarVerifier.java:498)
	at java.base/javax.crypto.JarVerifier.verifyJars(JarVerifier.java:314)
	at java.base/javax.crypto.JarVerifier.verify(JarVerifier.java:257)
	at java.base/javax.crypto.ProviderVerifier.verify(ProviderVerifier.java:129)
	at java.base/javax.crypto.JceSecurity.verifyProvider(JceSecurity.java:191)
	at java.base/javax.crypto.JceSecurity.getVerificationResult(JceSecurity.java:217)
	at java.base/javax.crypto.Cipher.getInstance(Cipher.java:690)
	... 2 more


---------- BEGIN SOURCE ----------
import javax.crypto.*;
import java.io.*;
import java.security.*;

public class ProviderTest
{
    public static void main(String[] args)
    {
        try
        {
            printProviders();

            Cipher.getInstance("AES", "BCFIPS");
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void printProviders()
    {
        System.out.println( "JVM SecurityProvider list:\n");
        Provider[] providers = Security.getProviders();
        for(int i=0; i < providers.length; i++)
        {
            Provider provider = providers[i];
            System.out.println( "Provider at position = "+ (i+1) +" has name = "+provider.getName() );
        }
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
No work around available.


Comments
Fix request (11u): Requesting backport because this patch is a predecessor to JDK-8216039 which has to be taken over to keep parity to Oracle 11.0.5. It applies cleanly and shows no regressions.
26-06-2019

Workaround is to avoid adding the 3rd party provider as the most preferred provider. Once the 3rd party provider jar is verified with default JDK providers which do not throw NPE when calling Signature.setParameter(null), it can be moved to the most preferred position. After discussing with Sean, the more backward-compatible way of avoiding this issue is to skip calling Signature.setParameter() when parameter is null. Signature algorithms which require parameters such as RSASSA-PSS should handle this and error out when no parameter is given.
14-12-2018

I can reproduce the bug against my own JDK 12 build. Here is the debugging info showing the complete call stack: at java.base/sun.security.util.SignatureUtil.specialSetParameter(SignatureUtil.java:111) at java.base/sun.security.pkcs.SignerInfo.verify(SignerInfo.java:457) at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:578) at java.base/sun.security.pkcs.PKCS7.verify(PKCS7.java:595) at java.base/sun.security.util.SignatureFileVerifier.processImpl(SignatureFileVerifier.java:293) at java.base/sun.security.util.SignatureFileVerifier.process(SignatureFileVerifier.java:269) at java.base/java.util.jar.JarVerifier.processEntry(JarVerifier.java:316) at java.base/java.util.jar.JarVerifier.update(JarVerifier.java:230) at java.base/java.util.jar.JarFile.initializeVerifier(JarFile.java:758) at java.base/java.util.jar.JarFile.getInputStream(JarFile.java:839) at java.base/javax.crypto.JarVerifier.verifySingleJar(JarVerifier.java:420) at java.base/javax.crypto.JarVerifier.verifyJars(JarVerifier.java:314) at java.base/javax.crypto.JarVerifier.verify(JarVerifier.java:257) at java.base/javax.crypto.ProviderVerifier.verify(ProviderVerifier.java:129) at java.base/javax.crypto.JceSecurity.verifyProvider(JceSecurity.java:191) at java.base/javax.crypto.JceSecurity.getVerificationResult(JceSecurity.java:217) at java.base/javax.crypto.Cipher.getInstance(Cipher.java:721) at java.base/javax.crypto.Cipher.getInstance(Cipher.java:645) at ProviderTest.main(ProviderTest.java:9)
14-12-2018

The reason this is most likely passing on 12 is that you are testing with the OpenJDK binaries which do not verify signed JCE providers. But the bug could potentially still be triggered in some other way, so I am removing the 12-na label.
12-12-2018

The remaining question is why this provider validation passed for JDK 12 but not 11.
28-11-2018

I disagree with the submitter's comment regarding the catch block in sun.security.util.SignatureUtil.specialSetParameter method should cover NPE and InvalidAlgorithmParameterException. We should not ignore ALL exceptions thrown by Signature.setParameter(..) method especially those for indicating bad inputs. For more elaboration: Unless we add algorithm-specific knowledge into java.security.Signature class, it does not know if the current signature algorithm requires parameters or not. For signature algorithms which do not use/care parameters, they generally would not override the default impl in java.security.SignatureSpi.engineSetParameter(...) method which throws UnsupportedOperationException. This exception is handled by the catch block and will be ignored. For signature algorithms which takes parameters, null is a meaningful value and may lead to InvalidAlgorithmParameterException if non-null value is required or NPE if the provider attempts to use it without proper checking. Either way, both indicate a problem which should be passed up to the caller.
28-11-2018

Ran the attached testcase on the following versions: JDK 11 GA - Fail JDK 11.0.1 - Fail JDK 12-ea+16 - Pass Output on JDK 11.0.1 : >d:\jdk-11.0.1\bin\java -cp .;D:\bc-fips-1.0.1.jar ProviderTest JVM SecurityProvider list: Provider at position = 1 has name = BCFIPS Provider at position = 2 has name = SUN Provider at position = 3 has name = SunRsaSign Provider at position = 4 has name = SunEC Provider at position = 5 has name = SunJSSE Provider at position = 6 has name = SunJCE Provider at position = 7 has name = SunJGSS Provider at position = 8 has name = SunSASL Provider at position = 9 has name = XMLDSig Provider at position = 10 has name = SunPCSC Provider at position = 11 has name = JdkLDAP Provider at position = 12 has name = JdkSASL Provider at position = 13 has name = SunMSCAPI Provider at position = 14 has name = SunPKCS11 WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$CoreSecureRandom (file:/D:/bc-fips-1.0.1.jar) to method sun.security.jca.Providers.getSunPr WARNING: Please consider reporting this to the maintainers of org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$CoreSecureRandom WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release java.lang.SecurityException: JCE cannot authenticate the provider BCFIPS at java.base/javax.crypto.Cipher.getInstance(Cipher.java:694) at java.base/javax.crypto.Cipher.getInstance(Cipher.java:625) at ProviderTest.main(ProviderTest.java:13) Caused by: java.util.jar.JarException: file:/D:/bc-fips-1.0.1.jar is not signed by a trusted signer. at java.base/javax.crypto.JarVerifier.verifySingleJar(JarVerifier.java:498) at java.base/javax.crypto.JarVerifier.verifyJars(JarVerifier.java:314) at java.base/javax.crypto.JarVerifier.verify(JarVerifier.java:257) at java.base/javax.crypto.ProviderVerifier.verify(ProviderVerifier.java:129) at java.base/javax.crypto.JceSecurity.verifyProvider(JceSecurity.java:191) at java.base/javax.crypto.JceSecurity.getVerificationResult(JceSecurity.java:217) at java.base/javax.crypto.Cipher.getInstance(Cipher.java:690) ... 2 more Output on JDK 12-ea+16 : JVM SecurityProvider list: Provider at position = 1 has name = BCFIPS Provider at position = 2 has name = SUN Provider at position = 3 has name = SunRsaSign Provider at position = 4 has name = SunEC Provider at position = 5 has name = SunJSSE Provider at position = 6 has name = SunJCE Provider at position = 7 has name = SunJGSS Provider at position = 8 has name = SunSASL Provider at position = 9 has name = XMLDSig Provider at position = 10 has name = SunPCSC Provider at position = 11 has name = JdkLDAP Provider at position = 12 has name = JdkSASL Provider at position = 13 has name = SunMSCAPI Provider at position = 14 has name = SunPKCS11 WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$CoreSecureRandom (file:/D:/bc-fips-1.0.1.jar) to method sun.security.jca.Prov WARNING: Please consider reporting this to the maintainers of org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider$CoreSecureRandom WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release
20-11-2018