refactor CcidTransceiver
This commit is contained in:
@@ -21,66 +21,68 @@ import android.hardware.usb.UsbDeviceConnection;
|
|||||||
import android.hardware.usb.UsbEndpoint;
|
import android.hardware.usb.UsbEndpoint;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.auto.value.AutoValue;
|
||||||
import org.bouncycastle.util.Arrays;
|
import org.bouncycastle.util.Arrays;
|
||||||
import org.bouncycastle.util.encoders.Hex;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
public class CcidTransceiver {
|
public class CcidTransceiver {
|
||||||
|
private static final int CCID_HEADER_LENGTH = 10;
|
||||||
|
|
||||||
|
private static final int MESSAGE_TYPE_RDR_TO_PC_DATA_BLOCK = 0x80;
|
||||||
|
private static final int MESSAGE_TYPE_PC_TO_RDR_ICC_POWER_ON = 0x62;
|
||||||
|
private static final int MESSAGE_TYPE_PC_TO_RDR_XFR_BLOCK = 0x6f;
|
||||||
|
|
||||||
|
private static final int COMMAND_STATUS_SUCCESS = 0;
|
||||||
|
private static final int COMMAND_STATUS_TIME_EXTENSION_RQUESTED = 2;
|
||||||
|
|
||||||
|
private static final int SLOT_NUMBER = 0x00;
|
||||||
|
|
||||||
|
private static final int ICC_STATUS_SUCCESS = 0;
|
||||||
|
|
||||||
private static final int TIMEOUT = 20 * 1000; // 20s
|
private static final int TIMEOUT = 20 * 1000; // 20s
|
||||||
|
|
||||||
private byte mCounter;
|
private final UsbDeviceConnection usbConnection;
|
||||||
private UsbDeviceConnection mConnection;
|
private final UsbEndpoint usbBulkIn;
|
||||||
private UsbEndpoint mBulkIn;
|
private final UsbEndpoint usbBulkOut;
|
||||||
private UsbEndpoint mBulkOut;
|
|
||||||
|
|
||||||
public CcidTransceiver(final UsbDeviceConnection connection, final UsbEndpoint bulkIn,
|
private byte currentSequenceNumber;
|
||||||
final UsbEndpoint bulkOut) {
|
|
||||||
|
|
||||||
mConnection = connection;
|
CcidTransceiver(UsbDeviceConnection connection, UsbEndpoint bulkIn, UsbEndpoint bulkOut) {
|
||||||
mBulkIn = bulkIn;
|
usbConnection = connection;
|
||||||
mBulkOut = bulkOut;
|
usbBulkIn = bulkIn;
|
||||||
}
|
usbBulkOut = bulkOut;
|
||||||
|
|
||||||
public byte[] receiveRaw() throws UsbTransportException {
|
|
||||||
byte[] bytes;
|
|
||||||
do {
|
|
||||||
bytes = receive();
|
|
||||||
} while (isDataBlockNotReady(bytes));
|
|
||||||
|
|
||||||
checkDataBlockResponse(bytes);
|
|
||||||
|
|
||||||
return Arrays.copyOfRange(bytes, 10, bytes.length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Power of ICC
|
* Power of ICC
|
||||||
* Spec: 6.1.1 PC_to_RDR_IccPowerOn
|
* Spec: 6.1.1 PC_to_RDR_IccPowerOn
|
||||||
*
|
|
||||||
* @throws UsbTransportException
|
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public byte[] iccPowerOn() throws UsbTransportException {
|
public CcidDataBlock iccPowerOn() throws UsbTransportException {
|
||||||
|
byte sequenceNumber = currentSequenceNumber++;
|
||||||
final byte[] iccPowerCommand = {
|
final byte[] iccPowerCommand = {
|
||||||
0x62,
|
MESSAGE_TYPE_PC_TO_RDR_ICC_POWER_ON,
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00,
|
||||||
0x00,
|
SLOT_NUMBER,
|
||||||
mCounter++,
|
sequenceNumber,
|
||||||
0x00,
|
0x00, // voltage select = auto
|
||||||
0x00, 0x00
|
0x00, 0x00 // reserved for future use
|
||||||
};
|
};
|
||||||
|
|
||||||
sendRaw(iccPowerCommand);
|
sendRaw(iccPowerCommand, 0, iccPowerCommand.length);
|
||||||
|
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
byte[] atr = null;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
atr = receiveRaw();
|
return receiveDataBlock(sequenceNumber);
|
||||||
break;
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
Log.e(Constants.TAG, "Error waiting for device power on", e);
|
||||||
// Try more startTime
|
// Try more startTime
|
||||||
if (System.currentTimeMillis() - startTime > TIMEOUT) {
|
if (System.currentTimeMillis() - startTime > TIMEOUT) {
|
||||||
break;
|
break;
|
||||||
@@ -89,81 +91,155 @@ public class CcidTransceiver {
|
|||||||
SystemClock.sleep(100);
|
SystemClock.sleep(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (atr == null) {
|
throw new UsbTransportException("Couldn't power up Security Token");
|
||||||
throw new UsbTransportException("Couldn't power up Security Token");
|
|
||||||
}
|
|
||||||
|
|
||||||
return atr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transmits XfrBlock
|
* Transmits XfrBlock
|
||||||
* 6.1.4 PC_to_RDR_XfrBlock
|
* 6.1.4 PC_to_RDR_XfrBlock
|
||||||
|
*
|
||||||
* @param payload payload to transmit
|
* @param payload payload to transmit
|
||||||
* @throws UsbTransportException
|
|
||||||
*/
|
*/
|
||||||
public void sendXfrBlock(byte[] payload) throws UsbTransportException {
|
public CcidDataBlock sendXfrBlock(byte[] payload) throws UsbTransportException {
|
||||||
int l = payload.length;
|
int l = payload.length;
|
||||||
byte[] data = Arrays.concatenate(new byte[]{
|
byte sequenceNumber = currentSequenceNumber++;
|
||||||
0x6f,
|
byte[] headerData = {
|
||||||
(byte) l, (byte) (l >> 8), (byte) (l >> 16), (byte) (l >> 24),
|
MESSAGE_TYPE_PC_TO_RDR_XFR_BLOCK,
|
||||||
0x00,
|
(byte) l, (byte) (l >> 8), (byte) (l >> 16), (byte) (l >> 24),
|
||||||
mCounter++,
|
SLOT_NUMBER,
|
||||||
0x00,
|
sequenceNumber,
|
||||||
0x00, 0x00},
|
0x00, // block waiting time
|
||||||
payload);
|
0x00, 0x00 // level parameters
|
||||||
|
};
|
||||||
|
byte[] data = Arrays.concatenate(headerData, payload);
|
||||||
|
|
||||||
int send = 0;
|
int sentBytes = 0;
|
||||||
while (send < data.length) {
|
while (sentBytes < data.length) {
|
||||||
final int len = Math.min(mBulkIn.getMaxPacketSize(), data.length - send);
|
int bytesToSend = Math.min(usbBulkIn.getMaxPacketSize(), data.length - sentBytes);
|
||||||
sendRaw(Arrays.copyOfRange(data, send, send + len));
|
sendRaw(data, sentBytes, bytesToSend);
|
||||||
send += len;
|
sentBytes += bytesToSend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return receiveDataBlock(sequenceNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] receive() throws UsbTransportException {
|
private CcidDataBlock receiveDataBlock(byte expectedSequenceNumber) throws UsbTransportException {
|
||||||
byte[] buffer = new byte[mBulkIn.getMaxPacketSize()];
|
CcidDataBlock response;
|
||||||
byte[] result = null;
|
|
||||||
int readBytes = 0, totalBytes = 0;
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
int res = mConnection.bulkTransfer(mBulkIn, buffer, buffer.length, TIMEOUT);
|
response = receiveDataBlockImmediate(expectedSequenceNumber);
|
||||||
if (res < 0) {
|
} while (response.isStatusTimeoutExtensionRequest());
|
||||||
throw new UsbTransportException("USB error - failed to receive response " + res);
|
|
||||||
}
|
|
||||||
if (result == null) {
|
|
||||||
if (res < 10) {
|
|
||||||
throw new UsbTransportException("USB-CCID error - failed to receive CCID header");
|
|
||||||
}
|
|
||||||
totalBytes = ByteBuffer.wrap(buffer, 1, 4).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer().get() + 10;
|
|
||||||
result = new byte[totalBytes];
|
|
||||||
}
|
|
||||||
System.arraycopy(buffer, 0, result, readBytes, res);
|
|
||||||
readBytes += res;
|
|
||||||
} while (readBytes < totalBytes);
|
|
||||||
|
|
||||||
|
if (!response.isStatusSuccess()) {
|
||||||
|
throw new UsbTransportException("USB-CCID error: " + response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CcidDataBlock receiveDataBlockImmediate(byte expectedSequenceNumber) throws UsbTransportException {
|
||||||
|
byte[] buffer = new byte[usbBulkIn.getMaxPacketSize()];
|
||||||
|
|
||||||
|
int readBytes = usbConnection.bulkTransfer(usbBulkIn, buffer, buffer.length, TIMEOUT);
|
||||||
|
if (readBytes < CCID_HEADER_LENGTH) {
|
||||||
|
throw new UsbTransportException("USB-CCID error - failed to receive CCID header");
|
||||||
|
}
|
||||||
|
if (buffer[0] != (byte) MESSAGE_TYPE_RDR_TO_PC_DATA_BLOCK) {
|
||||||
|
throw new UsbTransportException("USB-CCID error - bad CCID header type " + buffer[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
CcidDataBlock result = CcidDataBlock.parseHeaderFromBytes(buffer);
|
||||||
|
|
||||||
|
if (expectedSequenceNumber != result.getSeq()) {
|
||||||
|
throw new UsbTransportException("USB-CCID error - expected sequence number " +
|
||||||
|
expectedSequenceNumber + ", got " + result);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] dataBuffer = new byte[result.getDataLength()];
|
||||||
|
int bufferedBytes = readBytes - CCID_HEADER_LENGTH;
|
||||||
|
System.arraycopy(buffer, CCID_HEADER_LENGTH, dataBuffer, 0, bufferedBytes);
|
||||||
|
|
||||||
|
while (bufferedBytes < dataBuffer.length) {
|
||||||
|
readBytes = usbConnection.bulkTransfer(usbBulkIn, buffer, buffer.length, TIMEOUT);
|
||||||
|
if (readBytes < 0) {
|
||||||
|
throw new UsbTransportException("USB error - failed reading response data! Header: " + result);
|
||||||
|
}
|
||||||
|
System.arraycopy(buffer, 0, dataBuffer, bufferedBytes, readBytes);
|
||||||
|
bufferedBytes += readBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result.withData(dataBuffer);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendRaw(final byte[] data) throws UsbTransportException {
|
private void sendRaw(byte[] data, int offset, int length) throws UsbTransportException {
|
||||||
final int tr1 = mConnection.bulkTransfer(mBulkOut, data, data.length, TIMEOUT);
|
int tr1;
|
||||||
if (tr1 != data.length) {
|
|
||||||
throw new UsbTransportException("USB error - failed to transmit data " + tr1);
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||||
|
tr1 = usbConnection.bulkTransfer(usbBulkOut, data, offset, length, TIMEOUT);
|
||||||
|
} else {
|
||||||
|
byte[] dataToSend = Arrays.copyOfRange(data, offset, offset+length);
|
||||||
|
tr1 = usbConnection.bulkTransfer(usbBulkOut, dataToSend, dataToSend.length, TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tr1 != length) {
|
||||||
|
throw new UsbTransportException("USB error - failed to transmit data (" + tr1 + "/" + length + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte getStatus(byte[] bytes) {
|
/** Corresponds to 6.2.1 RDR_to_PC_DataBlock. */
|
||||||
return (byte) ((bytes[7] >> 6) & 0x03);
|
@AutoValue
|
||||||
}
|
public abstract static class CcidDataBlock {
|
||||||
|
public abstract int getDataLength();
|
||||||
|
public abstract byte getSlot();
|
||||||
|
public abstract byte getSeq();
|
||||||
|
public abstract byte getStatus();
|
||||||
|
public abstract byte getError();
|
||||||
|
public abstract byte getChainParameter();
|
||||||
|
@Nullable
|
||||||
|
public abstract byte[] getData();
|
||||||
|
|
||||||
private void checkDataBlockResponse(byte[] bytes) throws UsbTransportException {
|
static CcidDataBlock parseHeaderFromBytes(byte[] headerBytes) {
|
||||||
final byte status = getStatus(bytes);
|
ByteBuffer buf = ByteBuffer.wrap(headerBytes);
|
||||||
if (status != 0) {
|
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
throw new UsbTransportException("USB-CCID error - status " + status + " error code: " + Hex.toHexString(bytes, 8, 1));
|
|
||||||
|
byte type = buf.get();
|
||||||
|
if (type != (byte) MESSAGE_TYPE_RDR_TO_PC_DATA_BLOCK) {
|
||||||
|
throw new IllegalArgumentException("Header has incorrect type value!");
|
||||||
|
}
|
||||||
|
int dwLength = buf.getInt();
|
||||||
|
byte bSlot = buf.get();
|
||||||
|
byte bSeq = buf.get();
|
||||||
|
byte bStatus = buf.get();
|
||||||
|
byte bError = buf.get();
|
||||||
|
byte bChainParameter = buf.get();
|
||||||
|
|
||||||
|
return new AutoValue_CcidTransceiver_CcidDataBlock(
|
||||||
|
dwLength, bSlot, bSeq, bStatus, bError, bChainParameter, null);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isDataBlockNotReady(byte[] bytes) {
|
CcidDataBlock withData(byte[] data) {
|
||||||
return getStatus(bytes) == 2;
|
if (getData() != null) {
|
||||||
|
throw new IllegalStateException("Cannot add data to this class twice!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AutoValue_CcidTransceiver_CcidDataBlock(
|
||||||
|
getDataLength(), getSlot(), getSeq(), getStatus(), getError(), getChainParameter(), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte getIccStatus() {
|
||||||
|
return (byte) (getStatus() & 0x03);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte getCommandStatus() {
|
||||||
|
return (byte) ((getStatus() >> 6) & 0x03);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isStatusTimeoutExtensionRequest() {
|
||||||
|
return getCommandStatus() == COMMAND_STATUS_TIME_EXTENSION_RQUESTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isStatusSuccess() {
|
||||||
|
return getIccStatus() == ICC_STATUS_SUCCESS && getCommandStatus() == COMMAND_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,23 +19,23 @@ package org.sufficientlysecure.keychain.securitytoken.usb;
|
|||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import org.bouncycastle.util.encoders.Hex;
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.securitytoken.usb.CcidTransceiver.CcidDataBlock;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
public class T1ShortApduProtocol implements CcidTransportProtocol {
|
class T1ShortApduProtocol implements CcidTransportProtocol {
|
||||||
private CcidTransceiver mTransceiver;
|
private CcidTransceiver mTransceiver;
|
||||||
|
|
||||||
public T1ShortApduProtocol(CcidTransceiver transceiver) throws UsbTransportException {
|
T1ShortApduProtocol(CcidTransceiver transceiver) throws UsbTransportException {
|
||||||
mTransceiver = transceiver;
|
mTransceiver = transceiver;
|
||||||
|
|
||||||
byte[] atr = mTransceiver.iccPowerOn();
|
CcidDataBlock atr = mTransceiver.iccPowerOn();
|
||||||
Log.d(Constants.TAG, "Usb transport connected T1/Short APDU, ATR=" + Hex.toHexString(atr));
|
Log.d(Constants.TAG, "Usb transport connected T1/Short APDU, ATR=" + atr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] transceive(@NonNull final byte[] apdu) throws UsbTransportException {
|
public byte[] transceive(@NonNull final byte[] apdu) throws UsbTransportException {
|
||||||
mTransceiver.sendXfrBlock(apdu);
|
CcidDataBlock response = mTransceiver.sendXfrBlock(apdu);
|
||||||
return mTransceiver.receiveRaw();
|
return response.getData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ package org.sufficientlysecure.keychain.securitytoken.usb.tpdu;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import org.bouncycastle.util.Arrays;
|
import org.bouncycastle.util.Arrays;
|
||||||
import org.bouncycastle.util.encoders.Hex;
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.securitytoken.usb.CcidTransceiver;
|
import org.sufficientlysecure.keychain.securitytoken.usb.CcidTransceiver;
|
||||||
|
import org.sufficientlysecure.keychain.securitytoken.usb.CcidTransceiver.CcidDataBlock;
|
||||||
import org.sufficientlysecure.keychain.securitytoken.usb.UsbTransportException;
|
import org.sufficientlysecure.keychain.securitytoken.usb.UsbTransportException;
|
||||||
import org.sufficientlysecure.keychain.securitytoken.usb.CcidTransportProtocol;
|
import org.sufficientlysecure.keychain.securitytoken.usb.CcidTransportProtocol;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
@@ -31,30 +31,28 @@ public class T1TpduProtocol implements CcidTransportProtocol {
|
|||||||
private final static int MAX_FRAME_LEN = 254;
|
private final static int MAX_FRAME_LEN = 254;
|
||||||
|
|
||||||
private byte mCounter = 0;
|
private byte mCounter = 0;
|
||||||
private CcidTransceiver mTransceiver;
|
private final CcidTransceiver ccidTransceiver;
|
||||||
private BlockChecksumType mChecksumType;
|
private final BlockChecksumType checksumType;
|
||||||
|
|
||||||
public T1TpduProtocol(final CcidTransceiver transceiver) throws UsbTransportException {
|
public T1TpduProtocol(CcidTransceiver transceiver) throws UsbTransportException {
|
||||||
mTransceiver = transceiver;
|
ccidTransceiver = transceiver;
|
||||||
|
|
||||||
// Connect
|
// Connect
|
||||||
byte[] atr = mTransceiver.iccPowerOn();
|
CcidDataBlock response = ccidTransceiver.iccPowerOn();
|
||||||
Log.d(Constants.TAG, "Usb transport connected T1/TPDU, ATR=" + Hex.toHexString(atr));
|
Log.d(Constants.TAG, "Usb transport connected T1/TPDU, ATR=" + response);
|
||||||
|
|
||||||
// TODO: set checksum from atr
|
// TODO: set checksum from atr
|
||||||
mChecksumType = BlockChecksumType.LRC;
|
checksumType = BlockChecksumType.LRC;
|
||||||
|
|
||||||
// PPS all auto
|
// PPS all auto
|
||||||
pps();
|
pps();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void pps() throws UsbTransportException {
|
private void pps() throws UsbTransportException {
|
||||||
byte[] pps = new byte[]{(byte) 0xFF, 1, (byte) (0xFF ^ 1)};
|
byte[] pps = new byte[]{(byte) 0xFF, 1, (byte) (0xFF ^ 1)};
|
||||||
|
|
||||||
mTransceiver.sendXfrBlock(pps);
|
CcidDataBlock response = ccidTransceiver.sendXfrBlock(pps);
|
||||||
|
Log.d(Constants.TAG, "PPS response " + response);
|
||||||
byte[] ppsResponse = mTransceiver.receiveRaw();
|
|
||||||
|
|
||||||
Log.d(Constants.TAG, "PPS response " + Hex.toHexString(ppsResponse));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] transceive(@NonNull byte[] apdu) throws UsbTransportException {
|
public byte[] transceive(@NonNull byte[] apdu) throws UsbTransportException {
|
||||||
@@ -72,10 +70,10 @@ public class T1TpduProtocol implements CcidTransportProtocol {
|
|||||||
// Send next frame
|
// Send next frame
|
||||||
Block block = newIBlock(mCounter++, hasMore, Arrays.copyOfRange(apdu, start, start + len));
|
Block block = newIBlock(mCounter++, hasMore, Arrays.copyOfRange(apdu, start, start + len));
|
||||||
|
|
||||||
mTransceiver.sendXfrBlock(block.getRawData());
|
CcidDataBlock response = ccidTransceiver.sendXfrBlock(block.getRawData());
|
||||||
|
|
||||||
// Receive I or R block
|
// Receive I or R block
|
||||||
responseBlock = getBlockFromResponse(mTransceiver.receiveRaw());
|
responseBlock = getBlockFromResponse(response);
|
||||||
|
|
||||||
start += len;
|
start += len;
|
||||||
|
|
||||||
@@ -104,9 +102,9 @@ public class T1TpduProtocol implements CcidTransportProtocol {
|
|||||||
|
|
||||||
while (((IBlock) responseBlock).getChaining()) {
|
while (((IBlock) responseBlock).getChaining()) {
|
||||||
Block ackBlock = newRBlock((byte) (((IBlock) responseBlock).getSequence() + 1));
|
Block ackBlock = newRBlock((byte) (((IBlock) responseBlock).getSequence() + 1));
|
||||||
mTransceiver.sendXfrBlock(ackBlock.getRawData());
|
CcidDataBlock response = ccidTransceiver.sendXfrBlock(ackBlock.getRawData());
|
||||||
|
|
||||||
responseBlock = getBlockFromResponse(mTransceiver.receiveRaw());
|
responseBlock = getBlockFromResponse(response);
|
||||||
|
|
||||||
if (responseBlock instanceof IBlock) {
|
if (responseBlock instanceof IBlock) {
|
||||||
responseApdu = Arrays.concatenate(responseApdu, responseBlock.getApdu());
|
responseApdu = Arrays.concatenate(responseApdu, responseBlock.getApdu());
|
||||||
@@ -120,8 +118,8 @@ public class T1TpduProtocol implements CcidTransportProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Factory methods
|
// Factory methods
|
||||||
public Block getBlockFromResponse(byte[] data) throws UsbTransportException {
|
public Block getBlockFromResponse(CcidDataBlock dataBlock) throws UsbTransportException {
|
||||||
final Block baseBlock = new Block(mChecksumType, data);
|
final Block baseBlock = new Block(checksumType, dataBlock.getData());
|
||||||
|
|
||||||
if ((baseBlock.getPcb() & IBlock.MASK_RBLOCK) == IBlock.MASK_VALUE_RBLOCK) {
|
if ((baseBlock.getPcb() & IBlock.MASK_RBLOCK) == IBlock.MASK_VALUE_RBLOCK) {
|
||||||
return new IBlock(baseBlock);
|
return new IBlock(baseBlock);
|
||||||
@@ -135,10 +133,10 @@ public class T1TpduProtocol implements CcidTransportProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public IBlock newIBlock(byte sequence, boolean chaining, byte[] apdu) throws UsbTransportException {
|
public IBlock newIBlock(byte sequence, boolean chaining, byte[] apdu) throws UsbTransportException {
|
||||||
return new IBlock(mChecksumType, (byte) 0, sequence, chaining, apdu);
|
return new IBlock(checksumType, (byte) 0, sequence, chaining, apdu);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RBlock newRBlock(byte sequence) throws UsbTransportException {
|
public RBlock newRBlock(byte sequence) throws UsbTransportException {
|
||||||
return new RBlock(mChecksumType, (byte) 0, sequence);
|
return new RBlock(checksumType, (byte) 0, sequence);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user