JDK-8175251 : Failed to load RSA private key from pkcs12
  • Type: Bug
  • Component: security-libs
  • Sub-Component: java.security
  • Affected Version: 8u121,9
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2017-02-18
  • Updated: 2018-02-08
  • Resolved: 2017-03-15
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 10 JDK 6 JDK 7 JDK 8 JDK 9 Other
10Fixed 6u151Fixed 7u141Fixed 8u131Fixed 9 b162Fixed openjdk7uFixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Linux localhost.localdomain 4.7.10-100.fc23.x86_64 #1 SMP Wed Oct 26 23:29:32 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
Additional information on reproducibility for JDK-8173460. I can reproduce the bug in different circumstances but with the same result. See steps to reproduce.

REGRESSION.  Last worked in version 8u112

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
In my project 

https://github.com/l-ra/openeet-java 

it is easy to reproduce. Either build the project from the source or download latest snapshot from 

https://github.com/l-ra/openeet/blob/master/releases/prerelease/openeet-lite-java8-20170115-0140.jar?raw=true

Using jdk update _121  run: java -jar openeet-lite-java8-20170115-0140.jar 


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
should output something like this
===== BEGIN EET REQUEST =====
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <wsse:Security 
...
... more of XML ...
...
          xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-7fdb-4327-96c0-09746434cbe6" bkp="A66DA004-03081577-1064904B-69D182A3-BAE332E9" dat_prij="2017-02-18T21:22:53+01:00"/><eet:Potvrzeni fik="398135bb-ff13-435c-9e9d-98b881fa6f1f-ff" test="true"/></eet:Odpoved></soapenv:Body></soapenv:Envelope>
===== END EET RESPONSE =====


ACTUAL -
Fails with exception (see error message field)



ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.IllegalArgumentException: Exception while loading p12 data
	at openeet.lite.EetRegisterRequest.loadP12(EetRegisterRequest.java:1369)
	at openeet.lite.EetRegisterRequest.<init>(EetRegisterRequest.java:856)
	at openeet.lite.EetRegisterRequest$Builder.build(EetRegisterRequest.java:764)
	at openeet.lite.Main.main(Main.java:22)
Caused by: java.security.UnrecoverableKeyException: Get Key failed: java.security.InvalidKeyException: Invalid RSA private key
	at sun.security.pkcs12.PKCS12KeyStore.engineGetKey(PKCS12KeyStore.java:410)
	at java.security.KeyStore.getKey(KeyStore.java:1023)
	at openeet.lite.EetRegisterRequest.loadP12(EetRegisterRequest.java:1355)
	... 3 more
Caused by: java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: Invalid RSA private key
	at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:217)
	at java.security.KeyFactory.generatePrivate(KeyFactory.java:372)
	at sun.security.pkcs12.PKCS12KeyStore.engineGetKey(PKCS12KeyStore.java:376)
	... 5 more
Caused by: java.security.InvalidKeyException: Invalid RSA private key
	at sun.security.rsa.RSAPrivateCrtKeyImpl.parseKeyBits(RSAPrivateCrtKeyImpl.java:206)
	at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:342)
	at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:356)
	at sun.security.rsa.RSAPrivateCrtKeyImpl.<init>(RSAPrivateCrtKeyImpl.java:91)
	at sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(RSAPrivateCrtKeyImpl.java:75)
	at sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:316)
	at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:213)
	... 7 more
Caused by: java.io.IOException: Invalid encoding: redundant leading 0s
	at sun.security.util.DerInputBuffer.getBigInteger(DerInputBuffer.java:152)
	at sun.security.util.DerInputStream.getBigInteger(DerInputStream.java:207)
	at sun.security.rsa.RSAPrivateCrtKeyImpl.getBigInteger(RSAPrivateCrtKeyImpl.java:214)
	at sun.security.rsa.RSAPrivateCrtKeyImpl.parseKeyBits(RSAPrivateCrtKeyImpl.java:196)
	... 13 more







REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
try {
			KeyStore ks=KeyStore.getInstance("PKCS12");
			ks.load(new ByteArrayInputStream(p12data), password);
			Enumeration<String> aliases= ks.aliases();
			while(aliases.hasMoreElements() ){
				String alias=aliases.nextElement();
>>exception here>>>				Key _key=ks.getKey(alias, password);
				if (_key!=null){
					Certificate _cert=ks.getCertificate(alias);
					if (_cert!=null){
						if (   _cert instanceof X509Certificate 
							&& _key instanceof RSAPrivateKey ){
							key=(PrivateKey) _key;
							certificate=(X509Certificate)_cert;
						}
					}
				}
			}
		}
		catch (Exception e ){
			throw new IllegalArgumentException("Exception while loading p12 data",e);
		}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Import pkcs12 file into windows store and export again. Then loading works as expected.


Comments
PKCS#8 has BER encoding for private key value. So, one more reason to allow the redundant leading 0s when loading PKCS8 keys. I will update the DER decoding code to only enforce the leading 0s check for Signatures.
13-03-2017

From submitter: --------------------- I'm not able to tell you how the example was generated because it was published by the Czech government as a part of public documentation for API of the government sales registration system. I just shortly investigated the related standards and it seems the Java parser is too strict. Starting at RFC7292 (https://tools.ietf.org/html/rfc7292#page-13) it is required the private key is stored using PKCS8 format. Looking at RFC5208 (https://www.ietf.org/rfc/rfc5208.txt) the PKCS8 uses BER encoding. As far as I know the BER encoding does not impose any limitation on INTEGER encoding and it is possible to use leading zeros. In my opinion new Java parser is not complianat to curent standards - it is too strict when DER is required but BER is sufficient.
01-03-2017

Openssl is able to remove the redundant 0s when extracting the private key. We can use the following 2 commands to normalize an affected pkcs12 file: 1. openssl pkcs12 -in pkcs12-file -out key-and-cert -nodes -passin pass:abcXYZ 2. openssl pkcs12 -in key-and-cert -export -out new-pkcs12-file -passout pass:abcXYZ
28-02-2017

It seems that some vendor's DER encoding impl will output BigInteger with redundant leading 0s. For backward compatibility, we may have to relax the DER check for non-signature cases.
28-02-2017

To submitter: ---------------- Can you please let us know how the EET_CA1_Playground-CZ1212121218.p12 file used in the code has been generated ?
28-02-2017