OTG: Add support for persistent usb connection

No need to reinsert token on each operation
This commit is contained in:
Nikita Mikhailov
2016-04-08 00:41:53 +06:00
parent 3798249570
commit b5eb6468fe
8 changed files with 131 additions and 110 deletions

View File

@@ -249,9 +249,9 @@ public class CreateSecurityTokenImportResetFragment
@Override
public void doNfcInBackground() throws IOException {
mTokenFingerprints = mCreateKeyActivity.mSmartcardDevice.getFingerprints();
mTokenAid = mCreateKeyActivity.mSmartcardDevice.getAid();
mTokenUserId = mCreateKeyActivity.mSmartcardDevice.getUserId();
mTokenFingerprints = mCreateKeyActivity.getSmartcardDevice().getFingerprints();
mTokenAid = mCreateKeyActivity.getSmartcardDevice().getAid();
mTokenUserId = mCreateKeyActivity.getSmartcardDevice().getUserId();
byte[] fp = new byte[20];
ByteBuffer.wrap(fp).put(mTokenFingerprints, 0, 20);

View File

@@ -140,6 +140,32 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenNfcActivity
if (mRequiredInput.mType != RequiredInputParcel.RequiredInputType.NFC_MOVE_KEY_TO_CARD
&& mRequiredInput.mType != RequiredInputParcel.RequiredInputType.NFC_RESET_CARD) {
obtainSecurityTokenPin(mRequiredInput);
checkPinAvailability();
} else {
// No need for pin, rescan USB devices
mUsbDispatcher.rescanDevices();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (REQUEST_CODE_PIN == requestCode) {
checkPinAvailability();
}
}
private void checkPinAvailability() {
try {
Passphrase passphrase = PassphraseCacheService.getCachedPassphrase(this,
mRequiredInput.getMasterKeyId(), mRequiredInput.getSubKeyId());
if (passphrase != null) {
// Rescan USB devices
mUsbDispatcher.rescanDevices();
}
} catch (PassphraseCacheService.KeyNotFoundException e) {
throw new AssertionError(
"tried to find passphrase for non-existing key. this is a programming error!");
}
}
@@ -275,28 +301,33 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenNfcActivity
nfcGuideView.setCurrentStatus(NfcGuideView.NfcGuideViewStatus.DONE);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
// check all 200ms if Security Token has been taken away
while (true) {
if (isNfcConnected()) {
try {
Thread.sleep(200);
} catch (InterruptedException ignored) {
if (mSmartcardDevice.allowPersistentConnection()) {
// Just close
finish();
} else {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
// check all 200ms if Security Token has been taken away
while (true) {
if (isNfcConnected()) {
try {
Thread.sleep(200);
} catch (InterruptedException ignored) {
}
} else {
return null;
}
} else {
return null;
}
}
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
finish();
}
}.execute();
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
finish();
}
}.execute();
}
}
/**

View File

@@ -31,7 +31,6 @@ import android.nfc.TagLostException;
import android.os.AsyncTask;
import android.os.Bundle;
import org.bouncycastle.util.encoders.Hex;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
@@ -41,9 +40,9 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.smartcard.SmartcardDevice;
import org.sufficientlysecure.keychain.smartcard.NfcTransport;
import org.sufficientlysecure.keychain.smartcard.OnDiscoveredUsbDeviceListener;
import org.sufficientlysecure.keychain.smartcard.SmartcardDevice;
import org.sufficientlysecure.keychain.smartcard.UsbConnectionManager;
import org.sufficientlysecure.keychain.smartcard.UsbTransport;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity;
@@ -72,7 +71,7 @@ public abstract class BaseSecurityTokenNfcActivity extends BaseActivity
private static final String FIDESMO_APP_PACKAGE = "com.fidesmo.sec.android";
public SmartcardDevice mSmartcardDevice = new SmartcardDevice();
protected SmartcardDevice mSmartcardDevice = SmartcardDevice.getInstance();
protected TagDispatcher mTagDispatcher;
protected UsbConnectionManager mUsbDispatcher;
private boolean mTagHandlingEnabled;
@@ -175,7 +174,7 @@ public abstract class BaseSecurityTokenNfcActivity extends BaseActivity
public void usbDeviceDiscovered(final UsbDevice device) {
// Actual NFC operations are executed in doInBackground to not block the UI thread
// Actual USB operations are executed in doInBackground to not block the UI thread
if (!mTagHandlingEnabled)
return;
new AsyncTask<Void, Void, IOException>() {
@@ -372,7 +371,6 @@ public abstract class BaseSecurityTokenNfcActivity extends BaseActivity
Log.d(Constants.TAG, "BaseNfcActivity.onPause");
mTagDispatcher.disableExclusiveNfc();
// mUsbDispatcher.stopListeningForDevices();
}
/**
@@ -453,10 +451,15 @@ public abstract class BaseSecurityTokenNfcActivity extends BaseActivity
}
protected void handleUsbDevice(UsbDevice device) throws IOException {
UsbManager usbManager = (UsbManager) getSystemService(USB_SERVICE);
mSmartcardDevice.setTransport(new UsbTransport(device, usbManager));
mSmartcardDevice.connectToDevice();
// Don't reconnect if device was already connected
if (!mSmartcardDevice.isConnected()
|| !(mSmartcardDevice.getTransport() instanceof UsbTransport)
|| !((UsbTransport) mSmartcardDevice.getTransport()).getUsbDevice().equals(device)) {
UsbManager usbManager = (UsbManager) getSystemService(USB_SERVICE);
mSmartcardDevice.setTransport(new UsbTransport(device, usbManager));
mSmartcardDevice.connectToDevice();
}
doNfcInBackground();
}
@@ -464,48 +467,6 @@ public abstract class BaseSecurityTokenNfcActivity extends BaseActivity
return mSmartcardDevice.isConnected();
}
/**
* Parses out the status word from a JavaCard response string.
*
* @param response A hex string with the response from the token
* @return A short indicating the SW1/SW2, or 0 if a status could not be determined.
*/
short parseCardStatus(String response) {
if (response.length() < 4) {
return 0; // invalid input
}
try {
return Short.parseShort(response.substring(response.length() - 4), 16);
} catch (NumberFormatException e) {
return 0;
}
}
public String getHolderName(String name) {
try {
String slength;
int ilength;
name = name.substring(6);
slength = name.substring(0, 2);
ilength = Integer.parseInt(slength, 16) * 2;
name = name.substring(2, ilength + 2);
name = (new String(Hex.decode(name))).replace('<', ' ');
return name;
} catch (IndexOutOfBoundsException e) {
// try-catch for https://github.com/FluffyKaon/OpenPGP-Card
// Note: This should not happen, but happens with
// https://github.com/FluffyKaon/OpenPGP-Card, thus return an empty string for now!
Log.e(Constants.TAG, "Couldn't get holder name, returning empty string!", e);
return "";
}
}
public static String getHex(byte[] raw) {
return new String(Hex.encode(raw));
}
public class IsoDepNotSupportedException extends IOException {
public IsoDepNotSupportedException(String detailMessage) {
@@ -575,4 +536,8 @@ public abstract class BaseSecurityTokenNfcActivity extends BaseActivity
super.onStart();
mUsbDispatcher.onStart();
}
public SmartcardDevice getSmartcardDevice() {
return mSmartcardDevice;
}
}