JDK11 & BC & TLS with RSASSA-PSS signature

MSKnete-S0/[email protected] Thu, 20 Dec 2018 16:39:07 +0100
Newsgroups gmane.comp.encryption.bouncy-castle.devel
Message-ID <trinity-a81ade49-f0a1-40d7-a783-d606b69305a4-1545320347580@3c-app-webde-bs14>
Hello all,

I run into an issue, when using JDK11, BC and TLS with RSASSA-PSS signature scheme. From JDK10 to JDK11 the handshake classes have been changed and especially the JDK class 'src/java.base/share/classes/sun/security/ssl/SignatureScheme.java' calls the signer object in an unfavourable manner.

Instead of calling setParameter() first and then initSign(), JDK11 does it the other way around (SignatureScheme.java, line 473/480).

Obviously, BC expect calling these two methods in the opposite order (org.bouncycastle.jcajce.provider.asymmetric.rsa.PSSSignatureSpi.java).

My remaining question: Who does it right? BC or JDK? Which side must be fixed?

I also attached a small sample which demonstrates the issue by comparing the BC implementation with the SunRsaSign implementation.

Further I found another mentioning of this behavior on the openjdk mailing list at http://mail.openjdk.java.net/pipermail/security-dev/2018-September/018265.html but sadly without any continuative response.

Any suggestion are welcome, to get RSASSA-PSS and BC working with JDK11.

Kind regards,

Michael

$ java -version

openjdk version "11.0.1" 2018-10-16

OpenJDK Runtime Environment 18.9 (build 11.0.1+13)

OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode)

$ javac -cp bcprov-jdk15on-160.jar Demo.java

$ java -cp bcprov-jdk15on-160.jar Demo

BCprov: [...]

SunJCE: [...]

FAIL: Signatures are not equal!

---------------------

Sample Source (Demo.java):

---------------------

import java.security.KeyPair;

import java.security.KeyPairGenerator;

import java.security.PrivateKey;

import java.security.SecureRandom;

import java.security.Security;

import java.security.Signature;

import java.security.spec.MGF1ParameterSpec;

import java.security.spec.PSSParameterSpec;

import java.util.Arrays;

public class Demo {

public static void main(final String[] args) throws Exception {

Security.insertProviderAt(new org.bouncycastle.jce.provider.BouncyCastleProvider(), 2);

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");

keyPairGenerator.initialize(2048);

KeyPair keyPair = keyPairGenerator.generateKeyPair();

PrivateKey privateKey = keyPair.getPrivate();

SecureRandom prngBC = SecureRandom.getInstance("SHA1PRNG");

prngBC.setSeed(12345678L); //we need equal randomness, dont do this in production!

Signature signerBC = Signature.getInstance("RSASSA-PSS", "BC");

// this breaks BC, since setParameter() is invoked AFTER init()

signerBC.initSign(privateKey, prngBC);

signerBC.setParameter(new PSSParameterSpec("SHA-512", "MGF1", new MGF1ParameterSpec("SHA-512"), 64, 1));

byte[] resultBC = signerBC.sign();

SecureRandom prngSun = SecureRandom.getInstance("SHA1PRNG");

prngSun.setSeed(12345678L); //we need equal randomness, dont do this in production!

Signature signerSun = Signature.getInstance("RSASSA-PSS", "SunRsaSign");

signerSun.initSign(privateKey, prngSun);

signerSun.setParameter(new PSSParameterSpec("SHA-512", "MGF1", new MGF1ParameterSpec("SHA-512"), 64, 1));

byte[] resultSun = signerSun.sign();

System.out.println("BCprov: " + Arrays.toString(resultBC));

System.out.println("SunJCE: " + Arrays.toString(resultSun));

if (Arrays.equals(resultBC, resultSun)) {

System.out.println("OK: Signatures are equal!");

} else {

System.err.println("FAIL: Signatures are not equal!");

}

}

}