Check for security token support

This commit is contained in:
Dominik Schürmann
2017-10-25 14:05:52 +02:00
committed by Vincent Breitmoser
parent e7705eaca8
commit 0920d97572
11 changed files with 126 additions and 19 deletions

View File

@@ -37,6 +37,14 @@ public class NfcTransport implements Transport {
private final Tag mTag;
private IsoCard mIsoCard;
public static class IsoDepNotSupportedException extends IOException {
IsoDepNotSupportedException(String detailMessage) {
super(detailMessage);
}
}
public NfcTransport(Tag tag) {
this.mTag = tag;
}
@@ -98,7 +106,7 @@ public class NfcTransport implements Transport {
public void connect() throws IOException {
mIsoCard = AndroidCard.get(mTag);
if (mIsoCard == null) {
throw new BaseSecurityTokenActivity.IsoDepNotSupportedException("Tag does not support ISO-DEP (ISO 14443-4)");
throw new IsoDepNotSupportedException("Tag does not support ISO-DEP (ISO 14443-4)");
}
mIsoCard.setTimeout(TIMEOUT);

View File

@@ -955,10 +955,18 @@ public class SecurityTokenConnection {
if (transportType == TransportType.USB) {
tokenType = mTransport.getTokenType();
} else {
tokenType = isFidesmoToken() ? TokenType.FIDESMO : TokenType.UNKNOWN;
tokenType = isFidesmoToken() ? TokenType.FIDESMO : TokenType.UNKNOWN_NFC;
}
return SecurityTokenInfo.create(transportType, tokenType, fingerprints, aid, userId, url, pwInfo[4], pwInfo[6]);
// TODO: bail out earlier on unsupported tokens to not execute other commands
SecurityTokenInfo info = SecurityTokenInfo.create(transportType, tokenType, fingerprints, aid, userId, url, pwInfo[4], pwInfo[6]);
if (! info.isSecurityTokenSupported()) {
throw new UnsupportedSecurityTokenException();
}
return info;
}
public static double parseOpenPgpVersion(final byte[] aid) {
@@ -966,4 +974,5 @@ public class SecurityTokenConnection {
while (minv > 0) minv /= 10.0;
return aid[6] + minv;
}
}

View File

@@ -3,6 +3,7 @@ package org.sufficientlysecure.keychain.securitytoken;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import android.os.Parcelable;
@@ -52,7 +53,7 @@ public abstract class SecurityTokenInfo implements Parcelable {
if (!BuildConfig.DEBUG) {
throw new UnsupportedOperationException("This operation is only available in debug builds!");
}
return SecurityTokenInfo.create(TransportType.NFC, TokenType.UNKNOWN,
return SecurityTokenInfo.create(TransportType.NFC, TokenType.UNKNOWN_NFC,
new byte[][] { KeyFormattingUtils.convertFingerprintHexFingerprint("1efdb4845ca242ca6977fddb1f788094fd3b430a") },
Hex.decode("010203040506"), "yubinu2@mugenguild.com", null, 3, 3);
}
@@ -61,7 +62,7 @@ public abstract class SecurityTokenInfo implements Parcelable {
if (!BuildConfig.DEBUG) {
throw new UnsupportedOperationException("This operation is only available in debug builds!");
}
return SecurityTokenInfo.create(TransportType.NFC, TokenType.UNKNOWN,
return SecurityTokenInfo.create(TransportType.NFC, TokenType.UNKNOWN_NFC,
new byte[][] { KeyFormattingUtils.convertFingerprintHexFingerprint("4700BA1AC417ABEF3CC7765AD686905837779C3E") },
Hex.decode("010203040506"), "yubinu2@mugenguild.com", "http://valodim.stratum0.net/mryubinu2.asc", 3, 3);
}
@@ -70,7 +71,7 @@ public abstract class SecurityTokenInfo implements Parcelable {
if (!BuildConfig.DEBUG) {
throw new UnsupportedOperationException("This operation is only available in debug builds!");
}
return SecurityTokenInfo.create(TransportType.NFC, TokenType.UNKNOWN,
return SecurityTokenInfo.create(TransportType.NFC, TokenType.UNKNOWN_NFC,
new byte[][] { KeyFormattingUtils.convertFingerprintHexFingerprint("4700BA1AC417ABEF3CC7765AD686905837779C3E") },
Hex.decode("010203040506"), "yubinu2@mugenguild.com", "http://valodim.stratum0.net/mryubinu2.asc", 0, 3);
}
@@ -79,7 +80,7 @@ public abstract class SecurityTokenInfo implements Parcelable {
if (!BuildConfig.DEBUG) {
throw new UnsupportedOperationException("This operation is only available in debug builds!");
}
return SecurityTokenInfo.create(TransportType.NFC, TokenType.UNKNOWN,
return SecurityTokenInfo.create(TransportType.NFC, TokenType.UNKNOWN_NFC,
new byte[][] { KeyFormattingUtils.convertFingerprintHexFingerprint("4700BA1AC417ABEF3CC7765AD686905837779C3E") },
Hex.decode("010203040506"), "yubinu2@mugenguild.com", "http://valodim.stratum0.net/mryubinu2.asc", 0, 0);
}
@@ -89,7 +90,31 @@ public abstract class SecurityTokenInfo implements Parcelable {
}
public enum TokenType {
YUBIKEY_NEO, YUBIKEY_4, FIDESMO, NITROKEY_PRO, NITROKEY_STORAGE, NITROKEY_START, GNUK, LEDGER_NANO_S, UNKNOWN
YUBIKEY_NEO, YUBIKEY_4, FIDESMO, NITROKEY_PRO, NITROKEY_STORAGE, NITROKEY_START, GNUK, LEDGER_NANO_S, UNKNOWN_NFC, UNKNOWN_USB
}
private static final HashSet<TokenType> SUPPORTED_SECURITY_TOKENS = new HashSet<>(Arrays.asList(
TokenType.UNKNOWN_NFC,
TokenType.FIDESMO,
TokenType.YUBIKEY_NEO,
TokenType.YUBIKEY_4,
TokenType.NITROKEY_PRO,
TokenType.NITROKEY_STORAGE
));
private static final HashSet<TokenType> SUPPORTED_PUT_KEY = new HashSet<>(Arrays.asList(
TokenType.UNKNOWN_NFC,
TokenType.FIDESMO,
TokenType.YUBIKEY_NEO,
TokenType.YUBIKEY_4 // Not clear, will be tested: https://github.com/open-keychain/open-keychain/issues/2069
));
public boolean isSecurityTokenSupported() {
return SUPPORTED_SECURITY_TOKENS.contains(getTokenType());
}
public boolean isPutKeySupported() {
return SUPPORTED_PUT_KEY.contains(getTokenType());
}
}

View File

@@ -0,0 +1,15 @@
package org.sufficientlysecure.keychain.securitytoken;
import java.io.IOException;
public class UnsupportedSecurityTokenException extends IOException {
UnsupportedSecurityTokenException() {
super();
}
UnsupportedSecurityTokenException(String detailMessage) {
super(detailMessage);
}
}

View File

@@ -101,6 +101,7 @@ public class UsbTransport implements Transport {
/**
* Check if device is was connected to and still is connected
*
* @return true if device is connected
*/
@Override
@@ -112,6 +113,7 @@ public class UsbTransport implements Transport {
/**
* Check if Transport supports persistent connections e.g connections which can
* handle multiple operations in one session
*
* @return true if transport supports persistent connections
*/
@Override
@@ -199,6 +201,7 @@ public class UsbTransport implements Transport {
/**
* Transmit and receive data
*
* @param data data to transmit
* @return received data
*/
@@ -263,7 +266,10 @@ public class UsbTransport implements Transport {
return TokenType.LEDGER_NANO_S;
}
}
throw new IllegalStateException("Unhandled usb token type!");
Log.d(Constants.TAG, "Unknown USB token. Vendor ID: " + usbDevice.getVendorId()
+ ", Product ID: " + usbDevice.getProductId());
return TokenType.UNKNOWN_USB;
}
/**

View File

@@ -45,10 +45,11 @@ import org.sufficientlysecure.keychain.securitytoken.CardException;
import org.sufficientlysecure.keychain.securitytoken.NfcTransport;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenConnection;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo;
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo.TokenType;
import org.sufficientlysecure.keychain.securitytoken.Transport;
import org.sufficientlysecure.keychain.securitytoken.UnsupportedSecurityTokenException;
import org.sufficientlysecure.keychain.securitytoken.UsbConnectionDispatcher;
import org.sufficientlysecure.keychain.securitytoken.usb.UsbTransport;
import org.sufficientlysecure.keychain.securitytoken.usb.UsbTransportException;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
@@ -238,11 +239,21 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity
return;
}
if (e instanceof IsoDepNotSupportedException) {
if (e instanceof NfcTransport.IsoDepNotSupportedException) {
onSecurityTokenError(getString(R.string.security_token_error_iso_dep_not_supported));
return;
}
if (e instanceof UsbTransportException) {
onSecurityTokenError(getString(R.string.security_token_error, e.getMessage()));
return;
}
if (e instanceof UnsupportedSecurityTokenException) {
onSecurityTokenError(getString(R.string.security_token_not_supported));
return;
}
short status;
if (e instanceof CardException) {
status = ((CardException) e).getResponseCode();
@@ -442,14 +453,6 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity
doSecurityTokenInBackground(stConnection);
}
public static class IsoDepNotSupportedException extends IOException {
public IsoDepNotSupportedException(String detailMessage) {
super(detailMessage);
}
}
/**
* Ask user if she wants to install PGP onto her Fidesmo token
*/

View File

@@ -79,6 +79,7 @@ class ManageSecurityTokenContract {
void showActionRetryOrFromFile();
void showActionLocked(int unlockAttempts);
void showActionEmptyToken();
void showActionUnsupportedToken();
void hideAction();
void operationImportKey(byte[] importKeyData);

View File

@@ -263,6 +263,11 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur
actionAnimator.setDisplayedChildId(R.id.token_layout_empty);
}
@Override
public void showActionUnsupportedToken() {
actionAnimator.setDisplayedChildId(R.id.token_layout_unsupported);
}
@Override
public void hideAction() {
actionAnimator.setDisplayedChild(0);

View File

@@ -164,6 +164,14 @@ class ManageSecurityTokenPresenter implements ManageSecurityTokenMvpPresenter {
private void performKeyCheck() {
boolean keyIsEmpty = tokenInfo.isEmpty();
boolean putKeyIsSupported = tokenInfo.isPutKeySupported();
if (keyIsEmpty && !putKeyIsSupported) {
view.statusLineOk();
view.showActionUnsupportedToken();
return;
}
if (keyIsEmpty) {
boolean tokenIsAdminLocked = tokenInfo.getVerifyAdminRetries() == 0;
if (tokenIsAdminLocked) {