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

Hard coded loop limit prevents reading of smart card data greater than 8k

    Details

    • Subcomponent:
    • Resolved In Build:
      b11
    • CPU:
      x86
    • OS:
      other
    • Verification:
      Not verified

      Backports

        Description

        FULL PRODUCT VERSION :
        java version "1.8.0_77"
        Java(TM) SE Runtime Environment (build 1.8.0_77-b03)
        Java HotSpot(TM) 64-Bit Server VM (build 25.77-b03, mixed mode)

        ADDITIONAL OS VERSION INFORMATION :
        Windows 10 but this should be occurring on all OSs

        EXTRA RELEVANT SYSTEM CONFIGURATION :
        generic smart card reader for contact/contactless smart cards (omnikey 5321)

        A DESCRIPTION OF THE PROBLEM :
        based on the open JDK files
        in
        sun/security/smartcardio/ChannelImpld.java
        private byte[] doTransmit(byte[] command) throws CardException

        there is a check in the loop to retrieve all the data in response to a card commnad. This check has the following erroneous error check (around line 185):

        if (++k >= 32) {
             throw new CardException("Could not obtain response");
        }

        this check prevents reading of response data > 8k and worse throws an incorrect exception.

        The default limit should be increased and possibly have the ability to be configured. Additionally the exception message needs to be corrected.


        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Get a smart card containing a structure with more than 8k of data (mine has 10k).
        Smart card reader



        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        ResponseAPDU should return succesfully and contain >8k of data.
        ACTUAL -
        Invalid exception is thrown.

        Exception in thread "main" javax.smartcardio.CardException: Could not obtain response
        at sun.security.smartcardio.ChannelImpl.doTransmit(ChannelImpl.java:186)
        at sun.security.smartcardio.ChannelImpl.transmit(ChannelImpl.java:90)
        at com.tvec.smartcardio.ErrorTest.main(ErrorTest.java:58)


        ERROR MESSAGES/STACK TRACES THAT OCCUR :
        Exception in thread "main" javax.smartcardio.CardException: Could not obtain response
        at sun.security.smartcardio.ChannelImpl.doTransmit(ChannelImpl.java:186)
        at sun.security.smartcardio.ChannelImpl.transmit(ChannelImpl.java:90)
        at com.tvec.smartcardio.ErrorTest.main(ErrorTest.java:58)


        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        package com.tvec.smartcardio;

        import java.security.NoSuchAlgorithmException;

        import javax.smartcardio.Card;
        import javax.smartcardio.CardChannel;
        import javax.smartcardio.CardException;
        import javax.smartcardio.CardTerminal;
        import javax.smartcardio.CommandAPDU;
        import javax.smartcardio.ResponseAPDU;
        import javax.smartcardio.TerminalFactory;

        import com.tvec.smart_card.pcsc.PCSCConstants.ShareMode;

        public class ErrorTest {
          public static void main(String args[]) throws CardException {
            // PCSCWrapper wrapper = new PCSCWrtapper();

            Card card = null;
            String readerName = "OMNIKEY CardMan 5x21 0";
            String protocol = "T=1";
            ShareMode shareMode = ShareMode.Exclusive;

            // TerminalFactory terminalFactory = TerminalFactory.getDefault();
            TerminalFactory terminalFactory = null;
            try {

              java.security.Provider provider = java.security.Security.getProvider("SunPCSC");

              terminalFactory = TerminalFactory.getInstance("PC/SC", null, provider);

              CardTerminal terminal = terminalFactory.terminals().getTerminal(
                  readerName);
              card = terminal.connect(protocol);
              if (shareMode == ShareMode.Exclusive) {
                card.beginExclusive();
              }

              CardChannel cardChannel = card.getBasicChannel();
              ResponseAPDU responseAPDU = null;

              // verify for access to large container in my test case
              CommandAPDU inCommandAPDU = new CommandAPDU(
                  ErrorTest.toSignedByteArray("0020008008313233343536ffff"));
              responseAPDU = cardChannel.transmit(inCommandAPDU);
              System.out.println(Integer.toHexString(responseAPDU.getSW()));

              // send command that returns a response greater than 8k
              inCommandAPDU = new CommandAPDU(
                  ErrorTest.toSignedByteArray("00cb3fff055c035fc108"));

              // exception will be thrown here when accessing large container.
              // javax.smartcardio.CardException: Could not obtain response
              // at
              // sun.security.smartcardio.ChannelImpl.doTransmit(ChannelImpl.java:186)
              // at sun.security.smartcardio.ChannelImpl.transmit(ChannelImpl.java:90)

              responseAPDU = cardChannel.transmit(inCommandAPDU);

              System.out.println(Integer.toHexString(responseAPDU.getSW()));
            } catch (NoSuchAlgorithmException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
            }
          }

          public static byte[] toSignedByteArray(String in) {
            // convert the string into bytes and add them to the out array
            in = in.toLowerCase();
            if (in.startsWith("0x")) {
              // pull off the 0x
              in = in.substring(2);
            }
            // pad with 0 to make length a multiple of 2
            // 2 chars make a byte
            if (in.length() % 2 > 0) {
              in = "0" + in;
            }

            // build the output array
            byte[] out = new byte[in.length() / 2];
            for (int i = 0; i < out.length; i++) {
              out[i] = (byte) ((Character.digit(in.charAt(i * 2), 16) << 4) + Character
                  .digit(in.charAt(i * 2 + 1), 16));
            }

            return out;
          }
        }
        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        I wrote my own provider using the open JDK source as a guide and a Windows JNI smartcard library. In my implementation I added a maximum loop try variable and increased the limit to 100 from 32. This however does not solve the issue for other platforms which I would like to deploy to.

          Attachments

            Issue Links

              Activity

                People

                • Assignee:
                  igerasim Ivan Gerasimov (Inactive)
                  Reporter:
                  webbuggrp Webbug Group
                • Votes:
                  0 Vote for this issue
                  Watchers:
                  7 Start watching this issue

                  Dates

                  • Created:
                    Updated:
                    Resolved: