diff --git a/Applet/src/com/android/javacard/keymaster/KMByteTag.java b/Applet/src/com/android/javacard/keymaster/KMByteTag.java index 1677a744..f896722d 100644 --- a/Applet/src/com/android/javacard/keymaster/KMByteTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMByteTag.java @@ -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, @@ -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) { @@ -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; } } diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 754cdcdb..e9600777 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -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; @@ -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); } @@ -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. @@ -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); @@ -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; } @@ -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); } @@ -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); @@ -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; @@ -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); + } } diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index 8d868be3..e5065d47 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -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; @@ -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; } @@ -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]; + } + } diff --git a/HAL/JavacardKeyMintOperation.cpp b/HAL/JavacardKeyMintOperation.cpp index 38cbb0b4..030f8295 100644 --- a/HAL/JavacardKeyMintOperation.cpp +++ b/HAL/JavacardKeyMintOperation.cpp @@ -82,15 +82,21 @@ ScopedAStatus JavacardKeyMintOperation::finish( const vector inData = input.value_or(vector()); DataView view = {.buffer = {}, .data = inData, .start = 0, .length = inData.size()}; const vector sign = signature.value_or(vector()); - 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 remaining = popNextChunk(view, view.length); return km_utils::kmError2ScopedAStatus(sendFinish(remaining, sign, aToken, tToken, confToken, *output));