From 8acf62a0e80f538610095faaf5128d9d842f2a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 2 Nov 2017 19:13:44 +0100 Subject: [PATCH] Use check for life cycle management to determine if token supports reset --- .../securitytoken/CardCapabilities.java | 5 ++++- .../securitytoken/SecurityTokenConnection.java | 3 ++- .../securitytoken/SecurityTokenInfo.java | 17 ++++++++++------- .../securitytoken/SecurityTokenUtilsTest.java | 10 +++++----- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/CardCapabilities.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/CardCapabilities.java index 2b5fd6151..de7cf7012 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/CardCapabilities.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/CardCapabilities.java @@ -17,7 +17,10 @@ package org.sufficientlysecure.keychain.securitytoken; +import org.bouncycastle.util.encoders.Hex; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.securitytoken.usb.UsbTransportException; +import org.sufficientlysecure.keychain.util.Log; import java.nio.ByteBuffer; import java.util.Arrays; @@ -72,7 +75,7 @@ class CardCapabilities { return capabilityBytes != null && (capabilityBytes[2] & MASK_EXTENDED) != 0; } - public boolean hasResetSupport() throws UsbTransportException { + public boolean hasLifeCycleManagement() throws UsbTransportException { byte[] lastBytes = Arrays.copyOfRange(historicalBytes, historicalBytes.length - 2, historicalBytes.length); boolean hasExpectedLastBytes = Arrays.equals(lastBytes, EXPECTED_PROCESSING_STATUS_BYTES); 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 b9be3cbe0..e26808e07 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenConnection.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenConnection.java @@ -990,11 +990,12 @@ public class SecurityTokenConnection { String userId = getUserId(); String url = getUrl(); byte[] pwInfo = getPwStatusBytes(); + boolean hasLifeCycleManagement = mCardCapabilities.hasLifeCycleManagement(); TransportType transportType = mTransport.getTransportType(); SecurityTokenInfo info = SecurityTokenInfo - .create(transportType, tokenType, fingerprints, aid, userId, url, pwInfo[4], pwInfo[6]); + .create(transportType, tokenType, fingerprints, aid, userId, url, pwInfo[4], pwInfo[6], hasLifeCycleManagement); if (! info.isSecurityTokenSupported()) { throw new UnsupportedSecurityTokenException(); 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 987560edd..8b443cd7d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenInfo.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenInfo.java @@ -35,6 +35,7 @@ public abstract class SecurityTokenInfo implements Parcelable { public abstract String getUrl(); public abstract int getVerifyRetries(); public abstract int getVerifyAdminRetries(); + public abstract boolean hasLifeCycleManagement(); public boolean isEmpty() { return getFingerprints().isEmpty(); @@ -42,7 +43,8 @@ public abstract class SecurityTokenInfo implements Parcelable { public static SecurityTokenInfo create(TransportType transportType, TokenType tokenType, byte[][] fingerprints, byte[] aid, String userId, String url, - int verifyRetries, int verifyAdminRetries) { + int verifyRetries, int verifyAdminRetries, + boolean hasLifeCycleSupport) { ArrayList fingerprintList = new ArrayList<>(fingerprints.length); for (byte[] fingerprint : fingerprints) { if (!Arrays.equals(EMPTY_ARRAY, fingerprint)) { @@ -50,7 +52,7 @@ public abstract class SecurityTokenInfo implements Parcelable { } } return new AutoValue_SecurityTokenInfo( - transportType, tokenType, fingerprintList, aid, userId, url, verifyRetries, verifyAdminRetries); + transportType, tokenType, fingerprintList, aid, userId, url, verifyRetries, verifyAdminRetries, hasLifeCycleSupport); } public static SecurityTokenInfo newInstanceDebugKeyserver() { @@ -59,7 +61,7 @@ public abstract class SecurityTokenInfo implements Parcelable { } return SecurityTokenInfo.create(TransportType.NFC, TokenType.UNKNOWN, new byte[][] { KeyFormattingUtils.convertFingerprintHexFingerprint("1efdb4845ca242ca6977fddb1f788094fd3b430a") }, - Hex.decode("010203040506"), "yubinu2@mugenguild.com", null, 3, 3); + Hex.decode("010203040506"), "yubinu2@mugenguild.com", null, 3, 3, true); } public static SecurityTokenInfo newInstanceDebugUri() { @@ -68,7 +70,7 @@ public abstract class SecurityTokenInfo implements Parcelable { } return SecurityTokenInfo.create(TransportType.NFC, TokenType.UNKNOWN, new byte[][] { KeyFormattingUtils.convertFingerprintHexFingerprint("4700BA1AC417ABEF3CC7765AD686905837779C3E") }, - Hex.decode("010203040506"), "yubinu2@mugenguild.com", "http://valodim.stratum0.net/mryubinu2.asc", 3, 3); + Hex.decode("010203040506"), "yubinu2@mugenguild.com", "http://valodim.stratum0.net/mryubinu2.asc", 3, 3, true); } public static SecurityTokenInfo newInstanceDebugLocked() { @@ -77,7 +79,7 @@ public abstract class SecurityTokenInfo implements Parcelable { } return SecurityTokenInfo.create(TransportType.NFC, TokenType.UNKNOWN, new byte[][] { KeyFormattingUtils.convertFingerprintHexFingerprint("4700BA1AC417ABEF3CC7765AD686905837779C3E") }, - Hex.decode("010203040506"), "yubinu2@mugenguild.com", "http://valodim.stratum0.net/mryubinu2.asc", 0, 3); + Hex.decode("010203040506"), "yubinu2@mugenguild.com", "http://valodim.stratum0.net/mryubinu2.asc", 0, 3, true); } public static SecurityTokenInfo newInstanceDebugLockedHard() { @@ -86,7 +88,7 @@ public abstract class SecurityTokenInfo implements Parcelable { } return SecurityTokenInfo.create(TransportType.NFC, TokenType.UNKNOWN, new byte[][] { KeyFormattingUtils.convertFingerprintHexFingerprint("4700BA1AC417ABEF3CC7765AD686905837779C3E") }, - Hex.decode("010203040506"), "yubinu2@mugenguild.com", "http://valodim.stratum0.net/mryubinu2.asc", 0, 0); + Hex.decode("010203040506"), "yubinu2@mugenguild.com", "http://valodim.stratum0.net/mryubinu2.asc", 0, 0, true); } public enum TransportType { @@ -138,8 +140,9 @@ public abstract class SecurityTokenInfo implements Parcelable { public boolean isResetSupported() { boolean isKnownSupported = SUPPORTED_USB_RESET.contains(getTokenType()); boolean isNfcTransport = getTransportType() == TransportType.NFC; + boolean hasLifeCycleManagement = hasLifeCycleManagement(); - return isKnownSupported || isNfcTransport; + return (isKnownSupported || isNfcTransport) && hasLifeCycleManagement; } public static Version parseGnukVersionString(String serialNo) { diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenUtilsTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenUtilsTest.java index 2cff99b78..ed952550e 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenUtilsTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenUtilsTest.java @@ -167,31 +167,31 @@ public class SecurityTokenUtilsTest extends Mockito { capabilities = new CardCapabilities(Hex.decode("007300008000000000000000000000")); Assert.assertEquals(capabilities.hasChaining(), true); Assert.assertEquals(capabilities.hasExtended(), false); - Assert.assertEquals(capabilities.hasResetSupport(), true); + Assert.assertEquals(capabilities.hasLifeCycleManagement(), true); // Yk 4 capabilities = new CardCapabilities(Hex.decode("0073000080059000")); Assert.assertEquals(capabilities.hasChaining(), true); Assert.assertEquals(capabilities.hasExtended(), false); - Assert.assertEquals(capabilities.hasResetSupport(), true); + Assert.assertEquals(capabilities.hasLifeCycleManagement(), true); // Nitrokey pro capabilities = new CardCapabilities(Hex.decode("0031c573c00140059000")); Assert.assertEquals(capabilities.hasChaining(), false); Assert.assertEquals(capabilities.hasExtended(), true); - Assert.assertEquals(capabilities.hasResetSupport(), true); + Assert.assertEquals(capabilities.hasLifeCycleManagement(), true); // GNUK without Life Cycle Management capabilities = new CardCapabilities(Hex.decode("00318473800180009000")); Assert.assertEquals(capabilities.hasChaining(), true); Assert.assertEquals(capabilities.hasExtended(), false); - Assert.assertEquals(capabilities.hasResetSupport(), false); + Assert.assertEquals(capabilities.hasLifeCycleManagement(), false); // GNUK with Life Cycle Management: ./configure --enable-factory-reset capabilities = new CardCapabilities(Hex.decode("00318473800180059000")); Assert.assertEquals(capabilities.hasChaining(), true); Assert.assertEquals(capabilities.hasExtended(), false); - Assert.assertEquals(capabilities.hasResetSupport(), true); + Assert.assertEquals(capabilities.hasLifeCycleManagement(), true); } @Test