I am trying to use the standard API (javax.smartcardio) that comes with Java 6 to read a facial image from a SmartCard. I have been able to do the same operation using the JPCSC 0.8 API but I would prefer to use the API in Java 6.
I verify the PIN successfully and then try to read the image from the card. The CommandAPDU contains:
Get Data Command: 00CB3FFF00 5C035FC108
The operation seems to be working based on the activity lights from the reader (OmniKey 3121) but it always fails with:
javax.smartcardio.CardException: Could not obtain response
at sun.security.smartcardio.ChannelImpl.doTransmit(Unknown Source)
at sun.security.smartcardio.ChannelImpl.transmit(Unknown Source)
I am able to read other data from the card such as the CHUID and the Auth Certificate.
First, you are speaking PIV-ese, not many, if any, know PIV here
second, facial is optional, therefore are you sure it's there ?
second, don't you have to loop your Get Data call to retrieve large data,
third, what is your results with the PIV Reference Implementation ?
Yes, I realize not many are working with valid PIV cards at this time. I am certain the facial image is on the card since I have code that uses the JPSC open source implementation to already extract the image. Also, I know the image request requires a verify of the PIN which is working.
I agree that I should have to loop the get response call but the initial command does not allow me to do that since it throws an exception.
I actually have a loop that checks to see if it got all of the data and subsequently calls get response. This is how it is working with the jpsc open source and I anticipated it working with the javax.smartcardio calls.
I am trying to port some working code that I wrote from the jpsc open source implementation to the javax.smartcardio since the interfaces are so similar.
You have given me one thing to try and that is in the initial call I am not specifying an expected length with the jpcsc api this did not seem to matter but upon my initial test by specifying a length it gets me past the exception.
Just an update to see if anyone has any more ideas.
Making the GET DATA card command with a length returns successfully with only the data that was requested (i.e. requesting 200 bytes returns 200 bytes).
The only problem is there is nothing else in the response since SW1 and SW2 in the response was 0x90,0x00. Any subsequent call to get response returns immediately with (0x69,0x85) Condition of use not satisfied.
Making the GET DATA card command with a length of 0 seems to try and read the entire facial image in one response but fails since the image must be larger than some internal value. I am certain there is a facial image since I am able to read it using another api.
Making the same type of GET DATA call on other objects returns successfully with all of the data (i.e. Card Auth Certificate).
If anyone has any ideas it would be appreciated. For now it looks to me like there is a bug in the javax.smartcardio API when the response exceeds a certain size. I would have expected a return of 0x61,0xXX if it was not able to read the entire response.
Just in case anyone is interested in this Thread other than me, I finally got everything working.
After looking at the OpenJDK source I discovered that the default for both a T=0 and a T=1 protocol is to fully read the response for a transmit. Normally this is not a problem if the object that you're trying to get is less than 8K (i.e. CHUID, Certs ...). The Facial Image is approximately 12K so it was always returning an exception after it tried to read 8K.
The 8K limit comes from a hard coded loop limit on read response of 32. Since each read only gets about 255 bytes or less the exception will always be thrown if the size goes above 8K and the T=0 and T=1 protocols are set to automatically read the response.
To work around this for larger objects you must set a system property for the protocol of the card to false so that you have to manually get the response.
Once this is set then after the get data command you're able to read the response yourself in a loop of as many times as needed. The only catch is that you must pass in a 0 as the response length on the original get data call or you will get the specified amount of data and nothing more.
Thanks for the update symmetrysolutions - I am encountering the same problem reading my PIV card. Would you be willing to share the code? I cannot figure out how to "read the response yourself". Multiple calls to the "get data" APDU always return SW = 61 00 with no bytes of data.