diff --git a/android/src/main/java/im/status/ethereum/keycard/RNStatusKeycardModule.java b/android/src/main/java/im/status/ethereum/keycard/RNStatusKeycardModule.java index ad34926..062b187 100644 --- a/android/src/main/java/im/status/ethereum/keycard/RNStatusKeycardModule.java +++ b/android/src/main/java/im/status/ethereum/keycard/RNStatusKeycardModule.java @@ -14,6 +14,7 @@ import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.ReadableMap; import java.io.IOException; import java.security.NoSuchAlgorithmException; @@ -119,11 +120,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void generateMnemonic(final String pairing, final String words, final Promise promise) { + public void generateMnemonic(final String words, final Promise promise) { new Thread(new Runnable() { public void run() { try { - promise.resolve(smartCard.generateMnemonic(pairing, words)); + promise.resolve(smartCard.generateMnemonic(words)); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); promise.reject(e); @@ -133,11 +134,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void generateAndLoadKey(final String mnemonic, final String pairing, final String pin, final Promise promise) { + public void generateAndLoadKey(final String mnemonic, final String pin, final Promise promise) { new Thread(new Runnable() { public void run() { try { - promise.resolve(smartCard.generateAndLoadKey(mnemonic, pairing, pin)); + promise.resolve(smartCard.generateAndLoadKey(mnemonic, pin)); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); promise.reject(e); @@ -147,11 +148,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void saveMnemonic(final String mnemonic, final String pairing, final String pin, final Promise promise) { + public void saveMnemonic(final String mnemonic, final String pin, final Promise promise) { new Thread(new Runnable() { public void run() { try { - smartCard.saveMnemonic(mnemonic, pairing, pin); + smartCard.saveMnemonic(mnemonic, pin); promise.resolve(true); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); @@ -162,11 +163,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void getApplicationInfo(final String pairingBase64, final Promise promise) { + public void getApplicationInfo(final Promise promise) { new Thread(new Runnable() { public void run() { try { - promise.resolve(smartCard.getApplicationInfo(pairingBase64)); + promise.resolve(smartCard.getApplicationInfo()); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); promise.reject(e); @@ -176,11 +177,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void deriveKey(final String path, final String pairing, final String pin, final Promise promise) { + public void deriveKey(final String path, final String pin, final Promise promise) { new Thread(new Runnable() { public void run() { try { - smartCard.deriveKey(path, pairing, pin); + smartCard.deriveKey(path, pin); promise.resolve(path); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); @@ -191,11 +192,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void exportKey(final String pairing, final String pin, final Promise promise) { + public void exportKey(final String pin, final Promise promise) { new Thread(new Runnable() { public void run() { try { - promise.resolve(smartCard.exportKey(pairing, pin)); + promise.resolve(smartCard.exportKey(pin)); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); promise.reject(e); @@ -205,11 +206,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void exportKeyWithPath(final String pairing, final String pin, final String path, final Promise promise) { + public void exportKeyWithPath(final String pin, final String path, final Promise promise) { new Thread(new Runnable() { public void run() { try { - promise.resolve(smartCard.exportKeyWithPath(pairing, pin, path)); + promise.resolve(smartCard.exportKeyWithPath(pin, path)); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); promise.reject(e); @@ -219,11 +220,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void getKeys(final String pairing, final String pin, final Promise promise) { + public void getKeys(final String pin, final Promise promise) { new Thread(new Runnable() { public void run() { try { - promise.resolve(smartCard.getKeys(pairing, pin)); + promise.resolve(smartCard.getKeys(pin)); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); promise.reject(e); @@ -233,11 +234,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void importKeys(final String pairing, final String pin, final Promise promise) { + public void importKeys(final String pin, final Promise promise) { new Thread(new Runnable() { public void run() { try { - promise.resolve(smartCard.importKeys(pairing, pin)); + promise.resolve(smartCard.importKeys(pin)); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); promise.reject(e); @@ -247,11 +248,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void sign(final String pairing, final String pin, final String hash, final Promise promise) { + public void sign(final String pin, final String hash, final Promise promise) { new Thread(new Runnable() { public void run() { try { - promise.resolve(smartCard.sign(pairing, pin, hash)); + promise.resolve(smartCard.sign(pin, hash)); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); promise.reject(e); @@ -261,11 +262,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void signWithPath(final String pairing, final String pin, final String path, final String hash, final Promise promise) { + public void signWithPath(final String pin, final String path, final String hash, final Promise promise) { new Thread(new Runnable() { public void run() { try { - promise.resolve(smartCard.signWithPath(pairing, pin, path, hash)); + promise.resolve(smartCard.signWithPath(pin, path, hash)); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); promise.reject(e); @@ -327,11 +328,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void verifyPin(final String pairing, final String pin, final Promise promise) { + public void verifyPin(final String pin, final Promise promise) { new Thread(new Runnable() { public void run() { try { - promise.resolve(smartCard.verifyPin(pairing, pin)); + promise.resolve(smartCard.verifyPin(pin)); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); promise.reject(e); @@ -341,11 +342,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void changePin(final String pairing, final String currentPin, final String newPin, final Promise promise) { + public void changePin(final String currentPin, final String newPin, final Promise promise) { new Thread(new Runnable() { public void run() { try { - smartCard.changePin(pairing, currentPin, newPin); + smartCard.changePin(currentPin, newPin); promise.resolve(true); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); @@ -356,11 +357,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void unblockPin(final String pairing, final String puk, final String newPin, final Promise promise) { + public void unblockPin(final String puk, final String newPin, final Promise promise) { new Thread(new Runnable() { public void run() { try { - smartCard.unblockPin(pairing, puk, newPin); + smartCard.unblockPin(puk, newPin); promise.resolve(true); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); @@ -371,11 +372,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void unpair(final String pairing, final String pin, final Promise promise) { + public void unpair(final String pin, final Promise promise) { new Thread(new Runnable() { public void run() { try { - smartCard.unpair(pairing, pin); + smartCard.unpair(pin); promise.resolve(true); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); @@ -401,11 +402,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void removeKey(final String pairing, final String pin, final Promise promise) { + public void removeKey(final String pin, final Promise promise) { new Thread(new Runnable() { public void run() { try { - smartCard.removeKey(pairing, pin); + smartCard.removeKey(pin); promise.resolve(true); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); @@ -416,11 +417,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void removeKeyWithUnpair(final String pairing, final String pin, final Promise promise) { + public void removeKeyWithUnpair(final String pin, final Promise promise) { new Thread(new Runnable() { public void run() { try { - smartCard.removeKeyWithUnpair(pairing, pin); + smartCard.removeKeyWithUnpair(pin); promise.resolve(true); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); @@ -431,11 +432,11 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements } @ReactMethod - public void unpairAndDelete(final String pairing, final String pin, final Promise promise) { + public void unpairAndDelete(final String pin, final Promise promise) { new Thread(new Runnable() { public void run() { try { - smartCard.unpairAndDelete(pairing, pin); + smartCard.unpairAndDelete(pin); promise.resolve(true); } catch (IOException | APDUException e) { Log.d(TAG, e.getMessage()); @@ -460,4 +461,10 @@ public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements public void setNFCMessage(String message, final Promise promise) { promise.resolve(true); } + + @ReactMethod + public void setPairings(ReadableMap pairings, final Promise promise) { + smartCard.setPairings(pairings); + promise.resolve(true); + } } diff --git a/android/src/main/java/im/status/ethereum/keycard/SmartCard.java b/android/src/main/java/im/status/ethereum/keycard/SmartCard.java index 99bdaa7..47289a3 100644 --- a/android/src/main/java/im/status/ethereum/keycard/SmartCard.java +++ b/android/src/main/java/im/status/ethereum/keycard/SmartCard.java @@ -21,6 +21,9 @@ import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; import java.util.Scanner; +import java.util.Map; +import java.util.HashMap; +import java.util.Iterator; import im.status.keycard.applet.RecoverableSignature; import im.status.keycard.globalplatform.GlobalPlatformCommandSet; @@ -46,6 +49,7 @@ public class SmartCard extends BroadcastReceiver implements CardListener { private EventEmitter eventEmitter; private static final String TAG = "SmartCard"; private Boolean started = false; + private HashMap pairings; private static final String MASTER_PATH = "m"; private static final String ROOT_PATH = "m/44'/60'/0'/0"; @@ -58,6 +62,7 @@ public class SmartCard extends BroadcastReceiver implements CardListener { this.cardManager = new NFCCardManager(); this.cardManager.setCardListener(this); this.eventEmitter = new EventEmitter(reactContext); + this.pairings = new HashMap<>(); } public String getName() { @@ -160,7 +165,8 @@ public class SmartCard extends BroadcastReceiver implements CardListener { // First thing to do is selecting the applet on the card. ApplicationInfo info = new ApplicationInfo(cmdSet.select().checkOK().getData()); - Log.i(TAG, "Instance UID: " + Hex.toHexString(info.getInstanceUID())); + String instanceUID = Hex.toHexString(info.getInstanceUID()); + Log.i(TAG, "Instance UID: " + instanceUID); Log.i(TAG, "Key UID: " + Hex.toHexString(info.getKeyUID())); Log.i(TAG, "Secure channel public key: " + Hex.toHexString(info.getSecureChannelPubKey())); Log.i(TAG, "Application version: " + info.getAppVersionString()); @@ -169,19 +175,12 @@ public class SmartCard extends BroadcastReceiver implements CardListener { cmdSet.autoPair(pairingPassword); Pairing pairing = cmdSet.getPairing(); - + pairings.put(instanceUID, pairing.toBase64()); return pairing.toBase64(); } - public String generateMnemonic(String pairingBase64, String words) throws IOException, APDUException { - KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); - cmdSet.select().checkOK(); - - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); + public String generateMnemonic(String words) throws IOException, APDUException { + KeycardCommandSet cmdSet = securedCommandSet(); Mnemonic mnemonic = new Mnemonic(cmdSet.generateMnemonic(KeycardCommandSet.GENERATE_MNEMONIC_12_WORDS).checkOK().getData()); @@ -198,18 +197,8 @@ public class SmartCard extends BroadcastReceiver implements CardListener { return mnemonic.toMnemonicPhrase(); } - public void saveMnemonic(String mnemonic, String pairingBase64, String pin) throws IOException, APDUException { - KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); - cmdSet.select().checkOK(); - - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); - - cmdSet.verifyPIN(pin).checkOK(); - Log.i(TAG, "pin verified"); + public void saveMnemonic(String mnemonic, String pin) throws IOException, APDUException { + KeycardCommandSet cmdSet = authenticatedCommandSet(pin); byte[] seed = Mnemonic.toBinarySeed(mnemonic, ""); cmdSet.loadKey(seed); @@ -217,7 +206,7 @@ public class SmartCard extends BroadcastReceiver implements CardListener { log("seed loaded to card"); } - public WritableMap getApplicationInfo(final String pairingBase64) throws IOException, APDUException { + public WritableMap getApplicationInfo() throws IOException, APDUException { KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); ApplicationInfo info = new ApplicationInfo(cmdSet.select().checkOK().getData()); @@ -227,7 +216,9 @@ public class SmartCard extends BroadcastReceiver implements CardListener { cardInfo.putBoolean("initialized?", info.isInitializedCard()); if (info.isInitializedCard()) { - Log.i(TAG, "Instance UID: " + Hex.toHexString(info.getInstanceUID())); + String instanceUID = Hex.toHexString(info.getInstanceUID()); + + Log.i(TAG, "Instance UID: " + instanceUID); Log.i(TAG, "Key UID: " + Hex.toHexString(info.getKeyUID())); Log.i(TAG, "Secure channel public key: " + Hex.toHexString(info.getSecureChannelPubKey())); Log.i(TAG, "Application version: " + info.getAppVersionString()); @@ -235,13 +226,9 @@ public class SmartCard extends BroadcastReceiver implements CardListener { Boolean isPaired = false; - if (pairingBase64.length() > 0) { - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - + if (pairings.containsKey(instanceUID)) { try { - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); + openSecureChannel(cmdSet); isPaired = true; } catch(APDUException e) { Log.i(TAG, "autoOpenSecureChannel failed: " + e.getMessage()); @@ -270,18 +257,8 @@ public class SmartCard extends BroadcastReceiver implements CardListener { return cardInfo; } - public void deriveKey(final String path, final String pairingBase64, final String pin) throws IOException, APDUException { - KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); - cmdSet.select().checkOK(); - - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); - - cmdSet.verifyPIN(pin).checkOK(); - Log.i(TAG, "pin verified"); + public void deriveKey(final String path, final String pin) throws IOException, APDUException { + KeycardCommandSet cmdSet = authenticatedCommandSet(pin); KeyPath currentPath = new KeyPath(cmdSet.getStatus(KeycardCommandSet.GET_STATUS_P1_KEY_PATH).checkOK().getData()); Log.i(TAG, "Current key path: " + currentPath); @@ -292,54 +269,24 @@ public class SmartCard extends BroadcastReceiver implements CardListener { } } - public String exportKey(final String pairingBase64, final String pin) throws IOException, APDUException { - KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); - cmdSet.select().checkOK(); - - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); - - cmdSet.verifyPIN(pin).checkOK(); - Log.i(TAG, "pin verified"); + public String exportKey(final String pin) throws IOException, APDUException { + KeycardCommandSet cmdSet = authenticatedCommandSet(pin); byte[] key = cmdSet.exportCurrentKey(true).checkOK().getData(); return Hex.toHexString(key); } - public String exportKeyWithPath(final String pairingBase64, final String pin, final String path) throws IOException, APDUException { - KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); - cmdSet.select().checkOK(); - - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); - - cmdSet.verifyPIN(pin).checkOK(); - Log.i(TAG, "pin verified"); + public String exportKeyWithPath(final String pin, final String path) throws IOException, APDUException { + KeycardCommandSet cmdSet = authenticatedCommandSet(pin); byte[] key = BIP32KeyPair.fromTLV(cmdSet.exportKey(path, false, true).checkOK().getData()).getPublicKey(); return Hex.toHexString(key); } - public WritableMap getKeys(final String pairingBase64, final String pin) throws IOException, APDUException { - KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); - cmdSet.select().checkOK(); - - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); - - cmdSet.verifyPIN(pin).checkOK(); - Log.i(TAG, "pin verified"); + public WritableMap getKeys(final String pin) throws IOException, APDUException { + KeycardCommandSet cmdSet = authenticatedCommandSet(pin); byte[] tlvWhisper = cmdSet.exportKey(WHISPER_PATH, false, false).checkOK().getData(); BIP32KeyPair whisperKeyPair = BIP32KeyPair.fromTLV(tlvWhisper); @@ -360,18 +307,8 @@ public class SmartCard extends BroadcastReceiver implements CardListener { return data; } - public WritableMap importKeys(final String pairingBase64, final String pin) throws IOException, APDUException { - KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); - cmdSet.select().checkOK(); - - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); - - cmdSet.verifyPIN(pin).checkOK(); - Log.i(TAG, "pin verified"); + public WritableMap importKeys(final String pin) throws IOException, APDUException { + KeycardCommandSet cmdSet = authenticatedCommandSet(pin); byte[] tlvEncryption = cmdSet.exportKey(ENCRYPTION_PATH, false, false).checkOK().getData(); BIP32KeyPair encryptionKeyPair = BIP32KeyPair.fromTLV(tlvEncryption); @@ -407,18 +344,8 @@ public class SmartCard extends BroadcastReceiver implements CardListener { return data; } - public WritableMap generateAndLoadKey(final String mnemonic, final String pairingBase64, final String pin) throws IOException, APDUException { - KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); - cmdSet.select().checkOK(); - - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); - - cmdSet.verifyPIN(pin).checkOK(); - Log.i(TAG, "pin verified"); + public WritableMap generateAndLoadKey(final String mnemonic, final String pin) throws IOException, APDUException { + KeycardCommandSet cmdSet = authenticatedCommandSet(pin); byte[] seed = Mnemonic.toBinarySeed(mnemonic, ""); BIP32KeyPair keyPair = BIP32KeyPair.fromBinarySeed(seed); @@ -473,70 +400,32 @@ public class SmartCard extends BroadcastReceiver implements CardListener { return init(userPin); } - public int verifyPin(final String pairingBase64, final String pin) throws IOException, APDUException { - KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); - cmdSet.select().checkOK(); - - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); - - cmdSet.verifyPIN(pin).checkOK(); - Log.i(TAG, "pin verified"); - - ApplicationStatus status = new ApplicationStatus(cmdSet.getStatus(KeycardCommandSet.GET_STATUS_P1_APPLICATION).checkOK().getData()); - - return status.getPINRetryCount(); + public int verifyPin(final String pin) throws IOException, APDUException { + KeycardCommandSet cmdSet = authenticatedCommandSet(pin); + return 3; } - public void changePin(final String pairingBase64, final String currentPin, final String newPin) throws IOException, APDUException { - KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); - cmdSet.select().checkOK(); - - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); - - cmdSet.verifyPIN(currentPin).checkOK(); - Log.i(TAG, "pin verified"); + public void changePin(final String currentPin, final String newPin) throws IOException, APDUException { + KeycardCommandSet cmdSet = authenticatedCommandSet(currentPin); cmdSet.changePIN(0, newPin); Log.i(TAG, "pin changed"); } - public void unblockPin(final String pairingBase64, final String puk, final String newPin) throws IOException, APDUException { - KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); - cmdSet.select().checkOK(); - - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); + public void unblockPin(final String puk, final String newPin) throws IOException, APDUException { + KeycardCommandSet cmdSet = securedCommandSet(); cmdSet.unblockPIN(puk, newPin).checkOK(); Log.i(TAG, "pin unblocked"); } - public void unpair(final String pairingBase64, final String pin) throws IOException, APDUException { - KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); - cmdSet.select().checkOK(); - - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); - - cmdSet.verifyPIN(pin).checkOK(); - Log.i(TAG, "pin verified"); + public void unpair(final String pin) throws IOException, APDUException { + KeycardCommandSet cmdSet = authenticatedCommandSet(pin); cmdSet.autoUnpair(); Log.i(TAG, "card unpaired"); + String instanceUID = Hex.toHexString(cmdSet.getApplicationInfo().getInstanceUID()); + pairings.remove(instanceUID); } public void delete() throws IOException, APDUException { @@ -550,35 +439,15 @@ public class SmartCard extends BroadcastReceiver implements CardListener { Log.i(TAG, "instance and package deleted"); } - public void removeKey(final String pairingBase64, final String pin) throws IOException, APDUException { - KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); - cmdSet.select().checkOK(); - - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); - - cmdSet.verifyPIN(pin).checkOK(); - Log.i(TAG, "pin verified"); + public void removeKey(final String pin) throws IOException, APDUException { + KeycardCommandSet cmdSet = authenticatedCommandSet(pin); cmdSet.removeKey(); Log.i(TAG, "key removed"); } - public void removeKeyWithUnpair(final String pairingBase64, final String pin) throws IOException, APDUException { - KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); - cmdSet.select().checkOK(); - - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); - - cmdSet.verifyPIN(pin).checkOK(); - Log.i(TAG, "pin verified"); + public void removeKeyWithUnpair(final String pin) throws IOException, APDUException { + KeycardCommandSet cmdSet = authenticatedCommandSet(pin); cmdSet.removeKey(); Log.i(TAG, "key removed"); @@ -588,25 +457,18 @@ public class SmartCard extends BroadcastReceiver implements CardListener { cmdSet.autoUnpair(); Log.i(TAG, "card unpaired"); + + String instanceUID = Hex.toHexString(cmdSet.getApplicationInfo().getInstanceUID()); + pairings.remove(instanceUID); } - public void unpairAndDelete(final String pairingBase64, final String pin) throws IOException, APDUException { - unpair(pairingBase64, pin); + public void unpairAndDelete(final String pin) throws IOException, APDUException { + unpair(pin); delete(); } - public String sign(final String pairingBase64, final String pin, final String message) throws IOException, APDUException { - KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); - cmdSet.select().checkOK(); - - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); - - cmdSet.verifyPIN(pin).checkOK(); - Log.i(TAG, "pin verified"); + public String sign(final String pin, final String message) throws IOException, APDUException { + KeycardCommandSet cmdSet = authenticatedCommandSet(pin); byte[] hash = Hex.decode(message); RecoverableSignature signature = new RecoverableSignature(hash, cmdSet.sign(hash).checkOK().getData()); @@ -628,18 +490,8 @@ public class SmartCard extends BroadcastReceiver implements CardListener { return sig; } - public String signWithPath(final String pairingBase64, final String pin, final String path, final String message) throws IOException, APDUException { - KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); - cmdSet.select().checkOK(); - - Pairing pairing = new Pairing(pairingBase64); - cmdSet.setPairing(pairing); - - cmdSet.autoOpenSecureChannel(); - Log.i(TAG, "secure channel opened"); - - cmdSet.verifyPIN(pin).checkOK(); - Log.i(TAG, "pin verified"); + public String signWithPath(final String pin, final String path, final String message) throws IOException, APDUException { + KeycardCommandSet cmdSet = authenticatedCommandSet(pin); byte[] hash = Hex.decode(message); @@ -695,4 +547,46 @@ public class SmartCard extends BroadcastReceiver implements CardListener { return sig; } + + public void setPairings(ReadableMap newPairings) { + pairings.clear(); + Iterator> i = newPairings.getEntryIterator(); + while (i.hasNext()) { + Map.Entry entry = i.next(); + String value = ((ReadableMap) entry.getValue()).getString("pairing"); + pairings.put(entry.getKey(), value); + } + } + + private KeycardCommandSet authenticatedCommandSet(String pin) throws IOException, APDUException { + KeycardCommandSet cmdSet = securedCommandSet(); + cmdSet.verifyPIN(pin).checkOK(); + Log.i(TAG, "pin verified"); + + return cmdSet; + } + + private KeycardCommandSet securedCommandSet() throws IOException, APDUException { + KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel); + cmdSet.select().checkOK(); + openSecureChannel(cmdSet); + + return cmdSet; + } + + private void openSecureChannel(KeycardCommandSet cmdSet) throws IOException, APDUException { + String instanceUID = Hex.toHexString(cmdSet.getApplicationInfo().getInstanceUID()); + String pairingBase64 = pairings.get(instanceUID); + + if (pairingBase64 == null) { + throw new APDUException("No pairing found"); + } + + Pairing pairing = new Pairing(pairingBase64); + cmdSet.setPairing(pairing); + + cmdSet.autoOpenSecureChannel(); + Log.i(TAG, "secure channel opened"); + } + } diff --git a/ios/SmartCard.swift b/ios/SmartCard.swift index 29546c7..63ed595 100644 --- a/ios/SmartCard.swift +++ b/ios/SmartCard.swift @@ -4,6 +4,7 @@ import os.log enum SmartCardError: Error { case invalidBase64 + case noPairing } enum DerivationPath: String { @@ -15,6 +16,8 @@ enum DerivationPath: String { } class SmartCard { + var pairings: [String: String] = [:] + func initialize(channel: CardChannel, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { let puk = self.randomPUK() let pairingPassword = self.randomPairingPassword(); @@ -33,12 +36,13 @@ class SmartCard { logAppInfo(info) try cmdSet.autoPair(password: pairingPassword) - - resolve(Data(cmdSet.pairing!.bytes).base64EncodedString()) + let pairing = Data(cmdSet.pairing!.bytes).base64EncodedString() + self.pairings[bytesToHex(info.instanceUID)] = pairing + resolve(pairing) } - func generateMnemonic(channel: CardChannel, pairingBase64: String, words: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { - let cmdSet = try securedCommandSet(channel: channel, pairingBase64: pairingBase64) + func generateMnemonic(channel: CardChannel, words: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + let cmdSet = try securedCommandSet(channel: channel) let mnemonic = try Mnemonic(rawData: cmdSet.generateMnemonic(length: GenerateMnemonicP1.length12Words).checkOK().data) mnemonic.wordList = words.components(separatedBy: .newlines) @@ -46,8 +50,8 @@ class SmartCard { resolve(mnemonic.toMnemonicPhrase()) } - func generateAndLoadKey(channel: CardChannel, mnemonic: String, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { - let cmdSet = try authenticatedCommandSet(channel: channel, pairingBase64: pairingBase64, pin: pin) + func generateAndLoadKey(channel: CardChannel, mnemonic: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + let cmdSet = try authenticatedCommandSet(channel: channel, pin: pin) let seed = Mnemonic.toBinarySeed(mnemonicPhrase: mnemonic) let keyPair = BIP32KeyPair(fromSeed: seed) @@ -77,15 +81,15 @@ class SmartCard { ]) } - func saveMnemonic(channel: CardChannel, mnemonic: String, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { - let cmdSet = try authenticatedCommandSet(channel: channel, pairingBase64: pairingBase64, pin: pin) + func saveMnemonic(channel: CardChannel, mnemonic: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + let cmdSet = try authenticatedCommandSet(channel: channel, pin: pin) let seed = Mnemonic.toBinarySeed(mnemonicPhrase: mnemonic) try cmdSet.loadKey(seed: seed).checkOK() os_log("seed loaded to card"); resolve(true) } - func getApplicationInfo(channel: CardChannel, pairingBase64: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + func getApplicationInfo(channel: CardChannel, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { let cmdSet = KeycardCommandSet(cardChannel: channel) let info = try ApplicationInfo(cmdSet.select().checkOK().data) @@ -97,9 +101,9 @@ class SmartCard { logAppInfo(info) var isPaired = false - if (!pairingBase64.isEmpty) { + if let _ = self.pairings[bytesToHex(info.instanceUID)] { do { - try openSecureChannel(cmdSet: cmdSet, pairingBase64: pairingBase64) + try openSecureChannel(cmdSet: cmdSet) isPaired = true } catch let error as CardError { os_log("autoOpenSecureChannel failed: %@", String(describing: error)); @@ -130,8 +134,8 @@ class SmartCard { resolve(cardInfo) } - func deriveKey(channel: CardChannel, path: String, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { - let cmdSet = try authenticatedCommandSet(channel: channel, pairingBase64: pairingBase64, pin: pin) + func deriveKey(channel: CardChannel, path: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + let cmdSet = try authenticatedCommandSet(channel: channel, pin: pin) let currentPath = try KeyPath(data: cmdSet.getStatus(info: GetStatusP1.keyPath.rawValue).checkOK().data); os_log("Current key path: %@", currentPath.description) @@ -143,21 +147,21 @@ class SmartCard { resolve(true) } - func exportKey(channel: CardChannel, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { - let cmdSet = try authenticatedCommandSet(channel: channel, pairingBase64: pairingBase64, pin: pin) + func exportKey(channel: CardChannel, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + let cmdSet = try authenticatedCommandSet(channel: channel, pin: pin) let key = try cmdSet.exportCurrentKey(publicOnly: true).checkOK().data resolve(bytesToHex(key)) } - func exportKeyWithPath(channel: CardChannel, pairingBase64: String, pin: String, path: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { - let cmdSet = try authenticatedCommandSet(channel: channel, pairingBase64: pairingBase64, pin: pin) + func exportKeyWithPath(channel: CardChannel, pin: String, path: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + let cmdSet = try authenticatedCommandSet(channel: channel, pin: pin) let key = try BIP32KeyPair(fromTLV: cmdSet.exportKey(path: path, makeCurrent: false, publicOnly: true).checkOK().data).publicKey; resolve(bytesToHex(key)) } - func importKeys(channel: CardChannel, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { - let cmdSet = try authenticatedCommandSet(channel: channel, pairingBase64: pairingBase64, pin: pin) + func importKeys(channel: CardChannel, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + let cmdSet = try authenticatedCommandSet(channel: channel, pin: pin) let encryptionKeyPair = try exportKey(cmdSet: cmdSet, path: .encryptionPath, makeCurrent: false, publicOnly: false) let masterPair = try exportKey(cmdSet: cmdSet, path: .masterPath, makeCurrent: false, publicOnly: true) @@ -183,8 +187,8 @@ class SmartCard { ]) } - func getKeys(channel: CardChannel, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { - let cmdSet = try authenticatedCommandSet(channel: channel, pairingBase64: pairingBase64, pin: pin) + func getKeys(channel: CardChannel, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + let cmdSet = try authenticatedCommandSet(channel: channel, pin: pin) let whisperKeyPair = try exportKey(cmdSet: cmdSet, path: .whisperPath, makeCurrent: false, publicOnly: false) let encryptionKeyPair = try exportKey(cmdSet: cmdSet, path: .encryptionPath, makeCurrent: false, publicOnly: false) @@ -201,14 +205,14 @@ class SmartCard { ]) } - func sign(channel: CardChannel, pairingBase64: String, pin: String, message: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { - let cmdSet = try authenticatedCommandSet(channel: channel, pairingBase64: pairingBase64, pin: pin) + func sign(channel: CardChannel, pin: String, message: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + let cmdSet = try authenticatedCommandSet(channel: channel, pin: pin) let sig = try processSignature(message) { return try cmdSet.sign(hash: $0) } resolve(sig) } - func signWithPath(channel: CardChannel, pairingBase64: String, pin: String, path: String, message: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { - let cmdSet = try authenticatedCommandSet(channel: channel, pairingBase64: pairingBase64, pin: pin) + func signWithPath(channel: CardChannel, pin: String, path: String, message: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + let cmdSet = try authenticatedCommandSet(channel: channel, pin: pin) let sig = try processSignature(message) { if (cmdSet.info!.appVersion < 0x0202) { let currentPath = try KeyPath(data: cmdSet.getStatus(info: GetStatusP1.keyPath.rawValue).checkOK().data); @@ -234,45 +238,45 @@ class SmartCard { resolve(sig) } - func verifyPin(channel: CardChannel, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { - let cmdSet = try authenticatedCommandSet(channel: channel, pairingBase64: pairingBase64, pin: pin) - let status = try ApplicationStatus(cmdSet.getStatus(info: GetStatusP1.application.rawValue).checkOK().data); - resolve(status.pinRetryCount) + func verifyPin(channel: CardChannel, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + let _ = try authenticatedCommandSet(channel: channel, pin: pin) + resolve(3) } - func changePin(channel: CardChannel, pairingBase64: String, currentPin: String, newPin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { - let cmdSet = try authenticatedCommandSet(channel: channel, pairingBase64: pairingBase64, pin: currentPin) + func changePin(channel: CardChannel, currentPin: String, newPin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + let cmdSet = try authenticatedCommandSet(channel: channel, pin: currentPin) try cmdSet.changePIN(pin: newPin).checkOK() os_log("pin changed") resolve(true) } - func unblockPin(channel: CardChannel, pairingBase64: String, puk: String, newPin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { - let cmdSet = try securedCommandSet(channel: channel, pairingBase64: pairingBase64) + func unblockPin(channel: CardChannel, puk: String, newPin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + let cmdSet = try securedCommandSet(channel: channel) try cmdSet.unblockPIN(puk: puk, newPIN: newPin).checkAuthOK() os_log("pin unblocked") resolve(true) } - func unpair(channel: CardChannel, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { - let cmdSet = try authenticatedCommandSet(channel: channel, pairingBase64: pairingBase64, pin: pin) + func unpair(channel: CardChannel, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + let cmdSet = try authenticatedCommandSet(channel: channel, pin: pin) try cmdSet.autoUnpair() os_log("card unpaired") + self.pairings[bytesToHex(cmdSet.info!.instanceUID)] = nil resolve(true) } - func removeKey(channel: CardChannel, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { - let cmdSet = try authenticatedCommandSet(channel: channel, pairingBase64: pairingBase64, pin: pin) + func removeKey(channel: CardChannel, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + let cmdSet = try authenticatedCommandSet(channel: channel, pin: pin) try cmdSet.removeKey().checkOK() os_log("key removed") resolve(true) } - func removeKeyWithUnpair(channel: CardChannel, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { - let cmdSet = try authenticatedCommandSet(channel: channel, pairingBase64: pairingBase64, pin: pin) + func removeKeyWithUnpair(channel: CardChannel, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void { + let cmdSet = try authenticatedCommandSet(channel: channel, pin: pin) try cmdSet.removeKey().checkOK() os_log("key removed") @@ -282,6 +286,8 @@ class SmartCard { try cmdSet.autoUnpair() os_log("card unpaired") + self.pairings[bytesToHex(cmdSet.info!.instanceUID)] = nil + resolve(true) } @@ -301,27 +307,40 @@ class SmartCard { return try BIP32KeyPair(fromTLV: tlvRoot) } - func authenticatedCommandSet(channel: CardChannel, pairingBase64: String, pin: String) throws -> KeycardCommandSet { - let cmdSet = try securedCommandSet(channel: channel, pairingBase64: pairingBase64) + func setPairings(newPairings: NSDictionary, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + self.pairings.removeAll() + for case let (instanceUID as String, v as NSDictionary) in newPairings { + self.pairings[instanceUID] = v["pairing"] as? String + } + + resolve(true) + } + + func authenticatedCommandSet(channel: CardChannel, pin: String) throws -> KeycardCommandSet { + let cmdSet = try securedCommandSet(channel: channel) try cmdSet.verifyPIN(pin: pin).checkAuthOK() os_log("pin verified") return cmdSet; } - func securedCommandSet(channel: CardChannel, pairingBase64: String) throws -> KeycardCommandSet { + func securedCommandSet(channel: CardChannel) throws -> KeycardCommandSet { let cmdSet = KeycardCommandSet(cardChannel: channel) try cmdSet.select().checkOK() - try openSecureChannel(cmdSet: cmdSet, pairingBase64: pairingBase64) + try openSecureChannel(cmdSet: cmdSet) return cmdSet } - func openSecureChannel(cmdSet: KeycardCommandSet, pairingBase64: String) throws -> Void { - cmdSet.pairing = try base64ToPairing(pairingBase64) + func openSecureChannel(cmdSet: KeycardCommandSet) throws -> Void { + if let pairingBase64 = self.pairings[bytesToHex(cmdSet.info!.instanceUID)] { + cmdSet.pairing = try base64ToPairing(pairingBase64) - try cmdSet.autoOpenSecureChannel() - os_log("secure channel opened") + try cmdSet.autoOpenSecureChannel() + os_log("secure channel opened") + } else { + throw SmartCardError.noPairing + } } func processSignature(_ message: String, sign: ([UInt8]) throws -> APDUResponse) throws -> String { diff --git a/ios/StatusKeycard.m b/ios/StatusKeycard.m index e33b1d4..bef9f7b 100644 --- a/ios/StatusKeycard.m +++ b/ios/StatusKeycard.m @@ -8,30 +8,31 @@ RCT_EXTERN_METHOD(nfcIsEnabled:(RCTPromiseResolveBlock)resolve reject: (RCTPromi RCT_EXTERN_METHOD(openNfcSettings:(RCTPromiseResolveBlock)resolve reject: (RCTPromiseRejectBlock)reject) RCT_EXTERN_METHOD(init:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) RCT_EXTERN_METHOD(pair:(NSString *)pairingPassword resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(generateMnemonic:(NSString *)pairing words:(NSString *)words resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(generateAndLoadKey:(NSString *)mnemonic pairing: (NSString *)pairing pin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(saveMnemonic:(NSString *)mnemonic pairing: (NSString *)pairing pin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(getApplicationInfo:(NSString *)pairingBase64 resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(deriveKey:(NSString *)path pairing: (NSString *)pairing pin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(exportKey:(NSString *)pairing pin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(exportKeyWithPath:(NSString *)pairing pin:(NSString *)pin path:(NSString *)path resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(importKeys:(NSString *)pairing pin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(getKeys:(NSString *)pairing pin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(sign:(NSString *)pairing pin:(NSString *)pin hash:(NSString *)hash resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(signWithPath:(NSString *)pairing pin:(NSString *)pin path:(NSString *)path hash:(NSString *)hash resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(generateMnemonic:(NSString *)words resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(generateAndLoadKey:(NSString *)mnemonic pin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(saveMnemonic:(NSString *)mnemonic pin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(getApplicationInfo:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(deriveKey:(NSString *)path pin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(exportKey:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(exportKeyWithPath:(NSString *)pin path:(NSString *)path resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(importKeys:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(getKeys:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(sign:(NSString *)pin hash:(NSString *)hash resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(signWithPath:(NSString *)pin path:(NSString *)path hash:(NSString *)hash resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) RCT_EXTERN_METHOD(signPinless:(NSString *)hash resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) RCT_EXTERN_METHOD(installApplet:(RCTPromiseResolveBlock)resolve reject: (RCTPromiseRejectBlock)reject) RCT_EXTERN_METHOD(installAppletAndInitCard:(String *)pin resolve: (RCTPromiseResolveBlock)resolve reject: (RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(verifyPin:(NSString *)pairing pin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(changePin:(NSString *)pairing currentPin:(NSString *)currentPin newPin:(NSString *)newPin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(unblockPin:(NSString *)pairing puk:(NSString *)puk newPin:(NSString *)newPin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(unpair:(NSString *)pairing pin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(verifyPin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(changePin:(NSString *)currentPin newPin:(NSString *)newPin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(unblockPin:(NSString *)puk newPin:(NSString *)newPin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(unpair:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) RCT_EXTERN_METHOD(delete:(RCTPromiseResolveBlock)resolve reject: (RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(removeKey:(NSString *)pairing pin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(removeKeyWithUnpair:(NSString *)pairing pin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(unpairAndDelete:(NSString *)pairing pin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(removeKey:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(removeKeyWithUnpair:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(unpairAndDelete:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) RCT_EXTERN_METHOD(startNFC:(NSString *)prompt resolve:(RCTPromiseResolveBlock)resolve reject: (RCTPromiseRejectBlock)reject) RCT_EXTERN_METHOD(stopNFC:(NSString *)err resolve:(RCTPromiseResolveBlock)resolve reject: (RCTPromiseRejectBlock)reject) RCT_EXTERN_METHOD(setNFCMessage:(NSString *)message resolve:(RCTPromiseResolveBlock)resolve reject: (RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(setPairings:(NSDictionary *)pairings resolve:(RCTPromiseResolveBlock)resolve reject: (RCTPromiseRejectBlock)reject) @end diff --git a/ios/StatusKeycard.swift b/ios/StatusKeycard.swift index edb2aac..c636f44 100644 --- a/ios/StatusKeycard.swift +++ b/ios/StatusKeycard.swift @@ -44,58 +44,58 @@ class StatusKeycard: RCTEventEmitter { } @objc - func generateMnemonic(_ pairing: String, words: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.generateMnemonic(channel: channel, pairingBase64: pairing, words: words, resolve: resolve, reject: reject) } + func generateMnemonic(_ words: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.generateMnemonic(channel: channel, words: words, resolve: resolve, reject: reject) } } @objc - func generateAndLoadKey(_ mnemonic: String, pairing: String, pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.generateAndLoadKey(channel: channel, mnemonic: mnemonic, pairingBase64: pairing, pin: pin, resolve: resolve, reject: reject) } + func generateAndLoadKey(_ mnemonic: String, pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.generateAndLoadKey(channel: channel, mnemonic: mnemonic, pin: pin, resolve: resolve, reject: reject) } } @objc - func saveMnemonic(_ mnemonic: String, pairing: String, pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.saveMnemonic(channel: channel, mnemonic: mnemonic, pairingBase64: pairing, pin: pin, resolve: resolve, reject: reject) } + func saveMnemonic(_ mnemonic: String, pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.saveMnemonic(channel: channel, mnemonic: mnemonic, pin: pin, resolve: resolve, reject: reject) } } @objc - func getApplicationInfo(_ pairingBase64: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.getApplicationInfo(channel: channel, pairingBase64: pairingBase64, resolve: resolve, reject: reject) } + func getApplicationInfo(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.getApplicationInfo(channel: channel, resolve: resolve, reject: reject) } } @objc - func deriveKey(_ path: String, pairing: String, pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.deriveKey(channel: channel, path: path, pairingBase64: pairing, pin: pin, resolve: resolve, reject: reject) } + func deriveKey(_ path: String, pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.deriveKey(channel: channel, path: path, pin: pin, resolve: resolve, reject: reject) } } @objc - func exportKey(_ pairing: String, pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.exportKey(channel: channel, pairingBase64: pairing, pin: pin, resolve: resolve, reject: reject) } + func exportKey(_ pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.exportKey(channel: channel, pin: pin, resolve: resolve, reject: reject) } } @objc - func exportKeyWithPath(_ pairing: String, pin: String, path: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.exportKeyWithPath(channel: channel, pairingBase64: pairing, pin: pin, path: path, resolve: resolve, reject: reject) } + func exportKeyWithPath(_ pin: String, path: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.exportKeyWithPath(channel: channel, pin: pin, path: path, resolve: resolve, reject: reject) } } @objc - func importKeys(_ pairing: String, pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.importKeys(channel: channel, pairingBase64: pairing, pin: pin, resolve: resolve, reject: reject) } + func importKeys(_ pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.importKeys(channel: channel, pin: pin, resolve: resolve, reject: reject) } } @objc - func getKeys(_ pairing: String, pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.getKeys(channel: channel, pairingBase64: pairing, pin: pin, resolve: resolve, reject: reject) } + func getKeys(_ pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.getKeys(channel: channel, pin: pin, resolve: resolve, reject: reject) } } @objc - func sign(_ pairing: String, pin: String, hash: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.sign(channel: channel, pairingBase64: pairing, pin: pin, message: hash, resolve: resolve, reject: reject) } + func sign(_ pin: String, hash: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.sign(channel: channel, pin: pin, message: hash, resolve: resolve, reject: reject) } } @objc - func signWithPath(_ pairing: String, pin: String, path: String, hash: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.signWithPath(channel: channel, pairingBase64: pairing, pin: pin, path: path, message: hash, resolve: resolve, reject: reject) } + func signWithPath(_ pin: String, path: String, hash: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.signWithPath(channel: channel, pin: pin, path: path, message: hash, resolve: resolve, reject: reject) } } @objc @@ -114,23 +114,23 @@ class StatusKeycard: RCTEventEmitter { } @objc - func verifyPin(_ pairing: String, pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.verifyPin(channel: channel, pairingBase64: pairing, pin: pin, resolve: resolve, reject: reject) } + func verifyPin(_ pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.verifyPin(channel: channel, pin: pin, resolve: resolve, reject: reject) } } @objc - func changePin(_ pairing: String, currentPin: String, newPin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.changePin(channel: channel, pairingBase64: pairing, currentPin: currentPin, newPin: newPin, resolve: resolve, reject: reject) } + func changePin(_ currentPin: String, newPin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.changePin(channel: channel, currentPin: currentPin, newPin: newPin, resolve: resolve, reject: reject) } } @objc - func unblockPin(_ pairing: String, puk: String, newPin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.unblockPin(channel: channel, pairingBase64: pairing, puk: puk, newPin: newPin, resolve: resolve, reject: reject) } + func unblockPin(_ puk: String, newPin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.unblockPin(channel: channel, puk: puk, newPin: newPin, resolve: resolve, reject: reject) } } @objc - func unpair(_ pairing: String, pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.unpair(channel: channel, pairingBase64: pairing, pin: pin, resolve: resolve, reject: reject) } + func unpair(_ pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.unpair(channel: channel, pin: pin, resolve: resolve, reject: reject) } } @objc @@ -139,20 +139,25 @@ class StatusKeycard: RCTEventEmitter { } @objc - func removeKey(_ pairing: String, pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.removeKey(channel: channel, pairingBase64: pairing, pin: pin, resolve: resolve, reject: reject) } + func removeKey(_ pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.removeKey(channel: channel, pin: pin, resolve: resolve, reject: reject) } } @objc - func removeKeyWithUnpair(_ pairing: String, pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { - keycardInvokation(reject) { [unowned self] channel in try self.smartCard.removeKeyWithUnpair(channel: channel, pairingBase64: pairing, pin: pin, resolve: resolve, reject: reject) } + func removeKeyWithUnpair(_ pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + keycardInvokation(reject) { [unowned self] channel in try self.smartCard.removeKeyWithUnpair(channel: channel, pin: pin, resolve: resolve, reject: reject) } } @objc - func unpairAndDelete(_ pairing: String, pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + func unpairAndDelete(_ pin: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { reject("E_KEYCARD", "Not implemented (unused)", nil) } + @objc + func setPairings(_ pairings: NSDictionary, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + self.smartCard.setPairings(newPairings: pairings, resolve: resolve, reject: reject) + } + @objc func startNFC(_ prompt: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { if #available(iOS 13.0, *) { diff --git a/package.json b/package.json index 8aa34d0..a75fc28 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-native-status-keycard", "homepage": "https://keycard.status.im/", - "version": "2.5.32", + "version": "2.5.33", "description": "React Native library to interact with Status Keycard using NFC connection (Android only)", "main": "index.js", "scripts": {