Skip to content

Commit

Permalink
Do not use APDU.isCommandChainingCLA() of the JC API
Browse files Browse the repository at this point in the history
Tests have shown that some card's implementations of this method are not in compliance with the API specification. Use a own convienence method to parse the CLA byte for the chaining bit.
  • Loading branch information
philipWendland committed Oct 31, 2014
1 parent 1d44209 commit cd69ad2
Showing 1 changed file with 25 additions and 9 deletions.
34 changes: 25 additions & 9 deletions src/net/pwendland/javacard/pki/IsoApplet.java
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ public void process(APDU apdu) {
}

// Command chaining checks
if( apdu.isCommandChainingCLA() ) {
if( isCommandChainingCLA(apdu) ) {
/*
* Command chaining only for:
* - PERFORM SECURITY OPERATION without extended APDUs
Expand Down Expand Up @@ -301,6 +301,23 @@ public void process(APDU apdu) {
}
}

/**
* \brief Parse the apdu's CLA byte to determine if the apdu is the first or second-last part of a chain.
*
* The Java Card API version 2.2.2 has a similar method (APDU.isCommandChainingCLA()), but tests have shown
* that some smartcard platform's implementations are wrong (not according to the JC API specification),
* specifically, but not limited to, JCOP 2.4.1 R3.
*
* \param apdu The apdu.
*
* \return true If the apdu is the [1;last[ part of a command chain,
* false if there is no chain or the apdu is the last part of the chain.
*/
static boolean isCommandChainingCLA(APDU apdu) {
byte[] buf = apdu.getBuffer();
return ((byte)(buf[0] & (byte)0x10) == (byte)0x10);
}

/**
* \brief Process the VERIFY apdu (INS = 20).
*
Expand Down Expand Up @@ -666,7 +683,7 @@ public void processGenerateAsymmetricKeypair(APDU apdu) throws ISOException {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
// Command chaining might be used for ECC, but not for RSA.
if(apdu.isCommandChainingCLA()) {
if(isCommandChainingCLA(apdu)) {
ISOException.throwIt(ISO7816.SW_COMMAND_CHAINING_NOT_SUPPORTED);
}
try {
Expand Down Expand Up @@ -1199,14 +1216,14 @@ private void decipher(APDU apdu) {

// Padding indicator should be "No further indication".
if(DEF_EXT_APDU && buf[offset_cdata] != (byte) 0x00
|| !DEF_EXT_APDU && apdu.isCommandChainingCLA() && buf[offset_cdata] != (byte) 0x00
|| !DEF_EXT_APDU && isCommandChainingCLA(apdu) && buf[offset_cdata] != (byte) 0x00
) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
}

// Use chaining if the card does not support extended APDUs.
if( !DEF_EXT_APDU ) {
if(apdu.isCommandChainingCLA()) {
if(isCommandChainingCLA(apdu)) {
// Copy the first part of the block to ram_buf, except padding indicator byte.
Util.arrayCopy(buf, (short)(apdu.getOffsetCdata()+1), ram_buf, (short) 0, (short)(lc-1));
ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS] = (short)(lc-1);
Expand Down Expand Up @@ -1323,7 +1340,7 @@ private void computeDigitalSignature(APDU apdu) throws ISOException {
// - Command chaining is performed and this is the first apdu in the chain.
if(ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS] == (short) 0) {
ecdsaSignature.init(ecKey, Signature.MODE_SIGN);
if(apdu.isCommandChainingCLA()) {
if(isCommandChainingCLA(apdu)) {
ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS] = (short) 1;
}
}
Expand All @@ -1340,7 +1357,7 @@ private void computeDigitalSignature(APDU apdu) throws ISOException {
}
}

if(!apdu.isCommandChainingCLA()) {
if(!isCommandChainingCLA(apdu)) {
sigLen = ecdsaSignature.sign(buf, pos, length, buf, (short) 0);
ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS] = (short) 0;
apdu.setOutgoingAndSend((short) 0, sigLen);
Expand Down Expand Up @@ -1405,7 +1422,6 @@ private void importPrivateKey(APDU apdu) throws ISOException {
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
}


if(currentAlgorithmRef[0] == ALG_GEN_RSA_2048) {
// RSA key import.
recvLen = apdu.setIncomingAndReceive();
Expand All @@ -1414,7 +1430,7 @@ private void importPrivateKey(APDU apdu) throws ISOException {
if(lc != recvLen) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
if(apdu.isCommandChainingCLA()) {
if(isCommandChainingCLA(apdu)) {
if(ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_BYTES_REMAINING] == (short) 0) {
/*
* First part of the chain.
Expand Down Expand Up @@ -1530,7 +1546,7 @@ private short doChainingOrExtAPDU(APDU apdu) throws ISOException {
recvLen = apdu.receiveBytes(offset_cdata);
}

if(apdu.isCommandChainingCLA()) {
if(isCommandChainingCLA(apdu)) {
// We are currently executing a chain with a particular INS.
ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_INS] = buf[ISO7816.OFFSET_INS];

Expand Down

0 comments on commit cd69ad2

Please sign in to comment.