From aef66e97ea77d91cee920433cdec4e25e4c90e40 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 31 Oct 2017 15:39:14 +0100 Subject: [PATCH] Disable reset for Gnuk token version < 1.2.5 --- .../securitytoken/SecurityTokenInfo.java | 34 +++++++++++++++++-- .../securitytoken/usb/UsbTransport.java | 6 +++- .../ui/token/ManageSecurityTokenContract.java | 1 + .../ui/token/ManageSecurityTokenFragment.java | 9 +++++ .../token/ManageSecurityTokenPresenter.java | 9 +++++ OpenKeychain/src/main/res/values/strings.xml | 4 ++- 6 files changed, 59 insertions(+), 4 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenInfo.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenInfo.java index 2547830bb..9fa9f58ba 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenInfo.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenInfo.java @@ -5,6 +5,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import android.os.Parcelable; import android.support.annotation.Nullable; @@ -18,6 +20,7 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; @AutoValue public abstract class SecurityTokenInfo implements Parcelable { private static final byte[] EMPTY_ARRAY = new byte[20]; + private static final Pattern GNUK_VERSION_PATTERN = Pattern.compile("FSIJ-(\\d\\.\\d\\.\\d)-.+"); public abstract TransportType getTransportType(); public abstract TokenType getTokenType(); @@ -90,7 +93,8 @@ 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_OLD, GNUK_UNKNOWN, GNUK_NEWER_1_25, LEDGER_NANO_S, UNKNOWN } private static final HashSet SUPPORTED_USB_TOKENS = new HashSet<>(Arrays.asList( @@ -98,7 +102,15 @@ public abstract class SecurityTokenInfo implements Parcelable { TokenType.YUBIKEY_4, TokenType.NITROKEY_PRO, TokenType.NITROKEY_STORAGE, - TokenType.GNUK + TokenType.GNUK_OLD, + TokenType.GNUK_UNKNOWN, + TokenType.GNUK_NEWER_1_25 + )); + + private static final HashSet SUPPORTED_USB_RESET = new HashSet<>(Arrays.asList( + TokenType.YUBIKEY_NEO, + TokenType.YUBIKEY_4, + TokenType.GNUK_NEWER_1_25 )); private static final HashSet SUPPORTED_USB_PUT_KEY = new HashSet<>(Arrays.asList( @@ -120,4 +132,22 @@ public abstract class SecurityTokenInfo implements Parcelable { return isKnownSupported || isNfcTransport; } + public boolean isResetSupported() { + boolean isKnownSupported = SUPPORTED_USB_RESET.contains(getTokenType()); + boolean isNfcTransport = getTransportType() == TransportType.NFC; + + return isKnownSupported || isNfcTransport; + } + + public static String parseGnukVersionString(String serialNo) { + if (serialNo == null) { + return null; + } + + Matcher matcher = GNUK_VERSION_PATTERN.matcher(serialNo); + if (!matcher.matches()) { + return null; + } + return matcher.group(1); + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/UsbTransport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/UsbTransport.java index 5b066d630..ae37841ef 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/UsbTransport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/UsbTransport.java @@ -34,6 +34,7 @@ import org.bouncycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.securitytoken.CommandApdu; import org.sufficientlysecure.keychain.securitytoken.ResponseApdu; +import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo; import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo.TokenType; import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo.TransportType; import org.sufficientlysecure.keychain.securitytoken.Transport; @@ -217,7 +218,10 @@ public class UsbTransport implements Transport { break; } case VENDOR_FSIJ: { - return TokenType.GNUK; + String serialNo = usbConnection.getSerial(); + String gnukVersion = SecurityTokenInfo.parseGnukVersionString(serialNo); + boolean versionBigger125 = gnukVersion != null && "1.2.5".compareTo(gnukVersion) < 0; + return versionBigger125 ? TokenType.GNUK_NEWER_1_25 : TokenType.GNUK_OLD; } case VENDOR_LEDGER: { return TokenType.LEDGER_NANO_S; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/token/ManageSecurityTokenContract.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/token/ManageSecurityTokenContract.java index ae110d8bc..a05bdb00f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/token/ManageSecurityTokenContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/token/ManageSecurityTokenContract.java @@ -98,6 +98,7 @@ class ManageSecurityTokenContract { void requestStoragePermission(); + void showErrorCannotReset(boolean isGnuk); void showErrorCannotUnlock(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/token/ManageSecurityTokenFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/token/ManageSecurityTokenFragment.java index 198b4ba09..faba27b1d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/token/ManageSecurityTokenFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/token/ManageSecurityTokenFragment.java @@ -352,6 +352,15 @@ public class ManageSecurityTokenFragment extends Fragment implements ManageSecur Notify.create(getActivity(), R.string.token_error_locked_indefinitely, Style.ERROR).show(); } + @Override + public void showErrorCannotReset(boolean isGnuk) { + if (isGnuk) { + Notify.create(getActivity(), R.string.token_error_cannot_reset_gnuk_old, Style.ERROR).show(); + } else { + Notify.create(getActivity(), R.string.token_error_cannot_reset, Style.ERROR).show(); + } + } + @Override public void showDisplayLogActivity(OperationResult result) { Intent intent = new Intent(getActivity(), LogDisplayActivity.class); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/token/ManageSecurityTokenPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/token/ManageSecurityTokenPresenter.java index a52a0ad87..dc731c979 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/token/ManageSecurityTokenPresenter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/token/ManageSecurityTokenPresenter.java @@ -30,6 +30,7 @@ import org.sufficientlysecure.keychain.operations.results.GenericOperationResult import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo; +import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo.TokenType; import org.sufficientlysecure.keychain.ui.token.ManageSecurityTokenContract.ManageSecurityTokenMvpPresenter; import org.sufficientlysecure.keychain.ui.token.ManageSecurityTokenContract.ManageSecurityTokenMvpView; import org.sufficientlysecure.keychain.ui.token.ManageSecurityTokenFragment.StatusLine; @@ -362,6 +363,14 @@ class ManageSecurityTokenPresenter implements ManageSecurityTokenMvpPresenter { @Override public void onClickResetToken() { + if (!tokenInfo.isResetSupported()) { + TokenType tokenType = tokenInfo.getTokenType(); + boolean isGnuk = tokenType == TokenType.GNUK_OLD || tokenType == TokenType.GNUK_UNKNOWN; + + view.showErrorCannotReset(isGnuk); + return; + } + view.showConfirmResetDialog(); } diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index ee4a8079b..8c9f2e346 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -1910,7 +1910,9 @@ "1 attempt left" "%d attempts left" - Too many reset attempts. Token is locked irrecoverably! + Too many reset attempts. Token cannot be unlocked! + "The Gnuk Token does not support reset until version 1.2.5" + "This Security Token does not support reset" Change PIN View Log