From b7723c1a4a4ea3b2367289a2a2b3c9b73daa9dde Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 13 Oct 2017 15:58:21 +0200 Subject: [PATCH] replace magic constants in APDU factory --- .../securitytoken/CommandAPDUFactory.java | 156 ++++++++++++++---- .../securitytoken/SCP11bSecureMessaging.java | 33 ++-- .../SecurityTokenConnection.java | 111 +++++++------ .../ui/SecurityTokenOperationActivity.java | 4 +- 4 files changed, 200 insertions(+), 104 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/CommandAPDUFactory.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/CommandAPDUFactory.java index ce78d7e41..583cf4376 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/CommandAPDUFactory.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/CommandAPDUFactory.java @@ -1,7 +1,6 @@ package org.sufficientlysecure.keychain.securitytoken; -import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.List; @@ -19,91 +18,178 @@ class CommandAPDUFactory { private static final int MAX_APDU_NE = 256; private static final int MAX_APDU_NE_EXT = 65536; - final int CLA = 0x00; + private static final int CLA = 0x00; + private static final int MASK_CLA_CHAINING = 1 << 4; - final int MASK_CLA_CHAINING = 1 << 4; + private static final int INS_SELECT_FILE = 0xA4; + private static final int P1_SELECT_FILE = 0x04; + private static final byte[] AID_SELECT_FILE_OPENPGP = Hex.decode("D27600012401"); + + private static final int INS_ACTIVATE_FILE = 0x44; + private static final int INS_TERMINATE_DF = 0xE6; + private static final int INS_GET_RESPONSE = 0xC0; + + private static final int INS_INTERNAL_AUTHENTICATE = 0x88; + private static final int P1_INTERNAL_AUTH_SECURE_MESSAGING = 0x01; + + private static final int INS_VERIFY = 0x20; + private static final int P2_VERIFY_PW1_SIGN = 0x81; + private static final int P2_VERIFY_PW1_OTHER = 0x82; + private static final int P2_VERIFY_PW3 = 0x83; + + private static final int INS_CHANGE_REFERENCE_DATA = 0x24; + private static final int P2_CHANGE_REFERENCE_DATA_PW1 = 0x81; + private static final int P2_CHANGE_REFERENCE_DATA_PW3 = 0x83; + + private static final int INS_RESET_RETRY_COUNTER = 0x2C; + private static final int P1_RESET_RETRY_COUNTER_NEW_PW = 0x02; + private static final int P2_RESET_RETRY_COUNTER = 0x81; + + private static final int INS_PERFORM_SECURITY_OPERATION = 0x2A; + private static final int P1_PSO_DECIPHER = 0x80; + private static final int P1_PSO_COMPUTE_DIGITAL_SIGNATURE = 0x9E; + private static final int P2_PSO_DECIPHER = 0x86; + private static final int P2_PSO_COMPUTE_DIGITAL_SIGNATURE = 0x9A; + + private static final int INS_SELECT_DATA = 0xA5; + private static final int P1_SELECT_DATA_FOURTH = 0x03; + private static final int P2_SELECT_DATA = 0x04; + private static final byte[] CP_SELECT_DATA_CARD_HOLDER_CERT = Hex.decode("60045C027F21"); + + private static final int INS_GET_DATA = 0xCA; + private static final int P1_GET_DATA_CARD_HOLDER_CERT = 0x7F; + private static final int P2_GET_DATA_CARD_HOLDER_CERT = 0x21; + + private static final int INS_PUT_DATA = 0xDA; + + private static final int INS_PUT_DATA_ODD = 0xDB; + private static final int P1_PUT_DATA_ODD_KEY = 0x3F; + private static final int P2_PUT_DATA_ODD_KEY = 0xFF; + + private static final int INS_GENERATE_ASYMMETRIC_KEY_PAIR = 0x47; + private static final int P1_GAKP_GENERATE = 0x80; + private static final int P1_GAKP_READ_PUBKEY_TEMPLATE = 0x81; + private static final byte[] CRT_GAKP_SECURE_MESSAGING = Hex.decode("A600"); + + private static final int P1_EMPTY = 0x00; + private static final int P2_EMPTY = 0x00; + + @NonNull + CommandAPDU createPutDataCommand(int dataObject, byte[] data) { + return new CommandAPDU(CLA, INS_PUT_DATA, (dataObject & 0xFF00) >> 8, dataObject & 0xFF, data); + } @NonNull CommandAPDU createPutKeyCommand(byte[] keyBytes) { - return new CommandAPDU(CLA, 0xDB, 0x3F, 0xFF, keyBytes); + // the odd PUT DATA INS is for compliance with ISO 7816-8. This is used only to put key data on the card + return new CommandAPDU(CLA, INS_PUT_DATA_ODD, P1_PUT_DATA_ODD_KEY, P2_PUT_DATA_ODD_KEY, keyBytes); } @NonNull CommandAPDU createComputeDigitalSignatureCommand(byte[] data) { - return new CommandAPDU(CLA, 0x2A, 0x9E, 0x9A, data, MAX_APDU_NE_EXT); - } - - - @NonNull - CommandAPDU createPutDataCommand(int dataObject, byte[] data) { - return new CommandAPDU(CLA, 0xDA, (dataObject & 0xFF00) >> 8, dataObject & 0xFF, data); + return new CommandAPDU(CLA, INS_PERFORM_SECURITY_OPERATION, P1_PSO_COMPUTE_DIGITAL_SIGNATURE, + P2_PSO_COMPUTE_DIGITAL_SIGNATURE, data, MAX_APDU_NE_EXT); } @NonNull CommandAPDU createDecipherCommand(byte[] data) { - return new CommandAPDU(CLA, 0x2A, 0x80, 0x86, data, MAX_APDU_NE_EXT); + return new CommandAPDU(CLA, INS_PERFORM_SECURITY_OPERATION, P1_PSO_DECIPHER, P2_PSO_DECIPHER, data, + MAX_APDU_NE_EXT); } @NonNull - CommandAPDU createChangeReferenceDataCommand(int pw, byte[] newPin, byte[] pin) { - return new CommandAPDU(CLA, 0x24, 0x00, pw, Arrays.concatenate(pin, newPin)); + CommandAPDU createChangePw1Command(byte[] pin, byte[] newPin) { + return new CommandAPDU(CLA, INS_CHANGE_REFERENCE_DATA, P1_EMPTY, + P2_CHANGE_REFERENCE_DATA_PW1, Arrays.concatenate(pin, newPin)); } @NonNull - CommandAPDU createResetRetryCounter(byte[] newPin) { - return new CommandAPDU(CLA, 0x2C, 0x02, 0x81, newPin); + CommandAPDU createChangePw3Command(byte[] adminPin, byte[] newAdminPin) { + return new CommandAPDU(CLA, INS_CHANGE_REFERENCE_DATA, P1_EMPTY, + P2_CHANGE_REFERENCE_DATA_PW3, Arrays.concatenate(adminPin, newAdminPin)); + } + + @NonNull + CommandAPDU createResetPw1Command(byte[] newPin) { + return new CommandAPDU(CLA, INS_RESET_RETRY_COUNTER, P1_RESET_RETRY_COUNTER_NEW_PW, + P2_RESET_RETRY_COUNTER, newPin); } @NonNull CommandAPDU createGetDataCommand(int p1, int p2) { - return new CommandAPDU(CLA, 0xCA, p1, p2, MAX_APDU_NE_EXT); - } - - @NonNull - CommandAPDU createGenerateKeyCommand(int slot) { - return new CommandAPDU(CLA, 0x47, 0x80, 0x00, new byte[] { (byte) slot, 0x00 }, MAX_APDU_NE_EXT); + return new CommandAPDU(CLA, INS_GET_DATA, p1, p2, MAX_APDU_NE_EXT); } @NonNull CommandAPDU createGetResponseCommand(int lastResponseSw2) { - return new CommandAPDU(CLA, 0xC0, 0x00, 0x00, lastResponseSw2); + return new CommandAPDU(CLA, INS_GET_RESPONSE, P1_EMPTY, P2_EMPTY, lastResponseSw2); } + @NonNull + CommandAPDU createVerifyPw1ForSignatureCommand(byte[] pin) { + return new CommandAPDU(CLA, INS_VERIFY, P1_EMPTY, P2_VERIFY_PW1_SIGN, pin); + } @NonNull - CommandAPDU createVerifyCommand(int mode, byte[] pin) { - return new CommandAPDU(CLA, 0x20, 0x00, mode, pin); + CommandAPDU createVerifyPw1ForOtherCommand(byte[] pin) { + return new CommandAPDU(CLA, INS_VERIFY, P1_EMPTY, P2_VERIFY_PW1_OTHER, pin); + } + + @NonNull + CommandAPDU createVerifyPw3Command(byte[] pin) { + return new CommandAPDU(CLA, INS_VERIFY, P1_EMPTY, P2_VERIFY_PW3, pin); + } + + @NonNull + CommandAPDU createSelectFileOpenPgpCommand() { + return new CommandAPDU(CLA, INS_SELECT_FILE, P1_SELECT_FILE, P2_EMPTY, AID_SELECT_FILE_OPENPGP); } @NonNull CommandAPDU createSelectFileCommand(String fileAid) { - return new CommandAPDU(CLA, 0xA4, 0x04, 0x00, Hex.decode(fileAid)); + return new CommandAPDU(CLA, INS_SELECT_FILE, P1_SELECT_FILE, P2_EMPTY, Hex.decode(fileAid)); } @NonNull CommandAPDU createReactivate2Command() { - return new CommandAPDU(CLA, 0x44, 0x00, 0x00); + return new CommandAPDU(CLA, INS_ACTIVATE_FILE, P1_EMPTY, P2_EMPTY); } @NonNull CommandAPDU createReactivate1Command() { - return new CommandAPDU(CLA, 0xE6, 0x00, 0x00); + return new CommandAPDU(CLA, INS_TERMINATE_DF, P1_EMPTY, P2_EMPTY); } @NonNull - CommandAPDU createInternalAuthenticateCommand(ByteArrayOutputStream pkout) { - return new CommandAPDU(0, 0x88, 0x01, 0x0, pkout.toByteArray(), MAX_APDU_NE_EXT); + CommandAPDU createInternalAuthForSecureMessagingCommand(byte[] authData) { + return new CommandAPDU(CLA, INS_INTERNAL_AUTHENTICATE, P1_INTERNAL_AUTH_SECURE_MESSAGING, P2_EMPTY, authData, + MAX_APDU_NE_EXT); } @NonNull - CommandAPDU createRetrievePublicKeyCommand(byte[] msgCert) { - return new CommandAPDU(0, 0x47, 0x81, 0x00, msgCert, MAX_APDU_NE_EXT); + CommandAPDU createGenerateKeyCommand(int slot) { + return new CommandAPDU(CLA, INS_GENERATE_ASYMMETRIC_KEY_PAIR, + P1_GAKP_GENERATE, P2_EMPTY, new byte[] { (byte) slot, 0x00 }, MAX_APDU_NE_EXT); } @NonNull - CommandAPDU createRetrieveCertificateCommand() { - return new CommandAPDU(0, 0xA5, 0x03, 0x04, - new byte[]{0x60, 0x04, 0x5C, 0x02, 0x7F, 0x21}); + CommandAPDU createRetrieveSecureMessagingPublicKeyCommand() { + // see https://github.com/ANSSI-FR/SmartPGP/blob/master/secure_messaging/smartpgp_sm.pdf + return new CommandAPDU(CLA, INS_GENERATE_ASYMMETRIC_KEY_PAIR, P1_GAKP_READ_PUBKEY_TEMPLATE, P2_EMPTY, + CRT_GAKP_SECURE_MESSAGING, MAX_APDU_NE_EXT); + } + + @NonNull + CommandAPDU createSelectSecureMessagingCertificateCommand() { + // see https://github.com/ANSSI-FR/SmartPGP/blob/master/secure_messaging/smartpgp_sm.pdf + // this command selects the fourth occurence of data tag 7F21 + return new CommandAPDU(CLA, INS_SELECT_DATA, P1_SELECT_DATA_FOURTH, P2_SELECT_DATA, + CP_SELECT_DATA_CARD_HOLDER_CERT); + } + + @NonNull + CommandAPDU createGetDataCardHolderCertCommand() { + return createGetDataCommand(P1_GET_DATA_CARD_HOLDER_CERT, P2_GET_DATA_CARD_HOLDER_CERT); } @NonNull diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SCP11bSecureMessaging.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SCP11bSecureMessaging.java index 0f0aa9521..15a76616b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SCP11bSecureMessaging.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SCP11bSecureMessaging.java @@ -17,17 +17,6 @@ package org.sufficientlysecure.keychain.securitytoken; -import android.content.Context; -import android.support.annotation.NonNull; - -import org.bouncycastle.asn1.nist.NISTNamedCurves; -import org.bouncycastle.asn1.x9.ECNamedCurveTable; -import org.bouncycastle.asn1.x9.X9ECParameters; -import org.bouncycastle.math.ec.ECCurve; -import org.bouncycastle.math.ec.ECPoint; -import org.bouncycastle.util.Arrays; -import org.sufficientlysecure.keychain.ui.SettingsSmartPGPAuthoritiesActivity; -import org.sufficientlysecure.keychain.util.Preferences; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -65,6 +54,9 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.InvalidParameterSpecException; import java.util.ArrayList; +import android.content.Context; +import android.support.annotation.NonNull; + import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; @@ -76,12 +68,19 @@ import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.smartcardio.CommandAPDU; import javax.smartcardio.ResponseAPDU; +import org.bouncycastle.asn1.nist.NISTNamedCurves; +import org.bouncycastle.asn1.x9.ECNamedCurveTable; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.Arrays; +import org.sufficientlysecure.keychain.ui.SettingsSmartPGPAuthoritiesActivity; +import org.sufficientlysecure.keychain.util.Preferences; class SCP11bSecureMessaging implements SecureMessaging { private static final byte OPENPGP_SECURE_MESSAGING_CLA_MASK = (byte)0x04; - private static final byte[] OPENPGP_SECURE_MESSAGING_KEY_CRT = new byte[] { (byte)0xA6, (byte)0 }; private static final byte OPENPGP_SECURE_MESSAGING_KEY_ATTRIBUTES_TAG = (byte)0xD4; private static final int AES_BLOCK_SIZE = 128 / 8; @@ -316,12 +315,12 @@ class SCP11bSecureMessaging implements SecureMessaging { if (prefs != null && prefs.getExperimentalSmartPGPAuthoritiesEnable()) { // retrieving certificate - cmd = commandFactory.createRetrieveCertificateCommand(); + cmd = commandFactory.createSelectSecureMessagingCertificateCommand(); resp = t.communicate(cmd); if (resp.getSW() != SecurityTokenConnection.APDU_SW_SUCCESS) { throw new SecureMessagingException("failed to select secure messaging certificate"); } - cmd = commandFactory.createGetDataCommand(0x7F, 0x21); + cmd = commandFactory.createGetDataCardHolderCertCommand(); resp = t.communicate(cmd); if (resp.getSW() != SecurityTokenConnection.APDU_SW_SUCCESS) { throw new SecureMessagingException("failed to retrieve secure messaging certificate"); @@ -330,8 +329,7 @@ class SCP11bSecureMessaging implements SecureMessaging { pkcard = verifyCertificate(ctx, eckf, resp.getData()); } else { - // retrieving public key - cmd = commandFactory.createRetrievePublicKeyCommand(OPENPGP_SECURE_MESSAGING_KEY_CRT); + cmd = commandFactory.createRetrieveSecureMessagingPublicKeyCommand(); resp = t.communicate(cmd); if (resp.getSW() != SecurityTokenConnection.APDU_SW_SUCCESS) { throw new SecureMessagingException("failed to retrieve secure messaging public key"); @@ -391,8 +389,7 @@ class SCP11bSecureMessaging implements SecureMessaging { pkout.writeTo(bout); pkout = bout; - // internal authenticate - cmd = commandFactory.createInternalAuthenticateCommand(pkout); + cmd = commandFactory.createInternalAuthForSecureMessagingCommand(pkout.toByteArray()); resp = t.communicate(cmd); if (resp.getSW() != SecurityTokenConnection.APDU_SW_SUCCESS) { throw new SecureMessagingException("failed to initiate internal authenticate"); 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 1d95c2e9f..6e2aadc86 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenConnection.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenConnection.java @@ -183,7 +183,7 @@ public class SecurityTokenConnection { // Connect on smartcard layer // Command APDU (page 51) for SELECT FILE command (page 29) - CommandAPDU select = commandFactory.createSelectFileCommand("D27600012401"); + CommandAPDU select = commandFactory.createSelectFileOpenPgpCommand(); ResponseAPDU response = communicate(select); // activate connection if (response.getSW() != APDU_SW_SUCCESS) { @@ -222,7 +222,7 @@ public class SecurityTokenConnection { } // Command APDU for RESET RETRY COUNTER command (page 33) - CommandAPDU changePin = commandFactory.createResetRetryCounter(newPin); + CommandAPDU changePin = commandFactory.createResetPw1Command(newPin); ResponseAPDU response = communicate(changePin); if (response.getSW() != APDU_SW_SUCCESS) { @@ -231,42 +231,48 @@ public class SecurityTokenConnection { } /** - * Modifies the user's PW1 or PW3. Before sending, the new PIN will be validated for + * Modifies the user's PW3. Before sending, the new PIN will be validated for * conformance to the token's requirements for key length. * - * @param pw For PW1, this is 0x81. For PW3 (Admin PIN), mode is 0x83. - * @param newPin The new PW1 or PW3. + * @param newAdminPin The new PW3. */ - public void modifyPin(int pw, byte[] newPin, Passphrase adminPin) throws IOException { - final int MAX_PW1_LENGTH_INDEX = 1; + public void modifyPw3Pin(byte[] newAdminPin, Passphrase adminPin) throws IOException { final int MAX_PW3_LENGTH_INDEX = 3; byte[] pwStatusBytes = getPwStatusBytes(); - if (pw == 0x81) { - if (newPin.length < 6 || newPin.length > pwStatusBytes[MAX_PW1_LENGTH_INDEX]) { - throw new IOException("Invalid PIN length"); - } - } else if (pw == 0x83) { - if (newPin.length < 8 || newPin.length > pwStatusBytes[MAX_PW3_LENGTH_INDEX]) { - throw new IOException("Invalid PIN length"); - } - } else { - throw new IOException("Invalid PW index for modify PIN operation"); + if (newAdminPin.length < 8 || newAdminPin.length > pwStatusBytes[MAX_PW3_LENGTH_INDEX]) { + throw new IOException("Invalid PIN length"); } - byte[] pin; - if (pw == 0x83) { - if (adminPin == null) { - throw new IllegalArgumentException("Changing the admin pin requires admin pin argument!"); - } - pin = adminPin.toStringUnsafe().getBytes(); - } else { - pin = mPin.toStringUnsafe().getBytes(); + byte[] pin = adminPin.toStringUnsafe().getBytes(); + + CommandAPDU changePin = commandFactory.createChangePw3Command(pin, newAdminPin); + ResponseAPDU response = communicate(changePin); + + if (response.getSW() != APDU_SW_SUCCESS) { + throw new CardException("Failed to change PIN", response.getSW()); + } + } + + /** + * Modifies the user's PW1. Before sending, the new PIN will be validated for + * conformance to the token's requirements for key length. + * + * @param newPin The new PW1. + */ + public void modifyPw1Pin(byte[] newPin) throws IOException { + final int MAX_PW1_LENGTH_INDEX = 1; + + byte[] pwStatusBytes = getPwStatusBytes(); + + if (newPin.length < 6 || newPin.length > pwStatusBytes[MAX_PW1_LENGTH_INDEX]) { + throw new IOException("Invalid PIN length"); } - // Command APDU for CHANGE REFERENCE DATA command (page 32) - CommandAPDU changePin = commandFactory.createChangeReferenceDataCommand(pw, newPin, pin); + byte[] pin = mPin.toStringUnsafe().getBytes(); + + CommandAPDU changePin = commandFactory.createChangePw1Command(pin, newPin); ResponseAPDU response = communicate(changePin); if (response.getSW() != APDU_SW_SUCCESS) { @@ -287,7 +293,7 @@ public class SecurityTokenConnection { final KeyFormat kf = mOpenPgpCapabilities.getFormatForKeyType(KeyType.ENCRYPT); if (!mPw1ValidatedForDecrypt) { - verifyPin(0x82); // (Verify PW1 with mode 82 for decryption) + verifyPinForOther(); } byte[] data; @@ -410,31 +416,41 @@ public class SecurityTokenConnection { } /** - * Verifies the user's PW1 or PW3 with the appropriate mode. - * - * @param mode For PW1, this is 0x81 for signing, 0x82 for everything else. - * For PW3 (Admin PIN), mode is 0x83. + * Verifies the user's PW1 with the appropriate mode. */ - private void verifyPin(int mode) throws IOException { + private void verifyPinForSignature() throws IOException { byte[] pin = mPin.toStringUnsafe().getBytes(); - ResponseAPDU response = tryPin(mode, pin);// login + ResponseAPDU response = communicate(commandFactory.createVerifyPw1ForSignatureCommand(pin)); if (response.getSW() != APDU_SW_SUCCESS) { throw new CardException("Bad PIN!", response.getSW()); } - if (mode == 0x81) { - mPw1ValidatedForSignature = true; - } else if (mode == 0x82) { - mPw1ValidatedForDecrypt = true; + mPw1ValidatedForSignature = true; + } + + /** + * Verifies the user's PW1 with the appropriate mode. + */ + private void verifyPinForOther() throws IOException { + byte[] pin = mPin.toStringUnsafe().getBytes(); + + // Command APDU for VERIFY command (page 32) + ResponseAPDU response = communicate(commandFactory.createVerifyPw1ForOtherCommand(pin)); + if (response.getSW() != APDU_SW_SUCCESS) { + throw new CardException("Bad PIN!", response.getSW()); } + + mPw1ValidatedForDecrypt = true; } /** * Verifies the user's PW1 or PW3 with the appropriate mode. */ private void verifyAdminPin(Passphrase adminPin) throws IOException { - ResponseAPDU response = tryPin(0x83, adminPin.toStringUnsafe().getBytes()); + // Command APDU for VERIFY command (page 32) + ResponseAPDU response = + communicate(commandFactory.createVerifyPw3Command(adminPin.toStringUnsafe().getBytes())); if (response.getSW() != APDU_SW_SUCCESS) { throw new CardException("Bad PIN!", response.getSW()); } @@ -457,7 +473,7 @@ public class SecurityTokenConnection { // TODO use admin pin regardless, if we have it? if (dataObject == 0x0101 || dataObject == 0x0103) { if (!mPw1ValidatedForDecrypt) { - verifyPin(0x82); // (Verify PW1 for non-signing operations) + verifyPinForOther(); } } else if (!mPw3Validated) { verifyAdminPin(adminPin); @@ -640,7 +656,7 @@ public class SecurityTokenConnection { */ public byte[] calculateSignature(byte[] hash, int hashAlgo) throws IOException { if (!mPw1ValidatedForSignature) { - verifyPin(0x81); // (Verify PW1 with mode 81 for signing) + verifyPinForSignature(); } byte[] dsi; @@ -869,11 +885,6 @@ public class SecurityTokenConnection { return response.getData(); } - private ResponseAPDU tryPin(int mode, byte[] pin) throws IOException { - // Command APDU for VERIFY command (page 32) - return communicate(commandFactory.createVerifyCommand(mode, pin)); - } - /** * Resets security token, which deletes all keys and data objects. * This works by entering a wrong PIN and then Admin PIN 4 times respectively. @@ -883,8 +894,9 @@ public class SecurityTokenConnection { // try wrong PIN 4 times until counter goes to C0 byte[] pin = "XXXXXX".getBytes(); for (int i = 0; i <= 4; i++) { - ResponseAPDU response = tryPin(0x81, pin); - if (response.getSW() == APDU_SW_SUCCESS) { // Should NOT accept! + // Command APDU for VERIFY command (page 32) + ResponseAPDU response = communicate(commandFactory.createVerifyPw1ForSignatureCommand(pin)); + if (response.getSW() == APDU_SW_SUCCESS) { throw new CardException("Should never happen, XXXXXX has been accepted!", response.getSW()); } } @@ -892,7 +904,8 @@ public class SecurityTokenConnection { // try wrong Admin PIN 4 times until counter goes to C0 byte[] adminPin = "XXXXXXXX".getBytes(); for (int i = 0; i <= 4; i++) { - ResponseAPDU response = tryPin(0x83, adminPin); + // Command APDU for VERIFY command (page 32) + ResponseAPDU response = communicate(commandFactory.createVerifyPw3Command(adminPin)); if (response.getSW() == APDU_SW_SUCCESS) { // Should NOT accept! throw new CardException("Should never happen, XXXXXXXX has been accepted", response.getSW()); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SecurityTokenOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SecurityTokenOperationActivity.java index 4a3c60256..40d609842 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SecurityTokenOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SecurityTokenOperationActivity.java @@ -273,8 +273,8 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenActivity { } // change PINs afterwards - stConnection.modifyPin(0x81, newPin, null); - stConnection.modifyPin(0x83, newAdminPin, adminPin); + stConnection.modifyPw1Pin(newPin); + stConnection.modifyPw3Pin(newAdminPin, adminPin); break; }