JDK-8028431 : NullPointerException in DerValue.equals(DerValue)
Type:Bug
Component:security-libs
Sub-Component:java.security
Affected Version:7,8
Priority:P4
Status:Closed
Resolution:Fixed
OS:generic
CPU:generic
Submitted:2013-11-15
Updated:2020-07-28
Resolved:2014-01-22
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.
sun.security.util.DerValue.equals(DerValue) method does not check that null is passed. As a result, NullPointerException can occur.
Comments
Fix request (8u)
I'd like to request an approval for a 8u backport so we have parity between different JDKs. Risk for this patch is minimal. It applied almost cleanly except for a copyright date. Review approval here: https://mail.openjdk.java.net/pipermail/jdk8u-dev/2020-April/011574.html
17-04-2020
The problem was found during fuzz testing. The following application was used:
import java.io.FileInputStream;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
public class X509CertificateLoad {
/**
* Load a X509 certificate from file.
*/
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream(args[0]);
CertificateFactory cf = CertificateFactory.getInstance("X509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(fis);
System.out.println("SUCCESS");
}
}
It just loads x509 certificate from file that is fuzzed. Please see attached test. The test fails with the following output:
x509: Error parsing extension: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
java.io.IOException: insufficient data
at sun.security.util.DerInputBuffer.truncate(DerInputBuffer.java:125)
at sun.security.util.DerValue.<init>(DerValue.java:279)
at sun.security.util.DerInputStream.getDerValue(DerInputStream.java:417)
at sun.security.x509.AccessDescription.<init>(AccessDescription.java:65)
at sun.security.x509.AuthorityInfoAccessExtension.<init>(AuthorityInfoAccessExtension.java:127)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at sun.security.x509.CertificateExtensions.parseExtension(CertificateExtensions.java:111)
at sun.security.x509.CertificateExtensions.init(CertificateExtensions.java:87)
at sun.security.x509.CertificateExtensions.<init>(CertificateExtensions.java:77)
at sun.security.x509.X509CertInfo.parse(X509CertInfo.java:740)
at sun.security.x509.X509CertInfo.<init>(X509CertInfo.java:169)
at sun.security.x509.X509CertImpl.parse(X509CertImpl.java:1747)
at sun.security.x509.X509CertImpl.<init>(X509CertImpl.java:196)
at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:97)
at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:339)
at X509CertificateLoad.main(X509CertificateLoad.java:13)
0000: 30 74 30 24 06 08 2B 06 01 05 05 07 30 01 86 18 0t0$..+.....0...
0010: 68 74 74 70 3A 2F 2F 6F 63 73 70 2E 64 69 67 69 http://ocsp.digi
0020: 63 65 72 74 2E 63 6F 6D 30 4C 06 0C 2B 06 01 05 cert.com0L..+...
0030: 05 07 30 02 86 40 68 74 74 70 3A 2F 2F 63 61 63 ..0..@http://cac
0040: 65 72 74 73 2E 64 69 67 69 63 65 72 74 2E 63 6F erts.digicert.co
0050: 6D 2F 44 69 67 69 43 65 72 74 41 73 73 75 72 65 m/DigiCertAssure
0060: 64 49 44 43 6F 64 65 53 69 67 6E 69 6E 67 43 41 dIDCodeSigningCA
0070: 2D 31 2E 63 72 74 -1.crt
Exception in thread "main" java.lang.NullPointerException
at sun.security.util.DerValue.equals(DerValue.java:772)
at sun.security.x509.AlgorithmId.equals(AlgorithmId.java:274)
at sun.security.x509.X509CertImpl.parse(X509CertImpl.java:1754)
at sun.security.x509.X509CertImpl.<init>(X509CertImpl.java:196)
at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:97)
at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:339)
at X509CertificateLoad.main(X509CertificateLoad.java:13)
sun.security.x509.X509CertImpl.parse() method tries to create X509CertInfo instance, and IOException is thrown. But this exception is just ignored. But anyway then the "inner" and "outer" signature algorithms are compared:
src/share/classes/sun/security/x509/X509CertImpl.java
...
// The CertificateInfo
info = new X509CertInfo(seq[0]);
// the "inner" and "outer" signature algorithms must match
AlgorithmId infoSigAlg = (AlgorithmId)info.get(
CertificateAlgorithmId.NAME
+ DOT +
CertificateAlgorithmId.ALGORITHM);
if (! algId.equals(infoSigAlg))
throw new CertificateException("Signature algorithm mismatch");
...
AlgorithmId.equals() method does not check that params is null, so null is passed to DerValue.equals() method:
src/share/classes/sun/security/util/DerValue.java
...
public boolean equals(DerValue other) {
if (this == other) {
return true;
}
if (tag != other.tag) {
return false;
}
if (data == other.data) {
return true;
}
// make sure the order of lock is always consistent to avoid a deadlock
return (System.identityHashCode(this.data)
> System.identityHashCode(other.data)) ?
doEquals(this, other):
doEquals(other, this);
}
...
This is not a regression in 7u, NPE is thrown on JDK 7 b147.
CertificateException is thrown as expected on JDK 8 b113, but anyway DerValue.equals() method does not check that null is passed. So JDK 8 is also affected.
The certificate that was used for testing is invalid. I did not try to create a valid one that contains null in params of AlgorithmId instance. But according to http://www.ietf.org/rfc/rfc2459.txt, parameters is optional:
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL }
So I guess it is possible to create a valid certificate to reproduce the problem.
The problem can be fixed by adding a check that null is passed to DerValue.equals() method:
http://cr.openjdk.java.net/~asmotrak/8028431/webrev.00/