I may not have understood the question/context properly, given the answer.

The Cardedge is t0-biased - hosts enumerate object directories to learn object sizes, and then send n read object commands each of which is < 256 byte. Hosts compute the necessary offset in the object stream for each nth round. This practice puts intelligence into the protocol, and dumbs down the card requirements.

This policy is enforced by the internal method:

private void sendData(APDU apdu, byte[] data, short offset, short size) {
       if (size > 255) {
           ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
       }

Util.arrayCopyNonAtomic(data, offset, apdu.getBuffer(), (short) 0, size); //original
       apdu.setOutgoingAndSend((short)0, (short)size);
   }

So, in protocol terms it appears that size > 256 is an authorizred state. However, this implementation objects, and send an exception. Presumably, a different implmenetation with more effective resource management could handle the size > 256 issue, perhaps according to the 7816-4 command pattern (whose practice for LE/LC go beyond T0 rules for LE and LC handling).


From: "Tripp Hyde" <[EMAIL PROTECTED]>
Reply-To: MUSCLE  <[email protected]>
To: "MUSCLE" <[email protected]>
Subject: RE: [Muscle] Data and 61XX
Date: Mon, 21 Nov 2005 13:02:17 -0500

Thanks for the input Karsten.  Much appreciated.

Tripp Hyde


-----Original Message-----
From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED] Behalf Of Karsten Ohme
Sent: Monday, November 21, 2005 12:40 PM
To: MUSCLE
Subject: Re: [Muscle] Data and 61XX


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

_______________________________________________
Muscle mailing list
[email protected]
http://lists.drizzle.com/mailman/listinfo/muscle


_______________________________________________
Muscle mailing list
[email protected]
http://lists.drizzle.com/mailman/listinfo/muscle

Reply via email to