JDK-8028591 : NegativeArraySizeException in sun.security.util.DerInputStream.getUnalignedBitString()
  • 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-19
  • Updated: 2020-07-28
  • Resolved: 2014-03-13
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 7 JDK 8 JDK 9 Other
7u271Fixed 8u261Fixed 9 b06Fixed openjdk7uFixed
Description
sun.security.util.DerInputStream.getUnalignedBitString() tries to read DER-encoded bit string, but it does not check that length tag is zero or negative. As a result, NegativeArraySizeException can be thrown.
Comments
8u approval: Reviewed by Martin Balao: https://mail.openjdk.java.net/pipermail/jdk8u-dev/2020-May/011765.html Patch is a stable fix (present since 2014-03-25 in 9u) that adds necessary range checks. It's also on the Oracle parity list (8u261).
21-05-2020

RFR for 8u: https://mail.openjdk.java.net/pipermail/jdk8u-dev/2020-May/011747.html
20-05-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 a test in webrev below that is based on this code. The test fails with the following output: java.lang.NegativeArraySizeException at sun.security.util.DerInputStream.getUnalignedBitString(DerInputStream.java:238) at sun.security.x509.X509Key.parse(X509Key.java:170) at sun.security.x509.CertificateX509Key.<init>(CertificateX509Key.java:75) at sun.security.x509.X509CertInfo.parse(X509CertInfo.java:705) 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 X509BadCertificate.main(X509BadCertificate.java:48) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at com.sun.javatest.regtest.MainWrapper$MainThread.run(MainWrapper.java:94) at java.lang.Thread.run(Thread.java:722) The problem is in sun.security.util.DerInputStream.getUnalignedBitString() method: http://hg.openjdk.java.net/jdk7u/jdk7u-dev/jdk/file/837746b32b81/src/share/classes/sun/security/util/DerInputStream.java ... 222 /** 223 * Get a bit string from the input stream. The bit string need 224 * not be byte-aligned. 225 */ 226 public BitArray getUnalignedBitString() throws IOException { 227 if (buffer.read() != DerValue.tag_BitString) 228 throw new IOException("DER input not a bit string"); 229 230 int length = getLength(buffer) - 1; 231 232 /* 233 * First byte = number of excess bits in the last octet of the 234 * representation. 235 */ 236 int validBits = length*8 - buffer.read(); 237 238 byte[] repn = new byte[length]; 239 240 if ((length != 0) && (buffer.read(repn) != length)) 241 throw new IOException("short read of DER bit string"); 242 return new BitArray(validBits, repn); 243 } ... sun.security.util.DerInputStream.getLength() method can return 0 or -1 values. Negative value means that indefinite-length encoding. There is not a check for 0 or -1 values, so NegativeArraySizeException can occur in 238 line. This is not a regression in 7u, NPE is thrown on JDK 7 b147. The same issue is for JDK 8. The certificate that was used for testing is invalid. Since indefinite-length encoding is not allowed for DER encoding, I think there could not be a valid certificate to reproduce this NegativeArraySizeException. But anyway it is expected that getLength() can return 0 or -1, and return length should be checked. So I think it is P4. The problem can be fixed by adding a check that length is not 0 or negative: http://cr.openjdk.java.net/~asmotrak/8028591/webrev.00/
07-12-2014

That's good. I guess you will give different names to the bad certs and each time a new one is found a new @run line will be added to X509BadCertificate.java. Also, why is othervm used? (We'd better move the discussion to a code review mail thread).
21-11-2013

Recently I found only JDK-8028431 on fuzzed certificates. The same test is used in both bugs.
20-11-2013

I see several bugs on fuzzed certificates. Is it possible to use the same test? We can create a sub-directory holding these bad certs and the test just iterates through all of them.
20-11-2013