JCOP4 workaround (defer initialization)

This commit is contained in:
Michele Balistreri 2020-01-23 19:05:49 +03:00
parent bca030f069
commit 1d16a82117
No known key found for this signature in database
GPG Key ID: E9567DA33A4F791A
6 changed files with 15 additions and 26 deletions

View File

@ -64,11 +64,11 @@ public class InstallTask extends DefaultTask {
} }
}); });
logger.info("Installing the Keycard Applet"); logger.info("Installing the Keycard Applet");
cmdSet.installKeycardApplet(); cmdSet.installKeycardApplet().checkOK();
logger.info("Installing the NDEF Applet"); logger.info("Installing the NDEF Applet");
cmdSet.installNDEFApplet(new byte[0]); cmdSet.installNDEFApplet(new byte[0]).checkOK();
logger.info("Installing the Cash Applet"); logger.info("Installing the Cash Applet");
cmdSet.installCashApplet(); cmdSet.installCashApplet().checkOK();
} catch (IOException e) { } catch (IOException e) {
throw new GradleException("I/O error", e); throw new GradleException("I/O error", e);
} catch (APDUException e) { } catch (APDUException e) {

View File

@ -40,7 +40,7 @@ public class CashApplet extends Applet {
*/ */
public CashApplet(byte[] bArray, short bOffset, byte bLength) { public CashApplet(byte[] bArray, short bOffset, byte bLength) {
crypto = new Crypto(); crypto = new Crypto();
secp256k1 = new SECP256k1(crypto); secp256k1 = new SECP256k1();
keypair = new KeyPair(KeyPair.ALG_EC_FP, SECP256k1.SECP256K1_KEY_SIZE); keypair = new KeyPair(KeyPair.ALG_EC_FP, SECP256k1.SECP256K1_KEY_SIZE);
publicKey = (ECPublicKey) keypair.getPublic(); publicKey = (ECPublicKey) keypair.getPublic();

View File

@ -167,8 +167,7 @@ public class KeycardApplet extends Applet {
*/ */
public KeycardApplet(byte[] bArray, short bOffset, byte bLength) { public KeycardApplet(byte[] bArray, short bOffset, byte bLength) {
crypto = new Crypto(); crypto = new Crypto();
secp256k1 = new SECP256k1(crypto); secp256k1 = new SECP256k1();
secureChannel = new SecureChannel(PAIRING_MAX_CLIENT_COUNT, crypto, secp256k1);
uid = new byte[UID_LENGTH]; uid = new byte[UID_LENGTH];
crypto.random.generateData(uid, (short) 0, UID_LENGTH); crypto.random.generateData(uid, (short) 0, UID_LENGTH);
@ -199,7 +198,7 @@ public class KeycardApplet extends Applet {
derivationOutput = JCSystem.makeTransientByteArray((short) (Crypto.KEY_SECRET_SIZE + CHAIN_CODE_SIZE), JCSystem.CLEAR_ON_RESET); derivationOutput = JCSystem.makeTransientByteArray((short) (Crypto.KEY_SECRET_SIZE + CHAIN_CODE_SIZE), JCSystem.CLEAR_ON_RESET);
data = new byte[MAX_DATA_LENGTH + 1]; data = new byte[(short)(MAX_DATA_LENGTH + 1)];
register(bArray, (short) (bOffset + 1), bArray[bOffset]); register(bArray, (short) (bOffset + 1), bArray[bOffset]);
} }
@ -214,6 +213,9 @@ public class KeycardApplet extends Applet {
public void process(APDU apdu) throws ISOException { public void process(APDU apdu) throws ISOException {
// If we have no PIN it means we still have to initialize the applet. // If we have no PIN it means we still have to initialize the applet.
if (pin == null) { if (pin == null) {
if (secureChannel == null) {
secureChannel = new SecureChannel(PAIRING_MAX_CLIENT_COUNT, crypto, secp256k1);
}
processInit(apdu); processInit(apdu);
return; return;
} }

View File

@ -54,14 +54,12 @@ public class SECP256k1 {
private KeyAgreement ecPointMultiplier; private KeyAgreement ecPointMultiplier;
private Crypto crypto;
ECPrivateKey tmpECPrivateKey; ECPrivateKey tmpECPrivateKey;
/** /**
* Allocates objects needed by this class. Must be invoked during the applet installation exactly 1 time. * Allocates objects needed by this class. Must be invoked during the applet installation exactly 1 time.
*/ */
SECP256k1(Crypto crypto) { SECP256k1() {
this.crypto = crypto;
this.ecPointMultiplier = KeyAgreement.getInstance(ALG_EC_SVDP_DH_PLAIN_XY, false); this.ecPointMultiplier = KeyAgreement.getInstance(ALG_EC_SVDP_DH_PLAIN_XY, false);
this.tmpECPrivateKey = (ECPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, SECP256K1_KEY_SIZE, false); this.tmpECPrivateKey = (ECPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, SECP256K1_KEY_SIZE, false);
setCurveParameters(tmpECPrivateKey); setCurveParameters(tmpECPrivateKey);

View File

@ -56,13 +56,14 @@ public class SecureChannel {
scEncKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_256, false); scEncKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_256, false);
scMacKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_256, false); scMacKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_256, false);
secret = JCSystem.makeTransientByteArray((short)(SC_SECRET_LENGTH * 2), JCSystem.CLEAR_ON_DESELECT);
pairingKeys = new byte[(short)(PAIRING_KEY_LENGTH * pairingLimit)];
scKeypair = new KeyPair(KeyPair.ALG_EC_FP, SC_KEY_LENGTH); scKeypair = new KeyPair(KeyPair.ALG_EC_FP, SC_KEY_LENGTH);
secp256k1.setCurveParameters((ECKey) scKeypair.getPrivate()); secp256k1.setCurveParameters((ECKey) scKeypair.getPrivate());
secp256k1.setCurveParameters((ECKey) scKeypair.getPublic()); secp256k1.setCurveParameters((ECKey) scKeypair.getPublic());
scKeypair.genKeyPair(); scKeypair.genKeyPair();
secret = JCSystem.makeTransientByteArray((short)(SC_SECRET_LENGTH * 2), JCSystem.CLEAR_ON_DESELECT);
pairingKeys = new byte[(short)(PAIRING_KEY_LENGTH * pairingLimit)];
remainingSlots = pairingLimit; remainingSlots = pairingLimit;
} }

View File

@ -289,19 +289,7 @@ public class KeycardTest {
response = cmdSet.getStatus(KeycardApplet.GET_STATUS_P1_APPLICATION); response = cmdSet.getStatus(KeycardApplet.GET_STATUS_P1_APPLICATION);
assertEquals(0x9000, response.getSw()); assertEquals(0x9000, response.getSw());
// Verify that the keys are changed correctly. Since we do not know the internal counter we just iterate until that
// happens for a maximum of SC_COUNTER_MAX times
byte[] initialKey = new ApplicationInfo(cmdSet.select().getData()).getSecureChannelPubKey();
for (int i = 0; i < SecureChannel.SC_COUNTER_MAX; i++) {
byte[] otherKey = new ApplicationInfo(cmdSet.select().getData()).getSecureChannelPubKey();
if (!Arrays.equals(initialKey, otherKey)) {
secureChannel.generateSecret(otherKey);
cmdSet.autoOpenSecureChannel();
break;
}
}
} }
@Test @Test
@ -384,7 +372,7 @@ public class KeycardTest {
cmdSet.openSecureChannel(secureChannel.getPairingIndex(), secureChannel.getPublicKey()); cmdSet.openSecureChannel(secureChannel.getPairingIndex(), secureChannel.getPublicKey());
// Pair multiple indexes // Pair multiple indexes
for (int i = 1; i < 5; i++) { for (int i = 1; i < KeycardApplet.PAIRING_MAX_CLIENT_COUNT; i++) {
cmdSet.autoPair(sharedSecret); cmdSet.autoPair(sharedSecret);
assertEquals(i, secureChannel.getPairingIndex()); assertEquals(i, secureChannel.getPairingIndex());
cmdSet.autoOpenSecureChannel(); cmdSet.autoOpenSecureChannel();
@ -403,7 +391,7 @@ public class KeycardTest {
assertEquals(0x9000, response.getSw()); assertEquals(0x9000, response.getSw());
} }
for (byte i = 0; i < 4; i++) { for (byte i = 0; i < (KeycardApplet.PAIRING_MAX_CLIENT_COUNT - 1); i++) {
response = cmdSet.unpair(i); response = cmdSet.unpair(i);
assertEquals(0x9000, response.getSw()); assertEquals(0x9000, response.getSw());
} }