Merge pull request #89 from status-im/internal-factory-reset

Internal factory reset
This commit is contained in:
Michele Balistreri 2023-06-06 17:03:32 +02:00 committed by GitHub
commit 146c049b45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 103 additions and 15 deletions

View File

@ -59,7 +59,7 @@ dependencies {
testCompile(files("../jcardsim/jcardsim-3.0.5-SNAPSHOT.jar")) testCompile(files("../jcardsim/jcardsim-3.0.5-SNAPSHOT.jar"))
testCompile('org.web3j:core:2.3.1') testCompile('org.web3j:core:2.3.1')
testCompile('org.bitcoinj:bitcoinj-core:0.14.5') testCompile('org.bitcoinj:bitcoinj-core:0.14.5')
testCompile('com.github.status-im.status-keycard-java:desktop:15a61e1') testCompile('com.github.status-im.status-keycard-java:desktop:3.1.2')
testCompile('org.bouncycastle:bcprov-jdk15on:1.65') testCompile('org.bouncycastle:bcprov-jdk15on:1.65')
testCompile("org.junit.jupiter:junit-jupiter-api:5.1.1") testCompile("org.junit.jupiter:junit-jupiter-api:5.1.1")
testRuntime("org.junit.jupiter:junit-jupiter-engine:5.1.1") testRuntime("org.junit.jupiter:junit-jupiter-engine:5.1.1")

View File

@ -4,5 +4,5 @@ repositories {
} }
dependencies { dependencies {
compile 'com.github.status-im.status-keycard-java:desktop:15a61e1' compile 'com.github.status-im.status-keycard-java:desktop:3.1.2'
} }

View File

@ -13,6 +13,7 @@ public class KeycardApplet extends Applet {
static final byte INS_GET_STATUS = (byte) 0xF2; static final byte INS_GET_STATUS = (byte) 0xF2;
static final byte INS_INIT = (byte) 0xFE; static final byte INS_INIT = (byte) 0xFE;
static final byte INS_FACTORY_RESET = (byte) 0xFD;
static final byte INS_VERIFY_PIN = (byte) 0x20; static final byte INS_VERIFY_PIN = (byte) 0x20;
static final byte INS_CHANGE_PIN = (byte) 0x21; static final byte INS_CHANGE_PIN = (byte) 0x21;
static final byte INS_UNBLOCK_PIN = (byte) 0x22; static final byte INS_UNBLOCK_PIN = (byte) 0x22;
@ -85,6 +86,9 @@ public class KeycardApplet extends Applet {
static final byte STORE_DATA_P1_NDEF = 0x01; static final byte STORE_DATA_P1_NDEF = 0x01;
static final byte STORE_DATA_P1_CASH = 0x02; static final byte STORE_DATA_P1_CASH = 0x02;
static final byte FACTORY_RESET_P1_MAGIC = (byte) 0xAA;
static final byte FACTORY_RESET_P2_MAGIC = 0x55;
static final byte TLV_SIGNATURE_TEMPLATE = (byte) 0xA0; static final byte TLV_SIGNATURE_TEMPLATE = (byte) 0xA0;
static final byte TLV_KEY_TEMPLATE = (byte) 0xA1; static final byte TLV_KEY_TEMPLATE = (byte) 0xA1;
@ -105,8 +109,9 @@ public class KeycardApplet extends Applet {
static final byte CAPABILITY_KEY_MANAGEMENT = (byte) 0x02; static final byte CAPABILITY_KEY_MANAGEMENT = (byte) 0x02;
static final byte CAPABILITY_CREDENTIALS_MANAGEMENT = (byte) 0x04; static final byte CAPABILITY_CREDENTIALS_MANAGEMENT = (byte) 0x04;
static final byte CAPABILITY_NDEF = (byte) 0x08; static final byte CAPABILITY_NDEF = (byte) 0x08;
static final byte CAPABILITY_FACTORY_RESET = (byte) 0x10;
static final byte APPLICATION_CAPABILITIES = (byte)(CAPABILITY_SECURE_CHANNEL | CAPABILITY_KEY_MANAGEMENT | CAPABILITY_CREDENTIALS_MANAGEMENT | CAPABILITY_NDEF); static final byte APPLICATION_CAPABILITIES = (byte)(CAPABILITY_SECURE_CHANNEL | CAPABILITY_KEY_MANAGEMENT | CAPABILITY_CREDENTIALS_MANAGEMENT | CAPABILITY_NDEF | CAPABILITY_FACTORY_RESET);
static final byte[] EIP_1581_PREFIX = { (byte) 0x80, 0x00, 0x00, 0x2B, (byte) 0x80, 0x00, 0x00, 0x3C, (byte) 0x80, 0x00, 0x06, 0x2D}; static final byte[] EIP_1581_PREFIX = { (byte) 0x80, 0x00, 0x00, 0x2B, (byte) 0x80, 0x00, 0x00, 0x3C, (byte) 0x80, 0x00, 0x06, 0x2D};
@ -282,6 +287,9 @@ public class KeycardApplet extends Applet {
case INS_STORE_DATA: case INS_STORE_DATA:
storeData(apdu); storeData(apdu);
break; break;
case INS_FACTORY_RESET:
factoryReset(apdu);
return;
default: default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
break; break;
@ -1008,6 +1016,26 @@ public class KeycardApplet extends Applet {
return (short) ((short)((short) 0x4000 >>> (short) (amount - 1)) | tmp); return (short) ((short)((short) 0x4000 >>> (short) (amount - 1)) | tmp);
} }
/**
* Clear all keys and erases the key UID.
*/
private void clearKeys() {
keyPathLen = 0;
pinlessPathLen = 0;
tmpPathLen = 0;
isExtended = false;
masterPrivate.clearKey();
masterPublic.clearKey();
resetCurveParameters();
Util.arrayFillNonAtomic(masterChainCode, (short) 0, (short) masterChainCode.length, (byte) 0);
Util.arrayFillNonAtomic(altChainCode, (short) 0, (short) altChainCode.length, (byte) 0);
Util.arrayFillNonAtomic(keyPath, (short) 0, (short) keyPath.length, (byte) 0);
Util.arrayFillNonAtomic(pinlessPath, (short) 0, (short) pinlessPath.length, (byte) 0);
Util.arrayFillNonAtomic(tmpPath, (short) 0, (short) tmpPath.length, (byte) 0);
Util.arrayFillNonAtomic(derivationOutput, (short) 0, (short) derivationOutput.length, (byte) 0);
Util.arrayFillNonAtomic(keyUID, (short) 0, (short) keyUID.length, (byte) 0);
}
/** /**
* Processes the REMOVE KEY command. Removes the master key and all derived keys. Secure Channel and PIN * Processes the REMOVE KEY command. Removes the master key and all derived keys. Secure Channel and PIN
* authentication are required. * authentication are required.
@ -1022,16 +1050,28 @@ public class KeycardApplet extends Applet {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
} }
keyPathLen = 0; clearKeys();
pinlessPathLen = 0; }
isExtended = false;
masterPrivate.clearKey(); private void factoryReset(APDU apdu) {
masterPublic.clearKey(); byte[] apduBuffer = apdu.getBuffer();
resetCurveParameters();
Util.arrayFillNonAtomic(masterChainCode, (short) 0, (short) masterChainCode.length, (byte) 0); if ((apduBuffer[OFFSET_P1] != FACTORY_RESET_P1_MAGIC) || (apduBuffer[ISO7816.OFFSET_P2] != FACTORY_RESET_P2_MAGIC)) {
Util.arrayFillNonAtomic(altChainCode, (short) 0, (short) altChainCode.length, (byte) 0); ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
Util.arrayFillNonAtomic(keyPath, (short) 0, (short) keyPath.length, (byte) 0); }
Util.arrayFillNonAtomic(pinlessPath, (short) 0, (short) pinlessPath.length, (byte) 0);
clearKeys();
pin = null;
mainPIN = null;
altPIN = null;
puk = null;
secureChannel = null;
crypto.random.generateData(uid, (short) 0, UID_LENGTH);
Util.arrayFillNonAtomic(data, (short) 0, (short) data.length, (byte) 0);
if (JCSystem.isObjectDeletionSupported()) {
JCSystem.requestObjectDeletion();
}
} }
/** /**

View File

@ -128,6 +128,10 @@ public class KeycardTest {
capabilities.add("ndef"); capabilities.add("ndef");
} }
if (info.hasFactoryResetCapability()) {
capabilities.add("factoryReset");
}
CapabilityCondition.availableCapabilities = capabilities; CapabilityCondition.availableCapabilities = capabilities;
} }
@ -210,6 +214,11 @@ public class KeycardTest {
usbManager.start(); usbManager.start();
} }
private static void initCard(KeycardCommandSet cmdSet) throws Exception {
assertEquals(0x9000, cmdSet.init("000000", "024680", "012345678901", sharedSecret, (byte) 3, (byte) 5).getSw());
cmdSet.select().checkOK();
}
private static void initIfNeeded() throws Exception { private static void initIfNeeded() throws Exception {
KeyPair identKeyPair = Certificate.generateIdentKeyPair(); KeyPair identKeyPair = Certificate.generateIdentKeyPair();
Certificate cert = Certificate.createCertificate(caKeyPair, identKeyPair); Certificate cert = Certificate.createCertificate(caKeyPair, identKeyPair);
@ -225,8 +234,7 @@ public class KeycardTest {
sharedSecret = cmdSet.pairingPasswordToSecret(System.getProperty("im.status.keycard.test.pairing", "KeycardDefaultPairing")); sharedSecret = cmdSet.pairingPasswordToSecret(System.getProperty("im.status.keycard.test.pairing", "KeycardDefaultPairing"));
if (!cmdSet.getApplicationInfo().isInitializedCard()) { if (!cmdSet.getApplicationInfo().isInitializedCard()) {
assertEquals(0x9000, cmdSet.init("000000", "024680", "012345678901", sharedSecret, (byte) 3, (byte) 5).getSw()); initCard(cmdSet);
cmdSet.select().checkOK();
initCapabilities(cmdSet.getApplicationInfo()); initCapabilities(cmdSet.getApplicationInfo());
} }
} }
@ -932,6 +940,46 @@ public class KeycardTest {
assertEquals(0, info.getKeyUID().length); assertEquals(0, info.getKeyUID().length);
} }
@Test
@DisplayName("FACTORY RESET command")
@Capabilities("factoryReset")
void factoryResetTest() throws Exception {
KeyPairGenerator g = keypairGenerator();
KeyPair keyPair = g.generateKeyPair();
// Invalid P1 P2
APDUResponse response = sdkChannel.send(new APDUCommand(0x80, KeycardApplet.INS_FACTORY_RESET, 0, 0, new byte[0]));
assertEquals(0x6a86, response.getSw());
// Good case
response = cmdSet.factoryReset();
assertEquals(0x9000, response.getSw());
response = cmdSet.getStatus(KeycardCommandSet.GET_STATUS_P1_KEY_PATH);
assertEquals(0x6d00, response.getSw());
response = cmdSet.select();
assertEquals(0x9000, response.getSw());
assertFalse(cmdSet.getApplicationInfo().isInitializedCard());
initCard(cmdSet);
response = cmdSet.select();
assertEquals(0x9000, response.getSw());
if (cmdSet.getApplicationInfo().hasSecureChannelCapability()) {
cmdSet.autoPair(sharedSecret);
cmdSet.autoOpenSecureChannel();
}
if (cmdSet.getApplicationInfo().hasCredentialsManagementCapability()) {
response = cmdSet.verifyPIN("000000");
assertEquals(0x9000, response.getSw());
}
assertFalse(cmdSet.getKeyInitializationStatus());
}
@Test @Test
@DisplayName("GENERATE KEY command") @DisplayName("GENERATE KEY command")
@Capabilities("keyManagement") @Capabilities("keyManagement")