Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8157404

Unable to read certain PKCS12 keystores from SequenceInputStream

    XMLWordPrintable

    Details

    • Subcomponent:
    • Resolved In Build:
      b15
    • CPU:
      generic
    • OS:
      generic
    • Verification:
      Verified

      Description

      FULL PRODUCT VERSION :


      A DESCRIPTION OF THE PROBLEM :
      When loading a PKCS12 file (that has a big undefined length DER value in it), i noticed that the loading succeeds when i load it from file directly, but fails when loaded though a servlet:

      Exception in thread "main" java.io.IOException: not all indef len BER resolved
      at sun.security.util.DerIndefLenConverter.convert(DerIndefLenConverter.java:340)
      at sun.security.util.DerValue.init(DerValue.java:376)
      at sun.security.util.DerValue.<init>(DerValue.java:320)
      at sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1914)
      at java.security.KeyStore.load(KeyStore.java:1445)

      When loading through a servlet, the container is using a SequenceInputStream (first x bytes are in memory, rest on disk).

      Root cause analysis:

      When loading a PKCS12 that has an 'indefinite length' value in it, the decoder assumes that stream.available represents the complete 'indefinite.length' section. However, this is not always the case. When using eg a SequenceInputStream, available will only return the available size of one element of the sequence, not the complete sequence.

      Relevant code in sun.security.util.DerValue:

      if(this.length == -1) {
                  int bytes = ((InputStream)in).available();
                  byte offset = 2;
                  byte[] indefData = new byte[bytes + offset];
                  indefData[0] = this.tag;
                  indefData[1] = lenByte;
                  DataInputStream dis = new DataInputStream((InputStream)in);
                  dis.readFully(indefData, offset, bytes);
                  dis.close();
                  DerIndefLenConverter derIn = new DerIndefLenConverter();
                  in = new ByteArrayInputStream(derIn.convert(indefData));
                  if(this.tag != ((InputStream)in).read()) {
                      throw new IOException("Indefinite length encoding not supported");
                  }

                  this.length = DerInputStream.getLength((InputStream)in);
              }


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
          public static void main(String[] args) throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException
          {
              KeyStore p12 = KeyStore.getInstance("pkcs12");
              File file = new File("test.p12");
              ByteArrayOutputStream os = new ByteArrayOutputStream();
              java.nio.file.Files.copy(file.toPath(), os);
              os.flush();
              byte[] bytes = os.toByteArray();
              p12.load(new ByteArrayInputStream(bytes), "motive".toCharArray());
              int split = 10;
              p12.load(createSplitStream(bytes, split), "motive".toCharArray());

          }

          private static SequenceInputStream createSplitStream(byte[] bytes, int split) {
              return new SequenceInputStream(new ByteArrayInputStream(bytes, 0, split), new ByteArrayInputStream(bytes, split, bytes.length - split));
          }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Workaround is to store the stream i get from our servlet to a bytearray first and then pass a bytearraystream to keystore.load

        Attachments

          Activity

            People

            • Assignee:
              weijun Weijun Wang
              Reporter:
              webbuggrp Webbug Group
            • Votes:
              0 Vote for this issue
              Watchers:
              7 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: