Skip to content

Commit

Permalink
Merge pull request #263 from tangem/IOS-3289_check_wallet
Browse files Browse the repository at this point in the history
Check wallet with the wallet's status
  • Loading branch information
tureck1y authored Apr 4, 2023
2 parents 6a731aa + e351826 commit d2c3e00
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 15 deletions.
2 changes: 1 addition & 1 deletion TangemSdk/TangemSdk/Common/Card/CardSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public extension Card {
public let isHDWalletAllowed: Bool
/// Is allowed to create backup
public let isBackupAllowed: Bool
/// Is allowed to import keys. COS. v6.10+
/// Is allowed to import keys. COS. v6.11+
public let isKeysImportAllowed: Bool
/// Is allowed to delete wallet. COS before v4
@SkipEncoding
Expand Down
4 changes: 2 additions & 2 deletions TangemSdk/TangemSdk/Common/Card/Wallet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ public extension Card.Wallet {
}

@available(iOS 13.0, *)
extension Card.Wallet {
public extension Card.Wallet {
/// Status of the wallet.
enum Status: Int, StatusType { //TODO: Specify
enum Status: Int, StatusType, JSONStringConvertible { //TODO: Specify
/// Wallet not created
case empty = 1
/// Wallet created and can be used for signing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import Foundation

/// Deserialized response from the Tangem card after `AttestWalletKeyCommand`.
@available(iOS 13.0, *)
public struct AttestWalletKeyResponse: JSONStringConvertible {
/// Unique Tangem card ID number
public let cardId: String
Expand All @@ -18,13 +19,15 @@ public struct AttestWalletKeyResponse: JSONStringConvertible {
public let walletSignature: Data
/// Challenge, used to check wallet
public let challenge: Data
/// Confirmation signature of the wallet ownership. COS: 2.01+.
/// Confirmation signature of the wallet ownership. COS: 2.01+. And a wallet's status for COS: 6.11+.
/// - `ConfirmationMode.none` : No signature will be returned.
/// - `ConfirmationMode.static` : Wallet's public key signed with the card's private key.
/// - `ConfirmationMode.dynamic`: Wallet's public key, `challenge`, and `publicKeySalt`, signed with the card's private key.
/// - `ConfirmationMode.static` : Wallet's public key and wallet's status (COS 6.11+) signed with the card's private key.
/// - `ConfirmationMode.dynamic`: Wallet's public key, wallet's status (COS 6.11+), `challenge`, and `publicKeySalt`, signed with the card's private key.
public let cardSignature: Data?
/// Optional random salt, generated by the card for `dynamic` `confirmationMode`. COS: 2.01+.
public let publicKeySalt: Data?
/// Status of the wallet. COS v.6.11+
public let walletStatus: Card.Wallet.Status?
/// Counter of `AttestWalletKey` command executions. A very big value of this counter may indicate a hacking attempts. COS: 2.01+.
let counter: Int?
}
Expand Down Expand Up @@ -63,14 +66,17 @@ public final class AttestWalletKeyCommand: Command {
transceive(in: session) {result in
switch result {
case .success(let checkWalletResponse):
guard let curve = session.environment.card?.wallets[self.walletPublicKey]?.curve else {
guard let card = session.environment.card,
let curve = card.wallets[self.walletPublicKey]?.curve else {
completion(.failure(.cardError))
return
}

do {
let verifyResult = try self.verify(response: checkWalletResponse, curve: curve)
if verifyResult {
let isWalletSignatureValid = try self.verifyWalletSignature(response: checkWalletResponse, curve: curve)
let isCardSignatureValid = try self.verifyCardSignature(response: checkWalletResponse,
cardPublicKey: card.cardPublicKey)
if isWalletSignatureValid && isCardSignatureValid {
completion(.success(checkWalletResponse))
} else {
completion(.failure(.cardVerificationFailed))
Expand Down Expand Up @@ -127,15 +133,38 @@ public final class AttestWalletKeyCommand: Command {
challenge: self.challenge,
cardSignature: try decoder.decode(.cardSignature),
publicKeySalt: try decoder.decode(.publicKeySalt),
walletStatus: try decoder.decode(.status),
counter: try decoder.decode(.checkWalletCounter))
}

private func verify(response: AttestWalletKeyResponse, curve: EllipticCurve) throws -> Bool {
private func verifyWalletSignature(response: AttestWalletKeyResponse, curve: EllipticCurve) throws -> Bool {
return try CryptoUtils.verify(curve: curve,
publicKey: walletPublicKey,
message: challenge + response.salt,
signature: response.walletSignature)
}

private func verifyCardSignature(response: AttestWalletKeyResponse, cardPublicKey: Data) throws -> Bool {
guard let cardSignature = response.cardSignature else {
return true
}

var message = walletPublicKey

// Dynamic verification
if let publicKeySalt = response.publicKeySalt {
message += challenge + publicKeySalt
}

if let walletStatus = response.walletStatus {
message += walletStatus.rawValue.byte
}

return try CryptoUtils.verify(curve: .secp256k1,
publicKey: cardPublicKey,
message: message,
signature: cardSignature)
}
}

@available(iOS 13.0, *)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ final class CreateWalletCommand: Command {
self.privateKey = nil
}

/// Default initializer
/// Use this initializer to import a key from the seed. COS v6.11+.
/// - Parameter curve: Elliptic curve of the wallet. `Card.supportedCurves` contains all curves supported by the card
/// - Parameter seed: BIP39 seed to create wallet from. COS v6.10+.
/// - Parameter seed: BIP39 seed to create wallet from.
init(curve: EllipticCurve, seed: Data) throws {
self.curve = curve
self.privateKey = try BIP32().makeMasterKey(from: seed, curve: curve)
Expand Down
4 changes: 2 additions & 2 deletions TangemSdk/TangemSdk/Operations/Wallet/CreateWalletTask.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ public class CreateWalletTask: CardSessionRunnable {
self.seed = nil
}

/// Default initializer
/// Use this initializer to import a key from the seed. COS v6.11+.
/// - Parameter curve: Elliptic curve of the wallet. `Card.supportedCurves` contains all curves supported by the card
/// - Parameter seed: BIP39 seed to create wallet from. COS v6.10+.
/// - Parameter seed: BIP39 seed to create wallet from.
public init(curve: EllipticCurve, seed: Data) {
self.curve = curve
self.seed = seed
Expand Down
2 changes: 1 addition & 1 deletion TangemSdk/TangemSdk/TangemSdk.swift
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public extension TangemSdk {
/// - curve: Elliptic curve of the wallet. `Card.supportedCurves` contains all curves supported by the card
/// - initialMessage: A custom description that shows at the beginning of the NFC session. If nil, default message will be used
/// - cardId: CID, Unique Tangem card ID number.
/// - seed: BIP39 seed to create wallet from. COS v.6.10+.
/// - seed: BIP39 seed to create wallet from. COS v.6.11+.
/// - completion: Returns `Swift.Result<CreateWalletResponse,TangemSdkError>`
func importWallet(curve: EllipticCurve,
cardId: String,
Expand Down

0 comments on commit d2c3e00

Please sign in to comment.