Skip to content

Commit

Permalink
Add the -lock and -unlock commands
Browse files Browse the repository at this point in the history
  • Loading branch information
martinpaljak committed Feb 13, 2014
1 parent 55990f4 commit 0824e58
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 60 deletions.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,24 @@ Command line samples assume default test keys of ```40..4F```. If you need custo
* Install applet.cap as default applet (with AID information from the CAP):

java -jar gp.jar -install applet.cap -default

* Set ```010B0371D78377B801F2D62AFC671D95``` key to a card with default ```40..4F``` key:

java -jar gp.jar -lock 010B0371D78377B801F2D62AFC671D95

* Set default ```40..4F``` key to card that was previously locked with ```010B0371D78377B801F2D62AFC671D95```:

java -jar gp.jar -key 010B0371D78377B801F2D62AFC671D95 -unlock

* Set the default ```40..4F``` keys to a G&D card that uses EMV diversification:

java -jar gp.jar -emv -unlock

* Show APDU-s sent to the card:

add ```-debug``` to your command

* Don't use MAC on commands (plain GlobalPlatform commands):
* Don't use MAC on commands (plain GlobalPlatform syntax):

add ```-mode clr``` to your command (not supported on all cards)

Expand Down
6 changes: 4 additions & 2 deletions src/openkms/gpj/CapFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ private byte[] createHeader(boolean includeDebug) {
int len = getCodeLength(includeDebug);
ByteArrayOutputStream bo = new ByteArrayOutputStream();
bo.write((byte) 0xC4);
// FIXME: usual length encoding.
if (len < 0x80) {
bo.write((byte) len);
} else if (len <= 0xFF) {
Expand Down Expand Up @@ -227,7 +228,7 @@ public List<byte[]> getLoadBlocks(boolean includeDebug, boolean separateComponen
bo.write(createHeader(includeDebug));
bo.write(getRawCode(includeDebug));
} catch (IOException ioe) {

throw new RuntimeException(ioe);
}
blocks = splitArray(bo.toByteArray(), blockSize);
} else {
Expand All @@ -246,7 +247,7 @@ public List<byte[]> getLoadBlocks(boolean includeDebug, boolean separateComponen
bo.write(createHeader(includeDebug));
bo.write(currentComponent);
} catch (IOException ioe) {

throw new RuntimeException(ioe);
}
currentComponent = bo.toByteArray();
}
Expand Down Expand Up @@ -283,6 +284,7 @@ public byte[] getLoadFileDataHash(boolean includeDebug) {

private List<byte[]> splitArray(byte[] array, int blockSize) {
List<byte[]> result = new ArrayList<byte[]>();

int len = array.length;
int offset = 0;
int left = len - offset;
Expand Down
47 changes: 37 additions & 10 deletions src/openkms/gpj/GPJTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
Expand All @@ -16,6 +17,7 @@
import joptsimple.OptionException;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import openkms.gpj.KeySet.Key;
import openkms.gpj.KeySet.KeyDiversification;
import openkms.gpj.KeySet.KeyType;

Expand Down Expand Up @@ -106,7 +108,7 @@ public static void main(String[] argv) throws Exception {
parser.accepts(OPT_KEK, "Specify KEK key").withRequiredArg().withValuesConvertedBy(GPJToolArgumentMatchers.key());
parser.accepts(OPT_KEY, "Specify master key").withRequiredArg().withValuesConvertedBy(GPJToolArgumentMatchers.key());
parser.accepts(CMD_LOCK, "Set new key").withRequiredArg().withValuesConvertedBy(GPJToolArgumentMatchers.key());
parser.accepts(CMD_UNLOCK, "Set default key").withRequiredArg().withValuesConvertedBy(GPJToolArgumentMatchers.key());
parser.accepts(CMD_UNLOCK, "Set default key");
parser.accepts(OPT_KEY_ID, "Specify key ID").withRequiredArg().ofType(Integer.class);
parser.accepts(OPT_KEY_VERSION, "Specify key version").withRequiredArg().ofType(Integer.class);

Expand Down Expand Up @@ -287,29 +289,29 @@ else if (args.has(OPT_EMV))

// --install <applet.cap>
if (args.has(CMD_INSTALL)) {
AID def = gp.getRegistry().getDefaultSelectedAID();
AID def = gp.getRegistry().getDefaultSelectedPackageAID();
if (def != null && args.has(OPT_DEFAULT)) {
if (args.has(OPT_REINSTALL)) {
gp.verbose("Removing current default applet/package");
// Remove all instances of default selected app
def = gp.getRegistry().getDefaultSelectedPackageAID();
gp.deleteAID(def, true); // XXX: What about different instances ?
// Remove all instances of default selected app package
gp.deleteAID(def, true);
}
}

File capfile = (File) args.valueOf(CMD_INSTALL);
CapFile instcap = new CapFile(new FileInputStream(capfile));

// Check if already installed, for some reason
// Take the applet AID from CAP but allow to override
AID aid = instcap.getAppletAIDs().get(0);
if (args.has(OPT_APPLET))
aid = (AID) args.valueOf(OPT_APPLET);

if (gp.getRegistry().allAIDs().contains(aid)) {
System.err.println("WARNING: Applet " + aid + " already present on card");
}

gp.verbose("Installing applet from package " + instcap.getPackageName());
gp.loadCapFile(instcap);
// instance will be aid, which is first applet from package
gp.installAndMakeSelecatable(instcap.getPackageAID(), aid, null, args.has(OPT_DEFAULT) ? (byte) 0x04 : 0x00, null, null);
}

Expand Down Expand Up @@ -337,9 +339,7 @@ else if (args.has(OPT_EMV))

// --list
if (args.has(CMD_LIST)) {
AIDRegistry registry = gp.getStatus();
registry = gp.getStatus();
for (AIDRegistryEntry e : registry) {
for (AIDRegistryEntry e : gp.getRegistry()) {
AID aid = e.getAID();
System.out.println("AID: " + GPUtils.byteArrayToString(aid.getBytes()) + " (" + GPUtils.byteArrayToReadableString(aid.getBytes()) + ")");
System.out.println(" " + e.getKind().toShortString() + " " + e.getLifeCycleString() + ": " + e.getPrivilegesString());
Expand All @@ -350,6 +350,33 @@ else if (args.has(OPT_EMV))
System.out.println();
}
}
// --lock
if (args.has(CMD_LOCK)) {
if (args.has(OPT_KEY) || args.has(OPT_MAC) || args.has(OPT_ENC) || args.has(OPT_KEK))
gp.printStrictWarning("Using --" + CMD_LOCK + " but specifying other keys");
byte[] new_key = ((Key)args.valueOf(CMD_LOCK)).getValue();
// Check that
List<KeySet.Key> keys = new ArrayList<KeySet.Key>();
keys.add(new KeySet.Key(01, 01, new_key));
keys.add(new KeySet.Key(01, 02, new_key));
keys.add(new KeySet.Key(01, 03, new_key));
gp.putKeys(keys, true);
}

// --unlock
if (args.has(CMD_UNLOCK)) {
// Check that
List<KeySet.Key> keys = new ArrayList<KeySet.Key>();
keys.add(new KeySet.Key(01, 01, GlobalPlatformData.defaultKey));
keys.add(new KeySet.Key(01, 02, GlobalPlatformData.defaultKey));
keys.add(new KeySet.Key(01, 03, GlobalPlatformData.defaultKey));
// Unlock with emv or visa keys writes new keys
if (args.has(OPT_VISA2) || args.has(OPT_EMV))
gp.putKeys(keys, false);
else
gp.putKeys(keys, true);
}

}
} catch (GPException e) {
// All GP exceptions halt the program unless it is run with -relax
Expand Down
2 changes: 1 addition & 1 deletion src/openkms/gpj/GPJToolArgumentMatchers.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public Key convert(String arg0) {
try {
return new Key(arg0);
} catch (IllegalArgumentException e) {
throw new ValueConversionException(arg0 + " is not a 3DES key!");
throw new ValueConversionException(arg0 + " is not a valid 3DES key!");
}
}
}
Expand Down
19 changes: 4 additions & 15 deletions src/openkms/gpj/GlobalPlatform.java
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ public void installAndMakeSelecatable(AID packageAID, AID appletAID, AID instanc

public void makeDefaultSelected(AID aid, byte privileges) throws CardException, GPException {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
// Only supported privilege. FIXME: for command interface, make it changeable
// Only supported privilege.
privileges = 0x04;
try {
bo.write(0);
Expand All @@ -704,9 +704,8 @@ public void makeDefaultSelected(AID aid, byte privileges) throws CardException,
dirty = true;
}

// TODO package vs applet
public void uninstallDefaultSelected(boolean deps) throws CardException, GPException {
AID def = getRegistry().getDefaultSelectedPackageAID();
AID def = getRegistry().getDefaultSelectedAID();
if (def != null) {
deleteAID(def, deps);
} else {
Expand Down Expand Up @@ -861,7 +860,7 @@ private byte[] getConcatenatedStatus(int p1, byte[] data) throws CardException,
* in case of communication errors
* @throws GPException
*/
public AIDRegistry getStatus() throws CardException, GPException {
private AIDRegistry getStatus() throws CardException, GPException {
AIDRegistry registry = new AIDRegistry();
int[] p1s = { 0x80, 0x40 };
for (int p1 : p1s) {
Expand Down Expand Up @@ -1028,17 +1027,7 @@ private CommandAPDU wrap(CommandAPDU command) throws CardException {
int le = command.getNe();
ByteArrayOutputStream t = new ByteArrayOutputStream();

// TODO: get from CardData
int maxLen = 255;

if (mac) {
maxLen -= 8;
}
if (enc) {
maxLen -= 8;
}

if (origLc > maxLen) {
if (origLc > getBlockSize()) {
throw new IllegalArgumentException("APDU too long for wrapping.");
}

Expand Down
47 changes: 22 additions & 25 deletions src/openkms/gpj/TLVUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@

import java.util.Arrays;

public final class TLVUtils {

public final class TLVUtils {

static short skipTag(byte [] data, short offset, byte tag) {
static short skipTag(byte[] data, short offset, byte tag) {
if (data[offset] == tag)
++offset;
return offset;
}

static short skip_tag_or_throw(byte [] data, short offset, byte tag) {
static short skip_tag_or_throw(byte[] data, short offset, byte tag) {
short skip = skipTag(data, offset, tag);
if (skip == offset)
throw new RuntimeException("Expected tag " + Integer.toHexString(tag) + " but had " + Integer.toHexString(data[offset]));
Expand All @@ -27,65 +26,66 @@ static short skipLength(byte[] data, short offset) {
}

static int get_byte_value(byte[] data, short offset) {
return (short)(data[offset] & 0x00FF);
return (short) (data[offset] & 0x00FF);
}

static short expectTag(byte[] data, short offset, byte tag) {
if (data[offset] == tag)
++offset;
return offset;
}
static short skipTagAndLength(byte []data, short offset, byte tag) {

static short skipTagAndLength(byte[] data, short offset, byte tag) {
offset = expectTag(data, offset, tag);
offset = skipLength(data, offset);
return offset;
}

static short getTagLength(byte [] data, short offset) {
static short getTagLength(byte[] data, short offset) {
++offset; // FIXME: jumpOverTag
return getLength(data, offset);
}

static int getTLVTag(byte [] data, short offset) {
static int getTLVTag(byte[] data, short offset) {
return data[offset] & 0xFF;
}

static String getTLVValueAsHex(byte [] data, short offset) {
static String getTLVValueAsHex(byte[] data, short offset) {
short len = getTagLength(data, offset);
return LoggingCardTerminal.encodeHexString(Arrays.copyOfRange(data, offset + 2, offset + 2 + len));
}

static byte[] getTLVValueAsBytes(byte [] data, short offset) {
static byte[] getTLVValueAsBytes(byte[] data, short offset) {
short len = getTagLength(data, offset);
return Arrays.copyOfRange(data, offset + 2, offset + 2 + len);
}

static byte[] getTLVAsBytes(byte [] data, short offset) {
static byte[] getTLVAsBytes(byte[] data, short offset) {
short len = getTagLength(data, offset);
return Arrays.copyOfRange(data, offset, offset + 2 + len);
}


static int getTLVValueOffset(byte [] data, short offset) {
static int getTLVValueOffset(byte[] data, short offset) {
// FIXME
return offset+2;
return offset + 2;
}
static short getTagLength(byte [] data, short offset, byte tag) {

static short getTagLength(byte[] data, short offset, byte tag) {
offset = expectTag(data, offset, tag);
offset = skipLength(data, offset);
return offset;
}

static short getLength(byte [] data, short offset) {
return (short)(data[offset] & 0x00FF);
static short getLength(byte[] data, short offset) {
return (short) (data[offset] & 0x00FF);
}

static short skipAnyTag(byte [] data, short offset) {
static short skipAnyTag(byte[] data, short offset) {
++offset; // FIXME
return (short) (offset + getLength(data, offset) +1 );
return (short) (offset + getLength(data, offset) + 1);
}

static short findTag(byte [] data, short offset, byte tag) {
static short findTag(byte[] data, short offset, byte tag) {
while (true) {
if (data[offset] == tag) {
return offset;
Expand All @@ -96,18 +96,15 @@ static short findTag(byte [] data, short offset, byte tag) {
}

// Given a MSB byte array with a length, increment it by one.
public static void buffer_increment(byte[] buffer, short offset, short len) {
static void buffer_increment(byte[] buffer, short offset, short len) {
if (len < 1)
return;
for (short i=(short) (offset+len-1); i >= offset; i--) {
for (short i = (short) (offset + len - 1); i >= offset; i--) {
if (buffer[i] != (byte) 0xFF) {
buffer[i]++;
break;
} else
buffer[i] = (byte) 0x00;
}
}

// String functions

}
Loading

0 comments on commit 0824e58

Please sign in to comment.