diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java index 369276c7..49929346 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java @@ -218,6 +218,12 @@ public KMAndroidSEProvider() { //Allocate buffer for certificate chain. if (!isUpgrading()) { certificateChain = new byte[CERT_CHAIN_MAX_SIZE]; + // Initialize attestationKey and preShared key with zeros. + Util.arrayFillNonAtomic(tmpArray, (short) 0, TMP_ARRAY_SIZE, (byte) 0); + // Create attestation key of P-256 curve. + createAttestationKey(tmpArray, (short)0, (short) 32); + // Pre-shared secret key length is 32 bytes. + createPresharedKey(tmpArray, (short)0, (short) KMRepository.SHARED_SECRET_KEY_SIZE); } androidSEProvider = this; } @@ -987,22 +993,18 @@ public KMOperation initSymmetricOperation(byte purpose, byte alg, opr = getOperationInstanceFromPool(); // Convert macLength to bytes macLength = (short) (macLength / 8); - JCSystem.beginTransaction(); opr.setCipher(cipher); opr.setCipherAlgorithm(alg); opr.setBlockMode(blockMode); opr.setPaddingAlgorithm(padding); opr.setMode(purpose); opr.setMacLength(macLength); - JCSystem.commitTransaction(); break; case KMType.HMAC: Signature signerVerifier = createHmacSignerVerifier(purpose, digest, keyBuf, keyStart, keyLength); opr = getOperationInstanceFromPool(); - JCSystem.beginTransaction(); opr.setSignature(signerVerifier); - JCSystem.commitTransaction(); break; default: CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); @@ -1065,23 +1067,19 @@ public KMOperation initAsymmetricOperation(byte purpose, byte alg, Signature signer = createRsaSigner(digest, padding, privKeyBuf, privKeyStart, privKeyLength, pubModBuf, pubModStart, pubModLength); opr = getOperationInstanceFromPool(); - JCSystem.beginTransaction(); opr.setSignature(signer); opr.setCipherAlgorithm(alg); opr.setPaddingAlgorithm(padding); opr.setMode(purpose); - JCSystem.commitTransaction(); break; case KMType.DECRYPT: Cipher decipher = createRsaDecipher(padding, digest, privKeyBuf, privKeyStart, privKeyLength, pubModBuf, pubModStart, pubModLength); opr = getOperationInstanceFromPool(); - JCSystem.beginTransaction(); opr.setCipher(decipher); opr.setCipherAlgorithm(alg); opr.setPaddingAlgorithm(padding); opr.setMode(purpose); - JCSystem.commitTransaction(); break; default: KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); @@ -1093,9 +1091,7 @@ public KMOperation initAsymmetricOperation(byte purpose, byte alg, Signature signer = createEcSigner(digest, privKeyBuf, privKeyStart, privKeyLength); opr = getOperationInstanceFromPool(); - JCSystem.beginTransaction(); opr.setSignature(signer); - JCSystem.commitTransaction(); break; default: KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); @@ -1133,13 +1129,12 @@ public void clearCertificateChain() { @Override public void persistPartialCertificateChain(byte[] buf, short offset, short len, short totalLen) { // _____________________________________________________ - // | 2 Bytes | 1 Byte | 3 Bytes | Cert1 | 3 Bytes | Cert2|... - // |_________|________|_________|_______|_________|______| + // | 2 Bytes | 1 Byte | 3 Bytes | Cert1 | Cert2 |... + // |_________|________|_________|_______|________|_______ // First two bytes holds the length of the total buffer. // CBOR format: - // Next single byte holds the array header. - // Next 3 bytes holds the Byte array header with the cert1 length. - // Next 3 bytes holds the Byte array header with the cert2 length. + // Next single byte holds the byte string header. + // Next 3 bytes holds the total length of the certificate chain. if (totalLen > (short) (CERT_CHAIN_MAX_SIZE - 2)) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); } diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java index 502f3fb5..2a20541c 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java @@ -23,102 +23,110 @@ public class KMOperationImpl implements KMOperation { - private Cipher cipher; - private Signature signature; - private short cipherAlg; - private short padding; - private short mode; - private short blockMode; - private short macLength; + private static final short CIPHER_ALG_OFFSET = 0x00; + private static final short PADDING_OFFSET = 0x01; + private static final short OPER_MODE_OFFSET = 0x02; + private static final short BLOCK_MODE_OFFSET = 0x03; + private static final short MAC_LENGTH_OFFSET = 0x04; //This will hold the length of the buffer stored inside the //Java Card after the GCM update operation. - private short aesGcmUpdatedLen; + private static final short AES_GCM_UPDATE_LEN_OFFSET = 0x05; + private short[] parameters; + // Either one of Cipher/Signature instance is stored. + private Object[] operationInst; public KMOperationImpl() { + parameters = JCSystem.makeTransientShortArray((short) 6, JCSystem.CLEAR_ON_RESET); + operationInst = JCSystem.makeTransientObjectArray((short) 1, JCSystem.CLEAR_ON_RESET); } public short getMode() { - return mode; + return parameters[OPER_MODE_OFFSET]; } public void setMode(short mode) { - this.mode = mode; + parameters[OPER_MODE_OFFSET] = mode; } public short getMacLength() { - return macLength; + return parameters[MAC_LENGTH_OFFSET]; } public void setMacLength(short macLength) { - this.macLength = macLength; + parameters[MAC_LENGTH_OFFSET] = macLength; } public short getPaddingAlgorithm() { - return padding; + return parameters[PADDING_OFFSET]; } public void setPaddingAlgorithm(short alg) { - padding = alg; + parameters[PADDING_OFFSET] = alg; } public void setBlockMode(short mode) { - blockMode = mode; + parameters[BLOCK_MODE_OFFSET] = mode; } public short getBlockMode() { - return blockMode; + return parameters[BLOCK_MODE_OFFSET]; } public short getCipherAlgorithm() { - return cipherAlg; + return parameters[CIPHER_ALG_OFFSET]; } public void setCipherAlgorithm(short cipherAlg) { - this.cipherAlg = cipherAlg; + parameters[CIPHER_ALG_OFFSET] = cipherAlg; } public void setCipher(Cipher cipher) { - this.cipher = cipher; + operationInst[0] = cipher; } public void setSignature(Signature signer) { - this.signature = signer; + operationInst[0] = signer; } private void resetCipher() { - JCSystem.beginTransaction(); - cipher = null; - macLength = 0; - aesGcmUpdatedLen = 0; - blockMode = 0; - mode = 0; - cipherAlg = 0; - JCSystem.commitTransaction(); + operationInst[0] = null; + parameters[MAC_LENGTH_OFFSET] = 0; + parameters[AES_GCM_UPDATE_LEN_OFFSET] = 0; + parameters[BLOCK_MODE_OFFSET] = 0; + parameters[OPER_MODE_OFFSET] = 0; + parameters[CIPHER_ALG_OFFSET] = 0; + parameters[PADDING_OFFSET] = 0; } @Override public short update(byte[] inputDataBuf, short inputDataStart, - short inputDataLength, byte[] outputDataBuf, short outputDataStart) { - short len = cipher.update(inputDataBuf, inputDataStart, inputDataLength, - outputDataBuf, outputDataStart); - if (cipherAlg == KMType.AES && blockMode == KMType.GCM) { + short inputDataLength, byte[] outputDataBuf, short outputDataStart) { + short len = ((Cipher) operationInst[0]).update(inputDataBuf, inputDataStart, inputDataLength, + outputDataBuf, outputDataStart); + if (parameters[CIPHER_ALG_OFFSET] == KMType.AES && parameters[BLOCK_MODE_OFFSET] == KMType.GCM) { // Every time Block size data is stored as intermediate result. - aesGcmUpdatedLen += (short) (inputDataLength - len); + parameters[AES_GCM_UPDATE_LEN_OFFSET] += (short) (inputDataLength - len); } return len; } @Override public short update(byte[] inputDataBuf, short inputDataStart, - short inputDataLength) { - signature.update(inputDataBuf, inputDataStart, inputDataLength); + short inputDataLength) { + ((Signature) operationInst[0]).update(inputDataBuf, inputDataStart, inputDataLength); return 0; } @Override public short finish(byte[] inputDataBuf, short inputDataStart, - short inputDataLen, byte[] outputDataBuf, short outputDataStart) { + short inputDataLen, byte[] outputDataBuf, short outputDataStart) { byte[] tmpArray = KMAndroidSEProvider.getInstance().tmpArray; + Cipher cipher = (Cipher) operationInst[0]; + short cipherAlg = parameters[CIPHER_ALG_OFFSET]; + short blockMode = parameters[BLOCK_MODE_OFFSET]; + short mode = parameters[OPER_MODE_OFFSET]; + short macLength = parameters[MAC_LENGTH_OFFSET]; + short padding = parameters[PADDING_OFFSET]; short len = 0; try { if (cipherAlg == KMType.AES && blockMode == KMType.GCM) { @@ -126,7 +134,7 @@ public short finish(byte[] inputDataBuf, short inputDataStart, inputDataLen = (short) (inputDataLen - macLength); } } else if ((cipherAlg == KMType.DES || cipherAlg == KMType.AES) && - padding == KMType.PKCS7 && mode == KMType.ENCRYPT) { + padding == KMType.PKCS7 && mode == KMType.ENCRYPT) { byte blkSize = 16; byte paddingBytes; short inputlen = inputDataLen; @@ -146,15 +154,15 @@ public short finish(byte[] inputDataBuf, short inputDataStart, Util.arrayFillNonAtomic(tmpArray, (short) 0, inputlen, paddingBytes); // copy the input data Util.arrayCopyNonAtomic(inputDataBuf, inputDataStart, tmpArray, - (short) 0, inputDataLen); + (short) 0, inputDataLen); inputDataBuf = tmpArray; inputDataLen = inputlen; inputDataStart = 0; } len = cipher.doFinal(inputDataBuf, inputDataStart, inputDataLen, - outputDataBuf, outputDataStart); + outputDataBuf, outputDataStart); if ((cipherAlg == KMType.AES || cipherAlg == KMType.DES) && - padding == KMType.PKCS7 && mode == KMType.DECRYPT) { + padding == KMType.PKCS7 && mode == KMType.DECRYPT) { byte blkSize = 16; if (cipherAlg == KMType.DES) { blkSize = 8; @@ -177,10 +185,10 @@ public short finish(byte[] inputDataBuf, short inputDataStart, } else if (cipherAlg == KMType.AES && blockMode == KMType.GCM) { if (mode == KMType.ENCRYPT) { len += ((AEADCipher) cipher).retrieveTag(outputDataBuf, - (short) (outputDataStart + len), macLength); + (short) (outputDataStart + len), macLength); } else { boolean verified = ((AEADCipher) cipher).verifyTag(inputDataBuf, - (short) (inputDataStart + inputDataLen), macLength, macLength); + (short) (inputDataStart + inputDataLen), macLength, macLength); if (!verified) { KMException.throwIt(KMError.VERIFICATION_FAILED); } @@ -196,57 +204,58 @@ public short finish(byte[] inputDataBuf, short inputDataStart, @Override public short sign(byte[] inputDataBuf, short inputDataStart, - short inputDataLength, byte[] signBuf, short signStart) { + short inputDataLength, byte[] signBuf, short signStart) { short len = 0; try { - len = signature.sign(inputDataBuf, inputDataStart, inputDataLength, - signBuf, signStart); + len = ((Signature) operationInst[0]).sign(inputDataBuf, inputDataStart, inputDataLength, + signBuf, signStart); } finally { - KMAndroidSEProvider.getInstance().releaseSignatureInstance(signature); - signature = null; + KMAndroidSEProvider.getInstance().releaseSignatureInstance((Signature) operationInst[0]); + operationInst[0] = null; } return len; } @Override public boolean verify(byte[] inputDataBuf, short inputDataStart, - short inputDataLength, byte[] signBuf, short signStart, short signLength) { + short inputDataLength, byte[] signBuf, short signStart, short signLength) { boolean ret = false; try { - ret = signature.verify(inputDataBuf, inputDataStart, inputDataLength, - signBuf, signStart, signLength); + ret = ((Signature) operationInst[0]).verify(inputDataBuf, inputDataStart, inputDataLength, + signBuf, signStart, signLength); } finally { - KMAndroidSEProvider.getInstance().releaseSignatureInstance(signature); - signature = null; + KMAndroidSEProvider.getInstance().releaseSignatureInstance((Signature) operationInst[0]); + operationInst[0] = null; } return ret; } @Override public void abort() { - // do nothing - if (cipher != null) { - KMAndroidSEProvider.getInstance().releaseCipherInstance(cipher); - resetCipher(); - } - if (signature != null) { - KMAndroidSEProvider.getInstance().releaseSignatureInstance(signature); - signature = null; + if (operationInst[0] != null) { + if (parameters[OPER_MODE_OFFSET] == KMType.ENCRYPT || + parameters[OPER_MODE_OFFSET] == KMType.DECRYPT) { + KMAndroidSEProvider.getInstance().releaseCipherInstance((Cipher) operationInst[0]); + resetCipher(); + } else { + KMAndroidSEProvider.getInstance().releaseSignatureInstance((Signature) operationInst[0]); + } + operationInst[0] = null; } KMAndroidSEProvider.getInstance().releaseOperationInstance(this); } @Override public void updateAAD(byte[] dataBuf, short dataStart, short dataLength) { - ((AEADCipher) cipher).updateAAD(dataBuf, dataStart, dataLength); + ((AEADCipher) operationInst[0]).updateAAD(dataBuf, dataStart, dataLength); } @Override public short getAESGCMOutputSize(short dataSize, short macLength) { - if (mode == KMType.ENCRYPT) { - return (short) (aesGcmUpdatedLen + dataSize + macLength); + if (parameters[OPER_MODE_OFFSET] == KMType.ENCRYPT) { + return (short) (parameters[AES_GCM_UPDATE_LEN_OFFSET] + dataSize + macLength); } else { - return (short) (aesGcmUpdatedLen + dataSize - macLength); + return (short) (parameters[AES_GCM_UPDATE_LEN_OFFSET] + dataSize - macLength); } } } diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java index 20de91c8..c6948e63 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java @@ -1203,13 +1203,12 @@ public void clearCertificateChain() { public void persistPartialCertificateChain(byte[] buf, short offset, short len, short totalLen) { // _____________________________________________________ - // | 2 Bytes | 1 Byte | 3 Bytes | Cert1 | 3 Bytes | Cert2|... - // |_________|________|_________|_______|_________|______| + // | 2 Bytes | 1 Byte | 3 Bytes | Cert1 | Cert2 |... + // |_________|________|_________|_______|________|_______ // First two bytes holds the length of the total buffer. // CBOR format: - // Next single byte holds the array header. - // Next 3 bytes holds the Byte array header with the cert1 length. - // Next 3 bytes holds the Byte array header with the cert2 length. + // Next single byte holds the byte string header. + // Next 3 bytes holds the total length of the certificate chain. if (totalLen > (short) (CERT_CHAIN_MAX_SIZE - 2)) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); } diff --git a/Applet/src/com/android/javacard/keymaster/KMArray.java b/Applet/src/com/android/javacard/keymaster/KMArray.java index f2206474..bfa09269 100644 --- a/Applet/src/com/android/javacard/keymaster/KMArray.java +++ b/Applet/src/com/android/javacard/keymaster/KMArray.java @@ -36,7 +36,6 @@ public class KMArray extends KMType { public static final short ANY_ARRAY_LENGTH = 0x1000; private static final short ARRAY_HEADER_SIZE = 4; private static KMArray prototype; - private static short instPtr; private KMArray() { } @@ -45,7 +44,7 @@ private static KMArray proto(short ptr) { if (prototype == null) { prototype = new KMArray(); } - instPtr = ptr; + instanceTable[KM_ARRAY_OFFSET] = ptr; return prototype; } @@ -89,9 +88,9 @@ public void add(short index, short objPtr) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } Util.setShort( - heap, - (short) (instPtr + TLV_HEADER_SIZE + ARRAY_HEADER_SIZE + (short) (index * 2)), - objPtr); + heap, + (short) (instanceTable[KM_ARRAY_OFFSET] + TLV_HEADER_SIZE + ARRAY_HEADER_SIZE + (short) (index * 2)), + objPtr); } public short get(short index) { @@ -100,19 +99,19 @@ public short get(short index) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } return Util.getShort( - heap, (short) (instPtr + TLV_HEADER_SIZE + ARRAY_HEADER_SIZE + (short) (index * 2))); + heap, (short) (instanceTable[KM_ARRAY_OFFSET] + TLV_HEADER_SIZE + ARRAY_HEADER_SIZE + (short) (index * 2))); } public short containedType() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE)); + return Util.getShort(heap, (short) (instanceTable[KM_ARRAY_OFFSET] + TLV_HEADER_SIZE)); } public short getStartOff() { - return (short) (instPtr + TLV_HEADER_SIZE + ARRAY_HEADER_SIZE); + return (short) (instanceTable[KM_ARRAY_OFFSET] + TLV_HEADER_SIZE + ARRAY_HEADER_SIZE); } public short length() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 2)); + return Util.getShort(heap, (short) (instanceTable[KM_ARRAY_OFFSET] + TLV_HEADER_SIZE + 2)); } public byte[] getBuffer() { diff --git a/Applet/src/com/android/javacard/keymaster/KMBoolTag.java b/Applet/src/com/android/javacard/keymaster/KMBoolTag.java index 173e6269..69619c0d 100644 --- a/Applet/src/com/android/javacard/keymaster/KMBoolTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMBoolTag.java @@ -30,22 +30,21 @@ public class KMBoolTag extends KMTag { private static KMBoolTag prototype; - private static short instPtr; // The allowed tag keys of type bool tag. private static final short[] tags = { - CALLER_NONCE, - INCLUDE_UNIQUE_ID, - BOOTLOADER_ONLY, - ROLLBACK_RESISTANCE, - NO_AUTH_REQUIRED, - ALLOW_WHILE_ON_BODY, - TRUSTED_USER_PRESENCE_REQUIRED, - TRUSTED_CONFIRMATION_REQUIRED, - UNLOCKED_DEVICE_REQUIRED, - RESET_SINCE_ID_ROTATION, - EARLY_BOOT_ONLY, - DEVICE_UNIQUE_ATTESTATION + CALLER_NONCE, + INCLUDE_UNIQUE_ID, + BOOTLOADER_ONLY, + ROLLBACK_RESISTANCE, + NO_AUTH_REQUIRED, + ALLOW_WHILE_ON_BODY, + TRUSTED_USER_PRESENCE_REQUIRED, + TRUSTED_CONFIRMATION_REQUIRED, + UNLOCKED_DEVICE_REQUIRED, + RESET_SINCE_ID_ROTATION, + EARLY_BOOT_ONLY, + DEVICE_UNIQUE_ATTESTATION }; private KMBoolTag() { @@ -55,7 +54,7 @@ private static KMBoolTag proto(short ptr) { if (prototype == null) { prototype = new KMBoolTag(); } - instPtr = ptr; + instanceTable[KM_BOOL_TAG_OFFSET] = ptr; return prototype; } @@ -89,7 +88,7 @@ public static KMBoolTag cast(short ptr) { } public short getKey() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 2)); + return Util.getShort(heap, (short) (instanceTable[KM_BOOL_TAG_OFFSET] + TLV_HEADER_SIZE + 2)); } public short getTagType() { @@ -97,7 +96,7 @@ public short getTagType() { } public byte getVal() { - return heap[(short) (instPtr + TLV_HEADER_SIZE + 4)]; + return heap[(short) (instanceTable[KM_BOOL_TAG_OFFSET] + TLV_HEADER_SIZE + 4)]; } // validate the tag key. diff --git a/Applet/src/com/android/javacard/keymaster/KMByteBlob.java b/Applet/src/com/android/javacard/keymaster/KMByteBlob.java index 001bab01..a6f4c529 100644 --- a/Applet/src/com/android/javacard/keymaster/KMByteBlob.java +++ b/Applet/src/com/android/javacard/keymaster/KMByteBlob.java @@ -28,7 +28,6 @@ public class KMByteBlob extends KMType { private static KMByteBlob prototype; - private static short instPtr; private KMByteBlob() { } @@ -37,7 +36,7 @@ private static KMByteBlob proto(short ptr) { if (prototype == null) { prototype = new KMByteBlob(); } - instPtr = ptr; + instanceTable[KM_BYTE_BLOB_OFFSET] = ptr; return prototype; } @@ -75,7 +74,7 @@ public void add(short index, byte val) { if (index >= len) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } - heap[(short) (instPtr + TLV_HEADER_SIZE + index)] = val; + heap[(short) (instanceTable[KM_BYTE_BLOB_OFFSET] + TLV_HEADER_SIZE + index)] = val; } // Get the byte @@ -84,17 +83,17 @@ public byte get(short index) { if (index >= len) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } - return heap[(short) (instPtr + TLV_HEADER_SIZE + index)]; + return heap[(short) (instanceTable[KM_BYTE_BLOB_OFFSET] + TLV_HEADER_SIZE + index)]; } // Get the start of blob public short getStartOff() { - return (short) (instPtr + TLV_HEADER_SIZE); + return (short) (instanceTable[KM_BYTE_BLOB_OFFSET] + TLV_HEADER_SIZE); } // Get the length of the blob public short length() { - return Util.getShort(heap, (short) (instPtr + 1)); + return Util.getShort(heap, (short) (instanceTable[KM_BYTE_BLOB_OFFSET] + 1)); } // Get the buffer pointer in which blob is contained. @@ -127,8 +126,8 @@ public boolean isValid() { } public void decrementLength(short len) { - short length = Util.getShort(heap, (short) (instPtr + 1)); + short length = Util.getShort(heap, (short) (instanceTable[KM_BYTE_BLOB_OFFSET] + 1)); length = (short) (length - len); - Util.setShort(heap, (short) (instPtr + 1), length); + Util.setShort(heap, (short) (instanceTable[KM_BYTE_BLOB_OFFSET] + 1), length); } } diff --git a/Applet/src/com/android/javacard/keymaster/KMByteTag.java b/Applet/src/com/android/javacard/keymaster/KMByteTag.java index 4384891d..89401e4f 100644 --- a/Applet/src/com/android/javacard/keymaster/KMByteTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMByteTag.java @@ -29,29 +29,28 @@ public class KMByteTag extends KMTag { private static KMByteTag prototype; - private static short instPtr; // The allowed tag keys of type bool tag private static final short[] tags = { - APPLICATION_ID, - APPLICATION_DATA, - ROOT_OF_TRUST, - UNIQUE_ID, - ATTESTATION_CHALLENGE, - ATTESTATION_APPLICATION_ID, - ATTESTATION_ID_BRAND, - ATTESTATION_ID_DEVICE, - ATTESTATION_ID_PRODUCT, - ATTESTATION_ID_SERIAL, - ATTESTATION_ID_IMEI, - ATTESTATION_ID_MEID, - ATTESTATION_ID_MANUFACTURER, - ATTESTATION_ID_MODEL, - ASSOCIATED_DATA, - NONCE, - CONFIRMATION_TOKEN, - VERIFIED_BOOT_KEY, - VERIFIED_BOOT_HASH + APPLICATION_ID, + APPLICATION_DATA, + ROOT_OF_TRUST, + UNIQUE_ID, + ATTESTATION_CHALLENGE, + ATTESTATION_APPLICATION_ID, + ATTESTATION_ID_BRAND, + ATTESTATION_ID_DEVICE, + ATTESTATION_ID_PRODUCT, + ATTESTATION_ID_SERIAL, + ATTESTATION_ID_IMEI, + ATTESTATION_ID_MEID, + ATTESTATION_ID_MANUFACTURER, + ATTESTATION_ID_MODEL, + ASSOCIATED_DATA, + NONCE, + CONFIRMATION_TOKEN, + VERIFIED_BOOT_KEY, + VERIFIED_BOOT_HASH }; private KMByteTag() { @@ -61,7 +60,7 @@ private static KMByteTag proto(short ptr) { if (prototype == null) { prototype = new KMByteTag(); } - instPtr = ptr; + instanceTable[KM_BYTE_TAG_OFFSET] = ptr; return prototype; } @@ -107,7 +106,7 @@ public static KMByteTag cast(short ptr) { } public short getKey() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 2)); + return Util.getShort(heap, (short) (instanceTable[KM_BYTE_TAG_OFFSET] + TLV_HEADER_SIZE + 2)); } public short getTagType() { @@ -115,11 +114,11 @@ public short getTagType() { } public short getValue() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 4)); + return Util.getShort(heap, (short) (instanceTable[KM_BYTE_TAG_OFFSET] + TLV_HEADER_SIZE + 4)); } public short length() { - short blobPtr = Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 4)); + short blobPtr = Util.getShort(heap, (short) (instanceTable[KM_BYTE_TAG_OFFSET] + TLV_HEADER_SIZE + 4)); return KMByteBlob.cast(blobPtr).length(); } diff --git a/Applet/src/com/android/javacard/keymaster/KMDecoder.java b/Applet/src/com/android/javacard/keymaster/KMDecoder.java index 520ffb7c..c2579372 100644 --- a/Applet/src/com/android/javacard/keymaster/KMDecoder.java +++ b/Applet/src/com/android/javacard/keymaster/KMDecoder.java @@ -18,6 +18,7 @@ import javacard.framework.ISO7816; import javacard.framework.ISOException; +import javacard.framework.JCSystem; import javacard.framework.Util; public class KMDecoder { @@ -38,29 +39,33 @@ public class KMDecoder { private static final short UINT32_LENGTH = 0x1A; private static final short UINT64_LENGTH = 0x1B; - private byte[] buffer; - private short startOff; - private short length; - private short tagType; - private short tagKey; + private static final short SCRATCH_BUF_SIZE = 6; + private static final short START_OFFSET = 0; + private static final short LEN_OFFSET = 2; + private static final short TAG_KEY_OFFSET = 4; + private Object[] bufferRef; + private short[] scratchBuf; public KMDecoder() { - buffer = null; - startOff = 0; - length = 0; + bufferRef = JCSystem.makeTransientObjectArray((short) 1, JCSystem.CLEAR_ON_RESET); + scratchBuf = (short[]) JCSystem.makeTransientShortArray(SCRATCH_BUF_SIZE, JCSystem.CLEAR_ON_RESET); + bufferRef[0] = null; + scratchBuf[START_OFFSET] = (short) 0; + scratchBuf[LEN_OFFSET] = (short) 0; + scratchBuf[TAG_KEY_OFFSET] = (short) 0; } public short decode(short expression, byte[] buffer, short startOff, short length) { - this.buffer = buffer; - this.startOff = startOff; - this.length = (short) (startOff + length); + bufferRef[0] = buffer; + scratchBuf[START_OFFSET] = startOff; + scratchBuf[LEN_OFFSET] = (short) (startOff + length); return decode(expression); } public short decodeArray(short exp, byte[] buffer, short startOff, short length) { - this.buffer = buffer; - this.startOff = startOff; - this.length = (short) (startOff + length); + bufferRef[0] = buffer; + scratchBuf[START_OFFSET] = startOff; + scratchBuf[LEN_OFFSET] = (short) (startOff + length); short payloadLength = readMajorTypeWithPayloadLength(ARRAY_TYPE); short expLength = KMArray.cast(exp).length(); if (payloadLength > expLength) { @@ -139,7 +144,7 @@ private short decodeVerificationToken(short exp) { private short decodeHwAuthToken(short exp) { short vals = decode(KMHardwareAuthToken.cast(exp).getVals()); - return KMHardwareAuthToken.cast(exp).instance(vals); + return KMHardwareAuthToken.instance(vals); } private short decodeHmacSharingParam(short exp) { @@ -195,32 +200,32 @@ private short decodeKeyParam(short exp) { private short decodeEnumArrayTag(short exp) { readTagKey(KMEnumArrayTag.cast(exp).getTagType()); - return KMEnumArrayTag.instance(this.tagKey, decode(KMEnumArrayTag.cast(exp).getValues())); + return KMEnumArrayTag.instance(scratchBuf[TAG_KEY_OFFSET], decode(KMEnumArrayTag.cast(exp).getValues())); } private short decodeIntegerArrayTag(short exp) { readTagKey(KMIntegerArrayTag.cast(exp).getTagType()); // the values are array of integers. return KMIntegerArrayTag.instance(KMIntegerArrayTag.cast(exp).getTagType(), - this.tagKey, decode(KMIntegerArrayTag.cast(exp).getValues())); + scratchBuf[TAG_KEY_OFFSET], decode(KMIntegerArrayTag.cast(exp).getValues())); } private short decodeIntegerTag(short exp) { readTagKey(KMIntegerTag.cast(exp).getTagType()); // the value is an integer return KMIntegerTag.instance(KMIntegerTag.cast(exp).getTagType(), - this.tagKey, decode(KMIntegerTag.cast(exp).getValue())); + scratchBuf[TAG_KEY_OFFSET], decode(KMIntegerTag.cast(exp).getValue())); } private short decodeBytesTag(short exp) { readTagKey(KMByteTag.cast(exp).getTagType()); // The value must be byte blob - return KMByteTag.instance(this.tagKey, decode(KMByteTag.cast(exp).getValue())); + return KMByteTag.instance(scratchBuf[TAG_KEY_OFFSET], decode(KMByteTag.cast(exp).getValue())); } private short decodeArray(short exp) { short payloadLength = readMajorTypeWithPayloadLength(ARRAY_TYPE); - short arrPtr = KMArray.cast(exp).instance(payloadLength); + short arrPtr = KMArray.instance(payloadLength); short index = 0; short type; short obj; @@ -250,6 +255,8 @@ private short decodeArray(short exp) { private short decodeEnumTag(short exp) { readTagKey(KMEnumTag.cast(exp).getTagType()); + byte[] buffer = (byte[])bufferRef[0]; + short startOff = scratchBuf[START_OFFSET]; // Enum Tag value will always be integer with max 1 byte length. if ((buffer[startOff] & MAJOR_TYPE_MASK) != UINT_TYPE) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); @@ -264,14 +271,19 @@ private short decodeEnumTag(short exp) { incrementStartOff((short) 1); } else if (len == UINT8_LENGTH) { incrementStartOff((short) 1); + // startOff is incremented so update the startOff + // with latest value before using it. + startOff = scratchBuf[START_OFFSET]; enumVal = buffer[startOff]; incrementStartOff((short) 1); } - return KMEnumTag.instance(tagKey, enumVal); + return KMEnumTag.instance(scratchBuf[TAG_KEY_OFFSET], enumVal); } private short decodeBoolTag(short exp) { readTagKey(KMBoolTag.cast(exp).getTagType()); + byte[] buffer = (byte[])bufferRef[0]; + short startOff = scratchBuf[START_OFFSET]; // BOOL Tag is a leaf node and it must always have tiny encoded uint value = 1. if ((buffer[startOff] & MAJOR_TYPE_MASK) != UINT_TYPE) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); @@ -280,10 +292,12 @@ private short decodeBoolTag(short exp) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } incrementStartOff((short) 1); - return KMBoolTag.instance(tagKey); + return KMBoolTag.instance(scratchBuf[TAG_KEY_OFFSET]); } private short decodeEnum(short exp) { + byte[] buffer = (byte[])bufferRef[0]; + short startOff = scratchBuf[START_OFFSET]; // Enum value will always be integer with max 1 byte length. if ((buffer[startOff] & MAJOR_TYPE_MASK) != UINT_TYPE) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); @@ -298,6 +312,9 @@ private short decodeEnum(short exp) { incrementStartOff((short) 1); } else { incrementStartOff((short) 1); + // startOff is incremented so update the startOff + // with latest value before using it. + startOff = scratchBuf[START_OFFSET]; enumVal = buffer[startOff]; incrementStartOff((short) 1); } @@ -306,6 +323,8 @@ private short decodeEnum(short exp) { private short decodeInteger(short exp) { short inst; + short startOff = scratchBuf[START_OFFSET]; + byte[] buffer = (byte[])bufferRef[0]; if ((buffer[startOff] & MAJOR_TYPE_MASK) != UINT_TYPE) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } @@ -314,6 +333,9 @@ private short decodeInteger(short exp) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } incrementStartOff((short) 1); + // startOff is incremented so update the startOff + // with latest value before using it. + startOff = scratchBuf[START_OFFSET]; if (len < UINT8_LENGTH) { inst = KMInteger.uint_8((byte) (len & ADDITIONAL_MASK)); } else if (len == UINT8_LENGTH) { @@ -334,12 +356,14 @@ private short decodeInteger(short exp) { private short decodeByteBlob(short exp) { short payloadLength = readMajorTypeWithPayloadLength(BYTES_TYPE); - short inst = KMByteBlob.instance(buffer, startOff, payloadLength); + short inst = KMByteBlob.instance((byte[])bufferRef[0], scratchBuf[START_OFFSET], payloadLength); incrementStartOff(payloadLength); return inst; } private short peekTagType() { + byte[] buffer = (byte[])bufferRef[0]; + short startOff = scratchBuf[START_OFFSET]; if ((buffer[startOff] & MAJOR_TYPE_MASK) != UINT_TYPE) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } @@ -353,6 +377,8 @@ private short peekTagType() { } private void readTagKey(short expectedTagType) { + byte[] buffer = (byte[])bufferRef[0]; + short startOff = scratchBuf[START_OFFSET]; if ((buffer[startOff] & MAJOR_TYPE_MASK) != UINT_TYPE) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } @@ -360,8 +386,8 @@ private void readTagKey(short expectedTagType) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } incrementStartOff((short) 1); - this.tagType = readShort(); - this.tagKey = readShort(); + short tagType = readShort(); + scratchBuf[TAG_KEY_OFFSET] = readShort(); if (tagType != expectedTagType) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } @@ -389,31 +415,34 @@ private short readMajorTypeWithPayloadLength(short majorType) { } private short readShort() { + byte[] buffer = (byte[])bufferRef[0]; + short startOff = scratchBuf[START_OFFSET]; short val = Util.makeShort(buffer[startOff], buffer[(short) (startOff + 1)]); incrementStartOff((short) 2); return val; } private byte readByte() { - byte val = buffer[startOff]; + short startOff = scratchBuf[START_OFFSET]; + byte val = ((byte[])bufferRef[0])[startOff]; incrementStartOff((short) 1); return val; } private void incrementStartOff(short inc) { - startOff += inc; - if (startOff > this.length) { + scratchBuf[START_OFFSET] += inc; + if (scratchBuf[START_OFFSET] > scratchBuf[LEN_OFFSET]) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } } public short readCertificateChainLengthAndHeaderLen(byte[] buf, short bufOffset, short bufLen) { - this.buffer = buf; - this.startOff = bufOffset; - this.length = (short) (bufOffset + bufLen); + bufferRef[0] = buf; + scratchBuf[START_OFFSET] = bufOffset; + scratchBuf[LEN_OFFSET] = (short) (bufOffset + bufLen); short totalLen = readMajorTypeWithPayloadLength(BYTES_TYPE); - totalLen += (short) (startOff - bufOffset); + totalLen += (short) (scratchBuf[START_OFFSET] - bufOffset); return totalLen; } } diff --git a/Applet/src/com/android/javacard/keymaster/KMEncoder.java b/Applet/src/com/android/javacard/keymaster/KMEncoder.java index 61163c00..47e6d305 100644 --- a/Applet/src/com/android/javacard/keymaster/KMEncoder.java +++ b/Applet/src/com/android/javacard/keymaster/KMEncoder.java @@ -39,27 +39,34 @@ public class KMEncoder { private static final byte UINT64_LENGTH = (byte) 0x1B; private static final short TINY_PAYLOAD = 0x17; private static final short SHORT_PAYLOAD = 0x100; - private byte[] buffer; - private short startOff; - private short length; - private static short[] stack; - private static byte stackPtr; + private static final short STACK_SIZE = (short) 50; + private static final short SCRATCH_BUF_SIZE = (short) 6; + private static final short START_OFFSET = (short) 0; + private static final short LEN_OFFSET = (short) 2; + private static final short STACK_PTR_OFFSET = (short) 4; + + private Object[] bufferRef; + private short[] scratchBuf; + private short[] stack; public KMEncoder() { - buffer = null; - startOff = 0; - length = 0; - stack = JCSystem.makeTransientShortArray((short) 50, JCSystem.CLEAR_ON_RESET); + bufferRef = JCSystem.makeTransientObjectArray((short) 1, JCSystem.CLEAR_ON_RESET); + scratchBuf = JCSystem.makeTransientShortArray((short) SCRATCH_BUF_SIZE, JCSystem.CLEAR_ON_RESET); + stack = JCSystem.makeTransientShortArray(STACK_SIZE, JCSystem.CLEAR_ON_RESET); + bufferRef[0] = null; + scratchBuf[START_OFFSET] = (short) 0; + scratchBuf[LEN_OFFSET] = (short) 0; + scratchBuf[STACK_PTR_OFFSET] = (short) 0; } - private static void push(short objPtr) { - stack[stackPtr] = objPtr; - stackPtr++; + private void push(short objPtr) { + stack[scratchBuf[STACK_PTR_OFFSET]] = objPtr; + scratchBuf[STACK_PTR_OFFSET]++; } - private static short pop() { - stackPtr--; - return stack[stackPtr]; + private short pop() { + scratchBuf[STACK_PTR_OFFSET]--; + return stack[scratchBuf[STACK_PTR_OFFSET]]; } private void encode(short obj) { @@ -67,26 +74,26 @@ private void encode(short obj) { } public short encode(short object, byte[] buffer, short startOff) { - stackPtr = 0; - this.buffer = buffer; - this.startOff = startOff; + scratchBuf[STACK_PTR_OFFSET] = 0; + bufferRef[0] = buffer; + scratchBuf[START_OFFSET] = startOff; short len = (short) buffer.length; if ((len < 0) || (len > KMKeymasterApplet.MAX_LENGTH)) { - this.length = KMKeymasterApplet.MAX_LENGTH; + scratchBuf[LEN_OFFSET] = KMKeymasterApplet.MAX_LENGTH; } else { - this.length = (short) buffer.length; + scratchBuf[LEN_OFFSET] = (short) buffer.length; } //this.length = (short)(startOff + length); push(object); encode(); - return (short) (this.startOff - startOff); + return (short) (scratchBuf[START_OFFSET] - startOff); } // array{KMError.OK,Array{KMByteBlobs}} public void encodeCertChain(byte[] buffer, short offset, short length) { - this.buffer = buffer; - this.startOff = offset; - this.length = (short) (offset + 3); + bufferRef[0] = buffer; + scratchBuf[START_OFFSET] = offset; + scratchBuf[LEN_OFFSET] = (short) (offset + 3); writeMajorTypeWithLength(ARRAY_TYPE, (short) 2); // Array of 2 elements writeByte(UINT_TYPE); // Error.OK @@ -94,22 +101,22 @@ public void encodeCertChain(byte[] buffer, short offset, short length) { //array{KMError.OK,Array{KMByteBlobs}} public short encodeCert(byte[] certBuffer, short bufferStart, short certStart, short certLength) { - this.buffer = certBuffer; - this.startOff = certStart; - this.length = (short) (certStart + 1); + bufferRef[0] = certBuffer; + scratchBuf[START_OFFSET] = certStart; + scratchBuf[LEN_OFFSET] = (short) (certStart + 1); //Array header - 2 elements i.e. 1 byte - this.startOff--; + scratchBuf[START_OFFSET]--; // Error.Ok - 1 byte - this.startOff--; + scratchBuf[START_OFFSET]--; //Array header - 2 elements i.e. 1 byte - this.startOff--; + scratchBuf[START_OFFSET]--; // Cert Byte blob - typically 2 bytes length i.e. 3 bytes header - this.startOff -= 2; + scratchBuf[START_OFFSET] -= 2; if (certLength >= SHORT_PAYLOAD) { - this.startOff--; + scratchBuf[START_OFFSET]--; } - bufferStart = startOff; - if (this.startOff < bufferStart) { + bufferStart = scratchBuf[START_OFFSET]; + if (scratchBuf[START_OFFSET] < bufferStart) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } writeMajorTypeWithLength(ARRAY_TYPE, (short) 2); // Array of 2 elements @@ -120,9 +127,9 @@ public short encodeCert(byte[] certBuffer, short bufferStart, short certStart, s } public short encodeError(short err, byte[] buffer, short startOff, short length) { - this.buffer = buffer; - this.startOff = startOff; - this.length = (short) (startOff + length); + bufferRef[0] = buffer; + scratchBuf[START_OFFSET] = startOff; + scratchBuf[LEN_OFFSET] = (short) (startOff + length); // encode the err as UINT with value in err - should not be greater then 5 bytes. if (err < UINT8_LENGTH) { writeByte((byte) (UINT_TYPE | err)); @@ -133,11 +140,11 @@ public short encodeError(short err, byte[] buffer, short startOff, short length) writeByte((byte) (UINT_TYPE | UINT16_LENGTH)); writeShort(err); } - return (short) (this.startOff - startOff); + return (short) (scratchBuf[START_OFFSET] - startOff); } private void encode() { - while (stackPtr > 0) { + while (scratchBuf[STACK_PTR_OFFSET] > 0) { short exp = pop(); byte type = KMType.getType(exp); switch (type) { @@ -352,25 +359,28 @@ private void writeMajorTypeWithLength(byte majorType, short len) { } private void writeBytes(byte[] buf, short start, short len) { - Util.arrayCopyNonAtomic(buf, start, buffer, startOff, len); + byte[] buffer = (byte[]) bufferRef[0]; + Util.arrayCopyNonAtomic(buf, start, buffer, scratchBuf[START_OFFSET], len); incrementStartOff(len); } private void writeShort(short val) { - buffer[startOff] = (byte) ((val >> 8) & 0xFF); + byte[] buffer = (byte[]) bufferRef[0]; + buffer[scratchBuf[START_OFFSET]] = (byte) ((val >> 8) & 0xFF); incrementStartOff((short) 1); - buffer[startOff] = (byte) ((val & 0xFF)); + buffer[scratchBuf[START_OFFSET]] = (byte) ((val & 0xFF)); incrementStartOff((short) 1); } private void writeByte(byte val) { - buffer[startOff] = val; + byte[] buffer = (byte[]) bufferRef[0]; + buffer[scratchBuf[START_OFFSET]] = val; incrementStartOff((short) 1); } private void incrementStartOff(short inc) { - startOff += inc; - if (startOff >= this.length) { + scratchBuf[START_OFFSET] += inc; + if (scratchBuf[START_OFFSET] >= scratchBuf[LEN_OFFSET]) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } } diff --git a/Applet/src/com/android/javacard/keymaster/KMEnum.java b/Applet/src/com/android/javacard/keymaster/KMEnum.java index 6dbdf7ce..2b55a6ce 100644 --- a/Applet/src/com/android/javacard/keymaster/KMEnum.java +++ b/Applet/src/com/android/javacard/keymaster/KMEnum.java @@ -28,18 +28,17 @@ public class KMEnum extends KMType { private static KMEnum prototype; - private static short instPtr; // The allowed enum types. private static short[] types = { - HARDWARE_TYPE, - KEY_FORMAT, - KEY_DERIVATION_FUNCTION, - VERIFIED_BOOT_STATE, - DEVICE_LOCKED, - USER_AUTH_TYPE, - PURPOSE, - ECCURVE + HARDWARE_TYPE, + KEY_FORMAT, + KEY_DERIVATION_FUNCTION, + VERIFIED_BOOT_STATE, + DEVICE_LOCKED, + USER_AUTH_TYPE, + PURPOSE, + ECCURVE }; private static Object[] enums = null; @@ -51,7 +50,7 @@ private static KMEnum proto(short ptr) { if (prototype == null) { prototype = new KMEnum(); } - instPtr = ptr; + instanceTable[KM_ENUM_OFFSET] = ptr; return prototype; } @@ -61,7 +60,7 @@ public static short exp() { } public short length() { - return Util.getShort(heap, (short) (instPtr + 1)); + return Util.getShort(heap, (short) (instanceTable[KM_ENUM_OFFSET] + 1)); } public static KMEnum cast(short ptr) { @@ -97,40 +96,40 @@ private static void create() { // The allowed enum values to corresponding enum types in the types array. if (enums == null) { enums = - new Object[]{ - new byte[]{SOFTWARE, TRUSTED_ENVIRONMENT, STRONGBOX}, - new byte[]{X509, PKCS8, RAW}, - new byte[]{ - DERIVATION_NONE, - RFC5869_SHA256, - ISO18033_2_KDF1_SHA1, - ISO18033_2_KDF1_SHA256, - ISO18033_2_KDF2_SHA1, - ISO18033_2_KDF2_SHA256 - }, - new byte[]{SELF_SIGNED_BOOT, VERIFIED_BOOT, UNVERIFIED_BOOT, FAILED_BOOT}, - new byte[]{DEVICE_LOCKED_TRUE, DEVICE_LOCKED_FALSE}, - new byte[]{USER_AUTH_NONE, PASSWORD, FINGERPRINT, BOTH}, - new byte[]{ENCRYPT, DECRYPT, SIGN, VERIFY, WRAP_KEY, ATTEST_KEY}, - new byte[]{P_224, P_256, P_384, P_521} - }; + new Object[]{ + new byte[]{SOFTWARE, TRUSTED_ENVIRONMENT, STRONGBOX}, + new byte[]{X509, PKCS8, RAW}, + new byte[]{ + DERIVATION_NONE, + RFC5869_SHA256, + ISO18033_2_KDF1_SHA1, + ISO18033_2_KDF1_SHA256, + ISO18033_2_KDF2_SHA1, + ISO18033_2_KDF2_SHA256 + }, + new byte[]{SELF_SIGNED_BOOT, VERIFIED_BOOT, UNVERIFIED_BOOT, FAILED_BOOT}, + new byte[]{DEVICE_LOCKED_TRUE, DEVICE_LOCKED_FALSE}, + new byte[]{USER_AUTH_NONE, PASSWORD, FINGERPRINT, BOTH}, + new byte[]{ENCRYPT, DECRYPT, SIGN, VERIFY, WRAP_KEY, ATTEST_KEY}, + new byte[]{P_224, P_256, P_384, P_521} + }; } } public void setVal(byte val) { - heap[(short) (instPtr + TLV_HEADER_SIZE + 2)] = val; + heap[(short) (instanceTable[KM_ENUM_OFFSET] + TLV_HEADER_SIZE + 2)] = val; } public byte getVal() { - return heap[(short) (instPtr + TLV_HEADER_SIZE + 2)]; + return heap[(short) (instanceTable[KM_ENUM_OFFSET] + TLV_HEADER_SIZE + 2)]; } public void setEnumType(short type) { - Util.setShort(heap, (short) (instPtr + TLV_HEADER_SIZE), type); + Util.setShort(heap, (short) (instanceTable[KM_ENUM_OFFSET] + TLV_HEADER_SIZE), type); } public short getEnumType() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE)); + return Util.getShort(heap, (short) (instanceTable[KM_ENUM_OFFSET] + TLV_HEADER_SIZE)); } // isValidTag enumeration keys and values. diff --git a/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java b/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java index 1cc5730d..cd3981c4 100644 --- a/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java @@ -27,10 +27,9 @@ public class KMEnumArrayTag extends KMTag { private static KMEnumArrayTag prototype; - private static short instPtr; // The allowed tag keys of enum array type. - private static short[] tags = {PURPOSE, BLOCK_MODE, DIGEST, PADDING}; + private static final short[] tags = {PURPOSE, BLOCK_MODE, DIGEST, PADDING}; // Tag Values. private static Object[] enums = null; @@ -42,7 +41,7 @@ private static KMEnumArrayTag proto(short ptr) { if (prototype == null) { prototype = new KMEnumArrayTag(); } - instPtr = ptr; + instanceTable[KM_ENUM_ARRAY_TAG_OFFSET] = ptr; return prototype; } @@ -107,7 +106,7 @@ public static KMEnumArrayTag cast(short ptr) { } public short getKey() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 2)); + return Util.getShort(heap, (short) (instanceTable[KM_ENUM_ARRAY_TAG_OFFSET] + TLV_HEADER_SIZE + 2)); } public short getTagType() { @@ -115,11 +114,11 @@ public short getTagType() { } public short getValues() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 4)); + return Util.getShort(heap, (short) (instanceTable[KM_ENUM_ARRAY_TAG_OFFSET] + TLV_HEADER_SIZE + 4)); } public short length() { - short blobPtr = Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 4)); + short blobPtr = Util.getShort(heap, (short) (instanceTable[KM_ENUM_ARRAY_TAG_OFFSET] + TLV_HEADER_SIZE + 4)); return KMByteBlob.cast(blobPtr).length(); } @@ -127,14 +126,14 @@ public static void create() { if (enums == null) { // allowed tag values. enums = - new Object[]{ - new byte[]{ENCRYPT, DECRYPT, SIGN, VERIFY, WRAP_KEY, ATTEST_KEY}, - new byte[]{ECB, CBC, CTR, GCM}, - new byte[]{DIGEST_NONE, MD5, SHA1, SHA2_224, SHA2_256, SHA2_384, SHA2_512}, - new byte[]{ - PADDING_NONE, RSA_OAEP, RSA_PSS, RSA_PKCS1_1_5_ENCRYPT, RSA_PKCS1_1_5_SIGN, PKCS7 - } - }; + new Object[]{ + new byte[]{ENCRYPT, DECRYPT, SIGN, VERIFY, WRAP_KEY, ATTEST_KEY}, + new byte[]{ECB, CBC, CTR, GCM}, + new byte[]{DIGEST_NONE, MD5, SHA1, SHA2_224, SHA2_256, SHA2_384, SHA2_512}, + new byte[]{ + PADDING_NONE, RSA_OAEP, RSA_PSS, RSA_PKCS1_1_5_ENCRYPT, RSA_PKCS1_1_5_SIGN, PKCS7 + } + }; } } @@ -234,10 +233,10 @@ public boolean isValidPaddingModes(byte alg) { switch (alg) { case KMType.RSA: if (padding != KMType.RSA_OAEP - && padding != KMType.PADDING_NONE - && padding != KMType.RSA_PKCS1_1_5_SIGN - && padding != KMType.RSA_PKCS1_1_5_ENCRYPT - && padding != KMType.RSA_PSS) { + && padding != KMType.PADDING_NONE + && padding != KMType.RSA_PKCS1_1_5_SIGN + && padding != KMType.RSA_PKCS1_1_5_ENCRYPT + && padding != KMType.RSA_PSS) { return false; } break; diff --git a/Applet/src/com/android/javacard/keymaster/KMEnumTag.java b/Applet/src/com/android/javacard/keymaster/KMEnumTag.java index 485572ed..7493aa3d 100644 --- a/Applet/src/com/android/javacard/keymaster/KMEnumTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMEnumTag.java @@ -28,12 +28,11 @@ public class KMEnumTag extends KMTag { private static KMEnumTag prototype; - private static short instPtr; // The allowed tag keys of type enum tag. private static short[] tags = { - ALGORITHM, ECCURVE, BLOB_USAGE_REQ, USER_AUTH_TYPE, ORIGIN, HARDWARE_TYPE + ALGORITHM, ECCURVE, BLOB_USAGE_REQ, USER_AUTH_TYPE, ORIGIN, HARDWARE_TYPE }; private static Object[] enums = null; @@ -45,7 +44,7 @@ private static KMEnumTag proto(short ptr) { if (prototype == null) { prototype = new KMEnumTag(); } - instPtr = ptr; + instanceTable[KM_ENUM_TAG_OFFSET] = ptr; return prototype; } @@ -88,7 +87,7 @@ public static KMEnumTag cast(short ptr) { } public short getKey() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 2)); + return Util.getShort(heap, (short) (instanceTable[KM_ENUM_TAG_OFFSET] + TLV_HEADER_SIZE + 2)); } public short getTagType() { @@ -96,22 +95,22 @@ public short getTagType() { } public byte getValue() { - return heap[(short) (instPtr + TLV_HEADER_SIZE + 4)]; + return heap[(short) (instanceTable[KM_ENUM_TAG_OFFSET] + TLV_HEADER_SIZE + 4)]; } public static void create() { if (enums == null) { // enum tag values. enums = - new Object[]{ - new byte[]{RSA, DES, EC, AES, HMAC}, - new byte[]{P_224, P_256, P_384, P_521}, - new byte[]{STANDALONE, REQUIRES_FILE_SYSTEM}, - new byte[]{USER_AUTH_NONE, PASSWORD, FINGERPRINT, (byte) (PASSWORD & FINGERPRINT), - ANY}, - new byte[]{GENERATED, DERIVED, IMPORTED, UNKNOWN, SECURELY_IMPORTED}, - new byte[]{SOFTWARE, TRUSTED_ENVIRONMENT, STRONGBOX} - }; + new Object[]{ + new byte[]{RSA, DES, EC, AES, HMAC}, + new byte[]{P_224, P_256, P_384, P_521}, + new byte[]{STANDALONE, REQUIRES_FILE_SYSTEM}, + new byte[]{USER_AUTH_NONE, PASSWORD, FINGERPRINT, (byte) (PASSWORD & FINGERPRINT), + ANY}, + new byte[]{GENERATED, DERIVED, IMPORTED, UNKNOWN, SECURELY_IMPORTED}, + new byte[]{SOFTWARE, TRUSTED_ENVIRONMENT, STRONGBOX} + }; } } diff --git a/Applet/src/com/android/javacard/keymaster/KMException.java b/Applet/src/com/android/javacard/keymaster/KMException.java index 0f4f6740..bf588aba 100644 --- a/Applet/src/com/android/javacard/keymaster/KMException.java +++ b/Applet/src/com/android/javacard/keymaster/KMException.java @@ -16,21 +16,25 @@ package com.android.javacard.keymaster; +import javacard.framework.JCSystem; + /** * KMException is shared instance of exception used for all exceptions in the applet. It is used to * throw EMError errors. */ public class KMException extends RuntimeException { - public static short reason; + public short[] reason; public static KMException exception; private KMException() { + reason = JCSystem.makeTransientShortArray((short) 1, JCSystem.CLEAR_ON_RESET); } public static void throwIt(short reason) { - KMException.reason = reason; - throw instance(); + instance(); + exception.reason[(short) 0] = reason; + throw exception; } public static KMException instance() { @@ -41,7 +45,11 @@ public static KMException instance() { } public void clear() { - reason = KMError.UNKNOWN_ERROR; + exception.reason[(short) 0] = KMError.UNKNOWN_ERROR; + } + + public static short getReason() { + return exception.reason[0]; } } diff --git a/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java b/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java index 71e2e8bb..900e9069 100644 --- a/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java +++ b/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java @@ -37,7 +37,6 @@ public class KMHardwareAuthToken extends KMType { public static final byte MAC = 0x05; private static KMHardwareAuthToken prototype; - private static short instPtr; private KMHardwareAuthToken() { } @@ -58,7 +57,7 @@ private static KMHardwareAuthToken proto(short ptr) { if (prototype == null) { prototype = new KMHardwareAuthToken(); } - instPtr = ptr; + instanceTable[KM_HARDWARE_AUTH_TOKEN_OFFSET] = ptr; return prototype; } @@ -96,7 +95,7 @@ public static KMHardwareAuthToken cast(short ptr) { } public short getVals() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE)); + return Util.getShort(heap, (short) (instanceTable[KM_HARDWARE_AUTH_TOKEN_OFFSET] + TLV_HEADER_SIZE)); } public short length() { diff --git a/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java b/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java index 81a19bd3..f89ac608 100644 --- a/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java +++ b/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java @@ -32,7 +32,6 @@ public class KMHmacSharingParameters extends KMType { public static final byte NONCE = 0x01; private static KMHmacSharingParameters prototype; - private static short instPtr; private KMHmacSharingParameters() { } @@ -49,7 +48,7 @@ private static KMHmacSharingParameters proto(short ptr) { if (prototype == null) { prototype = new KMHmacSharingParameters(); } - instPtr = ptr; + instanceTable[KM_HMAC_SHARING_PARAMETERS_OFFSET] = ptr; return prototype; } @@ -79,7 +78,7 @@ public static KMHmacSharingParameters cast(short ptr) { } public short getVals() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE)); + return Util.getShort(heap, (short) (instanceTable[KM_HMAC_SHARING_PARAMETERS_OFFSET] + TLV_HEADER_SIZE)); } public short length() { diff --git a/Applet/src/com/android/javacard/keymaster/KMInteger.java b/Applet/src/com/android/javacard/keymaster/KMInteger.java index 1330f85f..aee6f9d5 100644 --- a/Applet/src/com/android/javacard/keymaster/KMInteger.java +++ b/Applet/src/com/android/javacard/keymaster/KMInteger.java @@ -29,7 +29,6 @@ public class KMInteger extends KMType { public static final short UINT_32 = 4; public static final short UINT_64 = 8; private static KMInteger prototype; - private static short instPtr; private KMInteger() { } @@ -38,7 +37,7 @@ private static KMInteger proto(short ptr) { if (prototype == null) { prototype = new KMInteger(); } - instPtr = ptr; + instanceTable[KM_INTEGER_OFFSET] = ptr; return prototype; } @@ -115,7 +114,7 @@ public static short uint_64(byte[] num, short offset) { // Get the length of the integer public short length() { - return Util.getShort(heap, (short) (instPtr + 1)); + return Util.getShort(heap, (short) (instanceTable[KM_INTEGER_OFFSET] + 1)); } // Get the buffer pointer in which blob is contained. @@ -125,7 +124,7 @@ public byte[] getBuffer() { // Get the start of value public short getStartOff() { - return (short) (instPtr + TLV_HEADER_SIZE); + return (short) (instanceTable[KM_INTEGER_OFFSET] + TLV_HEADER_SIZE); } public void getValue(byte[] dest, short destOff, short length) { @@ -136,28 +135,28 @@ public void getValue(byte[] dest, short destOff, short length) { length = length(); destOff += length; } - Util.arrayCopyNonAtomic(heap, (short) (instPtr + TLV_HEADER_SIZE), dest, destOff, length); + Util.arrayCopyNonAtomic(heap, (short) (instanceTable[KM_INTEGER_OFFSET] + TLV_HEADER_SIZE), dest, destOff, length); } public void setValue(byte[] src, short srcOff) { - Util.arrayCopyNonAtomic(src, srcOff, heap, (short) (instPtr + TLV_HEADER_SIZE), length()); + Util.arrayCopyNonAtomic(src, srcOff, heap, (short) (instanceTable[KM_INTEGER_OFFSET] + TLV_HEADER_SIZE), length()); } public short value(byte[] dest, short destOff) { - Util.arrayCopyNonAtomic(heap, (short) (instPtr + TLV_HEADER_SIZE), dest, destOff, length()); + Util.arrayCopyNonAtomic(heap, (short) (instanceTable[KM_INTEGER_OFFSET] + TLV_HEADER_SIZE), dest, destOff, length()); return length(); } public short getShort() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 2)); + return Util.getShort(heap, (short) (instanceTable[KM_INTEGER_OFFSET] + TLV_HEADER_SIZE + 2)); } public short getSignificantShort() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE)); + return Util.getShort(heap, (short) (instanceTable[KM_INTEGER_OFFSET] + TLV_HEADER_SIZE)); } public byte getByte() { - return heap[(short) (instPtr + TLV_HEADER_SIZE + 3)]; + return heap[(short) (instanceTable[KM_INTEGER_OFFSET] + TLV_HEADER_SIZE + 3)]; } public boolean isZero() { @@ -177,13 +176,13 @@ public static short compare(short num1, short num2) { len = KMInteger.cast(num2).length(); KMInteger.cast(num2).getValue(repository.getHeap(), (short) (num2Buf + (short) (8 - len)), len); return KMInteger.unsignedByteArrayCompare( - repository.getHeap(), num1Buf, - repository.getHeap(), num2Buf, - (short) 8); + repository.getHeap(), num1Buf, + repository.getHeap(), num2Buf, + (short) 8); } public static byte unsignedByteArrayCompare(byte[] a1, short offset1, byte[] a2, short offset2, - short length) { + short length) { byte count = (byte) 0; short val1 = (short) 0; short val2 = (short) 0; diff --git a/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java b/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java index b97f5fa6..e292c5e6 100644 --- a/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java @@ -28,7 +28,6 @@ public class KMIntegerArrayTag extends KMTag { private static KMIntegerArrayTag prototype; - private static short instPtr; private static final short[] tags = {USER_SECURE_ID}; @@ -39,7 +38,7 @@ private static KMIntegerArrayTag proto(short ptr) { if (prototype == null) { prototype = new KMIntegerArrayTag(); } - instPtr = ptr; + instanceTable[KM_INTEGER_ARRAY_TAG_OFFSET] = ptr; return prototype; } @@ -95,15 +94,15 @@ public static KMIntegerArrayTag cast(short ptr) { } public short getTagType() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE)); + return Util.getShort(heap, (short) (instanceTable[KM_INTEGER_ARRAY_TAG_OFFSET] + TLV_HEADER_SIZE)); } public short getKey() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 2)); + return Util.getShort(heap, (short) (instanceTable[KM_INTEGER_ARRAY_TAG_OFFSET] + TLV_HEADER_SIZE + 2)); } public short getValues() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 4)); + return Util.getShort(heap, (short) (instanceTable[KM_INTEGER_ARRAY_TAG_OFFSET] + TLV_HEADER_SIZE + 4)); } public short length() { @@ -137,7 +136,7 @@ private static boolean validateTagType(short tagType) { public static boolean contains(short tagId, short tagValue, short params) { short tag = - KMKeyParameters.findTag(KMType.UINT_ARRAY_TAG, tagId, params); + KMKeyParameters.findTag(KMType.UINT_ARRAY_TAG, tagId, params); if (tag != KMType.INVALID_VALUE) { short index = 0; tag = KMIntegerArrayTag.cast(tag).getValues(); diff --git a/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java b/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java index 44136ec4..6ddec4bd 100644 --- a/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java @@ -28,28 +28,27 @@ public class KMIntegerTag extends KMTag { private static KMIntegerTag prototype; - private static short instPtr; // Allowed tag keys. private static final short[] tags = { - // UINT - KEYSIZE, - MIN_MAC_LENGTH, - MIN_SEC_BETWEEN_OPS, - MAX_USES_PER_BOOT, - USERID, - AUTH_TIMEOUT, - OS_VERSION, - OS_PATCH_LEVEL, - VENDOR_PATCH_LEVEL, - BOOT_PATCH_LEVEL, - MAC_LENGTH, - // ULONG - RSA_PUBLIC_EXPONENT, - // DATE - ACTIVE_DATETIME, - ORIGINATION_EXPIRE_DATETIME, - USAGE_EXPIRE_DATETIME, - CREATION_DATETIME + // UINT + KEYSIZE, + MIN_MAC_LENGTH, + MIN_SEC_BETWEEN_OPS, + MAX_USES_PER_BOOT, + USERID, + AUTH_TIMEOUT, + OS_VERSION, + OS_PATCH_LEVEL, + VENDOR_PATCH_LEVEL, + BOOT_PATCH_LEVEL, + MAC_LENGTH, + // ULONG + RSA_PUBLIC_EXPONENT, + // DATE + ACTIVE_DATETIME, + ORIGINATION_EXPIRE_DATETIME, + USAGE_EXPIRE_DATETIME, + CREATION_DATETIME }; private KMIntegerTag() { @@ -59,7 +58,7 @@ private static KMIntegerTag proto(short ptr) { if (prototype == null) { prototype = new KMIntegerTag(); } - instPtr = ptr; + instanceTable[KM_INTEGER_TAG_OFFSET] = ptr; return prototype; } @@ -115,15 +114,15 @@ public static KMIntegerTag cast(short ptr) { } public short getTagType() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE)); + return Util.getShort(heap, (short) (instanceTable[KM_INTEGER_TAG_OFFSET] + TLV_HEADER_SIZE)); } public short getKey() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 2)); + return Util.getShort(heap, (short) (instanceTable[KM_INTEGER_TAG_OFFSET] + TLV_HEADER_SIZE + 2)); } public short getValue() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 4)); + return Util.getShort(heap, (short) (instanceTable[KM_INTEGER_TAG_OFFSET] + TLV_HEADER_SIZE + 4)); } public short length() { @@ -160,7 +159,7 @@ public static short getShortValue(short tagType, short tagKey, short keyParamete } public static short getValue( - byte[] buf, short offset, short tagType, short tagKey, short keyParameters) { + byte[] buf, short offset, short tagType, short tagKey, short keyParameters) { short ptr; if ((tagType == UINT_TAG) || (tagType == ULONG_TAG) || (tagType == DATE_TAG)) { ptr = KMKeyParameters.findTag(tagType, tagKey, keyParameters); @@ -173,7 +172,7 @@ public static short getValue( } public boolean isValidKeySize(byte alg) { - short val = KMIntegerTag.cast(instPtr).getValue(); + short val = KMIntegerTag.cast(instanceTable[KM_INTEGER_TAG_OFFSET]).getValue(); if (KMInteger.cast(val).getSignificantShort() != 0) { return false; } diff --git a/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java b/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java index 2ad16117..7913f6ff 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java @@ -31,7 +31,6 @@ public class KMKeyCharacteristics extends KMType { public static final byte SOFTWARE_ENFORCED = 0x00; public static final byte HARDWARE_ENFORCED = 0x01; private static KMKeyCharacteristics prototype; - private static short instPtr; private KMKeyCharacteristics() { } @@ -50,7 +49,7 @@ private static KMKeyCharacteristics proto(short ptr) { if (prototype == null) { prototype = new KMKeyCharacteristics(); } - instPtr = ptr; + instanceTable[KM_KEY_CHARACTERISTICS_OFFSET] = ptr; return prototype; } @@ -80,7 +79,7 @@ public static KMKeyCharacteristics cast(short ptr) { } public short getVals() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE)); + return Util.getShort(heap, (short) (instanceTable[KM_KEY_CHARACTERISTICS_OFFSET] + TLV_HEADER_SIZE)); } public short length() { diff --git a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java index cfdd9c30..0ef85ae4 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java @@ -28,7 +28,6 @@ public class KMKeyParameters extends KMType { private static KMKeyParameters prototype; - private static short instPtr; private KMKeyParameters() { } @@ -37,7 +36,7 @@ private static KMKeyParameters proto(short ptr) { if (prototype == null) { prototype = new KMKeyParameters(); } - instPtr = ptr; + instanceTable[KM_KEY_PARAMETERS_OFFSET] = ptr; return prototype; } @@ -74,7 +73,7 @@ public static KMKeyParameters cast(short ptr) { } public short getVals() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE)); + return Util.getShort(heap, (short) (instanceTable[KM_KEY_PARAMETERS_OFFSET] + TLV_HEADER_SIZE)); } public short length() { diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 8f40f775..6db348b3 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -170,6 +170,11 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final byte AES_GCM_NONCE_LENGTH = 12; // ComputeHMAC constants private static final short HMAC_SHARED_PARAM_MAX_SIZE = 64; + // Maximum certificate size. + private static final short MAX_CERT_SIZE = 2048; + // Buffer constants. + private static final short BUF_START_OFFSET = 0; + private static final short BUF_LEN_OFFSET = 2; // Keymaster Applet attributes protected static byte keymasterState = ILLEGAL_STATE; @@ -177,13 +182,11 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe protected static KMDecoder decoder; protected static KMRepository repository; protected static KMSEProvider seProvider; - protected static byte[] buffer; - protected static short bufferLength; - protected static short bufferStartOffset; + protected static Object[] bufferRef; + protected static short[] bufferProp; protected static short[] tmpVariables; protected static short[] data; - protected byte provisionStatus = NOT_PROVISIONED; - protected static final short MAX_CERT_SIZE = 2048; + protected static byte provisionStatus = NOT_PROVISIONED; /** * Registers this applet. @@ -192,10 +195,7 @@ protected KMKeymasterApplet(KMSEProvider seImpl) { seProvider = seImpl; boolean isUpgrading = seImpl.isUpgrading(); repository = new KMRepository(isUpgrading); - byte[] buf = JCSystem.makeTransientByteArray((short) 32, JCSystem.CLEAR_ON_DESELECT); - data = JCSystem.makeTransientShortArray((short) DATA_ARRAY_SIZE, JCSystem.CLEAR_ON_RESET); - tmpVariables = - JCSystem.makeTransientShortArray((short) TMP_VARIABLE_ARRAY_SIZE, JCSystem.CLEAR_ON_RESET); + initializeTransientArrays(); if (!isUpgrading) { keymasterState = KMKeymasterApplet.INIT_STATE; seProvider.createMasterKey((short) (KMRepository.MASTER_KEY_SIZE * 8)); @@ -205,6 +205,15 @@ protected KMKeymasterApplet(KMSEProvider seImpl) { decoder = new KMDecoder(); } + private void initializeTransientArrays() { + data = JCSystem.makeTransientShortArray((short) DATA_ARRAY_SIZE, JCSystem.CLEAR_ON_RESET); + bufferRef = JCSystem.makeTransientObjectArray((short) 1, JCSystem.CLEAR_ON_RESET); + bufferProp = JCSystem.makeTransientShortArray((short) 4, JCSystem.CLEAR_ON_RESET); + tmpVariables = + JCSystem.makeTransientShortArray((short) TMP_VARIABLE_ARRAY_SIZE, JCSystem.CLEAR_ON_RESET); + bufferProp[BUF_START_OFFSET] = 0; + bufferProp[BUF_LEN_OFFSET] = 0; + } /** * Selects this applet. * @@ -322,7 +331,7 @@ public void process(APDU apdu) { if (!(apduIns > INS_BEGIN_KM_CMD && apduIns < INS_END_KM_CMD)) { ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } - buffer = repository.getHeap(); + bufferRef[0] = repository.getHeap(); // Process the apdu if (keymasterState == KMKeymasterApplet.IN_PROVISION_STATE) { switch (apduIns) { @@ -466,7 +475,7 @@ && isProvisioningComplete())) { } } catch (KMException exception) { freeOperations(); - sendError(apdu, KMException.reason); + sendError(apdu, KMException.getReason()); exception.clear(); } catch (ISOException exp) { sendError(apdu, mapISOErrorToKMError(exp.getReason())); @@ -522,9 +531,9 @@ private void processDeviceLockedCmd(APDU apdu) { tmpVariables[1] = KMVerificationToken.exp(); KMArray.cast(tmpVariables[0]).add((short) 1, tmpVariables[1]); // Decode the arguments - tmpVariables[0] = decoder.decode(tmpVariables[0], buffer, bufferStartOffset, bufferLength); + tmpVariables[0] = decoder.decode(tmpVariables[0], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); tmpVariables[1] = KMArray.cast(tmpVariables[0]).get((short) 0); tmpVariables[1] = KMInteger.cast(tmpVariables[1]).getByte(); @@ -559,14 +568,14 @@ private void resetData() { * Sends a response, may be extended response, as requested by the command. */ public static void sendOutgoing(APDU apdu) { - if (((short) (bufferLength + bufferStartOffset)) > ((short) repository + if (((short) (bufferProp[BUF_LEN_OFFSET] + bufferProp[BUF_START_OFFSET])) > ((short) repository .getHeap().length)) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } // Send data apdu.setOutgoing(); - apdu.setOutgoingLength(bufferLength); - apdu.sendBytesLong(buffer, bufferStartOffset, bufferLength); + apdu.setOutgoingLength(bufferProp[BUF_LEN_OFFSET]); + apdu.sendBytesLong((byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); } /** @@ -576,12 +585,12 @@ public static void receiveIncoming(APDU apdu) { byte[] srcBuffer = apdu.getBuffer(); short recvLen = apdu.setIncomingAndReceive(); short srcOffset = apdu.getOffsetCdata(); - bufferLength = apdu.getIncomingLength(); - bufferStartOffset = repository.allocReclaimableMemory(bufferLength); - short index = bufferStartOffset; + bufferProp[BUF_LEN_OFFSET] = apdu.getIncomingLength(); + bufferProp[BUF_START_OFFSET] = repository.allocReclaimableMemory(bufferProp[BUF_LEN_OFFSET]); + short index = bufferProp[BUF_START_OFFSET]; - while (recvLen > 0 && ((short) (index - bufferStartOffset) < bufferLength)) { - Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, index, recvLen); + while (recvLen > 0 && ((short) (index - bufferProp[BUF_START_OFFSET]) < bufferProp[BUF_LEN_OFFSET])) { + Util.arrayCopyNonAtomic(srcBuffer, srcOffset, (byte[]) bufferRef[0], index, recvLen); index += recvLen; recvLen = apdu.receiveBytes(srcOffset); } @@ -605,9 +614,9 @@ private void processGetHwInfoCmd(APDU apdu) { JavacardKeymasterDevice, (short) 0, (short) JavacardKeymasterDevice.length)); resp.add((short) 2, KMByteBlob.instance(Google, (short) 0, (short) Google.length)); - bufferStartOffset = repository.allocAvailableMemory(); - // Encode the response - actual bufferLength is 86 - bufferLength = encoder.encode(respPtr, buffer, bufferStartOffset); + bufferProp[BUF_START_OFFSET] = repository.allocAvailableMemory(); + // Encode the response - actual bufferProp[BUF_LEN_OFFSET] is 86 + bufferProp[BUF_LEN_OFFSET] = encoder.encode(respPtr, (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET]); // send buffer to master sendOutgoing(apdu); } @@ -619,9 +628,9 @@ private void processAddRngEntropyCmd(APDU apdu) { short argsProto = KMArray.instance((short) 1); KMArray.cast(argsProto).add((short) 0, KMByteBlob.exp()); // Decode the argument - short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + short args = decoder.decode(argsProto, (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); // Process KMByteBlob blob = KMByteBlob.cast(KMArray.cast(args).get((short) 0)); @@ -639,14 +648,14 @@ private void processGetCertChainCmd(APDU apdu) { // Add arrayHeader and KMError.OK tmpVariables[0] += 2; tmpVariables[1] = KMByteBlob.instance(tmpVariables[0]); - buffer = KMByteBlob.cast(tmpVariables[1]).getBuffer(); - bufferStartOffset = KMByteBlob.cast(tmpVariables[1]).getStartOff(); - bufferLength = KMByteBlob.cast(tmpVariables[1]).length(); + bufferRef[0] = KMByteBlob.cast(tmpVariables[1]).getBuffer(); + bufferProp[BUF_START_OFFSET] = KMByteBlob.cast(tmpVariables[1]).getStartOff(); + bufferProp[BUF_LEN_OFFSET] = KMByteBlob.cast(tmpVariables[1]).length(); // read the cert chain from non-volatile memory. Cert chain is already in // CBOR format. - seProvider.readCertificateChain(buffer, (short) (bufferStartOffset + 2)); + seProvider.readCertificateChain((byte[]) bufferRef[0], (short) (bufferProp[BUF_START_OFFSET] + 2)); // Encode cert chain. - encoder.encodeCertChain(buffer, bufferStartOffset, bufferLength); + encoder.encodeCertChain((byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); sendOutgoing(apdu); } @@ -658,9 +667,9 @@ private void processProvisionAttestationCertParams(APDU apdu) { KMArray.cast(argsProto).add((short) 0, blob); // Cert - DER encoded issuer KMArray.cast(argsProto).add((short) 1, blob); // Cert - Expiry Time // Decode the argument. - short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + short args = decoder.decode(argsProto, (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); // save issuer - DER Encoded tmpVariables[0] = KMArray.cast(args).get((short) 0); @@ -686,21 +695,21 @@ private void processProvisionAttestationCertChainCmd(APDU apdu) { byte[] srcBuffer = apdu.getBuffer(); short recvLen = apdu.setIncomingAndReceive(); short srcOffset = apdu.getOffsetCdata(); - bufferLength = apdu.getIncomingLength(); - bufferStartOffset = repository.alloc(bufferLength); + bufferProp[BUF_LEN_OFFSET] = apdu.getIncomingLength(); + bufferProp[BUF_START_OFFSET] = repository.alloc(bufferProp[BUF_LEN_OFFSET]); short bytesRead = 0; - Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, bufferStartOffset, + Util.arrayCopyNonAtomic(srcBuffer, srcOffset, (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], recvLen); // tmpVariables[1] holds the total length + Header length. - tmpVariables[1] = decoder.readCertificateChainLengthAndHeaderLen(buffer, - bufferStartOffset, recvLen); - while (recvLen > 0 && ((short) bytesRead <= bufferLength)) { - seProvider.persistPartialCertificateChain(buffer, bufferStartOffset, - recvLen, bufferLength); + tmpVariables[1] = decoder.readCertificateChainLengthAndHeaderLen((byte[]) bufferRef[0], + bufferProp[BUF_START_OFFSET], recvLen); + while (recvLen > 0 && ((short) bytesRead <= bufferProp[BUF_LEN_OFFSET])) { + seProvider.persistPartialCertificateChain((byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], + recvLen, bufferProp[BUF_LEN_OFFSET]); bytesRead += recvLen; recvLen = apdu.receiveBytes(srcOffset); if (recvLen > 0) { - Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, bufferStartOffset, + Util.arrayCopyNonAtomic(srcBuffer, srcOffset, (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], recvLen); } } @@ -723,9 +732,9 @@ private void processProvisionAttestationKey(APDU apdu) { KMArray.cast(argsProto).add((short) 2, blob); // Decode the argument - short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + short args = decoder.decode(argsProto, (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); // key params should have os patch, os version and verified root of trust data[KEY_PARAMETERS] = KMArray.cast(args).get((short) 0); @@ -788,9 +797,9 @@ private void processProvisionAttestIdsCmd(APDU apdu) { short argsProto = KMArray.instance((short) 1); KMArray.cast(argsProto).add((short) 0, keyparams); // Decode the argument. - short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + short args = decoder.decode(argsProto, (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); data[KEY_PARAMETERS] = KMArray.cast(args).get((short) 0); // persist attestation Ids - if any is missing then exception occurs @@ -811,9 +820,9 @@ private void processProvisionSharedSecretCmd(APDU apdu) { short argsProto = KMArray.instance((short) 1); KMArray.cast(argsProto).add((short) 0, blob); // Decode the argument. - short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + short args = decoder.decode(argsProto, (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); tmpVariables[0] = KMArray.cast(args).get((short) 0); if (tmpVariables[0] != KMType.INVALID_VALUE @@ -832,8 +841,8 @@ private void processGetProvisionStatusCmd(APDU apdu) { KMArray.cast(tmpVariables[0]).add((short) 0, KMInteger.uint_16(KMError.OK)); KMArray.cast(tmpVariables[0]).add((short) 1, KMInteger.uint_16(provisionStatus)); - bufferStartOffset = repository.allocAvailableMemory(); - bufferLength = encoder.encode(tmpVariables[0], buffer, bufferStartOffset); + bufferProp[BUF_START_OFFSET] = repository.allocAvailableMemory(); + bufferProp[BUF_LEN_OFFSET] = encoder.encode(tmpVariables[0], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET]); sendOutgoing(apdu); } @@ -885,9 +894,9 @@ private void processGetKeyCharacteristicsCmd(APDU apdu) { KMArray.cast(tmpVariables[0]).add((short) 1, KMByteBlob.exp()); KMArray.cast(tmpVariables[0]).add((short) 2, KMByteBlob.exp()); // Decode the arguments - tmpVariables[0] = decoder.decode(tmpVariables[0], buffer, bufferStartOffset, bufferLength); + tmpVariables[0] = decoder.decode(tmpVariables[0], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); data[KEY_BLOB] = KMArray.cast(tmpVariables[0]).get((short) 0); data[APP_ID] = KMArray.cast(tmpVariables[0]).get((short) 1); @@ -907,9 +916,9 @@ private void processGetKeyCharacteristicsCmd(APDU apdu) { KMArray.cast(tmpVariables[0]).add((short) 0, KMInteger.uint_16(KMError.OK)); KMArray.cast(tmpVariables[0]).add((short) 1, data[KEY_CHARACTERISTICS]); - bufferStartOffset = repository.allocAvailableMemory(); + bufferProp[BUF_START_OFFSET] = repository.allocAvailableMemory(); // Encode the response - bufferLength = encoder.encode(tmpVariables[0], buffer, bufferStartOffset); + bufferProp[BUF_LEN_OFFSET] = encoder.encode(tmpVariables[0], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET]); sendOutgoing(apdu); } @@ -924,9 +933,9 @@ private void processGetHmacSharingParamCmd(APDU apdu) { KMArray.cast(tmpVariables[3]).add((short) 0, KMInteger.uint_16(KMError.OK)); KMArray.cast(tmpVariables[3]).add((short) 1, tmpVariables[2]); - bufferStartOffset = repository.allocAvailableMemory(); + bufferProp[BUF_START_OFFSET] = repository.allocAvailableMemory(); // Encode the response - bufferLength = encoder.encode(tmpVariables[3], buffer, bufferStartOffset); + bufferProp[BUF_LEN_OFFSET] = encoder.encode(tmpVariables[3], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET]); sendOutgoing(apdu); } @@ -945,9 +954,9 @@ private void processDeleteKeyCmd(APDU apdu) { short argsProto = KMArray.instance((short) 1); KMArray.cast(argsProto).add((short) 0, KMByteBlob.exp()); // Decode the argument - short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + short args = decoder.decode(argsProto, (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); // Process data[KEY_BLOB] = KMArray.cast(args).get((short) 0); @@ -986,9 +995,9 @@ private void processComputeSharedHmacCmd(APDU apdu) { tmpVariables[2] = KMArray.instance((short) 1); KMArray.cast(tmpVariables[2]).add((short) 0, tmpVariables[0]); // Vector of hmac params // Decode the arguments - tmpVariables[0] = decoder.decode(tmpVariables[2], buffer, bufferStartOffset, bufferLength); + tmpVariables[0] = decoder.decode(tmpVariables[2], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); data[HMAC_SHARING_PARAMS] = KMArray.cast(tmpVariables[0]).get((short) 0); // Concatenate HMAC Params @@ -1090,9 +1099,9 @@ private void processComputeSharedHmacCmd(APDU apdu) { KMArray.cast(tmpVariables[0]).add((short) 0, KMInteger.uint_16(KMError.OK)); KMArray.cast(tmpVariables[0]).add((short) 1, tmpVariables[1]); - bufferStartOffset = repository.allocAvailableMemory(); + bufferProp[BUF_START_OFFSET] = repository.allocAvailableMemory(); // Encode the response - bufferLength = encoder.encode(tmpVariables[0], buffer, bufferStartOffset); + bufferProp[BUF_LEN_OFFSET] = encoder.encode(tmpVariables[0], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET]); sendOutgoing(apdu); } @@ -1130,9 +1139,9 @@ private void processUpgradeKeyCmd(APDU apdu) { KMArray.cast(tmpVariables[1]).add((short) 0, KMByteBlob.exp()); // Key Blob KMArray.cast(tmpVariables[1]).add((short) 1, tmpVariables[2]); // Key Params // Decode the arguments - tmpVariables[2] = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); + tmpVariables[2] = decoder.decode(tmpVariables[1], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); data[KEY_BLOB] = KMArray.cast(tmpVariables[2]).get((short) 0); data[KEY_PARAMETERS] = KMArray.cast(tmpVariables[2]).get((short) 1); @@ -1168,9 +1177,9 @@ private void processUpgradeKeyCmd(APDU apdu) { KMArray.cast(tmpVariables[0]).add((short) 0, KMInteger.uint_16(KMError.OK)); KMArray.cast(tmpVariables[0]).add((short) 1, data[KEY_BLOB]); - bufferStartOffset = repository.allocAvailableMemory(); + bufferProp[BUF_START_OFFSET] = repository.allocAvailableMemory(); // Encode the response - bufferLength = encoder.encode(tmpVariables[0], buffer, bufferStartOffset); + bufferProp[BUF_LEN_OFFSET] = encoder.encode(tmpVariables[0], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET]); sendOutgoing(apdu); } @@ -1199,9 +1208,9 @@ private void processImportWrappedKeyCmd(APDU apdu) { KMArray.cast(tmpVariables[1]).add((short) 10, KMInteger.exp()); // Password Sid KMArray.cast(tmpVariables[1]).add((short) 11, KMInteger.exp()); // Biometric Sid // Decode the arguments - short args = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); + short args = decoder.decode(tmpVariables[1], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); // Step -0 - check whether the key format and algorithm supported // read algorithm @@ -1352,9 +1361,9 @@ private void processAttestKeyCmd(APDU apdu) { KMArray.cast(argsProto).add((short) 1, keyParams); // Decode the argument - short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + short args = decoder.decode(argsProto, (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); data[KEY_BLOB] = KMArray.cast(args).get((short) 0); data[KEY_PARAMETERS] = KMArray.cast(args).get((short) 1); @@ -1436,14 +1445,14 @@ private void processAttestKeyCmd(APDU apdu) { // buffer for cert - we allocate 2KBytes buffer // make this buffer size configurable tmpVariables[3] = KMByteBlob.instance(MAX_CERT_SIZE); - buffer = KMByteBlob.cast(tmpVariables[3]).getBuffer(); - bufferStartOffset = KMByteBlob.cast(tmpVariables[3]).getStartOff(); - bufferLength = KMByteBlob.cast(tmpVariables[3]).length(); - cert.buffer(buffer, bufferStartOffset, bufferLength); + bufferRef[0] = KMByteBlob.cast(tmpVariables[3]).getBuffer(); + bufferProp[BUF_START_OFFSET] = KMByteBlob.cast(tmpVariables[3]).getStartOff(); + bufferProp[BUF_LEN_OFFSET] = KMByteBlob.cast(tmpVariables[3]).length(); + cert.buffer((byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); cert.build(); - bufferStartOffset = - encoder.encodeCert(buffer, bufferStartOffset, cert.getCertStart(), cert.getCertLength()); - bufferLength = (short) (cert.getCertLength() + (cert.getCertStart() - bufferStartOffset)); + bufferProp[BUF_START_OFFSET] = + encoder.encodeCert((byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], cert.getCertStart(), cert.getCertLength()); + bufferProp[BUF_LEN_OFFSET] = (short) (cert.getCertLength() + (cert.getCertStart() - bufferProp[BUF_START_OFFSET])); sendOutgoing(apdu); } @@ -1541,9 +1550,9 @@ private void processAbortOperationCmd(APDU apdu) { receiveIncoming(apdu); tmpVariables[1] = KMArray.instance((short) 1); KMArray.cast(tmpVariables[1]).add((short) 0, KMInteger.exp()); - tmpVariables[2] = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); + tmpVariables[2] = decoder.decode(tmpVariables[1], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); data[OP_HANDLE] = KMArray.cast(tmpVariables[2]).get((short) 0); KMOperationState op = repository.findOperation(data[OP_HANDLE]); @@ -1569,9 +1578,9 @@ private void processFinishOperationCmd(APDU apdu) { tmpVariables[4] = KMVerificationToken.exp(); KMArray.cast(tmpVariables[1]).add((short) 5, tmpVariables[4]); // Decode the arguments - tmpVariables[2] = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); + tmpVariables[2] = decoder.decode(tmpVariables[1], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); data[OP_HANDLE] = KMArray.cast(tmpVariables[2]).get((short) 0); data[KEY_PARAMETERS] = KMArray.cast(tmpVariables[2]).get((short) 1); @@ -1611,9 +1620,9 @@ private void processFinishOperationCmd(APDU apdu) { KMArray.cast(tmpVariables[2]).add((short) 1, tmpVariables[1]); KMArray.cast(tmpVariables[2]).add((short) 2, data[OUTPUT_DATA]); - bufferStartOffset = repository.allocAvailableMemory(); + bufferProp[BUF_START_OFFSET] = repository.allocAvailableMemory(); // Encode the response - bufferLength = encoder.encode(tmpVariables[2], buffer, bufferStartOffset); + bufferProp[BUF_LEN_OFFSET] = encoder.encode(tmpVariables[2], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET]); sendOutgoing(apdu); } @@ -1983,9 +1992,9 @@ private void processUpdateOperationCmd(APDU apdu) { tmpVariables[4] = KMVerificationToken.exp(); KMArray.cast(tmpVariables[1]).add((short) 4, tmpVariables[4]); // Decode the arguments - tmpVariables[2] = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); + tmpVariables[2] = decoder.decode(tmpVariables[1], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); data[OP_HANDLE] = KMArray.cast(tmpVariables[2]).get((short) 0); data[KEY_PARAMETERS] = KMArray.cast(tmpVariables[2]).get((short) 1); @@ -2094,9 +2103,9 @@ private void processUpdateOperationCmd(APDU apdu) { KMArray.cast(tmpVariables[2]).add((short) 2, tmpVariables[1]); KMArray.cast(tmpVariables[2]).add((short) 3, data[OUTPUT_DATA]); - bufferStartOffset = repository.allocAvailableMemory(); + bufferProp[BUF_START_OFFSET] = repository.allocAvailableMemory(); // Encode the response - bufferLength = encoder.encode(tmpVariables[2], buffer, bufferStartOffset); + bufferProp[BUF_LEN_OFFSET] = encoder.encode(tmpVariables[2], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET]); sendOutgoing(apdu); } @@ -2114,9 +2123,9 @@ private void processBeginOperationCmd(APDU apdu) { tmpVariables[3] = KMHardwareAuthToken.exp(); KMArray.cast(tmpVariables[1]).add((short) 3, tmpVariables[3]); // Decode the arguments - args = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); + args = decoder.decode(tmpVariables[1], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); data[KEY_PARAMETERS] = KMArray.cast(args).get((short) 2); data[KEY_BLOB] = KMArray.cast(args).get((short) 1); @@ -2199,9 +2208,9 @@ private void processBeginOperationCmd(APDU apdu) { KMArray.cast(tmpVariables[0]).add((short) 1, tmpVariables[1]); KMArray.cast(tmpVariables[0]).add((short) 2, data[OP_HANDLE]); - bufferStartOffset = repository.allocAvailableMemory(); + bufferProp[BUF_START_OFFSET] = repository.allocAvailableMemory(); // Encode the response - bufferLength = encoder.encode(tmpVariables[0], buffer, bufferStartOffset); + bufferProp[BUF_LEN_OFFSET] = encoder.encode(tmpVariables[0], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET]); sendOutgoing(apdu); } @@ -2739,9 +2748,9 @@ private void processImportKeyCmd(APDU apdu) { KMArray.cast(tmpVariables[1]).add((short) 1, KMEnum.instance(KMType.KEY_FORMAT)); KMArray.cast(tmpVariables[1]).add((short) 2, KMByteBlob.exp()); // Decode the arguments - tmpVariables[2] = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); + tmpVariables[2] = decoder.decode(tmpVariables[1], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); data[KEY_PARAMETERS] = KMArray.cast(tmpVariables[2]).get((short) 0); tmpVariables[3] = KMArray.cast(tmpVariables[2]).get((short) 1); @@ -2809,9 +2818,9 @@ private void importKey(APDU apdu, byte[] scratchPad) { KMArray.cast(tmpVariables[0]).add((short) 1, data[KEY_BLOB]); KMArray.cast(tmpVariables[0]).add((short) 2, data[KEY_CHARACTERISTICS]); - bufferStartOffset = repository.allocAvailableMemory(); + bufferProp[BUF_START_OFFSET] = repository.allocAvailableMemory(); // Encode the response - bufferLength = encoder.encode(tmpVariables[0], buffer, bufferStartOffset); + bufferProp[BUF_LEN_OFFSET] = encoder.encode(tmpVariables[0], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET]); sendOutgoing(apdu); } @@ -3154,9 +3163,9 @@ private void processSetBootParamsCmd(APDU apdu) { KMArray.cast(argsProto).add((short) 6, tmpVariables[6]); KMArray.cast(argsProto).add((short) 7, tmpVariables[7]); // Decode the arguments - short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + short args = decoder.decode(argsProto, (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); tmpVariables[0] = KMArray.cast(args).get((short) 0); tmpVariables[1] = KMArray.cast(args).get((short) 1); @@ -3231,9 +3240,9 @@ private static void processGenerateKey(APDU apdu) { tmpVariables[1] = KMArray.instance((short) 1); KMArray.cast(tmpVariables[1]).add((short) 0, tmpVariables[0]); // Decode the argument - tmpVariables[2] = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); + tmpVariables[2] = decoder.decode(tmpVariables[1], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory - repository.reclaimMemory(bufferLength); + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); data[KEY_PARAMETERS] = KMArray.cast(tmpVariables[2]).get((short) 0); // Check if EarlyBootEnded tag is present. @@ -3311,9 +3320,9 @@ private static void processGenerateKey(APDU apdu) { KMArray.cast(tmpVariables[0]).add((short) 1, data[KEY_BLOB]); KMArray.cast(tmpVariables[0]).add((short) 2, data[KEY_CHARACTERISTICS]); - bufferStartOffset = repository.allocAvailableMemory(); + bufferProp[BUF_START_OFFSET] = repository.allocAvailableMemory(); // Encode the response - bufferLength = encoder.encode(tmpVariables[0], buffer, bufferStartOffset); + bufferProp[BUF_LEN_OFFSET] = encoder.encode(tmpVariables[0], (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET]); sendOutgoing(apdu); } @@ -3816,8 +3825,8 @@ private static short deriveKey(byte[] scratchPad) { } private static void sendError(APDU apdu, short err) { - bufferStartOffset = repository.alloc((short) 2); - bufferLength = encoder.encodeError(err, buffer, bufferStartOffset, (short) 5); + bufferProp[BUF_START_OFFSET] = repository.alloc((short) 2); + bufferProp[BUF_LEN_OFFSET] = encoder.encodeError(err, (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], (short) 5); sendOutgoing(apdu); } diff --git a/Applet/src/com/android/javacard/keymaster/KMOperationState.java b/Applet/src/com/android/javacard/keymaster/KMOperationState.java index f1c65ea4..3fbe47f2 100644 --- a/Applet/src/com/android/javacard/keymaster/KMOperationState.java +++ b/Applet/src/com/android/javacard/keymaster/KMOperationState.java @@ -31,6 +31,10 @@ public class KMOperationState { public static final byte MAX_REFS = 1; private static final byte DATA = 0; private static final byte REFS = 1; + private static final byte KMOPERATION = 0; + private static final byte SLOT = 1; + private static final byte TRUE = 1; + private static final byte FALSE = 0; // byte type private static final byte ALG = 0; private static final byte PURPOSE = 1; @@ -53,14 +57,15 @@ public class KMOperationState { // Object References private static final byte OPERATION = 0; - private static KMOperation op; - private static byte[] data; - private static Object[] slot; + private byte[] data; + private Object[] objRefs; private static KMOperationState prototype; - private static boolean dFlag; + private byte[] isDataUpdated; private KMOperationState() { data = JCSystem.makeTransientByteArray(MAX_DATA, JCSystem.CLEAR_ON_RESET); + objRefs = JCSystem.makeTransientObjectArray((short) 2, JCSystem.CLEAR_ON_RESET); + isDataUpdated = JCSystem.makeTransientByteArray((short) 1, JCSystem.CLEAR_ON_RESET); } private static KMOperationState proto() { @@ -73,28 +78,30 @@ private static KMOperationState proto() { public static KMOperationState instance(short opHandle, Object[] slot) { KMOperationState opState = proto(); opState.reset(); - Util.setShort(data, OP_HANDLE, opHandle); - KMOperationState.slot = slot; + Util.setShort(prototype.data, OP_HANDLE, opHandle); + prototype.objRefs[SLOT] = slot; return opState; } public static KMOperationState read(byte[] oprHandle, short off, Object[] slot) { KMOperationState opState = proto(); opState.reset(); - Util.arrayCopy((byte[]) slot[DATA], (short) 0, data, (short) 0, (short) data.length); + Util.arrayCopy((byte[]) slot[DATA], (short) 0, prototype.data, (short) 0, (short) prototype.data.length); Object[] ops = ((Object[]) slot[REFS]); - op = (KMOperation) ops[OPERATION]; - Util.setShort(data, OP_HANDLE, KMInteger.uint_64(oprHandle, off)); - KMOperationState.slot = slot; + prototype.objRefs[KMOPERATION] = ops[OPERATION]; + Util.setShort(prototype.data, OP_HANDLE, KMInteger.uint_64(oprHandle, off)); + prototype.objRefs[SLOT] = slot; return opState; } public void persist() { - if (!dFlag) { + if (FALSE == isDataUpdated[0]) { return; } - KMRepository.instance().persistOperation(data, Util.getShort(data, OP_HANDLE), op); - dFlag = false; + KMRepository.instance().persistOperation(data, + Util.getShort(data, OP_HANDLE), + (KMOperation) objRefs[KMOPERATION]); + isDataUpdated[0] = FALSE; } public void setKeySize(short keySize) { @@ -106,30 +113,31 @@ public short getKeySize() { } public void reset() { - dFlag = false; - op = null; - slot = null; + isDataUpdated[0] = FALSE; + objRefs[KMOPERATION] = null; + objRefs[SLOT] = null; Util.arrayFillNonAtomic( data, (short) 0, (short) data.length, (byte) 0); } private void dataUpdated() { - dFlag = true; + isDataUpdated[0] = TRUE; } public void release() { - Object[] ops = ((Object[]) slot[REFS]); + Object[] slots = (Object[]) objRefs[SLOT]; + Object[] ops = ((Object[]) slots[REFS]); ((KMOperation) ops[OPERATION]).abort(); JCSystem.beginTransaction(); Util.arrayFillNonAtomic( - (byte[]) slot[0], (short) 0, (short) ((byte[]) slot[0]).length, (byte) 0); + (byte[]) slots[0], (short) 0, (short) ((byte[]) slots[0]).length, (byte) 0); ops[OPERATION] = null; JCSystem.commitTransaction(); reset(); } public short getHandle() { - return Util.getShort(KMOperationState.data, OP_HANDLE); + return Util.getShort(data, OP_HANDLE); } public short getPurpose() { @@ -141,14 +149,14 @@ public void setPurpose(byte purpose) { dataUpdated(); } - public void setOperation(KMOperation operation) { - op = operation; + public void setOperation(KMOperation opr) { + objRefs[KMOPERATION] = opr; dataUpdated(); persist(); } public KMOperation getOperation() { - return op; + return (KMOperation) objRefs[KMOPERATION]; } public boolean isAuthPerOperationReqd() { diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index 94bde080..07caec72 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -86,10 +86,10 @@ public class KMRepository implements KMUpgradable { // Class Attributes private Object[] operationStateTable; private byte[] heap; - private short heapIndex; + private short[] heapIndex; private byte[] dataTable; private short dataIndex; - private short reclaimIndex; + private short[] reclaimIndex; // Singleton instance private static KMRepository repository; @@ -99,10 +99,12 @@ public static KMRepository instance() { } public KMRepository(boolean isUpgrading) { - newDataTable(isUpgrading); heap = JCSystem.makeTransientByteArray(HEAP_SIZE, JCSystem.CLEAR_ON_RESET); - heapIndex = 0; - reclaimIndex = HEAP_SIZE; + heapIndex = JCSystem.makeTransientShortArray((short) 1, JCSystem.CLEAR_ON_RESET); + reclaimIndex = JCSystem.makeTransientShortArray((short) 1, JCSystem.CLEAR_ON_RESET); + heapIndex[0] = (short) 0; + reclaimIndex[0] = HEAP_SIZE; + newDataTable(isUpgrading); operationStateTable = new Object[MAX_OPS]; // create and initialize operation state table. //First byte in the operation handle buffer denotes whether the operation is @@ -309,9 +311,9 @@ public void onProcess() { } public void clean() { - Util.arrayFillNonAtomic(heap, (short) 0, heapIndex, (byte) 0); - heapIndex = 0; - reclaimIndex = HEAP_SIZE; + Util.arrayFillNonAtomic(heap, (short) 0, heapIndex[0], (byte) 0); + heapIndex[0] = (short) 0; + reclaimIndex[0] = HEAP_SIZE; } public void onDeselect() { @@ -324,38 +326,38 @@ public void onSelect() { // This function uses memory from the back of the heap(transient memory). Call // reclaimMemory function immediately after the use. public short allocReclaimableMemory(short length) { - if ((((short) (reclaimIndex - length)) <= heapIndex) + if ((((short) (reclaimIndex[0] - length)) <= heapIndex[0]) || (length >= HEAP_SIZE / 2)) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } - reclaimIndex -= length; - return reclaimIndex; + reclaimIndex[0] -= length; + return reclaimIndex[0]; } // Reclaims the memory back. public void reclaimMemory(short length) { - if (reclaimIndex < heapIndex) { + if (reclaimIndex[0] < heapIndex[0]) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } - reclaimIndex += length; + reclaimIndex[0] += length; } public short allocAvailableMemory() { - if (heapIndex >= heap.length) { + if (heapIndex[0] >= heap.length) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } - short index = heapIndex; - heapIndex = (short) heap.length; + short index = heapIndex[0]; + heapIndex[0] = (short) heap.length; return index; } public short alloc(short length) { - if ((((short) (heapIndex + length)) > heap.length) || - (((short) (heapIndex + length)) > reclaimIndex)) { + if ((((short) (heapIndex[0] + length)) > heap.length) || + (((short) (heapIndex[0] + length)) > reclaimIndex[0])) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } - heapIndex += length; - return (short) (heapIndex - length); + heapIndex[0] += length; + return (short) (heapIndex[0] - length); } private short dataAlloc(short length) { diff --git a/Applet/src/com/android/javacard/keymaster/KMType.java b/Applet/src/com/android/javacard/keymaster/KMType.java index 59a4b172..f571275c 100644 --- a/Applet/src/com/android/javacard/keymaster/KMType.java +++ b/Applet/src/com/android/javacard/keymaster/KMType.java @@ -18,6 +18,7 @@ import javacard.framework.ISO7816; import javacard.framework.ISOException; +import javacard.framework.JCSystem; import javacard.framework.Util; /** @@ -275,11 +276,32 @@ public abstract class KMType { public static final short LENGTH_FROM_PDU = (short) 0xFFFF; public static final byte NO_VALUE = (byte) 0xff; + // Type offsets. + public static final byte KM_TYPE_BASE_OFFSET = 0; + public static final byte KM_ARRAY_OFFSET = KM_TYPE_BASE_OFFSET; + public static final byte KM_BOOL_TAG_OFFSET = KM_TYPE_BASE_OFFSET + 1; + public static final byte KM_BYTE_BLOB_OFFSET = KM_TYPE_BASE_OFFSET + 2; + public static final byte KM_BYTE_TAG_OFFSET = KM_TYPE_BASE_OFFSET + 3; + public static final byte KM_ENUM_OFFSET = KM_TYPE_BASE_OFFSET + 4; + public static final byte KM_ENUM_ARRAY_TAG_OFFSET = KM_TYPE_BASE_OFFSET + 5; + public static final byte KM_ENUM_TAG_OFFSET = KM_TYPE_BASE_OFFSET + 6; + public static final byte KM_HARDWARE_AUTH_TOKEN_OFFSET = KM_TYPE_BASE_OFFSET + 7; + public static final byte KM_HMAC_SHARING_PARAMETERS_OFFSET = KM_TYPE_BASE_OFFSET + 8; + public static final byte KM_INTEGER_OFFSET = KM_TYPE_BASE_OFFSET + 9; + public static final byte KM_INTEGER_ARRAY_TAG_OFFSET = KM_TYPE_BASE_OFFSET + 10; + public static final byte KM_INTEGER_TAG_OFFSET = KM_TYPE_BASE_OFFSET + 11; + public static final byte KM_KEY_CHARACTERISTICS_OFFSET = KM_TYPE_BASE_OFFSET + 12; + public static final byte KM_KEY_PARAMETERS_OFFSET = KM_TYPE_BASE_OFFSET + 13; + public static final byte KM_VERIFICATION_TOKEN_OFFSET = KM_TYPE_BASE_OFFSET + 14; protected static KMRepository repository; protected static byte[] heap; + // Instance table + public static final byte INSTANCE_TABLE_SIZE = 15; + protected static short[] instanceTable; public static void initialize() { + instanceTable = JCSystem.makeTransientShortArray(INSTANCE_TABLE_SIZE, JCSystem.CLEAR_ON_RESET); KMType.repository = KMRepository.instance(); KMType.heap = repository.getHeap(); } diff --git a/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java b/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java index 1a03b33c..1be88ded 100644 --- a/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java +++ b/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java @@ -36,7 +36,6 @@ public class KMVerificationToken extends KMType { public static final byte MAC = 0x04; private static KMVerificationToken prototype; - private static short instPtr; private KMVerificationToken() { } @@ -57,7 +56,7 @@ private static KMVerificationToken proto(short ptr) { if (prototype == null) { prototype = new KMVerificationToken(); } - instPtr = ptr; + instanceTable[KM_VERIFICATION_TOKEN_OFFSET] = ptr; return prototype; } @@ -94,7 +93,7 @@ public static KMVerificationToken cast(short ptr) { } public short getVals() { - return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE)); + return Util.getShort(heap, (short) (instanceTable[KM_VERIFICATION_TOKEN_OFFSET] + TLV_HEADER_SIZE)); } public short length() {