From 58e6564cc8d06d05666aa95c8d69bee8f3ae56bf Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Jun 2020 13:19:18 +0300 Subject: [PATCH 1/2] Updated on 2026-08-14 --- .../java/com/tangem/SessionEnvironment.kt | 1 + .../main/java/com/tangem/commands/Command.kt | 38 ++++++++- .../java/com/tangem/commands/SetPinCommand.kt | 83 +++++++++++++++++++ 3 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 tangem-core/src/main/java/com/tangem/commands/SetPinCommand.kt diff --git a/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt b/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt index 0534f85d0a..c2b744d811 100644 --- a/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt +++ b/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt @@ -25,6 +25,7 @@ data class SessionEnvironment( ) { var isDefaultPin1: Boolean = Companion.pin1.contentEquals(DEFAULT_PIN.calculateSha256()) + var isDefaultPin2: Boolean = pin2.contentEquals(DEFAULT_PIN2.calculateSha256()) var pin1: ByteArray = SessionEnvironment.pin1 private set 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..2c7263ca52 100644 --- a/tangem-core/src/main/java/com/tangem/commands/Command.kt +++ b/tangem-core/src/main/java/com/tangem/commands/Command.kt @@ -41,7 +41,18 @@ abstract class Command : ApduSerializable, CardSessionRu override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { Log.i("Command", "Initializing ${this::class.java.simpleName}") - transceive(session, callback) + + if (requiresPin2() && session.environment.isDefaultPin2) { + handlePin2(session, callback) + } else { + transceive(session, callback) + } + + } + + private fun Command<*>.requiresPin2(): Boolean { + return this is SignCommand || this is PurgeWalletCommand || + this is CreateWalletCommand || this is WriteUserDataCommand } open fun performPreCheck(card: Card): TangemSdkError? = null @@ -199,4 +210,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) + transceive(session, callback) + } + } + } + is CompletionResult.Success -> { + transceive(session, callback) + } + } + } + } } \ No newline at end of file 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..e079f82786 --- /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.SwapPIN, 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 From 11f0197caa72f30fce9b79e450983b3b6c10348c Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 23 Jun 2020 14:50:26 +0300 Subject: [PATCH 2/2] Updated on 2026-08-14 --- .../java/com/tangem/SessionEnvironment.kt | 6 ++--- .../main/java/com/tangem/commands/Command.kt | 23 ++++++++----------- .../tangem/commands/CreateWalletCommand.kt | 2 ++ .../com/tangem/commands/PurgeWalletCommand.kt | 2 ++ .../java/com/tangem/commands/SetPinCommand.kt | 2 +- .../java/com/tangem/commands/SignCommand.kt | 2 ++ .../tangem/commands/WriteUserDataCommand.kt | 2 ++ .../com/tangem/common/apdu/Instruction.kt | 2 +- 8 files changed, 22 insertions(+), 19 deletions(-) diff --git a/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt b/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt index c2b744d811..88050df353 100644 --- a/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt +++ b/tangem-core/src/main/java/com/tangem/SessionEnvironment.kt @@ -24,13 +24,13 @@ data class SessionEnvironment( val handleErrors: Boolean = true ) { - var isDefaultPin1: Boolean = Companion.pin1.contentEquals(DEFAULT_PIN.calculateSha256()) - var isDefaultPin2: Boolean = pin2.contentEquals(DEFAULT_PIN2.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 2c7263ca52..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,21 +38,11 @@ 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}") - - if (requiresPin2() && session.environment.isDefaultPin2) { - handlePin2(session, callback) - } else { - transceive(session, callback) - } - - } - - private fun Command<*>.requiresPin2(): Boolean { - return this is SignCommand || this is PurgeWalletCommand || - this is CreateWalletCommand || this is WriteUserDataCommand + transceive(session, callback) } open fun performPreCheck(card: Card): TangemSdkError? = null @@ -69,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) { @@ -192,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 @@ -225,7 +220,7 @@ abstract class Command : ApduSerializable, CardSessionRu transceive(session, callback) } else { session.environment.setPin2(SessionEnvironment.DEFAULT_PIN2) - transceive(session, callback) + callback(CompletionResult.Failure(TangemSdkError.Pin2OrCvcRequired())) } } } 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 index e079f82786..084e755cc1 100644 --- a/tangem-core/src/main/java/com/tangem/commands/SetPinCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/SetPinCommand.kt @@ -66,7 +66,7 @@ class SetPinCommand( tlvBuilder.append(TlvTag.NewPin, newPin1) tlvBuilder.append(TlvTag.NewPin2, newPin2) tlvBuilder.append(TlvTag.NewPin3, newPin3) - return CommandApdu(Instruction.SwapPIN, tlvBuilder.serialize()) + return CommandApdu(Instruction.SetPin, tlvBuilder.serialize()) } override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): SetPinResponse { 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),