From b5ff6d033efcebe609f06017349c49708480a3b4 Mon Sep 17 00:00:00 2001 From: Michele Balistreri Date: Tue, 8 Jan 2019 15:15:18 +0300 Subject: [PATCH] simplify PIN verification --- android/build.gradle | 4 +-- demo-android/build.gradle | 4 +-- .../im/status/keycard/app/MainActivity.java | 2 +- .../keycard/applet/KeycardCommandSet.java | 15 +++++++---- .../im/status/keycard/io/APDUResponse.java | 15 +++++++++++ .../status/keycard/io/WrongPINException.java | 27 +++++++++++++++++++ 6 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 lib/src/main/java/im/status/keycard/io/WrongPINException.java diff --git a/android/build.gradle b/android/build.gradle index 809ff2c..a2a33e8 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,8 +8,8 @@ android { defaultConfig { minSdkVersion 19 targetSdkVersion 28 - versionCode 2 - versionName "2.0" + versionCode 201 + versionName "2.0.1" } } diff --git a/demo-android/build.gradle b/demo-android/build.gradle index 6c4e41c..3dc1e69 100644 --- a/demo-android/build.gradle +++ b/demo-android/build.gradle @@ -6,8 +6,8 @@ android { applicationId "im.status.keycard.demo" minSdkVersion 19 targetSdkVersion 28 - versionCode 2 - versionName "2.0" + versionCode 201 + versionName "2.0.1" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { diff --git a/demo-android/src/main/java/im/status/keycard/app/MainActivity.java b/demo-android/src/main/java/im/status/keycard/app/MainActivity.java index 53a58d3..9265e23 100644 --- a/demo-android/src/main/java/im/status/keycard/app/MainActivity.java +++ b/demo-android/src/main/java/im/status/keycard/app/MainActivity.java @@ -89,7 +89,7 @@ public class MainActivity extends AppCompatActivity { Log.i(TAG, "Binary seed: " + Hex.toHexString(mnemonic.toBinarySeed())); // PIN authentication allows execution of privileged commands - cmdSet.verifyPIN("000000").checkOK(); + cmdSet.verifyPIN("000000").checkAuthOK(); Log.i(TAG, "Pin Verified."); diff --git a/lib/src/main/java/im/status/keycard/applet/KeycardCommandSet.java b/lib/src/main/java/im/status/keycard/applet/KeycardCommandSet.java index 7db019c..2cdafc0 100644 --- a/lib/src/main/java/im/status/keycard/applet/KeycardCommandSet.java +++ b/lib/src/main/java/im/status/keycard/applet/KeycardCommandSet.java @@ -1,9 +1,6 @@ package im.status.keycard.applet; -import im.status.keycard.io.APDUCommand; -import im.status.keycard.io.APDUException; -import im.status.keycard.io.APDUResponse; -import im.status.keycard.io.CardChannel; +import im.status.keycard.io.*; import org.bouncycastle.jce.interfaces.ECPrivateKey; import org.bouncycastle.jce.interfaces.ECPublicKey; @@ -74,11 +71,19 @@ public class KeycardCommandSet { private final CardChannel apduChannel; private SecureChannelSession secureChannel; + /** + * Creates a KeycardCommandSet using the given APDU Channel + * @param apduChannel APDU channel + */ public KeycardCommandSet(CardChannel apduChannel) { this.apduChannel = apduChannel; this.secureChannel = new SecureChannelSession(); } + /** + * Set the SecureChannel object + * @param secureChannel secure channel + */ protected void setSecureChannel(SecureChannelSession secureChannel) { this.secureChannel = secureChannel; } @@ -257,7 +262,7 @@ public class KeycardCommandSet { * Sends a VERIFY PIN APDU. The raw bytes of the given string are encrypted using the secure channel and used as APDU * data. * - * @param pin the pin + * @param pin the PIN * @return the raw card response * @throws IOException communication error */ diff --git a/lib/src/main/java/im/status/keycard/io/APDUResponse.java b/lib/src/main/java/im/status/keycard/io/APDUResponse.java index d1f529d..c79ced0 100644 --- a/lib/src/main/java/im/status/keycard/io/APDUResponse.java +++ b/lib/src/main/java/im/status/keycard/io/APDUResponse.java @@ -10,6 +10,7 @@ public class APDUResponse { public static final int SW_CARD_LOCKED = 0x6283; public static final int SW_REFERENCED_DATA_NOT_FOUND = 0x6A88; public static final int SW_CONDITIONS_OF_USE_NOT_SATISFIED = 0x6985; // applet may be already installed + public static final int SW_WRONG_PIN_MASK = 0x63C0; private byte[] apdu; private byte[] data; @@ -87,6 +88,20 @@ public class APDUResponse { } } + /** + * Checks response from an authentication command (VERIFY PIN, UNBLOCK PUK) + * + * @throws WrongPINException wrong PIN + * @throws APDUException unexpected response + */ + public APDUResponse checkAuthOK() throws WrongPINException, APDUException { + if ((this.sw & SW_WRONG_PIN_MASK) == SW_WRONG_PIN_MASK) { + throw new WrongPINException(sw2 & 0x0F); + } else { + return checkOK(); + } + } + /** * Returns the data field of this APDU. * diff --git a/lib/src/main/java/im/status/keycard/io/WrongPINException.java b/lib/src/main/java/im/status/keycard/io/WrongPINException.java new file mode 100644 index 0000000..6248a67 --- /dev/null +++ b/lib/src/main/java/im/status/keycard/io/WrongPINException.java @@ -0,0 +1,27 @@ +package im.status.keycard.io; + +/** + * Exception thrown when checking PIN/PUK + */ +public class WrongPINException extends APDUException { + private int retryAttempts; + + /** + * Construct an exception with the given number of retry attempts. + * + * @param retryAttempts the number of retry attempts + */ + public WrongPINException(int retryAttempts) { + super("Wrong PIN"); + this.retryAttempts = retryAttempts; + } + + /** + * Returns the number of available retry attempts. + * + * @return the number of retry attempts + */ + public int getRetryAttempts() { + return retryAttempts; + } +}