diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java new file mode 100644 index 00000000..0c483334 --- /dev/null +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java @@ -0,0 +1,8 @@ +package com.android.javacard.keymaster; + +import javacard.framework.Shareable; + +public interface KMBackupRestoreAgent extends Shareable { + void backup(byte[] buf, short start, short len); + short restore(byte[] buf, short start); +} diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java new file mode 100644 index 00000000..5f28c014 --- /dev/null +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java @@ -0,0 +1,63 @@ +package com.android.javacard.keymaster; + +import javacard.framework.AID; +import javacard.framework.APDU; +import javacard.framework.Applet; +import javacard.framework.JCSystem; +import javacard.framework.Shareable; +import javacard.framework.Util; + +public class KMBackupStoreApplet extends Applet implements KMBackupRestoreAgent { + private static final short DATA_TABLE_MEM_SIZE = 2048; + private static final byte[] aidArr = new byte[]{ (byte)0xA0, 0x00, 0x00, 0x00, 0x62}; + + private byte[] dataTable; + private short dataTableSize; + + private KMBackupStoreApplet() { + dataTable = new byte[DATA_TABLE_MEM_SIZE]; + } + + public static void install(byte bArray[], short bOffset, byte bLength) { + new KMBackupStoreApplet().register(); + } + + @Override + public boolean select() { + return true; + } + + @Override + public void process(APDU apdu) { + + } + + @Override + public void backup(byte[] buf, short start, short len) { + // Store the data + if (len > 0) { + JCSystem.beginTransaction(); + dataTableSize = len; + Util.arrayCopy(buf, start, dataTable, (short) 0, len); + JCSystem.commitTransaction(); + } + } + + @Override + public short restore(byte[] buf, short start) { + // Restore the data + Util.arrayCopy(dataTable, (short) 0, buf, start, dataTableSize); + return dataTableSize; + } + + @Override + public Shareable getShareableInterfaceObject(AID aid, byte param){ + byte[] aidBytes = new byte[10]; + byte len = aid.getBytes(aidBytes, (short)0); + if(Util.arrayCompare(aidArr,(short)0,aidBytes,(short)0,len) == 0){ + return this; + } + return null; + } + +} diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java index 0d4ec5d3..9b017990 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java @@ -26,6 +26,7 @@ import java.security.spec.MGF1ParameterSpec; import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; +import javacard.framework.AID; import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.JCSystem; @@ -68,6 +69,9 @@ public class KMJcardSimulator implements KMSEProvider { public static final short ENTROPY_POOL_SIZE = 16; // simulator does not support 256 bit aes keys public static final byte[] aesICV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; private static final int AES_GCM_KEY_SIZE = 16; + private static final byte[] aidArr = new byte[]{ (byte)0xA0, 0x00, 0x00, 0x00, 0x63}; + + public static boolean jcardSim = false; private static Signature kdf; private static Signature hmacSignature; @@ -478,18 +482,19 @@ public byte[] getTrueRandomNumber(short i) { @Override public short aesCCMSign( - byte[] bufIn, - short bufInStart, - short buffInLength, - byte[] masterKeySecret, - byte[] bufOut, - short bufStart) { - if (masterKeySecret.length > 16) { + byte[] bufIn, + short bufInStart, + short buffInLength, + byte[] masterKeySecret, + short masterKeyStart, + short masterKeyLen, + byte[] bufOut, + short bufStart) { + if (masterKeyLen > 16) { return -1; } - AESKey key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); - key.setKey(masterKeySecret, (short) 0); + key.setKey(masterKeySecret, masterKeyStart); byte[] in = new byte[buffInLength]; Util.arrayCopyNonAtomic(bufIn, bufInStart,in,(short)0,buffInLength); kdf.init(key, Signature.MODE_SIGN); @@ -499,7 +504,7 @@ public short aesCCMSign( return len; } - public HMACKey cmacKdf(byte[] keyMaterial, byte[] label, byte[] context, short contextStart, short contextLength) { + public HMACKey cmacKdf(byte[] keyMaterial, short keyMaterialStart, short keyMaterialLen, byte[] label, byte[] context, short contextStart, short contextLength) { // This is hardcoded to requirement - 32 byte output with two concatenated 16 bytes K1 and K2. final byte n = 2; // hardcoded final byte[] L = {0,0,1,0}; // [L] 256 bits - hardcoded 32 bits as per reference impl in keymaster. @@ -508,7 +513,7 @@ public HMACKey cmacKdf(byte[] keyMaterial, byte[] label, byte[] context, short c byte[] keyOut = new byte[(short)(n*16)]; Signature prf = Signature.getInstance(Signature.ALG_AES_CMAC_128, false); AESKey key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false); - key.setKey(keyMaterial, (short) 0); + key.setKey(keyMaterial, keyMaterialStart); prf.init(key, Signature.MODE_SIGN); byte i =1; short pos = 0; @@ -525,8 +530,8 @@ public HMACKey cmacKdf(byte[] keyMaterial, byte[] label, byte[] context, short c } @Override - public short cmacKdf(byte[] keyMaterial, byte[] label, byte[] context, short contextStart, short contextLength, byte[] keyBuf, short keyStart) { - HMACKey key = cmacKdf(keyMaterial,label,context,contextStart,contextLength); + public short cmacKdf(byte[] keyMaterial, short keyMaterialStart, short keyMaterialLen, byte[] label, byte[] context, short contextStart, short contextLength, byte[] keyBuf, short keyStart) { + HMACKey key = cmacKdf(keyMaterial,keyMaterialStart, keyMaterialLen, label,context,contextStart,contextLength); return key.getKey(keyBuf,keyStart); } @@ -1235,75 +1240,35 @@ public Signature createEcVerifier(short digest, byte[] pubKey, short pubKeyStart return ecVerifier; } - @Override - public short getSystemTimeInMilliSeconds(byte[] timeBuf, short timeStart, short timeOffset) { - return 0; - } - - @Override - public short addListener(KMEventListener listener, byte eventType) { - return 0; - } - - @Override - public short getEventData(byte[] eventBuf, short eventStart, short eventLength) { - return 0; - } - - @Override - public boolean isAlgSupported(byte alg) { - return true; - } - - @Override - public boolean isKeySizeSupported(byte alg, short keySize) { - return true; - } - - @Override - public boolean isCurveSupported(byte eccurve) { - return true; - } @Override - public boolean isDigestSupported(byte alg, byte digest) { + public boolean isBackupRestoreSupported() { return true; } @Override - public boolean isPaddingSupported(byte alg, byte padding) { - return true; - } - - @Override - public boolean isBlockModeSupported(byte alg, byte blockMode) { - return true; - } - - @Override - public boolean isSystemTimerSupported() { - return false; - } - - @Override - public boolean isBootEventSupported() { - return false; - } - - @Override - public boolean isPkcs8ParsingSupported() { - return false; + public KMAttestationCert getAttestationCert(boolean rsaCert) { + //certBuilder.reset(); + return KMAttestationCertImpl.instance(rsaCert); } @Override - public boolean isAttestationCertSupported() { - return true; + public void backup(byte[] buf, short start, short len) { + byte[] data = new byte[len]; + AID aid = JCSystem.lookupAID(aidArr,(short)0,(byte)aidArr.length); + KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem.getAppletShareableInterfaceObject(aid,(byte)0); + Util.arrayCopyNonAtomic(buf,start,data,(short)0,len); + backupStore.backup(data,(short)0,len); } @Override - public KMAttestationCert getAttestationCert(boolean rsaCert) { - //certBuilder.reset(); - return KMAttestationCertImpl.instance(rsaCert); + public short restore(byte[] buf, short start) { + byte[] data = new byte[2200]; + AID aid = JCSystem.lookupAID(aidArr,(short)0,(byte)aidArr.length); + KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem.getAppletShareableInterfaceObject(aid,(byte)0); + short len = backupStore.restore(data,(short)0); + Util.arrayCopyNonAtomic(data,(short)0,buf,start,len); + return len; } /* diff --git a/Applet/Applet/OracleSimProvider/com/android/javacard/keymaster/KMSimulator.java b/Applet/Applet/OracleSimProvider/com/android/javacard/keymaster/KMSimulator.java index 8d8d215e..c5d74fe0 100644 --- a/Applet/Applet/OracleSimProvider/com/android/javacard/keymaster/KMSimulator.java +++ b/Applet/Applet/OracleSimProvider/com/android/javacard/keymaster/KMSimulator.java @@ -307,6 +307,12 @@ public boolean aesGCMDecrypt( return verification; } + + @Override + public short cmacKdf(byte[] keyMaterial, short keyMaterialStart, short keyMaterialLen, byte[] label, byte[] context, short contextStart, short contextLength, byte[] keyBuf, short keyStart) { + return 0; + } + @Override public byte[] getTrueRandomNumber(short i) { // ignore the size as simulator only supports 128 bit entropy @@ -319,13 +325,15 @@ public short aesCCMSign( short bufInStart, short buffInLength, byte[] masterKeySecret, + short masterKeyStart, + short masterKeyLen, byte[] bufOut, short bufStart) { - if (masterKeySecret.length > 16) { + if (masterKeyLen > 16) { return -1; } - aes128Key.setKey(masterKeySecret, (short) 0); + aes128Key.setKey(masterKeySecret, masterKeyStart); kdf.init(aes128Key, Signature.MODE_SIGN); return kdf.sign(bufIn, bufInStart, buffInLength, bufOut, bufStart); } @@ -374,11 +382,6 @@ public HMACKey cmacKdf(byte[] keyMaterial, byte[] label, byte[] context, short c return null; } - @Override - public short cmacKdf(byte[] keyMaterial, byte[] label, byte[] context, short contextStart, short contextLength, byte[] keyBuf, short keyStart) { - return 0; - } - public short hmacSign(HMACKey key, byte[] data, short dataStart, short dataLength, byte[] mac, short macStart) { return 0; } @@ -498,73 +501,23 @@ private void incrementCounter() { } @Override - public short getSystemTimeInMilliSeconds(byte[] timeBuf, short timeStart, short timeOffset) { - return 0; - } - - @Override - public short addListener(KMEventListener listener, byte eventType) { - return 0; - } - - @Override - public short getEventData(byte[] eventBuf, short eventStart, short eventLength) { - return 0; - } - - @Override - public boolean isAlgSupported(byte alg) { + public boolean isBackupRestoreSupported() { return false; } @Override - public boolean isKeySizeSupported(byte alg, short keySize) { - return false; - } - - @Override - public boolean isCurveSupported(byte eccurve) { - return false; - } - - @Override - public boolean isDigestSupported(byte alg, byte digest) { - return false; - } - - @Override - public boolean isPaddingSupported(byte alg, byte padding) { - return false; - } - - @Override - public boolean isBlockModeSupported(byte alg, byte blockMode) { - return false; - } - - @Override - public boolean isSystemTimerSupported() { - return false; + public KMAttestationCert getAttestationCert(boolean rsaCert) { + return null; } @Override - public boolean isBootEventSupported() { - return false; - } + public void backup(byte[] buf, short start, short len) { - @Override - public boolean isPkcs8ParsingSupported() { - return false; } @Override - public boolean isAttestationCertSupported() { - return false; - } - - @Override - public KMAttestationCert getAttestationCert(boolean rsaCert) { - return null; + public short restore(byte[] buf, short start) { + return 0; } } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMBoolTag.java b/Applet/Applet/src/com/android/javacard/keymaster/KMBoolTag.java index ae0f75ac..15e6dc4f 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMBoolTag.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMBoolTag.java @@ -34,7 +34,9 @@ public class KMBoolTag extends KMTag { TRUSTED_USER_PRESENCE_REQUIRED, TRUSTED_CONFIRMATION_REQUIRED, UNLOCKED_DEVICE_REQUIRED, - RESET_SINCE_ID_ROTATION + RESET_SINCE_ID_ROTATION, + EARLY_BOOT_ENDED, + DEVICE_UNIQUE_ATTESTATION }; private KMBoolTag() {} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMByteBlob.java b/Applet/Applet/src/com/android/javacard/keymaster/KMByteBlob.java index 7f598eaa..decf9631 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMByteBlob.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMByteBlob.java @@ -109,4 +109,10 @@ public boolean isValid(){ } return true; } + + public void decrementLength(short len){ + short length = Util.getShort(heap, (short) (instPtr + 1)); + length = (short)(length - len); + Util.setShort(heap, (short) (instPtr + 1),length); + } } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMError.java b/Applet/Applet/src/com/android/javacard/keymaster/KMError.java index 25557d27..9bf97298 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMError.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMError.java @@ -72,6 +72,7 @@ public class KMError { public static short CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = 70; public static short NO_USER_CONFIRMATION = 71; public static short DEVICE_LOCKED = 72; + public static short EARLY_BOOT_ENDED = 73; public static short UNIMPLEMENTED = 100; public static short VERSION_MISMATCH = 101; public static short UNKNOWN_ERROR = 1000; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 2d70711b..5f6d823d 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -16,12 +16,14 @@ package com.android.javacard.keymaster; +import javacard.framework.AID; import javacard.framework.APDU; import javacard.framework.Applet; import javacard.framework.AppletEvent; import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.JCSystem; +import javacard.framework.Shareable; import javacard.framework.Util; import javacard.security.CryptoException; import javacardx.apdu.ExtendedLength; @@ -31,8 +33,6 @@ * objects. It also implements the keymaster state machine and handles javacard applet life cycle * events. */ -// TODO Currently implementing ExtendedLength for ease of testing -// - remove this in future. public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLength { // Constants. public static final byte AES_BLOCK_SIZE = 16; @@ -42,6 +42,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final short KM_HAL_VERSION = (short) 0x4000; private static final short MAX_AUTH_DATA_SIZE = (short) 512; private static final short MAX_IO_LENGTH = 0x600; + // "Keymaster HMAC Verification" - used for HMAC key verification. public static final byte[] sharingCheck = { 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x48, 0x4D, 0x41, 0x43, 0x20, 0x56, @@ -90,6 +91,8 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final byte INS_SET_BOOT_PARAMS_CMD = 0x24; private static final byte INS_DEVICE_LOCKED_CMD = 0x25; private static final byte INS_EARLY_BOOT_ENDED_CMD = 0x26; + private static final byte INS_BACKUP_CMD = 0x27; + private static final byte INS_RESTORE_CMD = 0x28; // Data Dictionary items public static final byte DATA_ARRAY_SIZE = 30; @@ -200,7 +203,7 @@ protected KMKeymasterApplet() { * @param bLength the length in bytes of the parameter data in bArray */ public static void install(byte[] bArray, short bOffset, byte bLength) { - new KMKeymasterApplet(); + new KMKeymasterApplet(); } /** @@ -247,6 +250,7 @@ public void uninstall() { @Override public void process(APDU apdu) { repository.onProcess(); + //getRepository(); // Verify whether applet is in correct state. if ((keymasterState != KMKeymasterApplet.ACTIVE_STATE) && (keymasterState != KMKeymasterApplet.FIRST_SELECT_STATE)) { @@ -272,7 +276,7 @@ public void process(APDU apdu) { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } // Validate whether INS can be supported - if (!(apduIns >= INS_GENERATE_KEY_CMD && apduIns <= INS_EARLY_BOOT_ENDED_CMD)) { + if (!(apduIns >= INS_GENERATE_KEY_CMD && apduIns <= INS_RESTORE_CMD)) { ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } // Validate if INS is provision command if applet is in FIRST_SELECT_STATE. @@ -360,6 +364,12 @@ public void process(APDU apdu) { case INS_EARLY_BOOT_ENDED_CMD: processEarlyBootEndedCmd(apdu); break; + case INS_BACKUP_CMD: + processBackupCmd(apdu); + break; + case INS_RESTORE_CMD: + processRestoreCmd(apdu); + break; default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } @@ -375,6 +385,25 @@ public void process(APDU apdu) { } } + private void processRestoreCmd(APDU apdu) { + //No arguments + if(seProvider.isBackupRestoreSupported()) sendError(apdu,KMError.UNIMPLEMENTED); + byte[] data = repository.getDataTable(); + short buf = KMByteBlob.instance((short)data.length); + short len = seProvider.restore(KMByteBlob.cast(buf).getBuffer(), + KMByteBlob.cast(buf).getStartOff()); + repository.restoreData(buf); + sendError(apdu, KMError.OK); + } + + private void processBackupCmd(APDU apdu) { + // No arguments + if(seProvider.isBackupRestoreSupported()) sendError(apdu,KMError.UNIMPLEMENTED); + byte[] data = repository.getDataTable(); + seProvider.backup(data,(short)0, (short)data.length); + sendError(apdu,KMError.OK); + } + private void freeOperations(){ if(data[OP_HANDLE] != KMType.INVALID_VALUE){ KMOperationState op = repository.findOperation(KMInteger.cast(data[OP_HANDLE]).getShort()); @@ -402,13 +431,17 @@ private void processDeviceLockedCmd(APDU apdu) { data[VERIFICATION_TOKEN] = KMArray.cast(tmpVariables[0]).get((short)1); validateVerificationToken(data[VERIFICATION_TOKEN],scratchPad); short verTime = KMVerificationToken.cast(data[VERIFICATION_TOKEN]).getTimestamp(); - short lastDeviceLockedTime = KMInteger.uint_64(repository.deviceLockedTimestamp, (short)0); + //short lastDeviceLockedTime = KMInteger.uint_64(repository.deviceLockedTimestamp, (short)0); + short lastDeviceLockedTime = repository.getDeviceTimeStamp(); if(KMInteger.compare(verTime,lastDeviceLockedTime) > 0){ Util.arrayFillNonAtomic(scratchPad,(short)0, (short)8, (byte)0); KMInteger.cast(verTime).getValue(scratchPad,(short)0,(short)8); - repository.deviceLockedFlag = true; - repository.deviceUnlockPasswordOnly = (tmpVariables[1] == 0x01); - Util.arrayCopy(scratchPad,(short)0,repository.deviceLockedTimestamp,(short)0,(short)repository.deviceLockedTimestamp.length); + //repository.deviceLockedFlag = true; + repository.setDeviceLock(true); + //repository.deviceUnlockPasswordOnly = (tmpVariables[1] == 0x01); + repository.setDeviceLockPasswordOnly(tmpVariables[1] == 0x01); + //Util.arrayCopy(scratchPad,(short)0,repository.deviceLockedTimestamp,(short)0,(short)repository.deviceLockedTimestamp.length); + repository.setDeviceLockTimestamp(scratchPad,(short)0,(short)8); } sendError(apdu,KMError.OK); } @@ -606,6 +639,16 @@ private void processProvisionCmd(APDU apdu) { keymasterState = KMKeymasterApplet.ACTIVE_STATE; } } +/* + byte[] tmp = repository.getDataTable(); + seProvider.backup(tmp,(short)0,(short)data.length); + Util.arrayFillNonAtomic( + KMByteBlob.cast(tmp).getBuffer(), + KMByteBlob.cast(tmp).getStartOff(), + KMByteBlob.cast(tmp).length(),(byte)0); + seProvider.restore( + KMByteBlob.cast(tmp).getBuffer(), + KMByteBlob.cast(tmp).getStartOff());*/ sendError(apdu, KMError.OK); } @@ -684,9 +727,12 @@ private void processGetHmacSharingParamCmd(APDU apdu) { // No Arguments // Create HMAC Sharing Parameters tmpVariables[2] = KMHmacSharingParameters.instance(); + /* KMHmacSharingParameters.cast(tmpVariables[2]).setNonce( KMByteBlob.instance(repository.getHmacNonce(), (short) 0, KMRepository.HMAC_SEED_NONCE_SIZE)); + */ + KMHmacSharingParameters.cast(tmpVariables[2]).setNonce(repository.getHmacNonce()); KMHmacSharingParameters.cast(tmpVariables[2]).setSeed(KMByteBlob.instance((short)0)); // prepare the response tmpVariables[3] = KMArray.instance((short) 2); @@ -764,6 +810,7 @@ private void processComputeSharedHmacCmd(APDU apdu) { //To check if nonce created by Strongbox is found. This value becomes 1 if both //seed and nonce created here are found in hmac sharing parameters received. tmpVariables[7] = 0; + tmpVariables[9] = repository.getHmacNonce(); while (tmpVariables[2] < tmpVariables[0]) { // read HmacSharingParam @@ -782,6 +829,7 @@ private void processComputeSharedHmacCmd(APDU apdu) { tmpVariables[6]); tmpVariables[3] += tmpVariables[6]; // increment the concat index }else if(tmpVariables[7] == 0){ + // TODO according to hal specs seed should always be empty. Confirm this. //The seed we are passing is of zero length so if seed length is zero //the seed generated here is found. tmpVariables[7] = 1; @@ -804,6 +852,7 @@ private void processComputeSharedHmacCmd(APDU apdu) { // Check if the nonce generated here is present in the hmacSharingParameters array. // Otherwise throw INVALID_ARGUMENT error. if (tmpVariables[7] == 1) { + /* if (0 == Util.arrayCompare( repository.getHeap(), (short) (tmpVariables[1] + tmpVariables[3]), @@ -814,6 +863,17 @@ private void processComputeSharedHmacCmd(APDU apdu) { } else { tmpVariables[7] = 0; } + */ + if (0 == Util.arrayCompare( + repository.getHeap(), + (short) (tmpVariables[1] + tmpVariables[3]), + KMByteBlob.cast(tmpVariables[9]).getBuffer(), + KMByteBlob.cast(tmpVariables[9]).getStartOff(), + tmpVariables[6])) { + tmpVariables[7] = 2; // hmac nonce for this keymaster found. + } else { + tmpVariables[7] = 0; + } } tmpVariables[3] += tmpVariables[6]; // increment by nonce length tmpVariables[2]++; // go to next hmac param in the vector @@ -822,8 +882,11 @@ private void processComputeSharedHmacCmd(APDU apdu) { KMException.throwIt(KMError.INVALID_ARGUMENT); } // generate the key and store it in scratch pad - 32 bytes + tmpVariables[8] = repository.getSharedKey(); tmpVariables[6] = seProvider.cmacKdf( - repository.getSharedKey(), ckdfLable , + KMByteBlob.cast(tmpVariables[8]).getBuffer(), + KMByteBlob.cast(tmpVariables[8]).getStartOff(), + KMByteBlob.cast(tmpVariables[8]).length(), ckdfLable , repository.getHeap(), tmpVariables[1], tmpVariables[3],scratchPad, (short) 0); // persist the computed hmac key. repository.initComputedHmac(scratchPad, (short) 0, tmpVariables[6]); @@ -875,8 +938,8 @@ private void processUpgradeKeyCmd(APDU apdu) { tmpVariables[0] = KMIntegerTag.cast(tmpVariables[0]).getValue(); tmpVariables[1] = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.OS_PATCH_LEVEL, data[HW_PARAMETERS]); tmpVariables[1] = KMIntegerTag.cast(tmpVariables[1]).getValue(); - tmpVariables[2] = KMInteger.uint_32(repository.osVersion,(short)0); - tmpVariables[3] = KMInteger.uint_32(repository.osPatch,(short)0); + tmpVariables[2] = repository.getOsVersion(); + tmpVariables[3] = repository.getOsPatch(); tmpVariables[4] = KMInteger.uint_8((byte)0); if(tmpVariables[0] != KMType.INVALID_VALUE){ // os version in key characteristics must be less the os version stored in javacard or the @@ -927,10 +990,6 @@ private void processExportKeyCmd(APDU apdu) { } private void processImportWrappedKeyCmd(APDU apdu) { - // Currently only RAW formatted import key blob are supported - if (repository.keyBlobCount > KMRepository.MAX_BLOB_STORAGE) { - ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); - } // Receive the incoming request fully from the master into buffer. receiveIncoming(apdu); byte[] scratchPad = apdu.getBuffer(); @@ -1089,6 +1148,13 @@ private void processAttestKeyCmd(APDU apdu) { data[KEY_PARAMETERS] = KMArray.cast(args).get((short) 1); //parse key blob parseEncryptedKeyBlob(scratchPad); + //TODO This below code is added to pass one of the VTS 4.1 tests. + //TODO Need to confirm with Shawn and modify this accordingly. + tmpVariables[0] = + KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.DEVICE_UNIQUE_ATTESTATION, data[KEY_PARAMETERS]); + if(tmpVariables[0] != KMType.INVALID_VALUE) { + KMException.throwIt(KMError.UNIMPLEMENTED); + } // The key which is being attested should be asymmetric i.e. RSA or EC tmpVariables[0] = KMEnumTag.getValue(KMType.ALGORITHM, data[HW_PARAMETERS]); if(tmpVariables[0] != KMType.RSA && tmpVariables[0] != KMType.EC){ @@ -1109,8 +1175,6 @@ private void processAttestKeyCmd(APDU apdu) { KMException.throwIt(KMError.INVALID_ARGUMENT); } cert.attestationChallenge(KMByteTag.cast(tmpVariables[0]).getValue()); - // extract key characteristics - //makeKeyCharacteristics(scratchPad); // unique id byte blob - uses application id and temporal month count of creation time. tmpVariables[0] = makeUniqueId(scratchPad); cert.uniqueId(tmpVariables[0]); @@ -1139,45 +1203,51 @@ private void processAttestKeyCmd(APDU apdu) { else tmpVariables[2] = convertToDate(tmpVariables[1], scratchPad, true); } else { // if no expiry tag is present then use the attestation key certificate's expiry time // that was provisioned in the provision command. This will be in Generalized or UTC time - tmpVariables[2] = KMByteBlob.instance(repository.getCertDataBuffer(), - repository.getCertExpiryTime(),repository.getCertExpiryTimeLen()); + // tmpVariables[2] = KMByteBlob.instance(repository.getCertDataBuffer(), + // repository.getCertExpiryTime(),repository.getCertExpiryTimeLen()); + tmpVariables[2] = repository.getCertExpiryTime(); } cert.notAfter(tmpVariables[2]); -// // read att application id. -// tmpVariables[4] = KMKeyParameters.findTag(KMType.BYTES_TAG,KMType.ATTESTATION_APPLICATION_ID,data[KEY_PARAMETERS]); -// if(tmpVariables[4] != KMType.INVALID_VALUE) tmpVariables[4] = KMByteTag.cast(tmpVariables[4]).getValue(); -// else tmpVariables[4] = 0; - -// // read att challenge -// tmpVariables[5] = KMKeyParameters.findTag(KMType.BYTES_TAG,KMType.ATTESTATION_CHALLENGE,data[KEY_PARAMETERS]); -// if(tmpVariables[5] == KMType.INVALID_VALUE) KMException.throwIt(KMError.ATTESTATION_CHALLENGE_MISSING); -// tmpVariables[5] = KMByteTag.cast(tmpVariables[5]).getValue(); addAttestationIds(cert); addTags(KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getHardwareEnforced(),true,cert); addTags(KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getSoftwareEnforced(),false,cert); if(repository.getAuthKeyId() != 0){ - cert.authKey(KMByteBlob.instance( + /* cert.authKey(KMByteBlob.instance( repository.getCertDataBuffer(), repository.getAuthKeyId(), repository.getAuthKeyIdLen())); + */ cert.authKey(repository.getAuthKeyId()); } - cert.deviceLocked(repository.deviceLockedFlag); - cert.issuer( + //cert.deviceLocked(repository.deviceLockedFlag); + cert.deviceLocked(repository.getDeviceLock()); + /* cert.issuer( KMByteBlob.instance( repository.getCertDataBuffer(), repository.getIssuer(), repository.getIssuerLen())); - cert.publicKey(data[PUB_KEY]); - cert.signingKey( + + */ + cert.issuer(repository.getIssuer()); + cert.publicKey(data[PUB_KEY]); + /* cert.signingKey( KMByteBlob.instance(repository.getAttKeyExponent(),(short)0, KMRepository.ATT_KEY_EXP_SIZE), KMByteBlob.instance(repository.getAttKeyModulus(),(short)0,KMRepository.ATT_KEY_MOD_SIZE)); - cert.verifiedBootHash( - KMByteBlob.instance(repository.verifiedBootHash,(short)0,(short)repository.verifiedBootHash.length)); - cert.verifiedBootKey( - KMByteBlob.instance(repository.verifiedBootKey,(short)0,(short)repository.verifiedBootKey.length)); + */ + cert.signingKey(repository.getAttKeyExponent(),repository.getAttKeyModulus()); + //cert.verifiedBootHash( + // KMByteBlob.instance(repository.verifiedBootHash,(short)0,(short)repository.verifiedBootHash.length)); + cert.verifiedBootHash(repository.getVerifiedBootHash()); + + // cert.verifiedBootKey( + // KMByteBlob.instance(repository.verifiedBootKey,(short)0,(short)repository.verifiedBootKey.length)); + cert.verifiedBootKey(repository.getVerifiedBootKey()); + /* if(repository.selfSignedBootFlag) cert.verifiedState(KMType.SELF_SIGNED_BOOT); else if(repository.verifiedBootFlag) cert.verifiedState(KMType.VERIFIED_BOOT); else cert.verifiedState(KMType.UNVERIFIED_BOOT); + + */ + cert.verifiedState(repository.getBootState()); // buffer for cert - we allocate 2KBytes buffer // TODO make this buffer size configurable tmpVariables[3] = KMByteBlob.instance(MAX_CERT_SIZE); @@ -1186,32 +1256,32 @@ private void processAttestKeyCmd(APDU apdu) { bufferLength = KMByteBlob.cast(tmpVariables[3]).length(); cert.buffer(buffer,bufferStartOffset,bufferLength); cert.build(); -// // create X509 certificate. -// KMAttestationCertImpl.encodeCert(tmpVariables[3]/*buf*/, data[KEY_CHARACTERISTICS]/*key char*/, -// tmpVariables[0]/*unique Id*/,tmpVariables[1]/*start*/,tmpVariables[2]/*end*/, -// data[PUB_KEY]/*pub key/modulus*/,tmpVariables[5],tmpVariables[4], rsaCert); -// -// // Now sign the cert -// // Create signer -// -// //Sign the cert - returns the length of complete cert -// tmpVariables[1] = KMAttestationCertImpl.sign(seProvider,repository.getAttKeyExponent(),(short)0, KMRepository.ATT_KEY_EXP_SIZE, -// repository.getAttKeyModulus(),(short)0,KMRepository.ATT_KEY_MOD_SIZE); -// -// // Send the response back. This is slightly different we do not copy the cert blob again. -// // We just add CBOR encoding around it. -// // Encode the response -// buffer = KMAttestationCertImpl.getBuffer(); -// // add CBOR header and elements -// bufferStartOffset = encoder.encodeCert(KMAttestationCertImpl.getBuffer(), KMAttestationCertImpl.getBufferStart(), -// KMAttestationCertImpl.getCertStart(), KMAttestationCert.getCertLength()); -// bufferLength = (short)(KMAttestationCert.getCertLength() + (KMAttestationCertImpl.getCertStart()- bufferStartOffset)); bufferStartOffset = encoder.encodeCert(buffer, bufferStartOffset, cert.getCertStart(), cert.getCertLength()); bufferLength = (short)(cert.getCertLength() + (cert.getCertStart()- bufferStartOffset)); sendOutgoing(apdu); } //-------------------------------- private void addAttestationIds(KMAttestationCert cert) { + final short[] attTags = new short[]{ + KMType.ATTESTATION_ID_BRAND, + KMType.ATTESTATION_ID_DEVICE, + KMType.ATTESTATION_ID_IMEI, + KMType.ATTESTATION_ID_MANUFACTURER, + KMType.ATTESTATION_ID_MEID, + KMType.ATTESTATION_ID_MODEL, + KMType.ATTESTATION_ID_PRODUCT, + KMType.ATTESTATION_ID_SERIAL}; + byte index = 0; + short attIdTag; + while(index < (short)attTags.length){ + attIdTag = repository.getAttId(mapToAttId(attTags[index])); + if (attIdTag != 0) { + attIdTag = KMByteTag.instance(attTags[index], attIdTag); + cert.extensionTag(attIdTag, true); + } + index++; + } + /* if(repository.isAttIdSupported()){ short attTag; short blob; @@ -1228,6 +1298,7 @@ private void addAttestationIds(KMAttestationCert cert) { } } } + */ } private void addTags(short params, boolean hwEnforced, KMAttestationCert cert) { @@ -1392,13 +1463,22 @@ private short makeUniqueId(byte[] scratchPad){ // Sign - signature becomes unique id of 32 bits. Use 128 bits master key as an hmac key. tmpVariables[0] = KMByteBlob.instance((short)32); + tmpVariables[2] = repository.getMasterKeySecret(); + /* tmpVariables[1]= seProvider.hmacSign( repository.getMasterKeySecret(),(short)0, - (short)repository.getMasterKeySecret().length, + (short)repository.getMasterKeySecret(, ).length, + scratchPad,(short)0,tmpVariables[1], + KMByteBlob.cast(tmpVariables[0]).getBuffer(), + KMByteBlob.cast(tmpVariables[0]).getStartOff()); +*/ + tmpVariables[1]= seProvider.hmacSign( + KMByteBlob.cast(tmpVariables[2]).getBuffer(), + KMByteBlob.cast(tmpVariables[2]).getStartOff(), + KMByteBlob.cast(tmpVariables[2]).length(), scratchPad,(short)0,tmpVariables[1], KMByteBlob.cast(tmpVariables[0]).getBuffer(), KMByteBlob.cast(tmpVariables[0]).getStartOff()); - if(tmpVariables[1] != 32){ KMException.throwIt(KMError.UNKNOWN_ERROR); } @@ -1780,17 +1860,23 @@ private void authorizeDeviceUnlock(short hwToken) { short ptr = KMKeyParameters.findTag( KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED, data[HW_PARAMETERS]); - if (ptr != KMType.INVALID_VALUE && repository.deviceLockedFlag) { + + if (ptr != KMType.INVALID_VALUE && repository.getDeviceLock()) { if (hwToken == KMType.INVALID_VALUE) KMException.throwIt(KMError.DEVICE_LOCKED); ptr = KMHardwareAuthToken.cast(hwToken).getTimestamp(); // Check if the current auth time stamp is greater then device locked time stamp - if (KMInteger.compare(ptr, KMInteger.uint_64(repository.deviceLockedTimestamp, (short) 0)) + short ts = repository.getDeviceTimeStamp(); + /*if (KMInteger.compare(ptr, KMInteger.uint_64(repository.deviceLockedTimestamp, (short) 0)) <= 0) { KMException.throwIt(KMError.DEVICE_LOCKED); + } + */ + if (KMInteger.compare(ptr, ts) <= 0) { + KMException.throwIt(KMError.DEVICE_LOCKED); } // Now check if the device unlock requires password only authentication and whether // auth token is generated through password authentication or not. - if (repository.deviceUnlockPasswordOnly) { + if (repository.getDeviceLockPasswordOnly()) { ptr = KMHardwareAuthToken.cast(hwToken).getHwAuthenticatorType(); ptr = KMEnum.cast(ptr).getVal(); if (((byte) ptr & KMType.PASSWORD) == 0) { @@ -1798,8 +1884,10 @@ private void authorizeDeviceUnlock(short hwToken) { } } // Unlock the device - repository.deviceLockedFlag = false; - Util.arrayFillNonAtomic(repository.deviceLockedTimestamp, (short) 0, (short) 8, (byte) 0); + //repository.deviceLockedFlag = false; + repository.setDeviceLock(false); + repository.clearDeviceLockTimeStamp(); + //Util.arrayFillNonAtomic(repository.deviceLockedTimestamp, (short) 0, (short) 8, (byte) 0); } } @@ -1851,7 +1939,8 @@ private void validateVerificationToken(short verToken, byte[] scratchPad) { } // hmac the data ptr = KMVerificationToken.cast(verToken).getMac(); - boolean verified = + short key = repository.getComputedHmacKey(); + /*boolean verified = seProvider.hmacVerify(repository.getComputedHmacKey(), (short) 0, (short) repository.getComputedHmacKey().length, @@ -1859,6 +1948,18 @@ private void validateVerificationToken(short verToken, byte[] scratchPad) { KMByteBlob.cast(ptr).getBuffer(), KMByteBlob.cast(ptr).getStartOff(), KMByteBlob.cast(ptr).length()); + + */ + boolean verified = + seProvider.hmacVerify( + KMByteBlob.cast(key).getBuffer(), + KMByteBlob.cast(key).getStartOff(), + KMByteBlob.cast(key).length(), + scratchPad, (short) 0, len, + KMByteBlob.cast(ptr).getBuffer(), + KMByteBlob.cast(ptr).getStartOff(), + KMByteBlob.cast(ptr).length()); + if(!verified){ KMException.throwIt(KMError.VERIFICATION_FAILED); } @@ -2081,14 +2182,24 @@ private void beginTrustedConfirmationOperation(KMOperationState op) { KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED, data[HW_PARAMETERS]) != KMType.INVALID_VALUE) { // get operation // get the hmac key - if (repository.getComputedHmacKey() == null) { + short key = repository.getComputedHmacKey(); + if ( key == 0) { KMException.throwIt(KMError.OPERATION_CANCELLED); } + /* op.setTrustedConfirmationSigner(seProvider.initSymmetricOperation( KMType.VERIFY,KMType.HMAC,KMType.SHA2_256,(byte)0,(byte)0,repository.getComputedHmacKey(), (short) 0, (short) repository.getComputedHmacKey().length,null,(short)0,(short)0,(short)0)); + */ + op.setTrustedConfirmationSigner(seProvider.initSymmetricOperation( + KMType.VERIFY,KMType.HMAC,KMType.SHA2_256,(byte)0,(byte)0, + KMByteBlob.cast(key).getBuffer(), + KMByteBlob.cast(key).getStartOff(), + KMByteBlob.cast(key).length(),null,(short)0,(short)0,(short)0)); + op.getTrustedConfirmationSigner().update(confirmationToken,(short)0,(short)confirmationToken.length); } + } private void authorizeAlgorithm(KMOperationState op){ @@ -2531,7 +2642,8 @@ private boolean validateHwToken(short hwToken, byte[] scratchPad) { len += 8; // hmac the data ptr = KMHardwareAuthToken.cast(hwToken).getMac(); - return seProvider.hmacVerify( + short key = repository.getComputedHmacKey(); + /*return seProvider.hmacVerify( repository.getComputedHmacKey(), (short) 0, (short) repository.getComputedHmacKey().length, @@ -2539,7 +2651,15 @@ private boolean validateHwToken(short hwToken, byte[] scratchPad) { KMByteBlob.cast(ptr).getBuffer(), KMByteBlob.cast(ptr).getStartOff(), KMByteBlob.cast(ptr).length()); - + */ + return seProvider.hmacVerify( + KMByteBlob.cast(key).getBuffer(), + KMByteBlob.cast(key).getStartOff(), + KMByteBlob.cast(key).length(), + scratchPad, (short) 0, len, + KMByteBlob.cast(ptr).getBuffer(), + KMByteBlob.cast(ptr).getStartOff(), + KMByteBlob.cast(ptr).length()); } private void authorizeKeyUsageForCount() { @@ -2561,9 +2681,6 @@ private void authorizeKeyUsageForCount() { } private void processImportKeyCmd(APDU apdu) { - if (repository.keyBlobCount > KMRepository.MAX_BLOB_STORAGE) { - ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); - } // Receive the incoming request fully from the master into buffer. receiveIncoming(apdu); byte[] scratchPad = apdu.getBuffer(); @@ -2631,6 +2748,11 @@ private void importKey(APDU apdu, byte[] scratchPad) { createEncryptedKeyBlob(scratchPad); tmpVariables[0] = KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.MAX_USES_PER_BOOT, data[KEY_PARAMETERS]); if (tmpVariables[0] != KMType.INVALID_VALUE){ + // before generating key, check whether max count reached + if (repository.getKeyBlobCount() > KMRepository.MAX_BLOB_STORAGE) { + //TODO which error to return? + KMException.throwIt(KMError.UNKNOWN_ERROR); + } repository.persistAuthTag(data[AUTH_TAG]); } @@ -2988,19 +3110,40 @@ private void processSetBootParamsCmd(APDU apdu) { KMException.throwIt(KMError.INVALID_ARGUMENT); } // Begin transaction - JCSystem.beginTransaction(); - KMInteger.cast(tmpVariables[0]).value(repository.osVersion, (short) 0); - KMInteger.cast(tmpVariables[1]).value(repository.osPatch, (short) 0); + // JCSystem.beginTransaction(); + repository.setOsVersion(KMInteger.cast(tmpVariables[0]).getBuffer(), + KMInteger.cast(tmpVariables[0]).getStartOff(), + KMInteger.cast(tmpVariables[0]).length()); + repository.setOsPatch(KMInteger.cast(tmpVariables[1]).getBuffer(), + KMInteger.cast(tmpVariables[1]).getStartOff(), + KMInteger.cast(tmpVariables[1]).length()); + //KMInteger.cast(tmpVariables[0]).value(repository.osVersion, (short) 0); + //KMInteger.cast(tmpVariables[1]).value(repository.osPatch, (short) 0); + //KMInteger.cast(valPtr).getValue(repository.osVersion, (short) 0, (short) 4); //valPtr = KMIntegerTag.cast(tmpVariables[1]).getValue(); //KMInteger.cast(valPtr).getValue(repository.osPatch, (short) 0, (short) 4); - repository.actualBootKeyLength = KMByteBlob.cast(tmpVariables[2]).length(); - KMByteBlob.cast(tmpVariables[2]) - .getValue(repository.verifiedBootKey, (short) 0, repository.actualBootKeyLength); - repository.actualBootHashLength = KMByteBlob.cast(tmpVariables[3]).length(); - KMByteBlob.cast(tmpVariables[3]) - .getValue(repository.verifiedBootHash, (short) 0, repository.actualBootHashLength); + + //repository.actualBootKeyLength = KMByteBlob.cast(tmpVariables[2]).length(); + //KMByteBlob.cast(tmpVariables[2]) + // .getValue(repository.verifiedBootKey, (short) 0, repository.actualBootKeyLength); + repository.setVerifiedBootKey( + KMByteBlob.cast(tmpVariables[2]).getBuffer(), + KMByteBlob.cast(tmpVariables[2]).getStartOff(), + KMByteBlob.cast(tmpVariables[2]).length()); + + //repository.actualBootHashLength = KMByteBlob.cast(tmpVariables[3]).length(); + //KMByteBlob.cast(tmpVariables[3]) + // .getValue(repository.verifiedBootHash, (short) 0, repository.actualBootHashLength); + repository.setVerifiedBootHash( + KMByteBlob.cast(tmpVariables[3]).getBuffer(), + KMByteBlob.cast(tmpVariables[3]).getStartOff(), + KMByteBlob.cast(tmpVariables[3]).length() + ); + byte enumVal = KMEnum.cast(tmpVariables[4]).getVal(); + repository.setBootState(enumVal); + /* if (enumVal == KMTag.SELF_SIGNED_BOOT) { repository.selfSignedBootFlag = true; repository.verifiedBootFlag = false; @@ -3011,8 +3154,11 @@ private void processSetBootParamsCmd(APDU apdu) { repository.selfSignedBootFlag = false; repository.verifiedBootFlag = false; } + + */ enumVal = KMEnum.cast(tmpVariables[5]).getVal(); - repository.deviceLockedFlag = (enumVal == KMType.DEVICE_LOCKED_TRUE); + //repository.deviceLockedFlag = (enumVal == KMType.DEVICE_LOCKED_TRUE); + repository.setDeviceLock(enumVal == KMType.DEVICE_LOCKED_TRUE); if (keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { setBootParamsDone = true; if (provisionDone) { @@ -3020,14 +3166,10 @@ private void processSetBootParamsCmd(APDU apdu) { } } // end transaction - JCSystem.commitTransaction(); + //JCSystem.commitTransaction(); } private static void processGenerateKey(APDU apdu) { - // before generating key, check whether max count reached - if (repository.keyBlobCount > KMRepository.MAX_BLOB_STORAGE) { - ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); - } // Receive the incoming request fully from the master into buffer. receiveIncoming(apdu); // Re-purpose the apdu buffer as scratch pad. @@ -3040,6 +3182,12 @@ private static void processGenerateKey(APDU apdu) { // Decode the argument tmpVariables[2] = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); data[KEY_PARAMETERS] = KMArray.cast(tmpVariables[2]).get((short) 0); + //Check if EarlyBootEnded tag is present. + tmpVariables[0] = + KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.EARLY_BOOT_ENDED, data[KEY_PARAMETERS]); + if(tmpVariables[0] != KMType.INVALID_VALUE) { + KMException.throwIt(KMError.EARLY_BOOT_ENDED); + } //Check if rollback resistance tag is present tmpVariables[0] = KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.ROLLBACK_RESISTANCE, data[KEY_PARAMETERS]); @@ -3090,6 +3238,11 @@ private static void processGenerateKey(APDU apdu) { tmpVariables[0] = KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.MAX_USES_PER_BOOT, data[KEY_PARAMETERS]); if (tmpVariables[0] != KMType.INVALID_VALUE){ + // before generating key, check whether max count reached + if (repository.getKeyBlobCount() > KMRepository.MAX_BLOB_STORAGE) { + //TODO which error to return? + KMException.throwIt(KMError.UNKNOWN_ERROR); + } repository.persistAuthTag(data[AUTH_TAG]); } @@ -3310,6 +3463,20 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { tmpVariables[0] = KMIntegerTag.getValue( scratchPad, (short) 0, KMType.UINT_TAG, KMType.OS_VERSION, data[HW_PARAMETERS]); + if (tmpVariables[0] != KMType.INVALID_VALUE){ + tmpVariables[1] = repository.getOsVersion(); + tmpVariables[1] = Util.arrayCompare( + KMInteger.cast(tmpVariables[1]).getBuffer(), + KMInteger.cast(tmpVariables[1]).getStartOff(), + scratchPad, (short) 0, tmpVariables[0]); + if(tmpVariables[1] == -1){ + // If the key characteristics has os version > current os version + KMException.throwIt(KMError.INVALID_KEY_BLOB); + }else if(tmpVariables[1] == 1){ + KMException.throwIt(KMError.KEY_REQUIRES_UPGRADE); + } + } + /* if ((tmpVariables[0] != KMType.INVALID_VALUE) && (Util.arrayCompare( repository.osVersion, (short) 0, scratchPad, (short) 0, tmpVariables[0]) @@ -3322,10 +3489,23 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { KMException.throwIt(KMError.KEY_REQUIRES_UPGRADE); } } + */ tmpVariables[0] = KMIntegerTag.getValue( scratchPad, (short) 0, KMType.UINT_TAG, KMType.OS_PATCH_LEVEL, data[HW_PARAMETERS]); - if ((tmpVariables[0] != KMType.INVALID_VALUE) + if (tmpVariables[0] != KMType.INVALID_VALUE){ + tmpVariables[1] = repository.getOsPatch(); + tmpVariables[1] = Util.arrayCompare( + KMInteger.cast(tmpVariables[1]).getBuffer(), + KMInteger.cast(tmpVariables[1]).getStartOff(), + scratchPad, (short) 0, tmpVariables[0]); + if(tmpVariables[1] == -1){ + KMException.throwIt(KMError.INVALID_KEY_BLOB); + }else if(tmpVariables[1] == 1){ + KMException.throwIt(KMError.KEY_REQUIRES_UPGRADE); + } + } + /*if ((tmpVariables[0] != KMType.INVALID_VALUE) && (Util.arrayCompare(repository.osPatch, (short) 0, scratchPad, (short) 0, tmpVariables[0]) != 0)) { if (Util.arrayCompare(repository.osPatch, (short) 0, scratchPad, (short) 0, tmpVariables[0]) @@ -3336,13 +3516,12 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { KMException.throwIt(KMError.KEY_REQUIRES_UPGRADE); } } + */ } private static void makeKeyCharacteristics(byte[] scratchPad) { - tmpVariables[0] = - KMInteger.instance(repository.osPatch, (short) 0, (short) repository.osPatch.length); - tmpVariables[1] = - KMInteger.instance(repository.osVersion, (short) 0, (short) repository.osVersion.length); + tmpVariables[0] = repository.getOsPatch(); + tmpVariables[1] = repository.getOsVersion(); data[HW_PARAMETERS] = KMKeyParameters.makeHwEnforced( data[KEY_PARAMETERS], @@ -3360,9 +3539,11 @@ private static void createEncryptedKeyBlob(byte[] scratchPad) { // make key characteristics - returns key characteristics in data[KEY_CHARACTERISTICS] makeKeyCharacteristics(scratchPad); // make root of trust blob - data[ROT] = - KMByteBlob.instance( - repository.verifiedBootKey, (short) 0, (short) repository.verifiedBootKey.length); + //data[ROT] = + // KMByteBlob.instance( + // repository.verifiedBootKey, (short) 0, (short) repository.verifiedBootKey.length); + data[ROT] = repository.getVerifiedBootKey(); + // make hidden key params list data[HIDDEN_PARAMETERS] = KMKeyParameters.makeHidden(data[KEY_PARAMETERS], data[ROT], scratchPad); @@ -3419,9 +3600,11 @@ private static void parseEncryptedKeyBlob(byte[] scratchPad) { data[SW_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getSoftwareEnforced(); // make root of trust blob - data[ROT] = - KMByteBlob.instance( - repository.verifiedBootKey, (short) 0, (short) repository.verifiedBootKey.length); + //data[ROT] = + // KMByteBlob.instance( + // repository.verifiedBootKey, (short) 0, (short) repository.verifiedBootKey.length); + data[ROT] = repository.getVerifiedBootKey(); + data[HIDDEN_PARAMETERS] = KMKeyParameters.makeHidden(data[APP_ID], data[APP_DATA], data[ROT], scratchPad); // make auth data @@ -3549,7 +3732,7 @@ private static short deriveKey(byte[] scratchPad) { // generate derivation material from hidden parameters tmpVariables[2] = encoder.encode(tmpVariables[0], repository.getHeap(), tmpVariables[1]); // create derived key i.e. MAC - tmpVariables[3] = +/* tmpVariables[3] = seProvider.aesCCMSign( repository.getHeap(), tmpVariables[1], @@ -3557,7 +3740,19 @@ private static short deriveKey(byte[] scratchPad) { repository.getMasterKeySecret(), scratchPad, (short) 0); - if (tmpVariables[3] < 0) { +*/ + tmpVariables[4] = repository.getMasterKeySecret(); + tmpVariables[3] = + seProvider.aesCCMSign( + repository.getHeap(), + tmpVariables[1], + tmpVariables[2], + KMByteBlob.cast(tmpVariables[4]).getBuffer(), + KMByteBlob.cast(tmpVariables[4]).getStartOff(), + KMByteBlob.cast(tmpVariables[4]).length(), + scratchPad, + (short) 0); + if (tmpVariables[3] < 0) { KMException.throwIt(KMError.UNKNOWN_ERROR); } // store the derived secret in data dictionary @@ -3572,7 +3767,6 @@ private static void sendError(APDU apdu, short err) { sendOutgoing(apdu); } - private short addIntegers(short num1, short num2){ short buf = repository.alloc((short)24); byte[] scratchPad = repository.getHeap(); @@ -3588,6 +3782,7 @@ private short addIntegers(short num1, short num2){ add(scratchPad, buf, (short)(buf+8), (short)(buf+16)); return KMInteger.uint_64(scratchPad,(short)(buf+16)); } + /* // num1 must be greater then or equal to num2 and both must be positive private short subtractIntegers(short num1, short num2){ @@ -3607,8 +3802,8 @@ private short subtractIntegers(short num1, short num2){ subtract(scratchPad,buf,(short)(buf+8),(short)(buf+16)); return KMInteger.uint_64(scratchPad,(short)(buf+16)); } - */ + private void add(byte[] buf, short op1, short op2, short result){ byte index = 7; byte carry = 0; @@ -3642,7 +3837,8 @@ private void subtract(byte[] buf, short op1, short op2, short result) { index--; } } - // use Euclid's formula: dividend = quotient*divisor + remainder + + // Use Euclid's formula: dividend = quotient*divisor + remainder // i.e. dividend - quotient*divisor = remainder where remainder < divisor. // so this is division by subtraction until remainder remains. private short divide(byte [] buf, short dividend, short divisor, short remainder){ @@ -3674,6 +3870,7 @@ private void copy(byte[] buf, short from, short to){ private byte compare(byte[] buf, short lhs, short rhs){ return Util.arrayCompare(buf,lhs,buf,rhs,(short)8); } + private void shiftLeft(byte[] buf, short start){ byte index = 7; byte carry = 0; @@ -3702,4 +3899,5 @@ private void shiftRight(byte[] buf, short start) { index++; } } + } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterStore.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterStore.java new file mode 100644 index 00000000..ed9286f6 --- /dev/null +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterStore.java @@ -0,0 +1,9 @@ +package com.android.javacard.keymaster; + +public interface KMKeymasterStore { + short getMasterKeySecret(byte[] buf, short start); + void createDocument(byte documentId, byte[]buf, short start, short len); + void updateData(byte documentId, short keyId, byte[]buf, short start, short len); + short getData(byte documentId, short keyId, byte[] buf, short start); + short getDocument(byte documentId, byte[] buf, short start); +} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java index 28bdda45..31494dd6 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -22,146 +22,97 @@ import javacard.framework.Util; public class KMRepository { - //TODO make the sizes configurable - public static final short INVALID_VALUE = (short) 0x8000; - public static final short HEAP_SIZE = 10000; - public static final short MAX_BLOB_STORAGE = 8; - public static final short AES_GCM_AUTH_TAG_LENGTH = 12; + // Data table configuration + public static final short DATA_INDEX_SIZE = 32; + public static final short DATA_INDEX_ENTRY_SIZE = 4; + public static final short DATA_MEM_SIZE = 2048; + public static final short DATA_INDEX_ENTRY_LENGTH = 0; + public static final short DATA_INDEX_ENTRY_OFFSET = 2; + + // Data table offsets + public static final byte MASTER_KEY = 8; + public static final byte SHARED_KEY = 9; + public static final byte COMPUTED_HMAC_KEY = 10; + public static final byte HMAC_NONCE = 11; + public static final byte ATT_ID_BRAND = 0; + public static final byte ATT_ID_DEVICE = 1; + public static final byte ATT_ID_PRODUCT = 2; + public static final byte ATT_ID_SERIAL = 3; + public static final byte ATT_ID_IMEI = 4; + public static final byte ATT_ID_MEID = 5; + public static final byte ATT_ID_MANUFACTURER = 6; + public static final byte ATT_ID_MODEL = 7; + public static final byte ATT_EXPONENT = 12; + public static final byte ATT_MODULUS = 13; + public static final byte CERT_AUTH_KEY_ID = 14; + public static final byte CERT_ISSUER = 15; + public static final byte CERT_EXPIRY_TIME = 16; + public static final byte BOOT_OS_VERSION = 17; + public static final byte BOOT_OS_PATCH = 18; + public static final byte BOOT_VERIFIED_BOOT_KEY = 19; + public static final byte BOOT_VERIFIED_BOOT_HASH = 20; + public static final byte BOOT_VERIFIED_BOOT_STATE = 21; + public static final byte BOOT_DEVICE_LOCKED_STATUS = 22; + public static final byte BOOT_DEVICE_LOCKED_TIME = 23; + public static final byte AUTH_TAG_1 = 24; + public static final byte AUTH_TAG_2 = 25; + public static final byte AUTH_TAG_3 = 26; + public static final byte AUTH_TAG_4 = 27; + public static final byte AUTH_TAG_5 = 28; + public static final byte AUTH_TAG_6 = 29; + public static final byte AUTH_TAG_7 = 30; + public static final byte AUTH_TAG_8 = 31; + + // Data Item sizes public static final short MASTER_KEY_SIZE = 16; public static final short SHARED_SECRET_KEY_SIZE = 32; - public static final short HMAC_SEED_NONCE_SIZE = 32; - public static final short MAX_OPS = 4; - public static final short COMPUTED_HMAC_KEY_SIZE = 32; - public static final short ATT_ID_HEAP_SIZE = 160; - public static final short CERT_DATA_MEM_SIZE = 256; - // Key Attestation related constants - public static final byte ATT_ID_TABLE_SIZE = 8; - public static final byte ATT_ID_HEADER_SIZE = 3; public static final short ATT_KEY_MOD_SIZE = 256; public static final short ATT_KEY_EXP_SIZE = 256; - public static final byte ATT_ID_OFFSET = 0x02; - public static final byte ATT_ID_LENGTH = 0x01; - public static final byte ATT_ID_TAG = 0x00; - public static final byte ATT_ID_BRAND = 0x00; - public static final byte ATT_ID_DEVICE = 0x01; - public static final byte ATT_ID_PRODUCT = 0x02; - public static final byte ATT_ID_SERIAL = 0x03; - public static final byte ATT_ID_IMEI = 0x04; - public static final byte ATT_ID_MEID = 0x05; - public static final byte ATT_ID_MANUFACTURER = 0x06; - public static final byte ATT_ID_MODEL = 0x07; - final short[] attIdTags ={ - KMType.ATTESTATION_ID_BRAND, - KMType.ATTESTATION_ID_DEVICE, - KMType.ATTESTATION_ID_PRODUCT, - KMType.ATTESTATION_ID_SERIAL, - KMType.ATTESTATION_ID_IMEI, - KMType.ATTESTATION_ID_MEID, - KMType.ATTESTATION_ID_MANUFACTURER, - KMType.ATTESTATION_ID_MODEL}; - public byte[] attestCertIssuer; - public byte[] attestCertAuthKeyId; + public static final short HMAC_SEED_NONCE_SIZE = 32; + public static final short COMPUTED_HMAC_KEY_SIZE = 32; + public static final short OS_VERSION_SIZE = 4; + public static final short OS_PATCH_SIZE = 4; + public static final short DEVICE_LOCK_TS_SIZE = 8; + public static final short DEVICE_LOCK_FLAG_SIZE = 1; + public static final short BOOT_STATE_SIZE = 1; + public static final short MAX_BLOB_STORAGE = 8; + public static final short AUTH_TAG_LENGTH = 12; + public static final short AUTH_TAG_ENTRY_SIZE = 14; + public static final short HEAP_SIZE = 10000; + public static final short MAX_OPS = 4; + + // Operation State Table + private Object[] operationStateTable; + private static short opIdCounter; + // Boot params constants public static final byte BOOT_KEY_MAX_SIZE = 32; public static final byte BOOT_HASH_MAX_SIZE = 32; - // Repository attributes - private static KMRepository repository; - public boolean deviceUnlockPasswordOnly; - private byte[] masterKey; - private byte[] sharedKey; - private byte[] computedHmacKey; - private byte[] hmacNonce; + // Volatile memory heap private byte[] heap; private short heapIndex; + private byte[] dataTable; + private short dataIndex; - //Attestation Id Table; - private Object[] attIdTable; - - // Operation State Table - private Object[] operationStateTable; - private static short opIdCounter; - - // boot parameters - //TODO change the following into private - public Object[] authTagRepo; - public short keyBlobCount; - public byte[] osVersion; - public byte[] osPatch; - public byte[] verifiedBootKey; - public short actualBootKeyLength; - public byte[] verifiedBootHash; - public short actualBootHashLength; - public boolean verifiedBootFlag; - public boolean selfSignedBootFlag; - public boolean deviceLockedFlag; - public byte[] deviceLockedTimestamp; - // attestation - private byte[] attKeyModulus; - private byte[] attKeyExponent; - private byte[] attIdMem; - private short attIdMemIndex; - // attestation cert data - private byte[] certData; - private short issuer; - private short issuerLen; - private short certExpiryTime; - private short certExpiryTimeLen; - private short authKeyId; - private short authKeyIdLen; - private short certDataIndex; - private boolean attIdSupported; + private static KMRepository repository; public static KMRepository instance() { return repository; } public KMRepository() { + newDataTable(); heap = JCSystem.makeTransientByteArray(HEAP_SIZE, JCSystem.CLEAR_ON_RESET); heapIndex = 0; - attIdMem = new byte[ATT_ID_HEAP_SIZE]; - attIdMemIndex = 0; - - authTagRepo = new Object[MAX_BLOB_STORAGE]; - short index = 0; - while (index < MAX_BLOB_STORAGE) { - authTagRepo[index] = new KMAuthTag(); - ((KMAuthTag) authTagRepo[index]).reserved = false; - ((KMAuthTag) authTagRepo[index]).authTag = new byte[AES_GCM_AUTH_TAG_LENGTH]; - ((KMAuthTag) authTagRepo[index]).usageCount = 0; - index++; - } - - osVersion = new byte[4]; - osPatch = new byte[4]; - verifiedBootKey = new byte[BOOT_KEY_MAX_SIZE]; - verifiedBootHash = new byte[BOOT_HASH_MAX_SIZE]; operationStateTable = new Object[MAX_OPS]; - index = 0; + byte index = 0; while(index < MAX_OPS){ operationStateTable[index] = new Object[]{new byte[2], new Object[] {new byte[KMOperationState.MAX_DATA], new Object[KMOperationState.MAX_REFS]}}; index++; } - deviceLockedFlag = false; - deviceLockedTimestamp = new byte[8]; - deviceUnlockPasswordOnly = false; - Util.arrayFillNonAtomic(deviceLockedTimestamp,(short)0,(short)8,(byte)0); - - attKeyModulus = new byte[ATT_KEY_MOD_SIZE]; - attKeyExponent = new byte[ATT_KEY_EXP_SIZE]; - attIdTable = new Object[ATT_ID_TABLE_SIZE]; - attIdSupported = false; - index = 0; - while(index < ATT_ID_TABLE_SIZE){ - attIdTable[index] = new short[ATT_ID_HEADER_SIZE]; - ((short[])attIdTable[index])[ATT_ID_TAG] = attIdTags[index]; - ((short[])attIdTable[index])[ATT_ID_LENGTH] = 0; - index++; - } - certData = new byte[CERT_DATA_MEM_SIZE]; - certDataIndex = 0; repository = this; } @@ -182,7 +133,6 @@ public KMOperationState reserveOperation(){ while(index < MAX_OPS){ opId = (byte[])((Object[])operationStateTable[index])[0]; if(Util.getShort(opId,(short)0) == 0){ - //Util.setShort(opId, (short)0,getOpId()); return KMOperationState.instance(/*Util.getShort(opId,(short)0)*/getOpId(),(Object[])((Object[])operationStateTable[index])[1]); } index++; @@ -190,6 +140,7 @@ public KMOperationState reserveOperation(){ return null; } + //TODO refactor following method public void persistOperation(byte[] data, short opHandle, KMOperation op, KMOperation hmacSigner) { short index = 0; byte[] opId; @@ -208,6 +159,7 @@ public void persistOperation(byte[] data, short opHandle, KMOperation op, KMOper } index++; } + index = 0; //Persist a new operation. while(index < MAX_OPS){ @@ -241,6 +193,7 @@ private short getOpId() { } return opIdCounter; } + public void releaseOperation(KMOperationState op){ short index = 0; byte[] var; @@ -254,54 +207,31 @@ public void releaseOperation(KMOperationState op){ index++; } } + public void initMasterKey(byte[] key, short len) { - if (masterKey == null) { - masterKey = new byte[MASTER_KEY_SIZE]; - if(len != MASTER_KEY_SIZE) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - Util.arrayCopy(key, (short) 0, masterKey, (short) 0, len); - } + if(len != MASTER_KEY_SIZE) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + writeDataEntry(MASTER_KEY,key, (short)0, len); } public void initHmacSharedSecretKey(byte[] key, short start, short len) { - if (sharedKey == null) { - sharedKey = new byte[SHARED_SECRET_KEY_SIZE]; - } if(len != SHARED_SECRET_KEY_SIZE) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - Util.arrayCopy(key, start, sharedKey, (short) 0, len); + writeDataEntry(SHARED_KEY,key,start,len); } public void initComputedHmac(byte[] key, short start, short len) { - if (computedHmacKey == null) { - computedHmacKey = new byte[COMPUTED_HMAC_KEY_SIZE]; - } if(len != COMPUTED_HMAC_KEY_SIZE) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - Util.arrayCopy(key, (short) 0, computedHmacKey, start, len); + writeDataEntry(COMPUTED_HMAC_KEY,key,start,len); } public void initHmacNonce(byte[] nonce, short offset, short len) { - if (hmacNonce == null) { - hmacNonce = new byte[HMAC_SEED_NONCE_SIZE]; - } - if (len != HMAC_SEED_NONCE_SIZE) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - Util.arrayCopy(nonce, offset, hmacNonce, (short) 0, len); - } - /* TODO according to hal specs seed should always be empty. - Confirm this before removing the code as it is also specified that keymasterdevice with storage - must store and return the seed. - public void initHmacSeed(byte[] seed, short len) { - if (hmacSeed == null) { - hmacSeed = new byte[HMAC_SEED_NONCE_SIZE]; + if (len != HMAC_SEED_NONCE_SIZE) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH);} + writeDataEntry(HMAC_NONCE,nonce,offset,len); } - if(len != HMAC_SEED_NONCE_SIZE) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - Util.arrayCopy(seed, (short) 0, hmacSeed, (short) 0, len); - } -*/ + public void onUninstall() { - // TODO change this - Util.arrayFillNonAtomic(masterKey, (short) 0, (short) masterKey.length, (byte) 0); + // Javacard Runtime environment cleans up the data. + } public void onProcess() {} @@ -313,10 +243,12 @@ public void clean() { public void onDeselect() {} - public void onSelect() {} + public void onSelect() { + // If write through caching is implemented then this method will restore the data into cache + } - public byte[] getMasterKeySecret() { - return masterKey; + public short getMasterKeySecret() { + return readData(MASTER_KEY); } public short alloc(short length) { @@ -327,266 +259,369 @@ public short alloc(short length) { return (short) (heapIndex - length); } - public byte[] getHeap() { - return heap; + private short dataAlloc(short length) { + if (((short) (dataIndex + length)) > dataTable.length) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } + dataIndex += length; + return (short) (dataIndex - length); + } + + + private void newDataTable(){ + if(dataTable == null) { + dataTable = new byte[DATA_MEM_SIZE]; + dataIndex = (short)(DATA_INDEX_SIZE*DATA_INDEX_ENTRY_SIZE); + } + } + + public void restoreData(short blob){ + JCSystem.beginTransaction(); + Util.arrayCopy( + KMByteBlob.cast(blob).getBuffer(),KMByteBlob.cast(blob).getStartOff(),dataTable,(short)0, + KMByteBlob.cast(blob).length() + ); + JCSystem.commitTransaction(); + } + + public byte[] getDataTable(){ + return dataTable; + } + + private void clearDataEntry(short id){ + JCSystem.beginTransaction(); + id = (short)(id * DATA_INDEX_ENTRY_SIZE); + short dataLen = Util.getShort(dataTable,(short)(id+DATA_INDEX_ENTRY_LENGTH)); + if (dataLen != 0) { + short dataPtr = Util.getShort(dataTable,(short)(id+DATA_INDEX_ENTRY_OFFSET)); + Util.arrayFillNonAtomic(dataTable, dataPtr,dataLen,(byte)0); + Util.arrayFillNonAtomic(dataTable, id,DATA_INDEX_ENTRY_SIZE,(byte)0); + } + JCSystem.commitTransaction(); + } + + private void writeDataEntry(short id, byte[] buf, short offset, short len) { + JCSystem.beginTransaction(); + short dataPtr; + id = (short)(id * DATA_INDEX_ENTRY_SIZE); + short dataLen = Util.getShort(dataTable,(short)(id+DATA_INDEX_ENTRY_LENGTH)); + if (dataLen == 0) { + dataPtr = dataAlloc(len); + Util.setShort(dataTable,(short)(id+DATA_INDEX_ENTRY_OFFSET),dataPtr); + Util.setShort(dataTable,(short)(id+DATA_INDEX_ENTRY_LENGTH),len); + Util.arrayCopyNonAtomic(buf, offset,dataTable,dataPtr, len); + } else { + if(len != dataLen) KMException.throwIt(KMError.UNKNOWN_ERROR); + dataPtr = Util.getShort(dataTable,(short)(id+DATA_INDEX_ENTRY_OFFSET)); + Util.arrayCopyNonAtomic(buf, offset,dataTable,dataPtr, len); + } + JCSystem.commitTransaction(); + } + + private short readDataEntry(short id, byte[] buf, short offset){ + id = (short)(id * DATA_INDEX_ENTRY_SIZE); + short len = Util.getShort(dataTable,(short)(id+DATA_INDEX_ENTRY_LENGTH)); + if (len != 0) { + Util.arrayCopyNonAtomic( + dataTable, + Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET)), + buf, + offset, + len); + } + return len; } - public byte[] getSharedKey() { - return sharedKey; + private short dataLength(short id){ + id = (short)(id * DATA_INDEX_ENTRY_SIZE); + return Util.getShort(dataTable,(short)(id+DATA_INDEX_ENTRY_LENGTH)); } - public byte[] getHmacNonce() { - return hmacNonce; + public byte[] getHeap() { + return heap; } - public void setHmacNonce(byte[] hmacNonce) { - Util.arrayCopy(hmacNonce, (short) 0, this.hmacNonce, (short) 0, HMAC_SEED_NONCE_SIZE); + + public short getSharedKey() { + return readData(SHARED_KEY); } - public byte[] getComputedHmacKey() { - return computedHmacKey; + + public short getHmacNonce() { + return readData(HMAC_NONCE); } - public void setComputedHmacKey(byte[] computedHmacKey) { - Util.arrayCopy( computedHmacKey, (short) 0, this.computedHmacKey, (short) 0, COMPUTED_HMAC_KEY_SIZE); + public short getComputedHmacKey() { + return readData(COMPUTED_HMAC_KEY); } public void persistAuthTag(short authTag) { + if(KMByteBlob.cast(authTag).length() != AUTH_TAG_LENGTH)KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + short authTagEntry = alloc(AUTH_TAG_ENTRY_SIZE); + Util.arrayCopyNonAtomic( + KMByteBlob.cast(authTag).getBuffer(), + KMByteBlob.cast(authTag).getStartOff(), + getHeap(),authTagEntry, AUTH_TAG_LENGTH); + Util.setShort(getHeap(),(short)(authTagEntry+AUTH_TAG_LENGTH),(short)0); short index = 0; while (index < MAX_BLOB_STORAGE) { - if (!((KMAuthTag) authTagRepo[index]).reserved) { + if(dataLength((short)(index+AUTH_TAG_1)) == 0){ JCSystem.beginTransaction(); - ((KMAuthTag) authTagRepo[index]).reserved = true; - Util.arrayCopy( - KMByteBlob.cast(authTag).getBuffer(), - KMByteBlob.cast(authTag).getStartOff(), - ((KMAuthTag) authTagRepo[index]).authTag , - (short) 0, - AES_GCM_AUTH_TAG_LENGTH); - keyBlobCount++; + writeDataEntry((short)(index+AUTH_TAG_1), + KMByteBlob.cast(authTagEntry).getBuffer(), + KMByteBlob.cast(authTagEntry).getStartOff(), + AUTH_TAG_ENTRY_SIZE); JCSystem.commitTransaction(); - break; } index++; } } public boolean validateAuthTag(short authTag) { - KMAuthTag tag = findTag(authTag); - return tag != null; + short tag = findTag(authTag); + return tag !=KMType.INVALID_VALUE; } public void removeAuthTag(short authTag) { - KMAuthTag tag = findTag(authTag); - if(tag == null){ - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } - JCSystem.beginTransaction(); - tag.reserved = false; - short index = 0; - while(index < AES_GCM_AUTH_TAG_LENGTH){ - tag.authTag[index] = 0; - index++; - } - tag.usageCount = 0; - keyBlobCount--; - JCSystem.commitTransaction(); + short tag = findTag(authTag); + if(tag ==KMType.INVALID_VALUE) KMException.throwIt(KMError.UNKNOWN_ERROR); + clearDataEntry(tag); } public void removeAllAuthTags() { JCSystem.beginTransaction(); - KMAuthTag tag; short index = 0; - short i; while (index < MAX_BLOB_STORAGE) { - tag = (KMAuthTag) authTagRepo[index]; - tag.reserved = false; - i = 0; - while(i < AES_GCM_AUTH_TAG_LENGTH){ - tag.authTag[i] = 0; - i++; - } - tag.usageCount = 0; + clearDataEntry((short)(index+AUTH_TAG_1)); index++; } - keyBlobCount = 0; - JCSystem.commitTransaction(); } - private KMAuthTag findTag(short authTag) { + private short findTag(short authTag) { + if(KMByteBlob.cast(authTag).length() != AUTH_TAG_LENGTH)KMException.throwIt(KMError.INVALID_INPUT_LENGTH); short index = 0; + short authTagEntry; short found; while (index < MAX_BLOB_STORAGE) { - if (((KMAuthTag) authTagRepo[index]).reserved) { + if (dataLength((short)(index+AUTH_TAG_1)) != 0) { + authTagEntry = readData((short)(index+AUTH_TAG_1)); found = - Util.arrayCompare( - ((KMAuthTag) authTagRepo[index]).authTag, - (short) 0, - KMByteBlob.cast(authTag).getBuffer(), - KMByteBlob.cast(authTag).getStartOff(), - AES_GCM_AUTH_TAG_LENGTH); - if (found == 0) { - return (KMAuthTag) authTagRepo[index]; - } + Util.arrayCompare( + KMByteBlob.cast(authTagEntry).getBuffer(), + KMByteBlob.cast(authTagEntry).getStartOff(), + KMByteBlob.cast(authTag).getBuffer(), + KMByteBlob.cast(authTag).getStartOff(), + AUTH_TAG_LENGTH); + if(found == 0)return (short)(index+AUTH_TAG_1); } index++; } - return null; + return KMType.INVALID_VALUE; } public short getRateLimitedKeyCount(short authTag) { - KMAuthTag tag = findTag(authTag); - if (tag != null) { - return tag.usageCount; + short tag = findTag(authTag); + short blob; + if (tag != KMType.INVALID_VALUE) { + blob = readData(tag); + return Util.getShort(KMByteBlob.cast(blob).getBuffer(), + (short)(KMByteBlob.cast(blob).getStartOff()+AUTH_TAG_LENGTH)); } return KMType.INVALID_VALUE; } public void setRateLimitedKeyCount(short authTag, short val) { - KMAuthTag tag = findTag(authTag); - JCSystem.beginTransaction(); - if (tag != null) { - tag.usageCount = val; + short tag = findTag(authTag); + short blob; + if (tag != KMType.INVALID_VALUE) { + blob = alloc((short)2); + Util.setShort(getHeap(),blob,val); + writeDataEntry(tag,getHeap(), blob,(short)2); } - JCSystem.commitTransaction(); } public void persistAttestationKey(short mod, short exp) { - JCSystem.beginTransaction(); - if(KMByteBlob.cast(mod).length() != ATT_KEY_MOD_SIZE) KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE); - Util.arrayCopy( + if(KMByteBlob.cast(mod).length() != ATT_KEY_MOD_SIZE || + KMByteBlob.cast(exp).length() != ATT_KEY_EXP_SIZE) KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE); + writeDataEntry(ATT_MODULUS, KMByteBlob.cast(mod).getBuffer(), KMByteBlob.cast(mod).getStartOff(), - attKeyModulus, - (short)0, KMByteBlob.cast(mod).length()); - - if(KMByteBlob.cast(exp).length() != ATT_KEY_EXP_SIZE) KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE); - Util.arrayCopy( + writeDataEntry(ATT_EXPONENT, KMByteBlob.cast(exp).getBuffer(), KMByteBlob.cast(exp).getStartOff(), - attKeyExponent, - (short)0, KMByteBlob.cast(exp).length()); - JCSystem.commitTransaction(); } - public byte[] getAttKeyModulus() { - return attKeyModulus; + public short getAttKeyModulus() { + return readData(ATT_MODULUS); } - public byte[] getAttKeyExponent() { - return attKeyExponent; + public short getAttKeyExponent() { + return readData(ATT_EXPONENT); } public void persistAttId(byte id, byte[] buf, short start, short len){ - JCSystem.beginTransaction(); - short[] attId = (short[])attIdTable[id]; - attId[ATT_ID_OFFSET] = allocAttIdMemory(len); - attId[ATT_ID_LENGTH] = len; - Util.arrayCopy(buf,start, attIdMem,attId[ATT_ID_OFFSET],len); - attIdSupported = true; - JCSystem.commitTransaction(); + writeDataEntry(id, buf,start,len); } - public short getAttId(byte id, byte[] buf, short start){ - short[] attId = (short[])attIdTable[id]; - Util.arrayCopy(attIdMem,attId[ATT_ID_OFFSET],buf,start,attId[ATT_ID_LENGTH]); - return attId[ATT_ID_LENGTH]; + public short getAttId(byte id){ + return readData(id); } - public short getAttIdOffset(byte id){ - short[] attId = (short[])attIdTable[id]; - return attId[ATT_ID_OFFSET]; + public void deleteAttIds(){ + clearDataEntry(ATT_ID_BRAND); + clearDataEntry(ATT_ID_MEID); + clearDataEntry(ATT_ID_DEVICE); + clearDataEntry(ATT_ID_IMEI); + clearDataEntry(ATT_ID_MODEL); + clearDataEntry(ATT_ID_PRODUCT); + clearDataEntry(ATT_ID_SERIAL); + clearDataEntry(ATT_ID_MANUFACTURER); } - public byte[] getAttIdBuffer(byte id){ - return attIdMem; + public short getIssuer() { + return readData(CERT_ISSUER); } - public short getAttIdLen(byte id){ - short[] attId = (short[])attIdTable[id]; - return attId[ATT_ID_LENGTH]; + public short readData(short id){ + short blob = KMByteBlob.instance(dataLength(id)); + if(readDataEntry(id,KMByteBlob.cast(blob).getBuffer(),KMByteBlob.cast(blob).getStartOff())== 0){ + return 0; + } + return blob; } - public short getAttIdTag(byte id){ - short[] attId = (short[])attIdTable[id]; - return attId[ATT_ID_TAG]; + public void setIssuer(byte[] buf, short start, short len) { + writeDataEntry(CERT_ISSUER,buf,start,len); } - private short allocAttIdMemory(short len){ - if (((short) (attIdMemIndex + len)) > attIdMem.length) { - ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + + public short getCertExpiryTime() { + return readData(CERT_EXPIRY_TIME); + } + + public void setCertExpiryTime(byte[] buf, short start, short len) { + writeDataEntry(CERT_EXPIRY_TIME, buf,start,len); + } + + public short getAuthKeyId() { + return readData(CERT_AUTH_KEY_ID); + } + + public void setAuthKeyId(byte[] buf, short start, short len) { + writeDataEntry(CERT_AUTH_KEY_ID,buf,start,len); + } + private static final byte[] zero = {0,0,0,0,0,0,0,0}; + + public short getOsVersion(){ + short blob = readData(BOOT_OS_VERSION); + if (blob != 0) { + return KMInteger.uint_32( + KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff()); + }else{ + return KMInteger.uint_32(zero,(short)0); } - attIdMemIndex += len; - return (short) (attIdMemIndex - len); } - public void deleteAttIds(){ - JCSystem.beginTransaction(); - Util.arrayFillNonAtomic(attIdMem,(short)0,(short)attIdMem.length,(byte)0); - short index = 0; - while(index < ATT_ID_TABLE_SIZE){ - short[] attId = (short[])attIdTable[index]; - attId[ATT_ID_OFFSET] = 0; - attId[ATT_ID_LENGTH] = 0; - index++; + public short getOsPatch(){ + short blob = readData(BOOT_OS_PATCH); + if (blob != 0) { + return KMInteger.uint_32( + KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff()); + }else{ + return KMInteger.uint_32(zero,(short)0); } - attIdSupported = false; - JCSystem.commitTransaction(); } - public boolean isAttIdSupported(){ - return attIdSupported; + + public short getVerifiedBootKey(){ + return readData(BOOT_VERIFIED_BOOT_KEY); } - public short getIssuer() { - return issuer; + + public short getVerifiedBootHash(){ + return readData(BOOT_VERIFIED_BOOT_HASH); } - public void setIssuer(byte[] buf, short start, short len) { - this.issuer = allocCertData(len); - this.issuerLen = len; - Util.arrayCopy(buf,start,certData, issuer,len); + public boolean getDeviceLock(){ + short blob = readData(BOOT_DEVICE_LOCKED_STATUS); + return (byte)((getHeap())[KMByteBlob.cast(blob).getStartOff()] & 0xFE) != 0; } - public short getIssuerLen() { - return issuerLen; + public byte getBootState(){ + short blob = readData(BOOT_VERIFIED_BOOT_STATE); + return (getHeap())[KMByteBlob.cast(blob).getStartOff()]; } - public short getCertExpiryTime() { - return certExpiryTime; + public boolean getDeviceLockPasswordOnly(){ + short blob = readData(BOOT_DEVICE_LOCKED_STATUS); + return (byte)((getHeap())[KMByteBlob.cast(blob).getStartOff()] & 0xFD) != 0; } - public void setCertExpiryTime(byte[] buf, short start, short len) { - this.certExpiryTime = allocCertData(len); - this.certExpiryTimeLen = len; - Util.arrayCopy(buf,start,certData, certExpiryTime,len); + public short getDeviceTimeStamp(){ + short blob = readData(BOOT_DEVICE_LOCKED_TIME); + if(blob != 0){ + return KMInteger.uint_64(KMByteBlob.cast(blob).getBuffer(), + KMByteBlob.cast(blob).getStartOff()); + }else{ + return KMInteger.uint_64(zero,(short)0); + } } - public short getCertExpiryTimeLen() { - return certExpiryTimeLen; + public void setOsVersion(byte[] buf, short start, short len){ + if(len != OS_VERSION_SIZE) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + writeDataEntry(BOOT_OS_VERSION,buf,start,len); } + public void setDeviceLock(boolean flag){ + short start = alloc(DEVICE_LOCK_FLAG_SIZE); + if(flag) (getHeap())[start] = (byte)((getHeap())[start] | 0x01); + else (getHeap())[start] = (byte)((getHeap())[start] & 0xFE); + writeDataEntry(BOOT_DEVICE_LOCKED_STATUS,getHeap(),start,DEVICE_LOCK_FLAG_SIZE); + } - public short getAuthKeyId() { - return authKeyId; + public void setDeviceLockPasswordOnly(boolean flag){ + short start = alloc(DEVICE_LOCK_FLAG_SIZE); + if(flag) (getHeap())[start] = (byte)((getHeap())[start] | 0x02); + else (getHeap())[start] = (byte)((getHeap())[start] & 0xFD); + writeDataEntry(BOOT_DEVICE_LOCKED_STATUS,getHeap(),start,DEVICE_LOCK_FLAG_SIZE); } - public void setAuthKeyId(byte[] buf, short start, short len) { - this.authKeyId = allocCertData(len); - this.authKeyIdLen = len; - Util.arrayCopy(buf,start,certData,authKeyId,len); + public void setDeviceLockTimestamp(byte[] buf, short start, short len){ + if(len != DEVICE_LOCK_TS_SIZE) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + writeDataEntry(BOOT_DEVICE_LOCKED_TIME, buf, start,len); } - public short getAuthKeyIdLen() { - return authKeyIdLen; + public void clearDeviceLockTimeStamp(){ + clearDataEntry(BOOT_DEVICE_LOCKED_TIME); } - public byte[] getCertDataBuffer(){ - return certData; + + public void setOsPatch(byte[] buf, short start, short len){ + if(len != OS_PATCH_SIZE) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + writeDataEntry(BOOT_OS_PATCH,buf,start,len); } - private short allocCertData(short len){ - if (((short) (certDataIndex + len)) > certData.length) { - ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + + public void setVerifiedBootKey(byte[] buf, short start, short len){ + if(len > BOOT_KEY_MAX_SIZE) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + writeDataEntry(BOOT_VERIFIED_BOOT_KEY,buf,start,len); + } + + public void setVerifiedBootHash(byte[] buf, short start, short len){ + if(len > BOOT_HASH_MAX_SIZE) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + writeDataEntry(BOOT_VERIFIED_BOOT_HASH,buf,start,len); + } + + public void setBootState(byte state){ + short start = alloc(BOOT_STATE_SIZE); + (getHeap())[start] = state; + writeDataEntry(BOOT_VERIFIED_BOOT_STATE,getHeap(),start,BOOT_STATE_SIZE); + } + + public short getKeyBlobCount(){ + byte index = 0; + byte count = 0; + while(index < MAX_BLOB_STORAGE){ + if(dataLength((short)(index+AUTH_TAG_1)) != 0) count++; + index++; } - certDataIndex += len; - return (short) (certDataIndex - len); + return count; } } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java index 171cddc2..5ca46154 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java @@ -84,21 +84,23 @@ boolean aesGCMDecrypt( short authTagLen); short aesCCMSign( - byte[] bufIn, - short bufInStart, - short buffInLength, - byte[] masterKeySecret, - byte[] bufOut, - short bufStart); + byte[] bufIn, + short bufInStart, + short buffInLength, + byte[] masterKeySecret, + short masterKeyStart, short masterKeyLen, byte[] bufOut, + short bufStart); short cmacKdf( - byte[] keyMaterial, - byte[] label, - byte[] context, - short contextStart, - short contextLength, - byte[] keyBuf, - short keyStart); + byte[] keyMaterial, + short keyMaterialStart, + short keyMaterialLen, + byte[] label, + byte[] context, + short contextStart, + short contextLength, + byte[] keyBuf, + short keyStart); short hmacSign( byte[] keyBuf, @@ -174,36 +176,11 @@ KMOperation initAsymmetricOperation( short pubModStart, short pubModLength); - // Timer API - short getSystemTimeInMilliSeconds(byte[] timeBuf, short timeStart, short timeOffset); - - // Events API - short addListener(KMEventListener listener, byte eventType); - - short getEventData(byte[] eventBuf, short eventStart, short eventLength); - - // Capability query - boolean isAlgSupported(byte alg); - - boolean isKeySizeSupported(byte alg, short keySize); - - boolean isCurveSupported(byte eccurve); - - boolean isDigestSupported(byte alg, byte digest); - - boolean isPaddingSupported(byte alg, byte padding); - - boolean isBlockModeSupported(byte alg, byte blockMode); - - boolean isSystemTimerSupported(); - - boolean isBootEventSupported(); - - boolean isPkcs8ParsingSupported(); - - boolean isAttestationCertSupported(); - //X509 Cert KMAttestationCert getAttestationCert(boolean rsaCert); + // Backup and restore + boolean isBackupRestoreSupported(); + void backup(byte[] buf, short start, short len); + short restore(byte[] buf, short start); } \ No newline at end of file diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMType.java b/Applet/Applet/src/com/android/javacard/keymaster/KMType.java index 7c7036e0..4bd91d3b 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMType.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMType.java @@ -227,6 +227,10 @@ public abstract class KMType { public static final short UNLOCKED_DEVICE_REQUIRED = (short) 0x01FD; // Reset Since Id Rotation public static final short RESET_SINCE_ID_ROTATION = (short) 0x03EC; + //Early boot ended. + public static final short EARLY_BOOT_ENDED = (short) 0x0131; + //Device unique attestation. + public static final short DEVICE_UNIQUE_ATTESTATION = (short) 0x02D0; // Byte Tag // Application Id @@ -294,4 +298,5 @@ protected static short exp(byte type) { Util.setShort(heap, (short) (ptr + 1), INVALID_VALUE); return ptr; } + } diff --git a/Applet/Applet/test/com/android/javacard/test/KMFunctionalTest.java b/Applet/Applet/test/com/android/javacard/test/KMFunctionalTest.java index 93753054..c9eb7c1f 100644 --- a/Applet/Applet/test/com/android/javacard/test/KMFunctionalTest.java +++ b/Applet/Applet/test/com/android/javacard/test/KMFunctionalTest.java @@ -17,6 +17,7 @@ package com.android.javacard.test; import com.android.javacard.keymaster.KMArray; +import com.android.javacard.keymaster.KMBackupStoreApplet; import com.android.javacard.keymaster.KMBoolTag; import com.android.javacard.keymaster.KMByteBlob; import com.android.javacard.keymaster.KMByteTag; @@ -42,13 +43,6 @@ import com.licel.jcardsim.utils.AIDUtil; import javacard.framework.AID; import javacard.framework.Util; -import javacard.security.AESKey; -import javacard.security.ECPrivateKey; -import javacard.security.ECPublicKey; -import javacard.security.HMACKey; -import javacard.security.KeyPair; -import javacard.security.RSAPrivateKey; -import javacard.security.RSAPublicKey; import javax.smartcardio.CommandAPDU; import javax.smartcardio.ResponseAPDU; import org.junit.Assert; @@ -96,17 +90,23 @@ public KMFunctionalTest(){ private void init(){ // Create simulator - //KMJcardSimulator.jcardSim = true; - AID appletAID1 = AIDUtil.create("A000000062"); - simulator.installApplet(appletAID1, KMKeymasterApplet.class); + AID appletAID = AIDUtil.create("A000000062"); + simulator.installApplet(appletAID, KMKeymasterApplet.class); // Select applet - simulator.selectApplet(appletAID1); + simulator.selectApplet(appletAID); // provision attest key provisionCmd(simulator); // set bootup parameters setBootParams(simulator,(short)1,(short)1); } + private void initBackUpStore(){ + // Create simulator + AID appletAID2 = AIDUtil.create("A000000063"); + simulator.installApplet(appletAID2, KMBackupStoreApplet.class); + //simulator.selectApplet(appletAID2); + } + private void setBootParams(CardSimulator simulator, short osVersion, short osPatchLevel){ // Argument 1 OS Version short versionPtr = KMInteger.uint_16(osVersion); @@ -244,11 +244,16 @@ private void provisionCmd(CardSimulator simulator) { } private void cleanUp(){ - AID appletAID1 = AIDUtil.create("A000000062"); + AID appletAID = AIDUtil.create("A000000062"); // Delete i.e. uninstall applet - simulator.deleteApplet(appletAID1); + simulator.deleteApplet(appletAID); } + private void cleanUpBkUpStore(){ + AID appletAID = AIDUtil.create("A000000063"); + // Delete i.e. uninstall applet + simulator.deleteApplet(appletAID); + } private CommandAPDU encodeApdu(byte ins, short cmd){ byte[] buf = new byte[2048]; buf[0] = (byte)0x80; @@ -264,6 +269,19 @@ private CommandAPDU encodeApdu(byte ins, short cmd){ return new CommandAPDU(apdu); } + @Test + public void testBackupRestore(){ + init(); + initBackUpStore(); + CommandAPDU commandAPDU = new CommandAPDU(0x80, 0x27, 0x40, 0x00); + ResponseAPDU response = simulator.transmitCommand(commandAPDU); + byte[] data = response.getBytes(); + Assert.assertEquals(data[0], KMError.OK); + commandAPDU = new CommandAPDU(0x80, 0x28, 0x40, 0x00); + response = simulator.transmitCommand(commandAPDU); + data = response.getBytes(); + Assert.assertEquals(data[0], KMError.OK); + } @Test public void testAesImportKeySuccess() { init(); @@ -569,10 +587,11 @@ private short signHwToken(short hwToken){ mac, (short)0); */ + short key = KMRepository.instance().getComputedHmacKey(); cryptoProvider.hmacSign( - KMRepository.instance().getComputedHmacKey(), - (short) 0, - (short) KMRepository.instance().getComputedHmacKey().length, + KMByteBlob.cast(key).getBuffer(), + KMByteBlob.cast(key).getStartOff(), + KMByteBlob.cast(key).length(), scratchPad, (short) 0, len, mac, (short)0); @@ -634,11 +653,11 @@ private short signVerificationToken(short verToken) { cryptoProvider.hmacSign(key, scratchPad, (short) 0, len, mac, (short)0); - */ - cryptoProvider.hmacSign(KMRepository.instance().getComputedHmacKey(), - (short) 0, - (short) KMRepository.instance().getComputedHmacKey().length, + short key = KMRepository.instance().getComputedHmacKey(); + cryptoProvider.hmacSign(KMByteBlob.cast(key).getBuffer(), + KMByteBlob.cast(key).getStartOff(), + KMByteBlob.cast(key).length(), scratchPad, (short) 0, len, mac, (short)0); @@ -648,7 +667,8 @@ private short signVerificationToken(short verToken) { @Test public void testEcImportKeySuccess() { - init();/* + init(); + /* KeyPair ecKeyPair = cryptoProvider.createECKeyPair(); byte[] pub = new byte[128]; short len = ((ECPublicKey)ecKeyPair.getPublic()).getW(pub,(short)0); @@ -1678,6 +1698,7 @@ public void testSignVerifyWithRsaSHA256Pss(){ testSignVerifyWithRsa(KMType.SHA2_256, KMType.RSA_PSS,false, true); cleanUp(); } + @Test public void testSignVerifyWithRsaSHA256Pkcs1WithUpdate(){ init(); @@ -1695,6 +1716,7 @@ public void testProvisionSuccess(){ provisionCmd(simulator); cleanUp(); } + @Test public void testAttestRsaKey(){ init();