Hmm, it looks like it should solve the problem I originally reported, so that's good :) If there's a testing Windows JRE/JDK somewhere I can test it here ;)
It might be worth investigating other calls to KeyUtil.isOracleJCEProvider, I think I remember this not being the only place where this issue might occur, from when I investigated it. (But for us this is the only place that matters :) ). Looking at the fix, I wonder if there might be one (very) edge case left, but again not one that would affect us :) I'll refer to the numbers in the following code. When a non Oracle provider (4: results false) is available and has high priority, which supports UNWRAP with the given key, but does not support DECRYPT with the given key (Ok, this is a -very- hypothetical case.. :) ). The first init (3) will select that provider, which will be stored in the cipher instance, and the second init (5) will fail, resulting in the whole method to fail, even if another provider/cipher (with lower priority) is available which could've handled the request. TBH the fix for 'JDK-8081297' (issue which is sadly hidden to the public ;) ) feels like a bit of a kludge. Based on whether 'the' provider is an internal Oracle one or not either UNWRAP or DECRYPT is selected/used. But because of delayed provider selection, it's hard to say what 'the' provider is to base this choice on :) It feels like the choice would have to actually involve multiple providers in some cases. I'd make a recommendation, but I'm not sure what exactly is fixed by JDK-8081297 ;) 1> boolean needFailover = false; 2> Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1); try { 3> cipher.init(Cipher.UNWRAP_MODE, privateKey, new TlsRsaPremasterSecretParameterSpec( maxVersion.v, currentVersion.v), generator); 4> needFailover = !KeyUtil.isOracleJCEProvider( cipher.getProvider().getName()); } catch (InvalidKeyException | UnsupportedOperationException iue) { if (debug != null && Debug.isOn("handshake")) { System.out.println("The Cipher provider " + cipher.getProvider().getName() + " may not support TlsRsaPremasterSecretParameterSpec"); } needFailover = true; } if (needFailover) { 5> cipher.init(Cipher.DECRYPT_MODE, privateKey); boolean failed = false; try { encoded = cipher.doFinal(encrypted); } catch (BadPaddingException bpe) { failed = true; } encoded = KeyUtil.checkTlsPreMasterSecretKey( maxVersion.v, currentVersion.v, generator, encoded, failed); preMaster = generatePreMasterSecret( maxVersion.v, currentVersion.v, encoded, generator); } else { preMaster = (SecretKey)cipher.unwrap(encrypted, "TlsRsaPremasterSecret", Cipher.SECRET_KEY); } Cheers! Jeroen Cranendonk On Thu, Mar 10, 2016 at 4:50 PM, Xuelei Fan <xuelei....@oracle.com> wrote: > Hi, > > Please review this update: > > http://cr.openjdk.java.net/~xuelei/8149017/webrev.00/ > > The problem is that calling Cipher.getProvider, or any method on Cipher, > forces the Cipher instance to skip the delayed provider selection which > is built into Cipher. > > In this update, Cipher.init() was changed to be the first call to an > instance of Cipher. > > Thanks, > Xuelei