Skip to content

Commit

Permalink
bring applet to protocol version 2.1
Browse files Browse the repository at this point in the history
  • Loading branch information
bitgamma committed Feb 12, 2019
1 parent ca65db5 commit eb73388
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 36 deletions.
69 changes: 48 additions & 21 deletions src/main/java/im/status/keycard/KeycardApplet.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* The applet's main class. All incoming commands a processed by this class.
*/
public class KeycardApplet extends Applet {
static final short APPLICATION_VERSION = (short) 0x0200;
static final short APPLICATION_VERSION = (short) 0x0201;

static final byte INS_GET_STATUS = (byte) 0xF2;
static final byte INS_SET_NDEF = (byte) 0xF3;
Expand Down Expand Up @@ -84,6 +84,14 @@ public class KeycardApplet extends Applet {
static final byte TLV_APPLICATION_INFO_TEMPLATE = (byte) 0xA4;
static final byte TLV_UID = (byte) 0x8F;
static final byte TLV_KEY_UID = (byte) 0x8E;
static final byte TLV_CAPABILITIES = (byte) 0x8D;

static final byte CAPABILITY_SECURE_CHANNEL = (byte) 0x01;
static final byte CAPABILITY_KEY_MANAGEMENT = (byte) 0x02;
static final byte CAPABILITY_CREDENTIALS_MANAGEMENT = (byte) 0x04;
static final byte CAPABILITY_NDEF = (byte) 0x08;

static final byte APPLICATION_CAPABILITIES = (byte)(CAPABILITY_SECURE_CHANNEL | CAPABILITY_KEY_MANAGEMENT | CAPABILITY_CREDENTIALS_MANAGEMENT | CAPABILITY_NDEF);

static final byte[] EIP_1581_PREFIX = { (byte) 0x80, 0x00, 0x00, 0x2B, (byte) 0x80, 0x00, 0x00, 0x3C, (byte) 0x80, 0x00, 0x06, 0x2D};

Expand Down Expand Up @@ -357,31 +365,50 @@ private void selectApplet(APDU apdu) {

byte[] apduBuffer = apdu.getBuffer();

apduBuffer[0] = TLV_APPLICATION_INFO_TEMPLATE;
apduBuffer[2] = TLV_UID;
apduBuffer[3] = UID_LENGTH;
Util.arrayCopyNonAtomic(uid, (short) 0, apduBuffer, (short) 4, UID_LENGTH);
apduBuffer[(short)(UID_LENGTH + 4)] = TLV_PUB_KEY;
short keyLength = secureChannel.copyPublicKey(apduBuffer, (short) (UID_LENGTH + 6));
apduBuffer[(short)(UID_LENGTH + 5)] = (byte) keyLength;
apduBuffer[(short)(UID_LENGTH + keyLength + 6)] = TLV_INT;
apduBuffer[(short)(UID_LENGTH + keyLength + 7)] = 2;
Util.setShort(apduBuffer, (short)(UID_LENGTH + keyLength + 8), APPLICATION_VERSION);
apduBuffer[(short)(UID_LENGTH + keyLength + 10)] = TLV_INT;
apduBuffer[(short)(UID_LENGTH + keyLength + 11)] = 1;
apduBuffer[(short)(UID_LENGTH + keyLength + 12)] = secureChannel.getRemainingPairingSlots();
apduBuffer[(short)(UID_LENGTH + keyLength + 13)] = TLV_KEY_UID;
short off = 0;

apduBuffer[off++] = TLV_APPLICATION_INFO_TEMPLATE;

if (privateKey.isInitialized()) {
apduBuffer[off++] = (byte) 0x81;
}

short lenoff = off++;

apduBuffer[off++] = TLV_UID;
apduBuffer[off++] = UID_LENGTH;
Util.arrayCopyNonAtomic(uid, (short) 0, apduBuffer, off, UID_LENGTH);
off += UID_LENGTH;

apduBuffer[off++] = TLV_PUB_KEY;
short keyLength = secureChannel.copyPublicKey(apduBuffer, (short) (off + 1));
apduBuffer[off++] = (byte) keyLength;
off += keyLength;

apduBuffer[off++] = TLV_INT;
apduBuffer[off++] = 2;
Util.setShort(apduBuffer, off, APPLICATION_VERSION);
off += 2;

apduBuffer[off++] = TLV_INT;
apduBuffer[off++] = 1;
apduBuffer[off++] = secureChannel.getRemainingPairingSlots();
apduBuffer[off++] = TLV_KEY_UID;

if (privateKey.isInitialized()) {
apduBuffer[(short)(UID_LENGTH + keyLength + 14)] = KEY_UID_LENGTH;
Util.arrayCopyNonAtomic(keyUID, (short) 0, apduBuffer, (short)(UID_LENGTH + keyLength + 15), KEY_UID_LENGTH);
keyLength += KEY_UID_LENGTH;
apduBuffer[off++] = KEY_UID_LENGTH;
Util.arrayCopyNonAtomic(keyUID, (short) 0, apduBuffer, off, KEY_UID_LENGTH);
off += KEY_UID_LENGTH;
} else {
apduBuffer[(short)(UID_LENGTH + keyLength + 14)] = 0;
apduBuffer[off++] = 0;
}

apduBuffer[1] = (byte)(keyLength + UID_LENGTH + 13);
apdu.setOutgoingAndSend((short) 0, (short)(apduBuffer[1] + 2));
apduBuffer[off++] = TLV_CAPABILITIES;
apduBuffer[off++] = 1;
apduBuffer[off++] = APPLICATION_CAPABILITIES;

apduBuffer[lenoff] = (byte)(off - lenoff - 1);
apdu.setOutgoingAndSend((short) 0, off);
}

/**
Expand Down
22 changes: 7 additions & 15 deletions src/test/java/im/status/keycard/KeycardTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.licel.jcardsim.smartcardio.CardSimulator;
import com.licel.jcardsim.smartcardio.CardTerminalSimulator;
import com.licel.jcardsim.utils.AIDUtil;
import im.status.keycard.applet.ApplicationInfo;
import im.status.keycard.applet.Identifiers;
import im.status.keycard.applet.KeycardCommandSet;
import im.status.keycard.desktop.PCSCCardChannel;
Expand Down Expand Up @@ -168,10 +169,10 @@ void openSecureChannelTest() throws Exception {

// 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 = extractPublicKeyFromSelect(cmdSet.select().getData());
byte[] initialKey = new ApplicationInfo(cmdSet.select().getData()).getSecureChannelPubKey();

for (int i = 0; i < SecureChannel.SC_COUNTER_MAX; i++) {
byte[] otherKey = extractPublicKeyFromSelect(cmdSet.select().getData());
byte[] otherKey = new ApplicationInfo(cmdSet.select().getData()).getSecureChannelPubKey();

if (!Arrays.equals(initialKey, otherKey)) {
secureChannel.generateSecret(otherKey);
Expand Down Expand Up @@ -697,9 +698,8 @@ void removeKeyTest() throws Exception {

response = cmdSet.select();
assertEquals(0x9000, response.getSw());
byte[] data = response.getData();
assertEquals(32, data[30 + data[21]]);
verifyKeyUID(Arrays.copyOfRange(data, (31 + data[21]), (63 + data[21])), (ECPublicKey) keyPair.getPublic());
ApplicationInfo info = new ApplicationInfo(response.getData());
verifyKeyUID(info.getKeyUID(), (ECPublicKey) keyPair.getPublic());

cmdSet.autoOpenSecureChannel();
response = cmdSet.verifyPIN("000000");
Expand All @@ -715,8 +715,8 @@ void removeKeyTest() throws Exception {

response = cmdSet.select();
assertEquals(0x9000, response.getSw());
data = response.getData();
assertEquals(0, data[30 + data[21]]);
info = new ApplicationInfo(response.getData());
assertEquals(0, info.getKeyUID().length);
}

@Test
Expand Down Expand Up @@ -1229,14 +1229,6 @@ private byte[] extractPublicKeyFromSignature(byte[] sig) {
return Arrays.copyOfRange(sig, 5, 5 + sig[4]);
}

private byte[] extractPublicKeyFromSelect(byte[] select) {
assertEquals(KeycardApplet.TLV_APPLICATION_INFO_TEMPLATE, select[0]);
assertEquals(KeycardApplet.TLV_UID, select[2]);
assertEquals(KeycardApplet.TLV_PUB_KEY, select[20]);

return Arrays.copyOfRange(select, 22, 22 + select[21]);
}

private void reset() {
if (USE_SIMULATOR) {
simulator.reset();
Expand Down

0 comments on commit eb73388

Please sign in to comment.