Tripp Hyde wrote: > Hello, I'm curious what Musclecard does in the following case. If > you want to retrieve data from the card that's greater than the size > of a transmission packet (say 256 bytes), the card sends back '61XX' > where XX indicates how much data is left. You can continue sending > GET RESPONSES to the card until you get all the data. However, after > searching through 7816-3 and 7816-4 I can't seem to find the answer > for the following case: > > What if you specify an Lc byte that is smaller than the amount of > data that could be returned. Does the card return a '6CXX' error, > does it return that smaller amount of data + '9000', or does it > return that smaller amount of data + '61XX' where XX is the amount of > data left? Or is this left open to the interpretation of the > application designer?
The return codes are specified by the Java Card specification. But they
are conforming to ISO 7816-4.
I quote from Java Card RE Specification Chapter 9, I hope this is the
case you are asking:
// Lr < Le
// 1. The card sends <0x61,Lr>
completion status bytes
// 2. The CAD sends GET
RESPONSE command with Le = Lr.
// 3. The card sends Lr bytes
of output data using the standard
T=0 <INS> or <~INS>
// procedure byte mechanism.
// 4. The card sends <SW1,SW2>
completion status on completion of the
// Applet.process method.
// Lr > Le
// 1. The card sends Le bytes
of output data using the standard
T=0 <INS> or
// <~INS> procedure byte
mechanism.
// 2. The card sends
<0x61,(Lr-Le)> completion status bytes
// 3. The CAD sends GET
RESPONSE command with new Le <= Lr.
// 4. The card sends (new) Le
bytes of output data using the
standard T=0 <INS> or
// <~INS> procedure byte
mechanism.
// 5. Repeat steps 2-4 as
necessary to send the remaining output
data bytes (Lr) as
// required.
// 6. The card sends <SW1,SW2>
completion status on completion of the
// Applet.process method.
>
> I'm just trying to figure out how others interpret this case.
> Thanks.
You can sneak through the code below, this should handle all cases
correctly.
Karsten
static LONG send_APDU(OPGP_CARD_INFO cardInfo, GP211_SECURITY_INFO
*secInfo, PBYTE capdu, DWORD capduLength, PBYTE rapdu, PDWORD rapduLength) {
LONG result;
// modified for managing all 4 cases with automatic APDU chaining
// when necessary...
BYTE apduCommand[261];
DWORD caseAPDU;
DWORD apduCommandLength = 261;
BYTE lc;
BYTE le;
BYTE la;
DWORD i;
DWORD offset = 0;
PBYTE responseData = NULL;
DWORD responseDataLength = *rapduLength;
LOG_START(_T("send_APDU"));
responseData = (PBYTE)malloc(sizeof(BYTE)*responseDataLength);
if (traceEnable) {
_ftprintf(traceFile, _T("--> "));
for (i=0; i<capduLength; i++) {
_ftprintf(traceFile, _T("%02X"), capdu[i]);
}
_ftprintf(traceFile, _T("\n"));
}
// main transmission block
// wrap command
result = wrap_command(capdu, capduLength, apduCommand,
&apduCommandLength, secInfo);
if ( OPGP_ERROR_SUCCESS != result) {
goto end;
}
apduCommand[0] |= cardInfo.logicalChannel;
// if T=1 or else T=0
if (cardInfo.protocol == OPGP_CARD_PROTOCOL_T1) {
// T=1 transmition
result = SCardTransmit(cardInfo.cardHandle,
SCARD_PCI_T1,
apduCommand,
apduCommandLength,
NULL,
responseData,
&responseDataLength
);
if ( SCARD_S_SUCCESS != result) {
goto end;
} // if ( SCARD_S_SUCCESS != result)
offset += responseDataLength - 2;
} else {
// Determine which type of Exchange between the reader
if (apduCommandLength == 4) {
// Case 1 short
caseAPDU = 1;
} else if (apduCommandLength == 5) {
// Case 2 short
caseAPDU = 2;
le = apduCommand[4];
} else {
lc = apduCommand[4];
if ((convertByte(lc) + 5) == apduCommandLength) {
// Case 3 short
caseAPDU = 3;
} else if ((convertByte(lc) + 5 + 1) ==
apduCommandLength) {
// Case 4 short
caseAPDU = 4;
le = apduCommand[apduCommandLength - 1];
apduCommandLength--;
} else {
{ result = OPGP_ERROR_UNRECOGNIZED_APDU_COMMAND; goto
end; }
}
} // if (Determine which type of Exchange)
// T=0 transmition (first command)
responseDataLength = *rapduLength;
result = SCardTransmit(cardInfo.cardHandle,
SCARD_PCI_T0,
apduCommand,
apduCommandLength,
NULL,
responseData,
&responseDataLength
);
if ( SCARD_S_SUCCESS != result) {
goto end;
} // if ( SCARD_S_SUCCESS != result)
offset += responseDataLength - 2;
// main switch block for cases 2 and 4
switch (caseAPDU) {
case 2: {
while ((responseData[responseDataLength +
offset - 2] == 0x61)
|| (responseData[responseDataLength +
offset - 2] == 0x6c)) {
//Le is not accepted by the card and
the card indicates the
available length La.
//The response TPDU from the card
indicates that the command is
aborted due to
//a wrong length and that the right
length is La: (SW1='6C' and SW2
codes La).
if (responseData[responseDataLength +
offset - 2] == 0x6c) {
la =
responseData[responseDataLength + offset - 1];
apduCommand[apduCommandLength-1] = la; // P3
// T=0 transmition (command w/
La)
responseDataLength =
*rapduLength - offset;
result =
SCardTransmit(cardInfo.cardHandle,
SCARD_PCI_T0,
apduCommand,
apduCommandLength,
NULL,
responseData+offset,
&responseDataLength
);
if ( SCARD_S_SUCCESS != result)
{
goto end;
}
// If La is greater that Le,
then the response TPDU is mapped
// onto the response APDU by
keeping only the first Le bytes
// of the body and the status
bytes SW1-SW2.
if (convertByte(le) <
convertByte(la)) {
memmove(responseData+offset+convertByte(le),
responseData+offset+responseDataLength-2, 2);
offset +=
convertByte(le);
break;
} // if (convertByte(le) <
convertByte(la))
offset += responseDataLength -
2;
le = la;
continue;
} // if (6C)
// Java Card specific. Java Card RE
Specification Chapter 9
// if (61)
if (responseData[responseDataLength +
offset - 2] == 0x61) {
// Lr < Le
// 1. The card sends <0x61,Lr>
completion status bytes
// 2. The CAD sends GET
RESPONSE command with Le = Lr.
// 3. The card sends Lr bytes
of output data using the standard
T=0 <INS> or <~INS>
// procedure byte mechanism.
// 4. The card sends <SW1,SW2>
completion status on completion of the
// Applet.process method.
// Lr > Le
// 1. The card sends Le bytes
of output data using the standard
T=0 <INS> or
// <~INS> procedure byte
mechanism.
// 2. The card sends
<0x61,(Lr-Le)> completion status bytes
// 3. The CAD sends GET
RESPONSE command with new Le <= Lr.
// 4. The card sends (new) Le
bytes of output data using the
standard T=0 <INS> or
// <~INS> procedure byte
mechanism.
// 5. Repeat steps 2-4 as
necessary to send the remaining output
data bytes (Lr) as
// required.
// 6. The card sends <SW1,SW2>
completion status on completion of the
// Applet.process method.
// These two cases behave the
same way
la =
responseData[responseDataLength + offset - 1];
apduCommand[0] = 0x00;;
apduCommand[1] = 0xC0; // INS
(Get Response)
apduCommand[2] = 0x00; // P1
apduCommand[3] = 0x00; // P2
apduCommand[4] = la;
apduCommandLength = 5;
le = la;
// T=0 transmition (command w/
La)
responseDataLength =
*rapduLength - offset;
result =
SCardTransmit(cardInfo.cardHandle,
SCARD_PCI_T0,
apduCommand,
apduCommandLength,
NULL,
responseData+offset,
&responseDataLength
);
if ( SCARD_S_SUCCESS != result)
{
goto end;
} // if ( SCARD_S_SUCCESS !=
result)
offset += responseDataLength -
2;
continue;
} // if (61)
} // while (61) || (6c)
break;
} // case 2
case 4: {
/* Note: Some smartcard are not fully compatible
with ISO normatives in case short 4.
So when a card returns a 0x9000 to
inform a good
transfer of the APDU command then the
terminal
have to terminate the transaction and
it shall
return the sw1 sw2 to the user. In the
case of
fully ISO, the terminal sends a get
response
to extract the "le" bytes requested
inside
the APDU command. */
// if 61 etc.
if (responseData[responseDataLength + offset -
2] == 0x61
|| responseData[responseDataLength +
offset - 2] == 0x90
|| responseData[responseDataLength +
offset - 2] == 0x9F) {
apduCommand[0] = 0x00;
apduCommand[1] = 0xC0; // INS (Get
Response)
apduCommand[2] = 0x00; // P1
apduCommand[3] = 0x00; // P2
apduCommandLength = 5;
// Default Case Le is requested in the
get response
apduCommand[4] = le; // P3
// verify if we have La < Le in the
case of sw2 = 0x61 or 0x9f
if (responseData[responseDataLength +
offset - 2] != 0x90) {
if
(convertByte(responseData[responseDataLength + offset - 1]) <
convertByte(le)) {
// La is requested in the get
response
apduCommand[4] =
responseData[responseDataLength + offset - 1];
le =
responseData[responseDataLength + offset - 1];
}
}
// T=0 transmission (command w/ Le or
La)
responseDataLength = *rapduLength -
offset;
result =
SCardTransmit(cardInfo.cardHandle,
SCARD_PCI_T0,
apduCommand,
apduCommandLength,
NULL,
responseData+offset,
&responseDataLength
);
if ( SCARD_S_SUCCESS != result) {
goto end;
} // if ( SCARD_S_SUCCESS != result)
offset += responseDataLength - 2;
} // if (61 etc.)
while ((responseData[responseDataLength +
offset - 2] == 0x61)
|| (responseData[responseDataLength +
offset - 2] == 0x6c)
|| (responseData[responseDataLength +
offset - 2] == 0x9f)) {
// if (6c)
if (responseData[responseDataLength +
offset - 2] == 0x6c) {
la =
responseData[responseDataLength + offset - 1];
apduCommand[apduCommandLength
-1] = la; // P3
// T=0 transmition (command w/
La)
responseDataLength =
*rapduLength - offset;
result =
SCardTransmit(cardInfo.cardHandle,
SCARD_PCI_T0,
apduCommand,
apduCommandLength,
NULL,
responseData+offset,
&responseDataLength
);
if ( SCARD_S_SUCCESS != result)
{
goto end;
}
// If La is greater that Le,
then the response TPDU is mapped
// onto the response APDU by
keeping only the first Le bytes
// of the body and the status
bytes SW1-SW2.
if (convertByte(le) <
convertByte(la)) {
memmove(responseData+offset+convertByte(le),
responseData+offset+responseDataLength-2, 2);
offset +=
convertByte(le);
break;
} // if (convertByte(le) <
convertByte(la))
offset += responseDataLength -
2;
le = la;
continue;
} // if (6c)
// if (61) || (9f)
if ((responseData[responseDataLength +
offset - 2] == 0x61)
|| (responseData[responseDataLength +
offset - 2] == 0x9f)) {
// Lr < Le
// 1. The card sends <0x61,Lr>
completion status bytes
// 2. The CAD sends GET
RESPONSE command with Le = Lr.
// 3. The card sends Lr bytes
of output data using the standard
T=0 <INS> or <~INS>
// procedure byte mechanism.
// 4. The card sends <SW1,SW2>
completion status on completion of the
// Applet.process method.
// Lr > Le
// 1. The card sends Le bytes
of output data using the standard
T=0 <INS> or
// <~INS> procedure byte
mechanism.
// 2. The card sends
<0x61,(Lr-Le)> completion status bytes
// 3. The CAD sends GET
RESPONSE command with new Le <= Lr.
// 4. The card sends (new) Le
bytes of output data using the
standard T=0 <INS> or
// <~INS> procedure byte
mechanism.
// 5. Repeat steps 2-4 as
necessary to send the remaining output
data bytes (Lr) as
// required.
// 6. The card sends <SW1,SW2>
completion status on completion of the
// Applet.process method.
la =
responseData[responseDataLength + offset - 1];
apduCommand[0] = 0x00;
apduCommand[1] = 0xC0; // INS
(Get Response)
apduCommand[2] = 0x00; // P1
apduCommand[3] = 0x00; // P2
apduCommand[4] = la;
apduCommandLength = 5;
le = la;
// T=0 transmition (command w/
La)
responseDataLength =
*rapduLength - offset;
result =
SCardTransmit(cardInfo.cardHandle,
SCARD_PCI_T0,
apduCommand,
apduCommandLength,
NULL,
responseData+offset,
&responseDataLength
);
if ( SCARD_S_SUCCESS != result)
{
goto end;
}
offset += responseDataLength -
2;
continue;
} // if (61) || (9f)
} // while (61) || (6c) || (9f)
break;
} // case 4
} // switch (main switch block for cases 2 and 4)
} // if (if T=1 or else T=0)
// if the case 3 command is actually a case 4 command and the cards
wants to responds something.
if (responseData[responseDataLength + offset - 2] == 0x61) {
la = responseData[responseDataLength + offset - 1];
apduCommand[0] = 0x00;;
apduCommand[1] = 0xC0; // INS (Get Response)
apduCommand[2] = 0x00; // P1
apduCommand[3] = 0x00; // P2
apduCommand[4] = la;
apduCommandLength = 5;
le = la;
// T=0 transmition (command w/ La)
responseDataLength = *rapduLength - offset;
result = SCardTransmit(cardInfo.cardHandle,
cardInfo.protocol == OPGP_CARD_PROTOCOL_T0 ?
SCARD_PCI_T0 :
SCARD_PCI_T1,
apduCommand,
apduCommandLength,
NULL,
responseData+offset,
&responseDataLength
);
if ( SCARD_S_SUCCESS != result) {
goto end;
} // if ( SCARD_S_SUCCESS != result)
offset += responseDataLength - 2;
} // if (61)
memcpy(rapdu, responseData, offset + 2);
*rapduLength = offset + 2;
if (traceEnable) {
_ftprintf(traceFile, _T("<-- "));
for (i=0; i<*rapduLength; i++) {
_ftprintf(traceFile, _T("%02X"), rapdu[i]);
}
_ftprintf(traceFile, _T("\n"));
}
if (rapdu[*rapduLength-2] != 0x90 || rapdu[*rapduLength-1] != 0x00) {
result = (OPGP_ISO7816_ERROR_PREFIX | (rapdu[*rapduLength-2] <<
8)) |
rapdu[*rapduLength-1];
goto end;
}
{ result = OPGP_ERROR_SUCCESS; goto end; }
end:
if (responseData)
free(responseData);
LOG_END(_T("send_APDU"), result);
return result;
}
>
> Tripp
>
> _______________________________________________ Muscle mailing list
> [email protected]
> http://lists.drizzle.com/mailman/listinfo/muscle
_______________________________________________
Muscle mailing list
[email protected]
http://lists.drizzle.com/mailman/listinfo/muscle
