determine token type during connect
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
package org.sufficientlysecure.keychain.securitytoken;
|
||||
|
||||
import android.nfc.Tag;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
@@ -118,8 +119,10 @@ public class NfcTransport implements Transport {
|
||||
return TransportType.NFC;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TokenType getTokenType() {
|
||||
public TokenType getTokenTypeIfAvailable() {
|
||||
// Sadly, the NFC transport has no direct information about the token type.
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,8 +76,7 @@ import java.util.List;
|
||||
public class SecurityTokenConnection {
|
||||
private static final int APDU_SW1_RESPONSE_AVAILABLE = 0x61;
|
||||
|
||||
// Fidesmo constants
|
||||
private static final String FIDESMO_APPS_AID_PREFIX = "A000000617";
|
||||
private static final String AID_PREFIX_FIDESMO = "A000000617";
|
||||
|
||||
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};
|
||||
|
||||
@@ -91,6 +90,7 @@ public class SecurityTokenConnection {
|
||||
private final Passphrase mPin;
|
||||
private final OpenPgpCommandApduFactory commandFactory;
|
||||
|
||||
private TokenType tokenType;
|
||||
private CardCapabilities mCardCapabilities;
|
||||
private OpenPgpCapabilities mOpenPgpCapabilities;
|
||||
private SecureMessaging mSecureMessaging;
|
||||
@@ -184,8 +184,8 @@ public class SecurityTokenConnection {
|
||||
|
||||
mTransport.connect();
|
||||
|
||||
// Connect on smartcard layer
|
||||
// Command APDU (page 51) for SELECT FILE command (page 29)
|
||||
determineTokenType();
|
||||
|
||||
CommandApdu select = commandFactory.createSelectFileOpenPgpCommand();
|
||||
ResponseApdu response = communicate(select); // activate connection
|
||||
|
||||
@@ -210,6 +210,30 @@ public class SecurityTokenConnection {
|
||||
}
|
||||
}
|
||||
|
||||
private void determineTokenType() throws IOException {
|
||||
tokenType = mTransport.getTokenTypeIfAvailable();
|
||||
if (tokenType != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
CommandApdu selectFidesmoApdu = commandFactory.createSelectFileCommand(AID_PREFIX_FIDESMO);
|
||||
if (communicate(selectFidesmoApdu).isSuccess()) {
|
||||
tokenType = TokenType.FIDESMO;
|
||||
return;
|
||||
}
|
||||
|
||||
/* We could determine if this is a yubikey here. The info isn't used at the moment, so we save the roundtrip
|
||||
// AID from https://github.com/Yubico/ykneo-oath/blob/master/build.xml#L16
|
||||
CommandApdu selectYubicoApdu = commandFactory.createSelectFileCommand("A000000527200101");
|
||||
if (communicate(selectYubicoApdu).isSuccess()) {
|
||||
tokenType = TokenType.YUBIKEY_UNKNOWN;
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
tokenType = TokenType.UNKNOWN;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setConnectionCapabilities(OpenPgpCapabilities openPgpCapabilities) throws IOException {
|
||||
this.mOpenPgpCapabilities = openPgpCapabilities;
|
||||
@@ -797,20 +821,6 @@ public class SecurityTokenConnection {
|
||||
return lastResponse;
|
||||
}
|
||||
|
||||
public boolean isFidesmoToken() {
|
||||
if (isConnected()) { // Check if we can still talk to the card
|
||||
try {
|
||||
// By trying to select any apps that have the Fidesmo AID prefix we can
|
||||
// see if it is a Fidesmo device or not
|
||||
CommandApdu apdu = commandFactory.createSelectFileCommand(FIDESMO_APPS_AID_PREFIX);
|
||||
return communicate(apdu).isSuccess();
|
||||
} catch (IOException e) {
|
||||
Log.e(Constants.TAG, "Card communication failed!", e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a key on the card in the given slot. If the slot is 0xB6 (the signature key),
|
||||
* this command also has the effect of resetting the digital signature counter.
|
||||
@@ -919,6 +929,10 @@ public class SecurityTokenConnection {
|
||||
return mTransport.isConnected();
|
||||
}
|
||||
|
||||
public TokenType getTokenType() {
|
||||
return tokenType;
|
||||
}
|
||||
|
||||
public void clearSecureMessaging() {
|
||||
if (mSecureMessaging != null) {
|
||||
mSecureMessaging.clearSession();
|
||||
@@ -931,10 +945,6 @@ public class SecurityTokenConnection {
|
||||
mSecureMessaging = sm;
|
||||
}
|
||||
|
||||
OpenPgpCapabilities getOpenPgpCapabilities() {
|
||||
return mOpenPgpCapabilities;
|
||||
}
|
||||
|
||||
public SecurityTokenInfo getTokenInfo() throws IOException {
|
||||
byte[] rawFingerprints = getFingerprints();
|
||||
|
||||
@@ -951,16 +961,9 @@ public class SecurityTokenConnection {
|
||||
byte[] pwInfo = getPwStatusBytes();
|
||||
|
||||
TransportType transportType = mTransport.getTransportType();
|
||||
TokenType tokenType;
|
||||
if (transportType == TransportType.USB) {
|
||||
tokenType = mTransport.getTokenType();
|
||||
} else {
|
||||
tokenType = isFidesmoToken() ? TokenType.FIDESMO : TokenType.UNKNOWN;
|
||||
}
|
||||
|
||||
// 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]);
|
||||
SecurityTokenInfo info = SecurityTokenInfo
|
||||
.create(transportType, tokenType, fingerprints, aid, userId, url, pwInfo[4], pwInfo[6]);
|
||||
|
||||
if (! info.isSecurityTokenSupported()) {
|
||||
throw new UnsupportedSecurityTokenException();
|
||||
@@ -974,5 +977,4 @@ public class SecurityTokenConnection {
|
||||
while (minv > 0) minv /= 10.0;
|
||||
return aid[6] + minv;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -93,29 +93,27 @@ public abstract class SecurityTokenInfo implements Parcelable {
|
||||
YUBIKEY_NEO, YUBIKEY_4, FIDESMO, NITROKEY_PRO, NITROKEY_STORAGE, NITROKEY_START, GNUK, LEDGER_NANO_S, UNKNOWN
|
||||
}
|
||||
|
||||
private static final HashSet<TokenType> SUPPORTED_SECURITY_TOKENS = new HashSet<>(Arrays.asList(
|
||||
TokenType.FIDESMO,
|
||||
private static final HashSet<TokenType> SUPPORTED_USB_TOKENS = new HashSet<>(Arrays.asList(
|
||||
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.FIDESMO,
|
||||
private static final HashSet<TokenType> SUPPORTED_USB_PUT_KEY = new HashSet<>(Arrays.asList(
|
||||
TokenType.YUBIKEY_NEO,
|
||||
TokenType.YUBIKEY_4 // Not clear, will be tested: https://github.com/open-keychain/open-keychain/issues/2069
|
||||
));
|
||||
|
||||
public boolean isSecurityTokenSupported() {
|
||||
boolean isKnownSupported = SUPPORTED_SECURITY_TOKENS.contains(getTokenType());
|
||||
boolean isKnownSupported = SUPPORTED_USB_TOKENS.contains(getTokenType());
|
||||
boolean isNfcTransport = getTransportType() == TransportType.NFC;
|
||||
|
||||
return isKnownSupported || isNfcTransport;
|
||||
}
|
||||
|
||||
public boolean isPutKeySupported() {
|
||||
boolean isKnownSupported = SUPPORTED_PUT_KEY.contains(getTokenType());
|
||||
boolean isKnownSupported = SUPPORTED_USB_PUT_KEY.contains(getTokenType());
|
||||
boolean isNfcTransport = getTransportType() == TransportType.NFC;
|
||||
|
||||
return isKnownSupported || isNfcTransport;
|
||||
|
||||
@@ -22,6 +22,9 @@ import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo.Transport
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
|
||||
/**
|
||||
* Abstraction for transmitting APDU commands
|
||||
*/
|
||||
@@ -60,6 +63,6 @@ public interface Transport {
|
||||
void connect() throws IOException;
|
||||
|
||||
TransportType getTransportType();
|
||||
|
||||
TokenType getTokenType();
|
||||
@Nullable
|
||||
TokenType getTokenTypeIfAvailable();
|
||||
}
|
||||
|
||||
@@ -230,8 +230,9 @@ public class UsbTransport implements Transport {
|
||||
return TransportType.USB;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TokenType getTokenType() {
|
||||
public TokenType getTokenTypeIfAvailable() {
|
||||
switch (usbDevice.getVendorId()) {
|
||||
case VENDOR_YUBICO: {
|
||||
switch (usbDevice.getProductId()) {
|
||||
@@ -267,9 +268,9 @@ public class UsbTransport implements Transport {
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(Constants.TAG, "Unknown USB token. Vendor ID: " + usbDevice.getVendorId()
|
||||
+ ", Product ID: " + usbDevice.getProductId());
|
||||
return TokenType.UNKNOWN;
|
||||
Log.d(Constants.TAG, "Unknown USB token. Vendor ID: " + usbDevice.getVendorId() + ", Product ID: " +
|
||||
usbDevice.getProductId());
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -45,6 +45,7 @@ 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;
|
||||
@@ -338,7 +339,7 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity
|
||||
}
|
||||
// 6A82 app not installed on security token!
|
||||
case 0x6A82: {
|
||||
if (stConnection.isFidesmoToken()) {
|
||||
if (stConnection.getTokenType() == TokenType.FIDESMO) {
|
||||
// Check if the Fidesmo app is installed
|
||||
if (isAndroidAppInstalled(FIDESMO_APP_PACKAGE)) {
|
||||
promptFidesmoPgpInstall();
|
||||
|
||||
Reference in New Issue
Block a user