diff --git a/tangem-core/src/main/java/com/tangem/CardManager.kt b/tangem-core/src/main/java/com/tangem/CardManager.kt index 8211251100..62c88bf19f 100644 --- a/tangem-core/src/main/java/com/tangem/CardManager.kt +++ b/tangem-core/src/main/java/com/tangem/CardManager.kt @@ -96,8 +96,7 @@ class CardManager( */ fun readIssuerData(cardId: String, callback: (result: TaskEvent) -> Unit) { - val getIssuerDataCommand = ReadIssuerDataCommand() - val task = SingleCommandTask(getIssuerDataCommand) + val task = ReadIssuerDataTask(config.issuerPublicKey) runTask(task, cardId, callback) } @@ -134,12 +133,12 @@ class CardManager( issuerDataSignature: ByteArray, issuerDataCounter: Int? = null, callback: (result: TaskEvent) -> Unit) { - val writeIssuerDataCommand = WriteIssuerDataCommand( + val task = WriteIssuerDataTask( issuerData, issuerDataSignature, - issuerDataCounter + issuerDataCounter, + config.issuerPublicKey ) - val task = SingleCommandTask(writeIssuerDataCommand) runTask(task, cardId, callback) } diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt index a045692a10..c681f5fed9 100644 --- a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt @@ -1,12 +1,12 @@ package com.tangem.commands +import com.tangem.commands.common.DefaultIssuerDataVerifier +import com.tangem.commands.common.IssuerDataMode +import com.tangem.commands.common.IssuerDataVerifier import com.tangem.common.CardEnvironment import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu -import com.tangem.common.extensions.calculateSha256 -import com.tangem.common.extensions.hexToBytes -import com.tangem.common.tlv.Tlv import com.tangem.common.tlv.TlvBuilder import com.tangem.common.tlv.TlvMapper import com.tangem.common.tlv.TlvTag @@ -50,12 +50,16 @@ class ReadIssuerDataResponse( * wallet balance signed by the issuer or additional issuer’s attestation data. * @property cardId CID, Unique Tangem card ID number. */ -class ReadIssuerDataCommand : CommandSerializer() { +class ReadIssuerDataCommand( + verifier: IssuerDataVerifier = DefaultIssuerDataVerifier() +) : CommandSerializer(), + IssuerDataVerifier by verifier { override fun serialize(cardEnvironment: CardEnvironment): CommandApdu { val tlvBuilder = TlvBuilder() tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1) tlvBuilder.append(TlvTag.CardId, cardEnvironment.cardId) + tlvBuilder.append(TlvTag.Mode, IssuerDataMode.ReadData) return CommandApdu(Instruction.ReadIssuerData, tlvBuilder.serialize()) } diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerExtraDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerExtraDataCommand.kt index 2504764a55..4e3f757395 100644 --- a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerExtraDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerExtraDataCommand.kt @@ -1,5 +1,8 @@ package com.tangem.commands +import com.tangem.commands.common.DefaultIssuerDataVerifier +import com.tangem.commands.common.IssuerDataMode +import com.tangem.commands.common.IssuerDataVerifier import com.tangem.common.CardEnvironment import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction @@ -62,7 +65,7 @@ class ReadIssuerExtraDataCommand( val tlvBuilder = TlvBuilder() tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1) tlvBuilder.append(TlvTag.CardId, cardEnvironment.cardId) - tlvBuilder.append(TlvTag.Mode, EXTRA_DATA_MODE) + tlvBuilder.append(TlvTag.Mode, IssuerDataMode.ReadExtraData) tlvBuilder.append(TlvTag.Offset, offset) return CommandApdu(Instruction.ReadIssuerData, tlvBuilder.serialize()) } diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt index 9066040e81..2ca018f2a0 100644 --- a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt @@ -1,13 +1,12 @@ package com.tangem.commands +import com.tangem.commands.common.DefaultIssuerDataVerifier +import com.tangem.commands.common.IssuerDataMode +import com.tangem.commands.common.IssuerDataVerifier import com.tangem.common.CardEnvironment import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu -import com.tangem.common.extensions.calculateSha256 -import com.tangem.common.extensions.hexToBytes -import com.tangem.common.extensions.toByteArray -import com.tangem.common.tlv.Tlv import com.tangem.common.tlv.TlvBuilder import com.tangem.common.tlv.TlvMapper import com.tangem.common.tlv.TlvTag @@ -33,13 +32,15 @@ class WriteIssuerDataResponse( class WriteIssuerDataCommand( private val issuerData: ByteArray, private val issuerDataSignature: ByteArray, - private val issuerDataCounter: Int? = null -) : CommandSerializer() { + private val issuerDataCounter: Int? = null, + verifier: IssuerDataVerifier = DefaultIssuerDataVerifier() +) : CommandSerializer(), IssuerDataVerifier by verifier { override fun serialize(cardEnvironment: CardEnvironment): CommandApdu { val tlvBuilder = TlvBuilder() tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1) tlvBuilder.append(TlvTag.CardId, cardEnvironment.cardId) + tlvBuilder.append(TlvTag.Mode, IssuerDataMode.WriteData) tlvBuilder.append(TlvTag.IssuerData, issuerData) tlvBuilder.append(TlvTag.IssuerDataSignature, issuerDataSignature) tlvBuilder.append(TlvTag.IssuerDataCounter, issuerDataCounter) diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt index 3ae08d0fe6..7a1b987cd5 100644 --- a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt @@ -1,5 +1,8 @@ package com.tangem.commands +import com.tangem.commands.common.DefaultIssuerDataVerifier +import com.tangem.commands.common.IssuerDataMode +import com.tangem.commands.common.IssuerDataVerifier import com.tangem.common.CardEnvironment import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction @@ -9,32 +12,6 @@ import com.tangem.common.tlv.TlvMapper import com.tangem.common.tlv.TlvTag import com.tangem.tasks.TaskError -/** - * This enum specifies modes for [WriteIssuerExtraDataCommand]. - */ -enum class IssuerDataMode(val code: Byte) { - /** - * This mode is required to initiate writing issuer extra data to the card. - */ - InitializeWritingExtraData(1), - /** - * With this mode, the command writes part of issuer extra data - * (block of a size [WriteIssuerExtraDataCommand.SINGLE_WRITE_SIZE]) to the card. - */ - WriteExtraData(2), - /** - * This mode is used after the issuer extra data was fully written to the card. - * Under this mode the command provides the issuer signature - * to confirm the validity of data that was written to card. - */ - FinalizeExtraData(3); - - companion object { - private val values = CardStatus.values() - fun byCode(code: Int): CardStatus? = values.find { it.code == code } - } -} - /** * This command writes Issuer Extra Data field and its issuer’s signature. * Issuer Extra Data is never changed or parsed from within the Tangem COS. diff --git a/tangem-core/src/main/java/com/tangem/commands/common/IssuerDataMode.kt b/tangem-core/src/main/java/com/tangem/commands/common/IssuerDataMode.kt new file mode 100644 index 0000000000..2ebded1b6d --- /dev/null +++ b/tangem-core/src/main/java/com/tangem/commands/common/IssuerDataMode.kt @@ -0,0 +1,44 @@ +package com.tangem.commands.common + +import com.tangem.commands.WriteIssuerExtraDataCommand + +/** + * This enum specifies modes for [WriteIssuerExtraDataCommand]. + */ +enum class IssuerDataMode(val code: Byte) { + + + /** + * This mode is required to read issuer data from the card. + */ + ReadData(0), + + /** + * This mode is required to write issuer data to the card. + */ + WriteData(0), + /** + * This mode is required to read issuer extra data from the card. + */ + ReadExtraData(1), + /** + * This mode is required to initiate writing issuer extra data to the card. + */ + InitializeWritingExtraData(1), + /** + * With this mode, the command writes part of issuer extra data + * (block of a size [WriteIssuerExtraDataCommand.SINGLE_WRITE_SIZE]) to the card. + */ + WriteExtraData(2), + /** + * This mode is used after the issuer extra data was fully written to the card. + * Under this mode the command provides the issuer signature + * to confirm the validity of data that was written to card. + */ + FinalizeExtraData(3); + + companion object { + private val values = values() + fun byCode(code: Byte): IssuerDataMode? = values.find { it.code == code } + } +} \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/commands/IssuerDataVerifier.kt b/tangem-core/src/main/java/com/tangem/commands/common/IssuerDataVerifier.kt similarity index 97% rename from tangem-core/src/main/java/com/tangem/commands/IssuerDataVerifier.kt rename to tangem-core/src/main/java/com/tangem/commands/common/IssuerDataVerifier.kt index cdc7bc4246..03bf58d56e 100644 --- a/tangem-core/src/main/java/com/tangem/commands/IssuerDataVerifier.kt +++ b/tangem-core/src/main/java/com/tangem/commands/common/IssuerDataVerifier.kt @@ -1,4 +1,4 @@ -package com.tangem.commands +package com.tangem.commands.common import com.tangem.common.tlv.TlvEncoder import com.tangem.common.tlv.TlvTag diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt index 217fd9a2ca..e2dce7d743 100644 --- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt +++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt @@ -2,7 +2,10 @@ package com.tangem.common.tlv import com.tangem.Log import com.tangem.commands.* -import com.tangem.common.extensions.* +import com.tangem.commands.common.IssuerDataMode +import com.tangem.common.extensions.calculateSha256 +import com.tangem.common.extensions.hexToBytes +import com.tangem.common.extensions.toByteArray import com.tangem.tasks.TaskError import java.util.* diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvMapper.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvMapper.kt index c542d583dc..ead8085ebe 100644 --- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvMapper.kt +++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvMapper.kt @@ -2,6 +2,7 @@ package com.tangem.common.tlv import com.tangem.Log import com.tangem.commands.* +import com.tangem.commands.common.IssuerDataMode import com.tangem.common.extensions.toDate import com.tangem.common.extensions.toHexString import com.tangem.common.extensions.toInt @@ -132,7 +133,7 @@ class TlvMapper(val tlvList: List) { TlvValueType.IssuerDataMode -> { typeCheck(tag) try { - IssuerDataMode.byCode(tlvValue.toInt()) as T + IssuerDataMode.byCode(tlvValue.toInt().toByte()) as T } catch (exception: Exception) { logException(tag, tlvValue.toInt().toString(), exception) throw TaskError.ConvertError() diff --git a/tangem-core/src/main/java/com/tangem/tasks/ReadIssuerDataTask.kt b/tangem-core/src/main/java/com/tangem/tasks/ReadIssuerDataTask.kt new file mode 100644 index 0000000000..d7c50dde31 --- /dev/null +++ b/tangem-core/src/main/java/com/tangem/tasks/ReadIssuerDataTask.kt @@ -0,0 +1,53 @@ +package com.tangem.tasks + +import com.tangem.commands.Card +import com.tangem.commands.ReadIssuerDataCommand +import com.tangem.commands.ReadIssuerDataResponse +import com.tangem.commands.common.IssuerDataToVerify +import com.tangem.common.CardEnvironment +import com.tangem.common.CompletionResult + +class ReadIssuerDataTask(private val issuerPublicKey: ByteArray? = null) : Task() { + + override fun onRun( + cardEnvironment: CardEnvironment, + currentCard: Card?, + callback: (result: TaskEvent) -> Unit) { + + val command = ReadIssuerDataCommand() + + sendCommand(command, cardEnvironment) { result -> + when (result) { + is CompletionResult.Success -> { + val data = result.data + if (data.issuerData.isEmpty()) { + completeNfcSession() + callback(TaskEvent.Event(result.data)) + callback(TaskEvent.Completion()) + return@sendCommand + } + val publicKey = issuerPublicKey ?: currentCard!!.issuerPublicKey!! + val issuerDataToVerify = IssuerDataToVerify( + cardEnvironment.cardId!!, + data.issuerData, + data.issuerDataCounter + ) + if (command.verify(publicKey, data.issuerDataSignature, issuerDataToVerify)) { + completeNfcSession() + callback(TaskEvent.Event(result.data)) + callback(TaskEvent.Completion()) + } else { + completeNfcSession(TaskError.VerificationFailed()) + callback(TaskEvent.Completion(TaskError.VerificationFailed())) + } + } + is CompletionResult.Failure -> { + if (result.error !is TaskError.UserCancelled) { + completeNfcSession(result.error) + } + callback(TaskEvent.Completion(result.error)) + } + } + } + } +} \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/tasks/ReadIssuerExtraDataTask.kt b/tangem-core/src/main/java/com/tangem/tasks/ReadIssuerExtraDataTask.kt index cf3cd25986..4f1397b8db 100644 --- a/tangem-core/src/main/java/com/tangem/tasks/ReadIssuerExtraDataTask.kt +++ b/tangem-core/src/main/java/com/tangem/tasks/ReadIssuerExtraDataTask.kt @@ -1,6 +1,10 @@ package com.tangem.tasks -import com.tangem.commands.* +import com.tangem.commands.Card +import com.tangem.commands.ReadIssuerExtraDataCommand +import com.tangem.commands.ReadIssuerExtraDataResponse +import com.tangem.commands.WriteIssuerExtraDataCommand +import com.tangem.commands.common.IssuerDataToVerify import com.tangem.common.CardEnvironment import com.tangem.common.CompletionResult import java.io.ByteArrayOutputStream diff --git a/tangem-core/src/main/java/com/tangem/tasks/WriteIssuerDataTask.kt b/tangem-core/src/main/java/com/tangem/tasks/WriteIssuerDataTask.kt new file mode 100644 index 0000000000..c8b3bcb083 --- /dev/null +++ b/tangem-core/src/main/java/com/tangem/tasks/WriteIssuerDataTask.kt @@ -0,0 +1,67 @@ +package com.tangem.tasks + +import com.tangem.commands.Card +import com.tangem.commands.SettingsMask +import com.tangem.commands.WriteIssuerDataCommand +import com.tangem.commands.WriteIssuerDataResponse +import com.tangem.commands.common.IssuerDataToVerify +import com.tangem.common.CardEnvironment +import com.tangem.common.CompletionResult + +class WriteIssuerDataTask( + private val issuerData: ByteArray, + private val issuerDataSignature: ByteArray, + private val issuerDataCounter: Int? = null, + private val issuerPublicKey: ByteArray? = null +) : Task() { + + private lateinit var card: Card + + override fun onRun( + cardEnvironment: CardEnvironment, + currentCard: Card?, + callback: (result: TaskEvent) -> Unit) { + + card = currentCard!! + val command = WriteIssuerDataCommand( + issuerData, issuerDataSignature, issuerDataCounter + ) + if (!isCounterValid(issuerDataCounter)) { + completeNfcSession(TaskError.MissingCounter()) + callback(TaskEvent.Completion(TaskError.MissingCounter())) + } else if (!verifySignature(command, cardEnvironment.cardId!!)) { + completeNfcSession(TaskError.VerificationFailed()) + callback(TaskEvent.Completion(TaskError.VerificationFailed())) + } + + sendCommand(command, cardEnvironment) { result -> + when (result) { + is CompletionResult.Success -> { + completeNfcSession() + callback(TaskEvent.Event(result.data)) + callback(TaskEvent.Completion()) + } + is CompletionResult.Failure -> { + if (result.error !is TaskError.UserCancelled) { + completeNfcSession(result.error) + } + callback(TaskEvent.Completion(result.error)) + } + } + } + } + + private fun isCounterValid(issuerDataCounter: Int?): Boolean = + if (isCounterRequired()) issuerDataCounter != null else true + + private fun isCounterRequired(): Boolean = + card.settingsMask?.contains(SettingsMask.protectIssuerDataAgainstReplay) != false + + private fun verifySignature(command: WriteIssuerDataCommand, cardId: String): Boolean { + return command.verify( + issuerPublicKey ?: card.issuerPublicKey!!, + issuerDataSignature, + IssuerDataToVerify(cardId, issuerData, issuerDataCounter) + ) + } +} \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/tasks/WriteIssuerExtraDataTask.kt b/tangem-core/src/main/java/com/tangem/tasks/WriteIssuerExtraDataTask.kt index f24deb929f..f56ac1c5d5 100644 --- a/tangem-core/src/main/java/com/tangem/tasks/WriteIssuerExtraDataTask.kt +++ b/tangem-core/src/main/java/com/tangem/tasks/WriteIssuerExtraDataTask.kt @@ -1,6 +1,11 @@ package com.tangem.tasks -import com.tangem.commands.* +import com.tangem.commands.Card +import com.tangem.commands.SettingsMask +import com.tangem.commands.WriteIssuerDataResponse +import com.tangem.commands.WriteIssuerExtraDataCommand +import com.tangem.commands.common.IssuerDataMode +import com.tangem.commands.common.IssuerDataToVerify import com.tangem.common.CardEnvironment import com.tangem.common.CompletionResult