diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenConnection.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenConnection.java index 6a71a98f6..f26534e5b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenConnection.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenConnection.java @@ -87,30 +87,34 @@ public class SecurityTokenConnection { private static final byte[] BLANK_FINGERPRINT = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + private static SecurityTokenConnection sCachedInstance; + private final JcaKeyFingerprintCalculator fingerprintCalculator = new JcaKeyFingerprintCalculator(); - private Transport mTransport; + @NonNull + private final Transport mTransport; + @NonNull + private final Passphrase mPin; + private CardCapabilities mCardCapabilities; private OpenPgpCapabilities mOpenPgpCapabilities; private SecureMessaging mSecureMessaging; - private Passphrase mPin; - private Passphrase mAdminPin; private boolean mPw1ValidatedForSignature; private boolean mPw1ValidatedForDecrypt; // Mode 82 does other things; consider renaming? private boolean mPw3Validated; - private SecurityTokenConnection() { + public static SecurityTokenConnection getInstanceForTransport(Transport transport, Passphrase pin) { + if (sCachedInstance == null || !sCachedInstance.isPersistentConnectionAllowed() || + !sCachedInstance.isConnected() || !sCachedInstance.mTransport.equals(transport)) { + sCachedInstance = new SecurityTokenConnection(transport, pin); + } + return sCachedInstance; } - public static double parseOpenPgpVersion(final byte[] aid) { - float minv = aid[7]; - while (minv > 0) minv /= 10.0; - return aid[6] + minv; - } - - public static SecurityTokenConnection getInstance() { - return LazyHolder.SECURITY_TOKEN_HELPER; + private SecurityTokenConnection(@NonNull Transport transport, @NonNull Passphrase pin) { + this.mTransport = transport; + this.mPin = pin; } private String getHolderName(byte[] name) { @@ -126,23 +130,7 @@ public class SecurityTokenConnection { } } - public Passphrase getPin() { - return mPin; - } - - public void setPin(final Passphrase pin) { - this.mPin = pin; - } - - public Passphrase getAdminPin() { - return mAdminPin; - } - - public void setAdminPin(final Passphrase adminPin) { - this.mAdminPin = adminPin; - } - - public void changeKey(CanonicalizedSecretKey secretKey, Passphrase passphrase) throws IOException { + public void changeKey(CanonicalizedSecretKey secretKey, Passphrase passphrase, Passphrase adminPin) throws IOException { long keyGenerationTimestamp = secretKey.getCreationTime().getTime() / 1000; byte[] timestampBytes = ByteBuffer.allocate(4).putInt((int) keyGenerationTimestamp).array(); KeyType keyType = KeyType.from(secretKey); @@ -160,9 +148,9 @@ public class SecurityTokenConnection { keyType.toString())); } - putKey(keyType, secretKey, passphrase); - putData(keyType.getFingerprintObjectId(), secretKey.getFingerprint()); - putData(keyType.getTimestampObjectId(), timestampBytes); + putKey(keyType, secretKey, passphrase, adminPin); + putData(adminPin, keyType.getFingerprintObjectId(), secretKey.getFingerprint()); + putData(adminPin, keyType.getTimestampObjectId(), timestampBytes); } private boolean isSlotEmpty(KeyType keyType) throws IOException { @@ -179,12 +167,18 @@ public class SecurityTokenConnection { return java.util.Arrays.equals(getKeyFingerprint(keyType), fingerprint); } + public void connectIfNecessary(Context context) throws IOException { + if (isConnected()) { + return; + } + + connectToDevice(context); + } + /** * Connect to device and select pgp applet - * - * @throws IOException */ - public void connectToDevice(final Context ctx) throws IOException { + private void connectToDevice(Context context) throws IOException { // Connect on transport layer mCardCapabilities = new CardCapabilities(); @@ -208,7 +202,7 @@ public class SecurityTokenConnection { if (mOpenPgpCapabilities.isHasSCP11bSM()) { try { - SCP11bSecureMessaging.establish(this, ctx); + SCP11bSecureMessaging.establish(this, context); } catch (SecureMessagingException e) { mSecureMessaging = null; Log.e(Constants.TAG, "failed to establish secure messaging", e); @@ -217,9 +211,9 @@ public class SecurityTokenConnection { } - public void resetPin(String newPinStr) throws IOException { + public void resetPin(Passphrase adminPin, String newPinStr) throws IOException { if (!mPw3Validated) { - verifyPin(0x83); // (Verify PW1 with mode 82 for decryption) + verifyAdminPin(adminPin); } byte[] newPin = newPinStr.getBytes(); @@ -246,7 +240,7 @@ public class SecurityTokenConnection { * @param pw For PW1, this is 0x81. For PW3 (Admin PIN), mode is 0x83. * @param newPin The new PW1 or PW3. */ - public void modifyPin(int pw, byte[] newPin) throws IOException { + public void modifyPin(int pw, byte[] newPin, Passphrase adminPin) throws IOException { final int MAX_PW1_LENGTH_INDEX = 1; final int MAX_PW3_LENGTH_INDEX = 3; @@ -266,7 +260,10 @@ public class SecurityTokenConnection { byte[] pin; if (pw == 0x83) { - pin = mAdminPin.toStringUnsafe().getBytes(); + if (adminPin == null) { + throw new IllegalArgumentException("Changing the admin pin requires admin pin argument!"); + } + pin = adminPin.toStringUnsafe().getBytes(); } else { pin = mPin.toStringUnsafe().getBytes(); } @@ -422,28 +419,30 @@ public class SecurityTokenConnection { * For PW3 (Admin PIN), mode is 0x83. */ private void verifyPin(int mode) throws IOException { - if (mPin != null || mode == 0x83) { + byte[] pin = mPin.toStringUnsafe().getBytes(); - byte[] pin; - if (mode == 0x83) { - pin = mAdminPin.toStringUnsafe().getBytes(); - } else { - pin = mPin.toStringUnsafe().getBytes(); - } - - ResponseAPDU response = tryPin(mode, pin);// login - if (response.getSW() != APDU_SW_SUCCESS) { - throw new CardException("Bad PIN!", response.getSW()); - } - - if (mode == 0x81) { - mPw1ValidatedForSignature = true; - } else if (mode == 0x82) { - mPw1ValidatedForDecrypt = true; - } else if (mode == 0x83) { - mPw3Validated = true; - } + ResponseAPDU response = tryPin(mode, pin);// login + if (response.getSW() != APDU_SW_SUCCESS) { + throw new CardException("Bad PIN!", response.getSW()); } + + if (mode == 0x81) { + mPw1ValidatedForSignature = true; + } else if (mode == 0x82) { + mPw1ValidatedForDecrypt = true; + } + } + + /** + * Verifies the user's PW1 or PW3 with the appropriate mode. + */ + private void verifyAdminPin(Passphrase adminPin) throws IOException { + ResponseAPDU response = tryPin(0x83, adminPin.toStringUnsafe().getBytes()); + if (response.getSW() != APDU_SW_SUCCESS) { + throw new CardException("Bad PIN!", response.getSW()); + } + + mPw3Validated = true; } /** @@ -454,16 +453,17 @@ public class SecurityTokenConnection { * @param dataObject The data object to be stored. * @param data The data to store in the object */ - private void putData(int dataObject, byte[] data) throws IOException { + private void putData(Passphrase adminPin, int dataObject, byte[] data) throws IOException { if (data.length > 254) { throw new IOException("Cannot PUT DATA with length > 254"); } + // TODO use admin pin regardless, if we have it? if (dataObject == 0x0101 || dataObject == 0x0103) { if (!mPw1ValidatedForDecrypt) { verifyPin(0x82); // (Verify PW1 for non-signing operations) } } else if (!mPw3Validated) { - verifyPin(0x83); // (Verify PW3) + verifyAdminPin(adminPin); } CommandAPDU command = new CommandAPDU(0x00, 0xDA, (dataObject & 0xFF00) >> 8, dataObject & 0xFF, data); @@ -475,7 +475,7 @@ public class SecurityTokenConnection { } - private void setKeyAttributes(final KeyType slot, final CanonicalizedSecretKey secretKey) + private void setKeyAttributes(Passphrase adminPin, final KeyType slot, final CanonicalizedSecretKey secretKey) throws IOException { if (mOpenPgpCapabilities.isAttributesChangable()) { @@ -493,7 +493,7 @@ public class SecurityTokenConnection { try { - putData(tag, SecurityTokenUtils.attributesFromSecretKey(slot, secretKey)); + putData(adminPin, tag, SecurityTokenUtils.attributesFromSecretKey(slot, secretKey)); mOpenPgpCapabilities.updateWithData(getData(0x00, tag)); @@ -512,14 +512,14 @@ public class SecurityTokenConnection { * 0xB8: Decipherment Key * 0xA4: Authentication Key */ - private void putKey(KeyType slot, CanonicalizedSecretKey secretKey, Passphrase passphrase) + private void putKey(KeyType slot, CanonicalizedSecretKey secretKey, Passphrase passphrase, Passphrase adminPin) throws IOException { RSAPrivateCrtKey crtSecretKey; ECPrivateKey ecSecretKey; ECPublicKey ecPublicKey; if (!mPw3Validated) { - verifyPin(0x83); // (Verify PW3 with mode 83) + verifyAdminPin(adminPin); } // Now we're ready to communicate with the token. @@ -528,7 +528,7 @@ public class SecurityTokenConnection { try { secretKey.unlock(passphrase); - setKeyAttributes(slot, secretKey); + setKeyAttributes(adminPin, slot, secretKey); switch (mOpenPgpCapabilities.getFormatForKeyType(slot).keyFormatType()) { case RSAKeyFormatType: @@ -836,15 +836,6 @@ public class SecurityTokenConnection { return lastResponse; } - public Transport getTransport() { - return mTransport; - } - - public void setTransport(Transport mTransport) { - clearSecureMessaging(); - this.mTransport = mTransport; - } - public boolean isFidesmoToken() { if (isConnected()) { // Check if we can still talk to the card try { @@ -873,13 +864,13 @@ public class SecurityTokenConnection { * @return the public key data objects, in TLV format. For RSA this will be the public modulus * (0x81) and exponent (0x82). These may come out of order; proper TLV parsing is required. */ - public byte[] generateKey(int slot) throws IOException { + public byte[] generateKey(Passphrase adminPin, int slot) throws IOException { if (slot != 0xB6 && slot != 0xB8 && slot != 0xA4) { throw new IOException("Invalid key slot"); } if (!mPw3Validated) { - verifyPin(0x83); // (Verify PW3 with mode 83) + verifyAdminPin(adminPin); } CommandAPDU apdu = new CommandAPDU(0x00, 0x47, 0x80, 0x00, new byte[]{(byte) slot, 0x00}, MAX_APDU_NE_EXT); @@ -962,14 +953,12 @@ public class SecurityTokenConnection { } public boolean isPersistentConnectionAllowed() { - return mTransport != null && - mTransport.isPersistentConnectionAllowed() && - (mSecureMessaging == null || - !mSecureMessaging.isEstablished()); + return mTransport.isPersistentConnectionAllowed() && + (mSecureMessaging == null || !mSecureMessaging.isEstablished()); } public boolean isConnected() { - return mTransport != null && mTransport.isConnected(); + return mTransport.isConnected(); } public void clearSecureMessaging() { @@ -1006,7 +995,9 @@ public class SecurityTokenConnection { return SecurityTokenInfo.create(fingerprints, aid, userId, url, pwInfo[4], pwInfo[6]); } - private static class LazyHolder { - private static final SecurityTokenConnection SECURITY_TOKEN_HELPER = new SecurityTokenConnection(); + public static double parseOpenPgpVersion(final byte[] aid) { + float minv = aid[7]; + while (minv > 0) minv /= 10.0; + return aid[6] + minv; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index 51d158710..fcb947016 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -32,6 +32,7 @@ import android.support.v4.app.TaskStackBuilder; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.securitytoken.KeyFormat; +import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection; import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo; import org.sufficientlysecure.keychain.ui.base.BaseSecurityTokenActivity; import org.sufficientlysecure.keychain.ui.token.ManageSecurityTokenFragment; @@ -133,17 +134,17 @@ public class CreateKeyActivity extends BaseSecurityTokenActivity { } @Override - protected void doSecurityTokenInBackground() throws IOException { + protected void doSecurityTokenInBackground(SecurityTokenConnection stConnection) throws IOException { if (mCurrentFragment instanceof SecurityTokenListenerFragment) { ((SecurityTokenListenerFragment) mCurrentFragment).doSecurityTokenInBackground(); return; } - tokenInfo = mSecurityTokenConnection.getTokenInfo(); + tokenInfo = stConnection.getTokenInfo(); } @Override - protected void onSecurityTokenPostExecute() { + protected void onSecurityTokenPostExecute(SecurityTokenConnection stConnection) { handleTokenInfo(tokenInfo); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SecurityTokenChangePinOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SecurityTokenChangePinOperationActivity.java index 95ac39143..1c03b00e7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SecurityTokenChangePinOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SecurityTokenChangePinOperationActivity.java @@ -32,6 +32,7 @@ import android.widget.ViewAnimator; import nordpol.android.NfcGuideView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection; import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo; import org.sufficientlysecure.keychain.service.input.SecurityTokenChangePinParcel; import org.sufficientlysecure.keychain.ui.base.BaseSecurityTokenActivity; @@ -138,15 +139,15 @@ public class SecurityTokenChangePinOperationActivity extends BaseSecurityTokenAc } @Override - protected void doSecurityTokenInBackground() throws IOException { - mSecurityTokenConnection.setAdminPin(new Passphrase(changePinInput.getAdminPin())); - mSecurityTokenConnection.resetPin(changePinInput.getNewPin()); + protected void doSecurityTokenInBackground(SecurityTokenConnection stConnection) throws IOException { + Passphrase adminPin = new Passphrase(changePinInput.getAdminPin()); + stConnection.resetPin(adminPin, changePinInput.getNewPin()); - resultTokenInfo = mSecurityTokenConnection.getTokenInfo(); + resultTokenInfo = stConnection.getTokenInfo(); } @Override - protected final void onSecurityTokenPostExecute() { + protected final void onSecurityTokenPostExecute(final SecurityTokenConnection stConnection) { Intent result = new Intent(); result.putExtra(RESULT_TOKEN_INFO, resultTokenInfo); setResult(RESULT_OK, result); @@ -156,17 +157,17 @@ public class SecurityTokenChangePinOperationActivity extends BaseSecurityTokenAc nfcGuideView.setCurrentStatus(NfcGuideView.NfcGuideViewStatus.DONE); - if (mSecurityTokenConnection.isPersistentConnectionAllowed()) { + if (stConnection.isPersistentConnectionAllowed()) { // Just close finish(); } else { - mSecurityTokenConnection.clearSecureMessaging(); + stConnection.clearSecureMessaging(); new AsyncTask() { @Override protected Void doInBackground(Void... params) { // check all 200ms if Security Token has been taken away while (true) { - if (isSecurityTokenConnected()) { + if (stConnection.isConnected()) { try { Thread.sleep(200); } catch (InterruptedException ignored) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SecurityTokenOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SecurityTokenOperationActivity.java index 1cd2ecd8f..4a3c60256 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SecurityTokenOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SecurityTokenOperationActivity.java @@ -44,6 +44,7 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.securitytoken.KeyType; +import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection; import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; @@ -185,12 +186,12 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenActivity { } @Override - protected void doSecurityTokenInBackground() throws IOException { + protected void doSecurityTokenInBackground(SecurityTokenConnection stConnection) throws IOException { switch (mRequiredInput.mType) { case SECURITY_TOKEN_DECRYPT: { long tokenKeyId = KeyFormattingUtils.getKeyIdFromFingerprint( - mSecurityTokenConnection.getKeyFingerprint(KeyType.ENCRYPT)); + stConnection.getKeyFingerprint(KeyType.ENCRYPT)); if (tokenKeyId != mRequiredInput.getSubKeyId()) { throw new IOException(getString(R.string.error_wrong_security_token)); @@ -208,7 +209,7 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenActivity { for (int i = 0; i < mRequiredInput.mInputData.length; i++) { byte[] encryptedSessionKey = mRequiredInput.mInputData[i]; - byte[] decryptedSessionKey = mSecurityTokenConnection + byte[] decryptedSessionKey = stConnection .decryptSessionKey(encryptedSessionKey, publicKeyRing.getPublicKey(tokenKeyId)); mInputParcel = mInputParcel.withCryptoData(encryptedSessionKey, decryptedSessionKey); } @@ -216,7 +217,7 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenActivity { } case SECURITY_TOKEN_SIGN: { long tokenKeyId = KeyFormattingUtils.getKeyIdFromFingerprint( - mSecurityTokenConnection.getKeyFingerprint(KeyType.SIGN)); + stConnection.getKeyFingerprint(KeyType.SIGN)); if (tokenKeyId != mRequiredInput.getSubKeyId()) { throw new IOException(getString(R.string.error_wrong_security_token)); @@ -227,15 +228,13 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenActivity { for (int i = 0; i < mRequiredInput.mInputData.length; i++) { byte[] hash = mRequiredInput.mInputData[i]; int algo = mRequiredInput.mSignAlgos[i]; - byte[] signedHash = mSecurityTokenConnection.calculateSignature(hash, algo); + byte[] signedHash = stConnection.calculateSignature(hash, algo); mInputParcel = mInputParcel.withCryptoData(hash, signedHash); } break; } case SECURITY_TOKEN_MOVE_KEY_TO_CARD: { - // TODO: assume PIN and Admin PIN to be default for this operation - mSecurityTokenConnection.setPin(new Passphrase("123456")); - mSecurityTokenConnection.setAdminPin(new Passphrase("12345678")); + Passphrase adminPin = new Passphrase("12345678"); KeyRepository keyRepository = KeyRepository.create(this); @@ -257,7 +256,7 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenActivity { long subkeyId = buf.getLong(); CanonicalizedSecretKey key = secretKeyRing.getSecretKey(subkeyId); - byte[] tokenSerialNumber = Arrays.copyOf(mSecurityTokenConnection.getAid(), 16); + byte[] tokenSerialNumber = Arrays.copyOf(stConnection.getAid(), 16); Passphrase passphrase; try { @@ -267,21 +266,21 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenActivity { throw new IOException("Unable to get cached passphrase!"); } - mSecurityTokenConnection.changeKey(key, passphrase); + stConnection.changeKey(key, passphrase, adminPin); // TODO: Is this really used anywhere? mInputParcel = mInputParcel.withCryptoData(subkeyBytes, tokenSerialNumber); } // change PINs afterwards - mSecurityTokenConnection.modifyPin(0x81, newPin); - mSecurityTokenConnection.modifyPin(0x83, newAdminPin); + stConnection.modifyPin(0x81, newPin, null); + stConnection.modifyPin(0x83, newAdminPin, adminPin); break; } case SECURITY_TOKEN_RESET_CARD: { - mSecurityTokenConnection.resetAndWipeToken(); - mResultTokenInfo = mSecurityTokenConnection.getTokenInfo(); + stConnection.resetAndWipeToken(); + mResultTokenInfo = stConnection.getTokenInfo(); break; } @@ -293,7 +292,7 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenActivity { } @Override - protected final void onSecurityTokenPostExecute() { + protected final void onSecurityTokenPostExecute(final SecurityTokenConnection stConnection) { handleResult(mInputParcel); // show finish @@ -301,17 +300,17 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenActivity { nfcGuideView.setCurrentStatus(NfcGuideView.NfcGuideViewStatus.DONE); - if (mSecurityTokenConnection.isPersistentConnectionAllowed()) { + if (stConnection.isPersistentConnectionAllowed()) { // Just close finish(); } else { - mSecurityTokenConnection.clearSecureMessaging(); + stConnection.clearSecureMessaging(); new AsyncTask() { @Override protected Void doInBackground(Void... params) { // check all 200ms if Security Token has been taken away while (true) { - if (isSecurityTokenConnected()) { + if (stConnection.isConnected()) { try { Thread.sleep(200); } catch (InterruptedException ignored) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ShowNfcSweetspotActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ShowNfcSweetspotActivity.java index 1a3f4cef3..1893d1f78 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ShowNfcSweetspotActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ShowNfcSweetspotActivity.java @@ -15,6 +15,7 @@ import android.view.animation.DecelerateInterpolator; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.securitytoken.NfcSweetspotData; +import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection; import org.sufficientlysecure.keychain.ui.base.BaseSecurityTokenActivity; @@ -88,7 +89,7 @@ public class ShowNfcSweetspotActivity extends BaseSecurityTokenActivity { } @Override - protected void onSecurityTokenPostExecute() { + protected void onSecurityTokenPostExecute(SecurityTokenConnection stConnection) { Intent result = new Intent(); result.putExtra(EXTRA_TOKEN_INFO, tokenInfo); setResult(Activity.RESULT_OK, result); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseSecurityTokenActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseSecurityTokenActivity.java index 413573084..26470a9f6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseSecurityTokenActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseSecurityTokenActivity.java @@ -68,12 +68,12 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity private static final String FIDESMO_APP_PACKAGE = "com.fidesmo.sec.android"; - protected SecurityTokenConnection mSecurityTokenConnection = SecurityTokenConnection.getInstance(); protected TagDispatcher mNfcTagDispatcher; protected UsbConnectionDispatcher mUsbDispatcher; private boolean mTagHandlingEnabled; protected SecurityTokenInfo tokenInfo; + private Passphrase mCachedPin; /** * Override to change UI before SecurityToken handling (UI thread) @@ -84,15 +84,15 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity /** * Override to implement SecurityToken operations (background thread) */ - protected void doSecurityTokenInBackground() throws IOException { - tokenInfo = mSecurityTokenConnection.getTokenInfo(); + protected void doSecurityTokenInBackground(SecurityTokenConnection stConnection) throws IOException { + tokenInfo = stConnection.getTokenInfo(); Log.d(Constants.TAG, "Security Token: " + tokenInfo); } /** * Override to handle result of SecurityToken operations (UI thread) */ - protected void onSecurityTokenPostExecute() { + protected void onSecurityTokenPostExecute(SecurityTokenConnection stConnection) { Intent intent = new Intent(this, CreateKeyActivity.class); intent.putExtra(CreateKeyActivity.EXTRA_SECURITY_TOKEN_INFO, tokenInfo); startActivity(intent); @@ -138,6 +138,10 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity // Actual Security Token operations are executed in doInBackground to not block the UI thread if (!mTagHandlingEnabled) return; + + final SecurityTokenConnection stConnection = + SecurityTokenConnection.getInstanceForTransport(transport, mCachedPin); + new AsyncTask() { @Override protected void onPreExecute() { @@ -148,7 +152,9 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity @Override protected IOException doInBackground(Void... params) { try { - handleSecurityToken(transport, BaseSecurityTokenActivity.this); + stConnection.connectIfNecessary(getBaseContext()); + + handleSecurityToken(stConnection); } catch (IOException e) { return e; } @@ -161,11 +167,11 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity super.onPostExecute(exception); if (exception != null) { - handleSecurityTokenError(exception); + handleSecurityTokenError(stConnection, exception); return; } - onSecurityTokenPostExecute(); + onSecurityTokenPostExecute(stConnection); } }.execute(); } @@ -223,7 +229,7 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity mNfcTagDispatcher.interceptIntent(intent); } - private void handleSecurityTokenError(IOException e) { + private void handleSecurityTokenError(SecurityTokenConnection stConnection, IOException e) { if (e instanceof TagLostException) { onSecurityTokenError(getString(R.string.security_token_error_tag_lost)); @@ -250,7 +256,7 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity SecurityTokenInfo tokeninfo = null; try { - tokeninfo = mSecurityTokenConnection.getTokenInfo(); + tokeninfo = stConnection.getTokenInfo(); } catch (IOException e2) { // don't care } @@ -271,7 +277,7 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity case 0x6982: { SecurityTokenInfo tokeninfo = null; try { - tokeninfo = mSecurityTokenConnection.getTokenInfo(); + tokeninfo = stConnection.getTokenInfo(); } catch (IOException e2) { // don't care } @@ -325,7 +331,7 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity } // 6A82 app not installed on security token! case 0x6A82: { - if (mSecurityTokenConnection.isFidesmoToken()) { + if (stConnection.isFidesmoToken()) { // Check if the Fidesmo app is installed if (isAndroidAppInstalled(FIDESMO_APP_PACKAGE)) { promptFidesmoPgpInstall(); @@ -391,12 +397,11 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity } protected void obtainSecurityTokenPin(RequiredInputParcel requiredInput) { - try { Passphrase passphrase = PassphraseCacheService.getCachedPassphrase(this, requiredInput.getMasterKeyId(), requiredInput.getSubKeyId()); if (passphrase != null) { - mSecurityTokenConnection.setPin(passphrase); + mCachedPin = passphrase; return; } @@ -421,7 +426,7 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity return; } CryptoInputParcel input = data.getParcelableExtra(PassphraseDialogActivity.RESULT_CRYPTO_INPUT); - mSecurityTokenConnection.setPin(input.getPassphrase()); + mCachedPin = input.getPassphrase(); break; } default: @@ -429,19 +434,8 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity } } - protected void handleSecurityToken(Transport transport, Context ctx) throws IOException { - // Don't reconnect if device was already connected - if (!(mSecurityTokenConnection.isPersistentConnectionAllowed() - && mSecurityTokenConnection.isConnected() - && mSecurityTokenConnection.getTransport().equals(transport))) { - mSecurityTokenConnection.setTransport(transport); - mSecurityTokenConnection.connectToDevice(ctx); - } - doSecurityTokenInBackground(); - } - - public boolean isSecurityTokenConnected() { - return mSecurityTokenConnection.isConnected(); + protected void handleSecurityToken(SecurityTokenConnection stConnection) throws IOException { + doSecurityTokenInBackground(stConnection); } public static class IsoDepNotSupportedException extends IOException { @@ -500,10 +494,6 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity mUsbDispatcher.onStart(); } - public SecurityTokenConnection getSecurityTokenHelper() { - return mSecurityTokenConnection; - } - /** * Run Security Token routines if last used token is connected and supports * persistent connections diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyActivity.java index 91e9916ed..0e9df8c4a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyActivity.java @@ -79,6 +79,7 @@ import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection; import org.sufficientlysecure.keychain.service.ChangeUnlockParcel; import org.sufficientlysecure.keychain.service.ImportKeyringParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; @@ -619,8 +620,8 @@ public class ViewKeyActivity extends BaseSecurityTokenActivity implements } @Override - protected void onSecurityTokenPostExecute() { - super.onSecurityTokenPostExecute(); + protected void onSecurityTokenPostExecute(SecurityTokenConnection stConnection) { + super.onSecurityTokenPostExecute(stConnection); finish(); }