Unkown error 0x16 on smartcard reader access

ε祈祈猫儿з 提交于 2019-12-04 13:26:08

There are two ways to interact with this reader over the Java Smartcard IO API:

  1. The first is to open a regular APDU transmission channel (from a PC/SC point of view this maps to T=0 or T=1 protocol). You can do this using

    Card card = getCard("*");
    

    However, this will require the reader to report the presence of a card. Otherwise you can't open a connection that way.

    You can then transmit APDU commands to the card (on the basic channel or a logical channel) and you can send special commands to the reader on the basic channel. These special commands have their class byte set to 0xFF to indicate that the command is intended to be interpreted by the reader (instead of being forwarded to the card). So this is not applicable for the "peripherals control" commands that start with 0xE0.

  2. Those "peripherals control" commands have to be sent to the reader using control commands with the control code SCARD_CTL_CODE(3500). As with opening a connection to the card, you can use getCard("*") if there is a card present on the reader. However, if you want to be able to send those commands to the reader even if there is no card present, you have to open a connection in "direct" mode:

    Card card = getCard("DIRECT");
    

    You can then send control commands using the method card.transmitControlCommand(). This method takes the control code as the first argument and the command (as byte array) as the second argument. Exchanging commands on the basic channel or any logical channel using channel.transmit() will usually not work in "direct" mode (hence the error code 0x16).

    The control code is calculated as

    public static final int SCARD_CTL_CODE(int command) {
        boolean isWindows = System.getProperty("os.name").startsWith("Windows");
        if (isWindows) {
            return 0x00310000 | (command << 2);
        } else {
            return 0x42000000 | command;
        }
    }
    

    Note the difference between Windows and other platforms.

    For instance, to send the buzzer control command, you would use

    byte[] command = new byte[] { (byte)0xE0, (byte)0x00, (byte)0x00, (byte)0x28, (byte)0x01, (byte)0x0A };
    byte[] response = card.transmitControlCommand(SCARD_CTL_CODE(3500), command);
    

    Finally, be aware that sending IOCTL control codes over PC/SC requires special driver support. Specifically, the standard CCID driver provided by Microsoft does not support sending escape commands by default (see USB CCID Class Driver Details). This driver supports escape commands only after enabling them through the registry value "EscapeCommandEnable". The error 0x1 that you showed in your question is a typical result of this missing support for escape commands.

    To reliably support all features of the reader (including escape commands) you need to use the "PC/SC Drivers" package provided by ACS on their website.

Try to use

card.transmitControlCommand(int controlCode, byte[] command)

instead of transmit. According to section 5.8 (page 41 of the pdf you linked to) controlcode is 3500, although it is unclear to me, if that is a hex or an int, so compare to SCARD_CTL_CODE, if you are able to. At least, I interpret the documentation this.

Usually you use transmitControlCommand to talk to the reader and transmit to talk to the card.

Fixed typo in ControlCode. Kudos to Torhan Bartel for telling me.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!