diff --git a/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt b/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt index 0534f85d0a..88050df353 100644 --- a/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt +++ b/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt @@ -24,12 +24,13 @@ data class SessionEnvironment( val handleErrors: Boolean = true ) { - var isDefaultPin1: Boolean = Companion.pin1.contentEquals(DEFAULT_PIN.calculateSha256()) - var pin1: ByteArray = SessionEnvironment.pin1 private set get() = SessionEnvironment.pin1 + fun isCurrentPin1Default(): Boolean = Companion.pin1.contentEquals(DEFAULT_PIN.calculateSha256()) + fun isCurrentPin2Default(): Boolean = pin2.contentEquals(DEFAULT_PIN2.calculateSha256()) + fun setPin1(pin1: String) { SessionEnvironment.pin1 = pin1.calculateSha256() } diff --git a/tangem-core/src/main/java/com/tangem/commands/Command.kt b/tangem-core/src/main/java/com/tangem/commands/Command.kt index 57cc3dd0a2..ce21f6cdba 100644 --- a/tangem-core/src/main/java/com/tangem/commands/Command.kt +++ b/tangem-core/src/main/java/com/tangem/commands/Command.kt @@ -38,6 +38,7 @@ interface CommandResponse abstract class Command : ApduSerializable, CardSessionRunnable { override val performPreflightRead: Boolean = true + open val requiresPin2: Boolean = false override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { Log.i("Command", "Initializing ${this::class.java.simpleName}") @@ -58,6 +59,11 @@ abstract class Command : ApduSerializable, CardSessionRu } } + if (requiresPin2 && session.environment.isCurrentPin2Default()) { + handlePin2(session, callback) + return + } + val apdu = serialize(session.environment) transceiveApdu(apdu, session) { result -> when (result) { @@ -181,7 +187,7 @@ abstract class Command : ApduSerializable, CardSessionRu session: CardSession, callback: (result: CompletionResult) -> Unit ) { - if (!session.environment.isDefaultPin1) { + if (!session.environment.isCurrentPin1Default()) { session.environment.setPin1(SessionEnvironment.DEFAULT_PIN) transceive(session, callback) return @@ -199,4 +205,29 @@ abstract class Command : ApduSerializable, CardSessionRu } } } + + private fun handlePin2( + session: CardSession, + callback: (result: CompletionResult) -> Unit + ) { + val checkPinCommand = SetPinCommand(session.environment.pin1, session.environment.pin2) + checkPinCommand.run(session) { result -> + when (result) { + is CompletionResult.Failure -> { + session.viewDelegate.onPinRequested { pin2 -> + if (!pin2.isNullOrEmpty()) { + session.environment.setPin2(pin2) + transceive(session, callback) + } else { + session.environment.setPin2(SessionEnvironment.DEFAULT_PIN2) + callback(CompletionResult.Failure(TangemSdkError.Pin2OrCvcRequired())) + } + } + } + is CompletionResult.Success -> { + transceive(session, callback) + } + } + } + } } \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt index 87f9f6dcbe..83a6cbd78d 100644 --- a/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt @@ -37,6 +37,8 @@ class CreateWalletResponse( */ class CreateWalletCommand : Command() { + override val requiresPin2 = true + override fun performPreCheck(card: Card): TangemSdkError? { if (card.isActivated) { return TangemSdkError.NotActivated() diff --git a/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt index c3765f4ccd..c4ca477ca3 100644 --- a/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt @@ -29,6 +29,8 @@ class PurgeWalletResponse( */ class PurgeWalletCommand : Command() { + override val requiresPin2 = true + override fun performPreCheck(card: Card): TangemSdkError? { if (card.status == CardStatus.NotPersonalized) { return TangemSdkError.NotPersonalized() diff --git a/tangem-core/src/main/java/com/tangem/commands/SetPinCommand.kt b/tangem-core/src/main/java/com/tangem/commands/SetPinCommand.kt new file mode 100644 index 0000000000..084e755cc1 --- /dev/null +++ b/tangem-core/src/main/java/com/tangem/commands/SetPinCommand.kt @@ -0,0 +1,83 @@ +package com.tangem.commands + +import com.tangem.SessionEnvironment +import com.tangem.TangemSdkError +import com.tangem.common.apdu.CommandApdu +import com.tangem.common.apdu.Instruction +import com.tangem.common.apdu.ResponseApdu +import com.tangem.common.apdu.StatusWord +import com.tangem.common.extensions.calculateSha256 +import com.tangem.common.tlv.TlvBuilder +import com.tangem.common.tlv.TlvDecoder +import com.tangem.common.tlv.TlvTag + +enum class SetPinStatus { + PinsNotChanged, + Pin1Changed, + Pin2Changed, + Pin3Changed, + Pins12Changed, + Pins13Changed, + Pins23Changed, + Pins123Changed, + ; + + companion object { + fun fromStatusWord(statusWord: StatusWord): SetPinStatus? { + return when (statusWord) { + StatusWord.ProcessCompleted -> PinsNotChanged + StatusWord.Pin1Changed -> Pin1Changed + StatusWord.Pin2Changed -> Pin2Changed + StatusWord.Pins12Changed -> Pins12Changed + StatusWord.Pin3Changed -> Pin3Changed + StatusWord.Pins13Changed -> Pins13Changed + StatusWord.Pins23Changed -> Pins23Changed + StatusWord.Pins123Changed -> Pins123Changed + else -> null + } + } + } +} + +class SetPinResponse( + /** + * CID, Unique Tangem card ID number. + */ + val cardId: String, + /** + * + */ + val status: SetPinStatus +) : CommandResponse + + +class SetPinCommand( + private val newPin1: ByteArray = SessionEnvironment.DEFAULT_PIN.calculateSha256(), + private val newPin2: ByteArray = SessionEnvironment.DEFAULT_PIN2.calculateSha256(), + private val newPin3: ByteArray? = null +) : Command() { + + override fun serialize(environment: SessionEnvironment): CommandApdu { + val tlvBuilder = TlvBuilder() + tlvBuilder.append(TlvTag.Pin, environment.pin1) + tlvBuilder.append(TlvTag.CardId, environment.card?.cardId) + tlvBuilder.append(TlvTag.Pin2, environment.pin2) + tlvBuilder.append(TlvTag.Cvc, environment.cvc) + tlvBuilder.append(TlvTag.NewPin, newPin1) + tlvBuilder.append(TlvTag.NewPin2, newPin2) + tlvBuilder.append(TlvTag.NewPin3, newPin3) + return CommandApdu(Instruction.SetPin, tlvBuilder.serialize()) + } + + override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): SetPinResponse { + val tlvData = apdu.getTlvData() ?: throw TangemSdkError.DeserializeApduFailed() + + val status = SetPinStatus.fromStatusWord(apdu.statusWord) ?: throw TangemSdkError.DecodingFailed() + + val decoder = TlvDecoder(tlvData) + return SetPinResponse( + cardId = decoder.decode(TlvTag.CardId), + status = status + ) + } +} \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt b/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt index c5d743975b..b48263e2d1 100644 --- a/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt @@ -32,6 +32,8 @@ class SignResponse( */ class SignCommand(private val hashes: Array) : Command() { + override val requiresPin2 = true + //TODO: Allow signing more than 10 hashes private val hashSizes = if (hashes.isNotEmpty()) hashes.first().size else 0 diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt index 97a406a2d3..380f18eaf1 100644 --- a/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt @@ -32,6 +32,8 @@ class WriteUserDataCommand(private val userData: ByteArray? = null, private val private val userCounter: Int? = null, private val userProtectedCounter: Int? = null) : Command() { + override val requiresPin2 = true + override fun performPreCheck(card: Card): TangemSdkError? { if (card.status == CardStatus.NotPersonalized) { return TangemSdkError.NotPersonalized() diff --git a/tangem-core/src/main/java/com/tangem/common/apdu/Instruction.kt b/tangem-core/src/main/java/com/tangem/common/apdu/Instruction.kt index 46c8989535..02a5eabf7b 100644 --- a/tangem-core/src/main/java/com/tangem/common/apdu/Instruction.kt +++ b/tangem-core/src/main/java/com/tangem/common/apdu/Instruction.kt @@ -15,7 +15,7 @@ enum class Instruction(var code: Int) { ReadIssuerData(0xF7), CreateWallet(0xF8), CheckWallet(0xF9), - SwapPIN(0xFA), + SetPin(0xFA), Sign(0xFB), PurgeWallet(0xFC), Activate(0xFE),