Skip to content
25 changes: 14 additions & 11 deletions Applet/src/com/android/javacard/keymaster/KMByteTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public class KMByteTag extends KMTag {

private static KMByteTag prototype;

// MAX ApplicationID or Application Data size
public static final short MAX_APP_ID_APP_DATA_SIZE = 64;

// The allowed tag keys of type bool tag
private static final short[] tags = {
APPLICATION_ID,
Expand Down Expand Up @@ -76,15 +79,8 @@ public static short exp() {
return ptr;
}

public static short instance(short key) {
if (!validateKey(key)) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
return instance(key, KMByteBlob.exp());
}

public static short instance(short key, short byteBlob) {
if (!validateKey(key)) {
if (!validateKey(key, byteBlob)) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
if (heap[byteBlob] != BYTE_BLOB_TYPE) {
Expand Down Expand Up @@ -124,13 +120,20 @@ public short length() {
return KMByteBlob.cast(blobPtr).length();
}

private static boolean validateKey(short key) {
private static boolean validateKey(short key, short keyBlob) {
boolean result = false;
short index = (short) tags.length;
while (--index >= 0) {
if (tags[index] == key) {
return true;
result = true;
if(key == APPLICATION_ID || key == APPLICATION_DATA) {
if (KMByteBlob.cast(keyBlob).length() > MAX_APP_ID_APP_DATA_SIZE) {
result = false;
}
}
break;
}
}
return false;
return result;
}
}
38 changes: 20 additions & 18 deletions Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe
public static final byte INS_UPDATE_CHALLENGE_CMD = KEYMINT_CMD_APDU_START + 32; //0x40
public static final byte INS_FINISH_SEND_DATA_CMD = KEYMINT_CMD_APDU_START + 33; //0x41
public static final byte INS_GET_RESPONSE_CMD = KEYMINT_CMD_APDU_START + 34; //0x42
private static final byte KEYMINT_CMD_APDU_END = KEYMINT_CMD_APDU_START + 35; //0x43
private static final byte INS_GET_HEAP_PROFILE_DATA = KEYMINT_CMD_APDU_START + 35; //0x43
private static final byte KEYMINT_CMD_APDU_END = KEYMINT_CMD_APDU_START + 36; //0x44

private static final byte INS_END_KM_CMD = 0x7F;

Expand Down Expand Up @@ -472,6 +473,9 @@ public void process(APDU apdu) {
case INS_GET_RKP_HARDWARE_INFO:
rkp.process(apduIns, apdu);
break;
case INS_GET_HEAP_PROFILE_DATA:
processGetHeapProfileData(apdu);
break;
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
Expand Down Expand Up @@ -585,6 +589,7 @@ protected void resetData() {
*/
public static void sendOutgoing(APDU apdu, short resp) {
//TODO handle the extended buffer stuff. We can reuse this.
short usedHeap = repository.getHeapIndex();
short bufferStartOffset = repository.allocAvailableMemory();
byte[] buffer = repository.getHeap();
// TODO we can change the following to incremental send.
Expand All @@ -593,6 +598,7 @@ public static void sendOutgoing(APDU apdu, short resp) {
.getHeap().length)) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
repository.updateHeapProfileData((short)(usedHeap + bufferLength));
// Send data
apdu.setOutgoing();
apdu.setOutgoingLength(bufferLength);
Expand Down Expand Up @@ -683,6 +689,10 @@ private void processGetKeyCharacteristicsCmd(APDU apdu) {
data[KEY_BLOB] = KMArray.cast(cmd).get((short) 0);
data[APP_ID] = KMArray.cast(cmd).get((short) 1);
data[APP_DATA] = KMArray.cast(cmd).get((short) 2);
if (KMByteBlob.cast(data[APP_ID]).length() > KMByteTag.MAX_APP_ID_APP_DATA_SIZE
|| KMByteBlob.cast(data[APP_DATA]).length() > KMByteTag.MAX_APP_ID_APP_DATA_SIZE) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
}
if (!KMByteBlob.cast(data[APP_ID]).isValid()) {
data[APP_ID] = KMType.INVALID_VALUE;
}
Expand Down Expand Up @@ -744,21 +754,6 @@ private short keyBlob(){
}

private void processDeleteKeyCmd(APDU apdu) {
short cmd = deleteKeyCmd(apdu);
data[KEY_BLOB] = KMArray.cast(cmd).get((short) 0);
try {
data[KEY_BLOB] = decoder.decodeArray(keyBlob(),
KMByteBlob.cast(data[KEY_BLOB]).getBuffer(),
KMByteBlob.cast(data[KEY_BLOB]).getStartOff(),
KMByteBlob.cast(data[KEY_BLOB]).length());
} catch (ISOException e) {
// As per VTS, deleteKey should return KMError.OK but in case if
// input is empty then VTS accepts UNIMPLEMENTED errorCode as well.
KMException.throwIt(KMError.UNIMPLEMENTED);
}
if (KMArray.cast(data[KEY_BLOB]).length() < 4) {
KMException.throwIt(KMError.INVALID_KEY_BLOB);
}
// Send ok
sendError(apdu, KMError.OK);
}
Expand Down Expand Up @@ -1223,7 +1218,6 @@ private KMAttestationCert makeCommonCert(byte[] scratchPad) {
return cert;
}


private KMAttestationCert makeAttestationCert(short attKeyBlob, short attKeyParam, short attChallenge, short issuer,
short hwParameters, short swParameters, byte[] scratchPad) {
KMAttestationCert cert = makeCommonCert(scratchPad);
Expand Down Expand Up @@ -1294,7 +1288,6 @@ private KMAttestationCert makeAttestationCert(short attKeyBlob, short attKeyPara
cert.verifiedBootHash(getVerifiedBootHash(scratchPad));
cert.verifiedBootKey(getBootKey(scratchPad));
cert.verifiedBootState((byte) kmDataStore.getBootState());

data[SECRET] = privKey;
data[KEY_BLOB] = origBlob;
return cert;
Expand Down Expand Up @@ -4222,4 +4215,13 @@ private void finishTrustedConfirmationOperation(KMOperationState op) {
}
}
}

private void processGetHeapProfileData(APDU apdu) {
// No Arguments
// prepare the response
short resp = KMArray.instance((short) 2);
KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK));
KMArray.cast(resp).add((short) 1, KMInteger.uint_16(repository.getMaxHeapUsed()));
sendOutgoing(apdu, resp);
}
}
17 changes: 17 additions & 0 deletions Applet/src/com/android/javacard/keymaster/KMRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public class KMRepository {
private byte[] heap;
private short[] heapIndex;
private short reclaimIndex;
//used for heap profiling
public static short[] maxHeapUsage;

// Singleton instance
private static KMRepository repository;
Expand All @@ -49,6 +51,7 @@ public static KMRepository instance() {
public KMRepository(boolean isUpgrading) {
heap = JCSystem.makeTransientByteArray(HEAP_SIZE, JCSystem.CLEAR_ON_RESET);
heapIndex = JCSystem.makeTransientShortArray((short)1, JCSystem.CLEAR_ON_RESET);
maxHeapUsage = JCSystem.makeTransientShortArray((short)1, JCSystem.CLEAR_ON_RESET);
reclaimIndex = HEAP_SIZE;
repository = this;
}
Expand Down Expand Up @@ -115,5 +118,19 @@ public short alloc(short length) {
public byte[] getHeap() {
return heap;
}

public short getHeapIndex() {
return heapIndex[0];
}

public void updateHeapProfileData(short size) {
if(size > maxHeapUsage[0]) {
maxHeapUsage[0] = size;
}
}

public short getMaxHeapUsed() {
return maxHeapUsage[0];
}

}
8 changes: 7 additions & 1 deletion HAL/JavacardKeyMintOperation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,21 @@ ScopedAStatus JavacardKeyMintOperation::finish(
const vector<uint8_t> inData = input.value_or(vector<uint8_t>());
DataView view = {.buffer = {}, .data = inData, .start = 0, .length = inData.size()};
const vector<uint8_t> sign = signature.value_or(vector<uint8_t>());
appendBufferedData(view);
if (!(bufferingMode_ == BufferingMode::EC_NO_DIGEST ||
bufferingMode_ == BufferingMode::RSA_NO_DIGEST)) {
appendBufferedData(view);
if (view.length > MAX_CHUNK_SIZE) {
auto err = updateInChunks(view, aToken, tToken, output);
if (err != KM_ERROR_OK) {
return km_utils::kmError2ScopedAStatus(err);
}
}
} else {
keymaster_error_t err = bufferData(view);
if (err != KM_ERROR_OK) {
return km_utils::kmError2ScopedAStatus(err);
}
appendBufferedData(view);
}
vector<uint8_t> remaining = popNextChunk(view, view.length);
return km_utils::kmError2ScopedAStatus(sendFinish(remaining, sign, aToken, tToken, confToken, *output));
Expand Down