add tests for CcidTransceiver
This commit is contained in:
@@ -23,6 +23,7 @@ import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import org.sufficientlysecure.keychain.securitytoken.usb.tpdu.T1ShortApduProtocol;
|
||||
@@ -54,6 +55,11 @@ abstract class CcidDescription {
|
||||
public abstract int getProtocols();
|
||||
public abstract int getFeatures();
|
||||
|
||||
@VisibleForTesting
|
||||
static CcidDescription fromValues(byte maxSlotIndex, byte voltageSupport, int protocols, int features) {
|
||||
return new AutoValue_CcidDescription(maxSlotIndex, voltageSupport, protocols, features);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static CcidDescription fromRawDescriptors(byte[] desc) throws UsbTransportException {
|
||||
int dwProtocols = 0, dwFeatures = 0;
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.google.auto.value.AutoValue;
|
||||
import org.bouncycastle.util.Arrays;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.securitytoken.usb.UsbTransportException.UsbCcidErrorException;
|
||||
|
||||
|
||||
public class CcidTransceiver {
|
||||
@@ -40,6 +41,7 @@ public class CcidTransceiver {
|
||||
|
||||
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_ICC_POWER_OFF = 0x63;
|
||||
private static final int MESSAGE_TYPE_PC_TO_RDR_XFR_BLOCK = 0x6f;
|
||||
|
||||
private static final int COMMAND_STATUS_SUCCESS = 0;
|
||||
@@ -86,15 +88,20 @@ public class CcidTransceiver {
|
||||
CcidDataBlock response = null;
|
||||
for (CcidDescription.Voltage v : usbCcidDescription.getVoltages()) {
|
||||
Log.v(Constants.TAG, "CCID: attempting to power on with voltage " + v.toString());
|
||||
response = iccPowerOnVoltage(v.powerOnValue);
|
||||
try {
|
||||
response = iccPowerOnVoltage(v.powerOnValue);
|
||||
} catch (UsbCcidErrorException e) {
|
||||
if (e.getErrorResponse().getError() == 7) { // Power select error
|
||||
Log.v(Constants.TAG, "CCID: failed to power on with voltage " + v.toString());
|
||||
iccPowerOff();
|
||||
Log.v(Constants.TAG, "CCID: powered off");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (response.getStatus() == 1 && response.getError() == 7) { // Power select error
|
||||
Log.v(Constants.TAG, "CCID: failed to power on with voltage " + v.toString());
|
||||
iccPowerOff();
|
||||
Log.v(Constants.TAG, "CCID: powered off");
|
||||
} else {
|
||||
break;
|
||||
throw e;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
if (response == null) {
|
||||
throw new UsbTransportException("Couldn't power up ICC2");
|
||||
@@ -127,7 +134,7 @@ public class CcidTransceiver {
|
||||
private void iccPowerOff() throws UsbTransportException {
|
||||
byte sequenceNumber = currentSequenceNumber++;
|
||||
final byte[] iccPowerCommand = {
|
||||
0x63,
|
||||
MESSAGE_TYPE_PC_TO_RDR_ICC_POWER_OFF,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
sequenceNumber,
|
||||
@@ -193,7 +200,7 @@ public class CcidTransceiver {
|
||||
} while (response.isStatusTimeoutExtensionRequest());
|
||||
|
||||
if (!response.isStatusSuccess()) {
|
||||
throw new UsbTransportException("USB-CCID error: " + response);
|
||||
throw new UsbCcidErrorException("USB-CCID error!", response);
|
||||
}
|
||||
|
||||
return response;
|
||||
@@ -213,7 +220,6 @@ public class CcidTransceiver {
|
||||
|
||||
throw new UsbTransportException("USB-CCID error - bad CCID header type " + inputBuffer[0]);
|
||||
}
|
||||
|
||||
CcidDataBlock result = CcidDataBlock.parseHeaderFromBytes(inputBuffer);
|
||||
|
||||
if (expectedSequenceNumber != result.getSeq()) {
|
||||
@@ -235,6 +241,7 @@ public class CcidTransceiver {
|
||||
}
|
||||
|
||||
result = result.withData(dataBuffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.securitytoken.usb;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import android.hardware.usb.UsbConstants;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbDeviceConnection;
|
||||
@@ -28,15 +31,13 @@ import android.support.annotation.Nullable;
|
||||
import android.util.Pair;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.securitytoken.CommandApdu;
|
||||
import org.sufficientlysecure.keychain.securitytoken.ResponseApdu;
|
||||
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo.TokenType;
|
||||
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo.TransportType;
|
||||
import org.sufficientlysecure.keychain.securitytoken.Transport;
|
||||
import org.sufficientlysecure.keychain.securitytoken.CommandApdu;
|
||||
import org.sufficientlysecure.keychain.securitytoken.ResponseApdu;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Based on USB CCID Specification rev. 1.1
|
||||
* http://www.usb.org/developers/docs/devclass_docs/DWG_Smart-Card_CCID_Rev110.pdf
|
||||
@@ -136,6 +137,7 @@ public class UsbTransport implements Transport {
|
||||
}
|
||||
|
||||
CcidDescription ccidDescription = CcidDescription.fromRawDescriptors(usbConnection.getRawDescriptors());
|
||||
Log.d(Constants.TAG, "CCID Description: " + ccidDescription);
|
||||
CcidTransceiver transceiver = new CcidTransceiver(usbConnection, usbBulkIn, usbBulkOut, ccidDescription);
|
||||
|
||||
ccidTransportProtocol = ccidDescription.getSuitableTransportProtocol();
|
||||
|
||||
@@ -19,6 +19,9 @@ package org.sufficientlysecure.keychain.securitytoken.usb;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.sufficientlysecure.keychain.securitytoken.usb.CcidTransceiver.CcidDataBlock;
|
||||
|
||||
|
||||
public class UsbTransportException extends IOException {
|
||||
public UsbTransportException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
@@ -31,4 +34,17 @@ public class UsbTransportException extends IOException {
|
||||
public UsbTransportException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
static class UsbCcidErrorException extends UsbTransportException {
|
||||
private CcidDataBlock errorResponse;
|
||||
|
||||
UsbCcidErrorException(String detailMessage, CcidDataBlock errorResponse) {
|
||||
super(detailMessage + " " + errorResponse);
|
||||
this.errorResponse = errorResponse;
|
||||
}
|
||||
|
||||
CcidDataBlock getErrorResponse() {
|
||||
return errorResponse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user