diff --git a/Applet/AndroidSEApplet/src/com/android/javacard/kmapplet/KMAndroidSEApplet.java b/Applet/AndroidSEApplet/src/com/android/javacard/kmapplet/KMAndroidSEApplet.java new file mode 100644 index 00000000..bdcf589f --- /dev/null +++ b/Applet/AndroidSEApplet/src/com/android/javacard/kmapplet/KMAndroidSEApplet.java @@ -0,0 +1,307 @@ +/* + * Copyright(C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" (short)0IS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.javacard.kmapplet; + +import org.globalplatform.upgrade.Element; +import org.globalplatform.upgrade.OnUpgradeListener; +import org.globalplatform.upgrade.UpgradeManager; + +import com.android.javacard.kmdevice.KMArray; +import com.android.javacard.kmdevice.KMByteBlob; +import com.android.javacard.kmdevice.KMByteTag; +import com.android.javacard.kmdevice.KMCose; +import com.android.javacard.kmdevice.KMCoseHeaders; +import com.android.javacard.kmdevice.KMCoseKey; +import com.android.javacard.kmdevice.KMDecoder; +import com.android.javacard.kmdevice.KMEnum; +import com.android.javacard.kmdevice.KMEnumArrayTag; +import com.android.javacard.kmdevice.KMEnumTag; +import com.android.javacard.kmdevice.KMInteger; +import com.android.javacard.kmdevice.KMKeyParameters; +import com.android.javacard.kmdevice.KMKeymasterDevice; +import com.android.javacard.kmdevice.KMKeymintDevice; +import com.android.javacard.kmdevice.KMMap; +import com.android.javacard.kmdevice.KMRepository; +import com.android.javacard.kmdevice.KMTag; +import com.android.javacard.kmdevice.KMTextString; +import com.android.javacard.seprovider.KMAndroidSEProvider; +import com.android.javacard.seprovider.KMError; +import com.android.javacard.kmdevice.KMException; +import com.android.javacard.seprovider.KMKeymasterProvision; +import com.android.javacard.seprovider.KMKeymintProvision; +import com.android.javacard.kmdevice.KMSEProvider; +import com.android.javacard.seprovider.KMType; + +import javacard.framework.APDU; +import javacard.framework.Applet; +import javacard.framework.AppletEvent; +import javacard.framework.ISO7816; +import javacard.framework.ISOException; +import javacard.framework.Util; +import javacard.security.CryptoException; +import javacardx.apdu.ExtendedLength; + +public class KMAndroidSEApplet extends Applet implements AppletEvent, OnUpgradeListener, ExtendedLength { + + private static final byte KM_BEGIN_STATE = 0x00; + private static final byte ILLEGAL_STATE = KM_BEGIN_STATE + 1; + + + // Provider specific Commands + private static final byte INS_KEYMINT_PROVIDER_APDU_START = 0x00; + private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = INS_KEYMINT_PROVIDER_APDU_START + 1; //0x01 + private static final byte INS_PROVISION_ATTESTATION_CERT_DATA_CMD = INS_KEYMINT_PROVIDER_APDU_START + 2; //0x02 + private static final byte INS_PROVISION_ATTEST_IDS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 3; + private static final byte INS_PROVISION_PRESHARED_SECRET_CMD = + INS_KEYMINT_PROVIDER_APDU_START + 4; + private static final byte INS_SET_BOOT_PARAMS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 5; + private static final byte INS_LOCK_PROVISIONING_CMD = INS_KEYMINT_PROVIDER_APDU_START + 6; + private static final byte INS_GET_PROVISION_STATUS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 7; + private static final byte INS_SET_VERSION_PATCHLEVEL_CMD = + INS_KEYMINT_PROVIDER_APDU_START + 8; //0x08 + private static final byte INS_SET_BOOT_ENDED_CMD = INS_KEYMINT_PROVIDER_APDU_START + 9; //0x09 + private static final byte INS_PROVISION_DEVICE_UNIQUE_KEY_CMD = + INS_KEYMINT_PROVIDER_APDU_START + 10; + private static final byte INS_PROVISION_ADDITIONAL_CERT_CHAIN_CMD = + INS_KEYMINT_PROVIDER_APDU_START + 11; + + // public static final byte BOOT_KEY_MAX_SIZE = 32; + // public static final byte BOOT_HASH_MAX_SIZE = 32; + + // Provision reporting status + + public static final byte KM_40 = 0x00; + public static final byte KM_41 = 0x01; + public static final byte KM_100 = 0x03; + + private static byte keymasterState = ILLEGAL_STATE; + //private static byte provisionStatus = NOT_PROVISIONED; + private static byte kmDevice; + private static KMSEProvider seProvider; + private static KMKeymasterProvision seProvisionInst; + private static KMDecoder decoderInst; + private static KMRepository repositoryInst; + private static KMKeymasterDevice kmDeviceInst; + + KMAndroidSEApplet() { + seProvider = (KMSEProvider) new KMAndroidSEProvider(); + repositoryInst = new KMRepository(seProvider.isUpgrading()); + decoderInst = new KMDecoder(); + if(kmDevice == KM_40 || kmDevice == KM_41) { + kmDeviceInst = new KMKeymasterDevice(seProvider, repositoryInst, decoderInst); + seProvisionInst = new KMKeymasterProvision(kmDeviceInst, seProvider, decoderInst, repositoryInst); + } else { + kmDeviceInst = new KMKeymintDevice(seProvider, repositoryInst, decoderInst); + seProvisionInst = new KMKeymintProvision(kmDeviceInst, seProvider, decoderInst, repositoryInst); + } + } + + /** + * Installs this applet. + * + * @param bArray the array containing installation parameters + * @param bOffset the starting offset in bArray + * @param bLength the length in bytes of the parameter data in bArray + */ + public static void install(byte[] bArray, short bOffset, byte bLength) { + // TODO Get the specification correctly. + byte Li = bArray[bOffset]; // Length of AID + byte Lc = bArray[(short) (bOffset + Li + 1)]; // Length of ControlInfo + byte La = bArray[(short) (bOffset + Li + Lc + 2)]; // Length of application data + if (La != 1) { + ISOException.throwIt(ISO7816.SW_DATA_INVALID); + } + kmDevice = bArray[(short) (bOffset + Li + Lc + 3)]; + new KMAndroidSEApplet().register(bArray, (short) (bOffset + 1), bArray[bOffset]); + } + + @Override + public void process(APDU apdu) { + try { + // If this is select applet apdu which is selecting this applet then return + if (apdu.isISOInterindustryCLA()) { + if (selectingApplet()) { + return; + } + } + short apduIns = validateApdu(apdu); + if (((KMAndroidSEProvider) seProvider).isPowerReset(false)) { + kmDeviceInst.powerReset(); + } + + if (((KMAndroidSEProvider) seProvider).isProvisionLocked()) { + switch (apduIns) { + case INS_SET_BOOT_PARAMS_CMD: + seProvisionInst.processSetBootParamsCmd(apdu); + break; + + case INS_SET_BOOT_ENDED_CMD: + //set the flag to mark boot ended + repositoryInst.setBootEndedStatus(true); + kmDeviceInst.sendError(apdu, KMError.OK); + break; + + default: + kmDeviceInst.process(apdu); + break; + } + return; + } + + if (apduIns == KMType.INVALID_VALUE) { + return; + } + switch (apduIns) { + case INS_PROVISION_ATTESTATION_KEY_CMD: // only keymaster + seProvisionInst.processProvisionAttestationKey(apdu); + break; + case INS_PROVISION_ATTESTATION_CERT_DATA_CMD: // only keymaster + seProvisionInst.processProvisionAttestationCertDataCmd(apdu); + break; + case INS_PROVISION_ATTEST_IDS_CMD: + seProvisionInst.processProvisionAttestIdsCmd(apdu); + break; + + case INS_PROVISION_PRESHARED_SECRET_CMD: + seProvisionInst.processProvisionPreSharedSecretCmd(apdu); + break; + + case INS_GET_PROVISION_STATUS_CMD: + seProvisionInst.processGetProvisionStatusCmd(apdu); + break; + + case INS_LOCK_PROVISIONING_CMD: + seProvisionInst.processLockProvisioningCmd(apdu); + break; + + case INS_SET_BOOT_PARAMS_CMD: + seProvisionInst.processSetBootParamsCmd(apdu); + break; + + case INS_PROVISION_DEVICE_UNIQUE_KEY_CMD: //only keymint + seProvisionInst.processProvisionDeviceUniqueKey(apdu); + break; + + case INS_PROVISION_ADDITIONAL_CERT_CHAIN_CMD:// only keymint + seProvisionInst.processProvisionAdditionalCertChain(apdu); + break; + + default: + kmDeviceInst.process(apdu); + break; + } + } catch (KMException exception) { + kmDeviceInst.sendError(apdu, KMException.reason()); + } catch (ISOException exp) { + kmDeviceInst.sendError(apdu, kmDeviceInst.mapISOErrorToKMError(exp.getReason())); + } catch (CryptoException e) { + kmDeviceInst.sendError(apdu, kmDeviceInst.mapCryptoErrorToKMError(e.getReason())); + } catch (Exception e) { + kmDeviceInst.sendError(apdu, KMError.GENERIC_UNKNOWN_ERROR); + } finally { + kmDeviceInst.clean(); + } + } + + @Override + public void onCleanup() { + } + + @Override + public void onConsolidate() { + } + + @Override + public void onRestore(Element element) { + element.initRead(); + keymasterState = element.readByte(); + repositoryInst.onRestore(element); + seProvider.onRestore(element); + seProvisionInst.onSave(element); + } + + @Override + public Element onSave() { + // SEProvider count + short primitiveCount = seProvider.getBackupPrimitiveByteCount(); + short objectCount = seProvider.getBackupObjectCount(); + + //Provision count + primitiveCount += seProvisionInst.getBackupPrimitiveByteCount(); + objectCount += seProvisionInst.getBackupObjectCount(); + + //Repository count + primitiveCount += repositoryInst.getBackupPrimitiveByteCount(); + objectCount += repositoryInst.getBackupObjectCount(); + //KMKeymasterApplet count + primitiveCount += computePrimitveDataSize(); + objectCount += computeObjectCount(); + + // Create element. + Element element = UpgradeManager.createElement(Element.TYPE_SIMPLE, + primitiveCount, objectCount); + element.write(keymasterState); + repositoryInst.onSave(element); + seProvider.onSave(element); + seProvisionInst.onSave(element); + return element; + } + + private short computePrimitveDataSize() { + // provisionStatus + keymasterState + return (short) 2; + } + + private short computeObjectCount() { + return (short) 0; + } + + private short validateApdu(APDU apdu) { + // Read the apdu header and buffer. + byte[] apduBuffer = apdu.getBuffer(); + short err = kmDeviceInst.validateApduHeader(apdu); + if (err != KMError.OK) { + kmDeviceInst.sendError(apdu, err); + return KMType.INVALID_VALUE; + } + return apduBuffer[ISO7816.OFFSET_INS]; + } + + @Override + public void uninstall() { + kmDeviceInst.onUninstall(); + } + + /** + * Selects this applet. + * + * @return Returns true if the keymaster is in correct state + */ + @Override + public boolean select() { + return kmDeviceInst.onSelect(); + + } + + /** + * De-selects this applet. + */ + @Override + public void deselect() { + kmDeviceInst.onDeselect(); + } +} + diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java deleted file mode 100644 index a210c4c6..00000000 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java +++ /dev/null @@ -1,556 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.keymaster; - -import org.globalplatform.upgrade.Element; -import org.globalplatform.upgrade.OnUpgradeListener; -import org.globalplatform.upgrade.UpgradeManager; - -import com.android.javacard.seprovider.KMAndroidSEProvider; -import com.android.javacard.seprovider.KMDeviceUniqueKey; -import com.android.javacard.seprovider.KMError; -import com.android.javacard.seprovider.KMException; -import com.android.javacard.seprovider.KMType; - -import javacard.framework.APDU; -import javacard.framework.ISO7816; -import javacard.framework.ISOException; -import javacard.framework.Util; - -public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeListener { - - private static final byte KM_BEGIN_STATE = 0x00; - private static final byte ILLEGAL_STATE = KM_BEGIN_STATE + 1; - private static final short POWER_RESET_MASK_FLAG = (short) 0x4000; - - // Provider specific Commands - private static final byte INS_KEYMINT_PROVIDER_APDU_START = 0x00; - private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = INS_KEYMINT_PROVIDER_APDU_START + 1; //0x01 - private static final byte INS_PROVISION_ATTESTATION_CERT_DATA_CMD = INS_KEYMINT_PROVIDER_APDU_START + 2; //0x02 - private static final byte INS_PROVISION_ATTEST_IDS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 3; - private static final byte INS_PROVISION_PRESHARED_SECRET_CMD = - INS_KEYMINT_PROVIDER_APDU_START + 4; - private static final byte INS_SET_BOOT_PARAMS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 5; - private static final byte INS_LOCK_PROVISIONING_CMD = INS_KEYMINT_PROVIDER_APDU_START + 6; - private static final byte INS_GET_PROVISION_STATUS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 7; - private static final byte INS_SET_VERSION_PATCHLEVEL_CMD = - INS_KEYMINT_PROVIDER_APDU_START + 8; //0x08 - private static final byte INS_SET_BOOT_ENDED_CMD = INS_KEYMINT_PROVIDER_APDU_START + 9; //0x09 - private static final byte INS_PROVISION_DEVICE_UNIQUE_KEY_CMD = - INS_KEYMINT_PROVIDER_APDU_START + 10; - private static final byte INS_PROVISION_ADDITIONAL_CERT_CHAIN_CMD = - INS_KEYMINT_PROVIDER_APDU_START + 11; - - private static final byte INS_KEYMINT_PROVIDER_APDU_END = 0x1F; - public static final byte BOOT_KEY_MAX_SIZE = 32; - public static final byte BOOT_HASH_MAX_SIZE = 32; - - // Provision reporting status -//Provision reporting status - private static final byte NOT_PROVISIONED = 0x00; - private static final byte PROVISION_STATUS_ATTESTATION_KEY = 0x01; - private static final byte PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x02; - private static final byte PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x04; - private static final byte PROVISION_STATUS_ATTEST_IDS = 0x08; - private static final byte PROVISION_STATUS_PRESHARED_SECRET = 0x10; - private static final byte PROVISION_STATUS_PROVISIONING_LOCKED = 0x20; - private static final byte PROVISION_STATUS_DEVICE_UNIQUE_KEY = 0x40; - private static final byte PROVISION_STATUS_ADDITIONAL_CERT_CHAIN = (byte) 0x80; - - public static final short SHARED_SECRET_KEY_SIZE = 32; - - private static byte keymasterState = ILLEGAL_STATE; - private static byte provisionStatus = NOT_PROVISIONED; - private static byte kmSpecification; - - KMAndroidSEApplet() { - super(new KMAndroidSEProvider(), kmSpecification); - } - - /** - * Installs this applet. - * - * @param bArray the array containing installation parameters - * @param bOffset the starting offset in bArray - * @param bLength the length in bytes of the parameter data in bArray - */ - public static void install(byte[] bArray, short bOffset, byte bLength) { - // TODO Get the specification correctly. - byte Li = bArray[bOffset]; // Length of AID - byte Lc = bArray[(short) (bOffset + Li + 1)]; // Length of ControlInfo - byte La = bArray[(short) (bOffset + Li + Lc + 2)]; // Length of application data - if (La != 1) { - ISOException.throwIt(ISO7816.SW_DATA_INVALID); - } - kmSpecification = bArray[(short) (bOffset + Li + Lc + 3)]; - new KMAndroidSEApplet().register(bArray, (short) (bOffset + 1), bArray[bOffset]); - } - - @Override - public void process(APDU apdu) { - try { - // If this is select applet apdu which is selecting this applet then return - if (apdu.isISOInterindustryCLA()) { - if (selectingApplet()) { - return; - } - } - short apduIns = validateApdu(apdu); - if (((KMAndroidSEProvider) seProvider).isPowerReset()) { - super.powerReset(); - } - - if (((KMAndroidSEProvider) seProvider).isProvisionLocked()) { - switch (apduIns) { - case INS_SET_BOOT_PARAMS_CMD: - processSetBootParamsCmd(apdu); - break; - - case INS_SET_BOOT_ENDED_CMD: - //set the flag to mark boot ended - repository.setBootEndedStatus(true); - sendError(apdu, KMError.OK); - break; - - default: - super.process(apdu); - break; - } - return; - } - - if (apduIns == KMType.INVALID_VALUE) { - return; - } - switch (apduIns) { - case INS_PROVISION_ATTESTATION_KEY_CMD: - processProvisionAttestationKey(apdu); - provisionStatus |= PROVISION_STATUS_ATTESTATION_KEY; - sendError(apdu, KMError.OK); - break; - case INS_PROVISION_ATTESTATION_CERT_DATA_CMD: - processProvisionAttestationCertDataCmd(apdu); - provisionStatus |= (PROVISION_STATUS_ATTESTATION_CERT_CHAIN | - PROVISION_STATUS_ATTESTATION_CERT_PARAMS); - sendError(apdu, KMError.OK); - break; - case INS_PROVISION_ATTEST_IDS_CMD: - processProvisionAttestIdsCmd(apdu); - provisionStatus |= PROVISION_STATUS_ATTEST_IDS; - sendError(apdu, KMError.OK); - break; - - case INS_PROVISION_PRESHARED_SECRET_CMD: - processProvisionPreSharedSecretCmd(apdu); - provisionStatus |= PROVISION_STATUS_PRESHARED_SECRET; - sendError(apdu, KMError.OK); - break; - - case INS_GET_PROVISION_STATUS_CMD: - processGetProvisionStatusCmd(apdu); - break; - - case INS_LOCK_PROVISIONING_CMD: - processLockProvisioningCmd(apdu); - break; - - case INS_SET_BOOT_PARAMS_CMD: - - processSetBootParamsCmd(apdu); - break; - - case INS_PROVISION_DEVICE_UNIQUE_KEY_CMD: - processProvisionDeviceUniqueKey(apdu); - break; - - case INS_PROVISION_ADDITIONAL_CERT_CHAIN_CMD: - processProvisionAdditionalCertChain(apdu); - break; - - default: - super.process(apdu); - break; - } - } finally { - repository.clean(); - } - } - - private static void processProvisionDeviceUniqueKey(APDU apdu) { - // Re-purpose the apdu buffer as scratch pad. - byte[] scratchPad = apdu.getBuffer(); - short arr = KMArray.instance((short) 1); - short coseKeyExp = KMCoseKey.exp(); - KMArray.cast(arr).add((short) 0, coseKeyExp); //[ CoseKey ] - arr = receiveIncoming(apdu, arr); - // Get cose key. - short coseKey = KMArray.cast(arr).get((short) 0); - short pubKeyLen = KMCoseKey.cast(coseKey).getEcdsa256PublicKey(scratchPad, (short) 0); - short privKeyLen = KMCoseKey.cast(coseKey).getPrivateKey(scratchPad, pubKeyLen); - //Store the Device unique Key. - seProvider.createDeviceUniqueKey(false, scratchPad, (short) 0, pubKeyLen, scratchPad, - pubKeyLen, privKeyLen); - short bcc = generateBcc(false, scratchPad); - short len = KMKeymasterApplet.encodeToApduBuffer(bcc, scratchPad, (short) 0, - MAX_COSE_BUF_SIZE); - ((KMAndroidSEProvider) seProvider).persistBootCertificateChain(scratchPad, (short) 0, len); - sendError(apdu, KMError.OK); - } - - private static void processProvisionAdditionalCertChain(APDU apdu) { - // Prepare the expression to decode - short headers = KMCoseHeaders.exp(); - short arrInst = KMArray.instance((short) 4); - KMArray.cast(arrInst).add((short) 0, KMByteBlob.exp()); - KMArray.cast(arrInst).add((short) 1, headers); - KMArray.cast(arrInst).add((short) 2, KMByteBlob.exp()); - KMArray.cast(arrInst).add((short) 3, KMByteBlob.exp()); - short coseSignArr = KMArray.exp(arrInst); - short map = KMMap.instance((short) 1); - KMMap.cast(map).add((short) 0, KMTextString.exp(), coseSignArr); - // receive incoming data and decode it. - byte[] srcBuffer = apdu.getBuffer(); - short recvLen = apdu.setIncomingAndReceive(); - short srcOffset = apdu.getOffsetCdata(); - short bufferLength = apdu.getIncomingLength(); - short bufferStartOffset = repository.allocReclaimableMemory(bufferLength); - short index = bufferStartOffset; - byte[] buffer = repository.getHeap(); - while (recvLen > 0 && ((short) (index - bufferStartOffset) < bufferLength)) { - Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, index, recvLen); - index += recvLen; - recvLen = apdu.receiveBytes(srcOffset); - } - // decode - map = decoder.decode(map, buffer, bufferStartOffset, bufferLength); - arrInst = KMMap.cast(map).getKeyValue((short) 0); - // Validate Additional certificate chain. - short leafCoseKey = - validateCertChain(false, KMCose.COSE_ALG_ES256, KMCose.COSE_ALG_ES256, arrInst, - srcBuffer, null); - // Compare the DK_Pub. - short pubKeyLen = KMCoseKey.cast(leafCoseKey).getEcdsa256PublicKey(srcBuffer, (short) 0); - KMDeviceUniqueKey uniqueKey = seProvider.getDeviceUniqueKey(false); - if (uniqueKey == null) { - KMException.throwIt(KMError.STATUS_FAILED); - } - short uniqueKeyLen = uniqueKey.getPublicKey(srcBuffer, pubKeyLen); - if ((pubKeyLen != uniqueKeyLen) || - (0 != Util.arrayCompare(srcBuffer, (short) 0, srcBuffer, pubKeyLen, pubKeyLen))) { - KMException.throwIt(KMError.STATUS_FAILED); - } - seProvider.persistAdditionalCertChain(buffer, bufferStartOffset, bufferLength); - //reclaim memory - repository.reclaimMemory(bufferLength); - sendError(apdu, KMError.OK); - } - - private void processProvisionAttestIdsCmd(APDU apdu) { - short keyparams = KMKeyParameters.exp(); - short cmd = KMArray.instance((short) 1); - KMArray.cast(cmd).add((short) 0, keyparams); - short args = receiveIncoming(apdu, cmd); - - short attData = KMArray.cast(args).get((short) 0); - // persist attestation Ids - if any is missing then exception occurs - setAttestationIds(attData); - } - - public void setAttestationIds(short attIdVals) { - KMKeyParameters instParam = KMKeyParameters.cast(attIdVals); - KMArray vals = KMArray.cast(instParam.getVals()); - short index = 0; - short length = vals.length(); - short key; - short type; - short obj; - while (index < length) { - obj = vals.get(index); - key = KMTag.getKey(obj); - type = KMTag.getTagType(obj); - - if (KMType.BYTES_TAG != type) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - obj = KMByteTag.cast(obj).getValue(); - ((KMAndroidSEProvider) seProvider).setAttestationId(key, KMByteBlob.cast(obj).getBuffer(), - KMByteBlob.cast(obj).getStartOff(), KMByteBlob.cast(obj).length()); - index++; - } - } - - private void processProvisionAttestationCertDataCmd(APDU apdu) { - // TODO Handle this function properly - processAttestationCertDataCmd(apdu); - } - - private void processProvisionAttestationKey(APDU apdu) { - // Arguments - short keyparams = KMKeyParameters.exp(); - short keyFormatPtr = KMEnum.instance(KMType.KEY_FORMAT); - short blob = KMByteBlob.exp(); - short argsProto = KMArray.instance((short) 3); - KMArray.cast(argsProto).add((short) 0, keyparams); - KMArray.cast(argsProto).add((short) 1, keyFormatPtr); - KMArray.cast(argsProto).add((short) 2, blob); - - short args = receiveIncoming(apdu, argsProto); - // Re-purpose the apdu buffer as scratch pad. - byte[] scratchPad = apdu.getBuffer(); - - // key params should have os patch, os version and verified root of trust - short keyParams = KMArray.cast(args).get((short) 0); - keyFormatPtr = KMArray.cast(args).get((short) 1); - short rawBlob = KMArray.cast(args).get((short) 2); - // Key format must be RAW format - short keyFormat = KMEnum.cast(keyFormatPtr).getVal(); - if (keyFormat != KMType.RAW) { - KMException.throwIt(KMError.UNIMPLEMENTED); - } - //byte origin = KMType.IMPORTED; - - // get algorithm - only EC keys expected - KMTag.assertPresence(keyParams, KMType.ENUM_TAG, KMType.ALGORITHM, KMError.INVALID_ARGUMENT); - short alg = KMEnumTag.getValue(KMType.ALGORITHM, keyParams); - if (alg != KMType.EC) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - // get digest - only SHA256 supported - KMTag.assertPresence(keyParams, KMType.ENUM_ARRAY_TAG, KMType.DIGEST, KMError.INVALID_ARGUMENT); - short len = KMEnumArrayTag.getValues(KMType.DIGEST, keyParams, scratchPad, (short) 0); - if (len != 1) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - if (scratchPad[0] != KMType.SHA2_256) { - KMException.throwIt(KMError.INCOMPATIBLE_DIGEST); - } - // Purpose should be ATTEST_KEY - KMTag.assertPresence(keyParams, KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, - KMError.INVALID_ARGUMENT); - len = KMEnumArrayTag.getValues(KMType.PURPOSE, keyParams, scratchPad, (short) 0); - if (len != 1) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - if (scratchPad[0] != KMType.ATTEST_KEY) { - KMException.throwIt(KMError.INCOMPATIBLE_PURPOSE); - } - // validate Curve - KMTag.assertPresence(keyParams, KMType.ENUM_TAG, KMType.ECCURVE, KMError.INVALID_ARGUMENT); - short curve = KMEnumTag.getValue(KMType.ECCURVE, keyParams); - if (curve != KMType.P_256) { - KMException.throwIt(KMError.UNSUPPORTED_EC_CURVE); - } - // Decode EC Key - short arrPtr = decodeRawECKey(rawBlob); - short secret = KMArray.cast(arrPtr).get((short) 0); - short pubKey = KMArray.cast(arrPtr).get((short) 1); - // Check whether key can be created - seProvider.importAsymmetricKey( - KMType.EC, - KMByteBlob.cast(secret).getBuffer(), - KMByteBlob.cast(secret).getStartOff(), - KMByteBlob.cast(secret).length(), - KMByteBlob.cast(pubKey).getBuffer(), - KMByteBlob.cast(pubKey).getStartOff(), - KMByteBlob.cast(pubKey).length()); - - // persist key - seProvider.createAttestationKey( - KMByteBlob.cast(secret).getBuffer(), - KMByteBlob.cast(secret).getStartOff(), - KMByteBlob.cast(secret).length()); - } - - private void processProvisionPreSharedSecretCmd(APDU apdu) { - short blob = KMByteBlob.exp(); - short argsProto = KMArray.instance((short) 1); - KMArray.cast(argsProto).add((short) 0, blob); - short args = receiveIncoming(apdu, argsProto); - - short val = KMArray.cast(args).get((short) 0); - - if (val != KMType.INVALID_VALUE - && KMByteBlob.cast(val).length() != SHARED_SECRET_KEY_SIZE) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - // Persist shared Hmac. - ((KMAndroidSEProvider) seProvider).createPresharedKey( - KMByteBlob.cast(val).getBuffer(), - KMByteBlob.cast(val).getStartOff(), - KMByteBlob.cast(val).length()); - - } - - //This function masks the error code with POWER_RESET_MASK_FLAG - // in case if card reset event occurred. The clients of the Applet - // has to extract the power reset status from the error code and - // process accordingly. - private static short buildErrorStatus(short err) { - short int32Ptr = KMInteger.instance((short) 4); - short powerResetStatus = 0; - if (((KMAndroidSEProvider) seProvider).isPowerReset()) { - powerResetStatus = POWER_RESET_MASK_FLAG; - } - - Util.setShort(KMInteger.cast(int32Ptr).getBuffer(), - KMInteger.cast(int32Ptr).getStartOff(), - powerResetStatus); - - Util.setShort(KMInteger.cast(int32Ptr).getBuffer(), - (short) (KMInteger.cast(int32Ptr).getStartOff() + 2), - err); - // reset power reset status flag to its default value. - //repository.restorePowerResetStatus(); //TODO - return int32Ptr; - } - - private void processGetProvisionStatusCmd(APDU apdu) { - short resp = KMArray.instance((short) 2); - KMArray.cast(resp).add((short) 0, buildErrorStatus(KMError.OK)); - KMArray.cast(resp).add((short) 1, KMInteger.uint_16(provisionStatus)); - sendOutgoing(apdu, resp); - } - - private void processSetBootParamsCmd(APDU apdu) { - short argsProto = KMArray.instance((short) 5); - - byte[] scratchPad = apdu.getBuffer(); - // Array of 4 expected arguments - // Argument 0 Boot Patch level - KMArray.cast(argsProto).add((short) 0, KMInteger.exp()); - // Argument 1 Verified Boot Key - KMArray.cast(argsProto).add((short) 1, KMByteBlob.exp()); - // Argument 2 Verified Boot Hash - KMArray.cast(argsProto).add((short) 2, KMByteBlob.exp()); - // Argument 3 Verified Boot State - KMArray.cast(argsProto).add((short) 3, KMEnum.instance(KMType.VERIFIED_BOOT_STATE)); - // Argument 4 Device Locked - KMArray.cast(argsProto).add((short) 4, KMEnum.instance(KMType.DEVICE_LOCKED)); - - short args = receiveIncoming(apdu, argsProto); - - short bootParam = KMArray.cast(args).get((short) 0); - - ((KMAndroidSEProvider) seProvider).setBootPatchLevel(KMInteger.cast(bootParam).getBuffer(), - KMInteger.cast(bootParam).getStartOff(), - KMInteger.cast(bootParam).length()); - - bootParam = KMArray.cast(args).get((short) 1); - if (KMByteBlob.cast(bootParam).length() > BOOT_KEY_MAX_SIZE) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - ((KMAndroidSEProvider) seProvider).setBootKey(KMByteBlob.cast(bootParam).getBuffer(), - KMByteBlob.cast(bootParam).getStartOff(), - KMByteBlob.cast(bootParam).length()); - - bootParam = KMArray.cast(args).get((short) 2); - if (KMByteBlob.cast(bootParam).length() > BOOT_HASH_MAX_SIZE) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - ((KMAndroidSEProvider) seProvider).setVerifiedBootHash(KMByteBlob.cast(bootParam).getBuffer(), - KMByteBlob.cast(bootParam).getStartOff(), - KMByteBlob.cast(bootParam).length()); - - bootParam = KMArray.cast(args).get((short) 3); - byte enumVal = KMEnum.cast(bootParam).getVal(); - ((KMAndroidSEProvider) seProvider).setBootState(enumVal); - - bootParam = KMArray.cast(args).get((short) 4); - enumVal = KMEnum.cast(bootParam).getVal(); - ((KMAndroidSEProvider) seProvider).setDeviceLocked(enumVal == KMType.DEVICE_LOCKED_TRUE); - - - // Clear the Computed SharedHmac and Hmac nonce from persistent memory. - Util.arrayFillNonAtomic(scratchPad, (short) 0, KMRepository.COMPUTED_HMAC_KEY_SIZE, (byte) 0); - seProvider.createComputedHmacKey(scratchPad, (short) 0, KMRepository.COMPUTED_HMAC_KEY_SIZE); - - super.reboot(); - sendError(apdu, KMError.OK); - } - - private void processLockProvisioningCmd(APDU apdu) { - ((KMAndroidSEProvider) seProvider).setProvisionLocked(true); - sendError(apdu, KMError.OK); - } - - @Override - public void onCleanup() { - } - - @Override - public void onConsolidate() { - } - - @Override - public void onRestore(Element element) { - element.initRead(); - provisionStatus = element.readByte(); - keymasterState = element.readByte(); - repository.onRestore(element); - seProvider.onRestore(element); - } - - @Override - public Element onSave() { - // SEProvider count - short primitiveCount = seProvider.getBackupPrimitiveByteCount(); - short objectCount = seProvider.getBackupObjectCount(); - //Repository count - primitiveCount += repository.getBackupPrimitiveByteCount(); - objectCount += repository.getBackupObjectCount(); - //KMKeymasterApplet count - primitiveCount += computePrimitveDataSize(); - objectCount += computeObjectCount(); - - // Create element. - Element element = UpgradeManager.createElement(Element.TYPE_SIMPLE, - primitiveCount, objectCount); - element.write(provisionStatus); - element.write(keymasterState); - repository.onSave(element); - seProvider.onSave(element); - return element; - } - - private short computePrimitveDataSize() { - // provisionStatus + keymasterState - return (short) 2; - } - - private short computeObjectCount() { - return (short) 0; - } - - private short validateApdu(APDU apdu) { - // Read the apdu header and buffer. - byte[] apduBuffer = apdu.getBuffer(); - byte apduClass = apduBuffer[ISO7816.OFFSET_CLA]; - - // Validate APDU Header. - if ((apduClass != CLA_ISO7816_NO_SM_NO_CHAN)) { - sendError(apdu, KMError.UNSUPPORTED_CLA); - return KMType.INVALID_VALUE; - } - - short err = specification.validateApduHeader(apdu); - if (err != KMError.OK) { - sendError(apdu, err); - return KMType.INVALID_VALUE; - } - return apduBuffer[ISO7816.OFFSET_INS]; - } -} - diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAESKey.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMAESKey.java similarity index 96% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAESKey.java rename to Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMAESKey.java index 7e34065e..d92e26ec 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAESKey.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMAESKey.java @@ -17,6 +17,8 @@ import org.globalplatform.upgrade.Element; +import com.android.javacard.kmdevice.KMMasterKey; + import javacard.security.AESKey; public class KMAESKey implements KMMasterKey { diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMAndroidSEProvider.java similarity index 95% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java rename to Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMAndroidSEProvider.java index 9b767b76..b9a8ec57 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMAndroidSEProvider.java @@ -18,6 +18,15 @@ import org.globalplatform.upgrade.Element; import org.globalplatform.upgrade.UpgradeManager; +import com.android.javacard.kmdevice.KMAttestationKey; +import com.android.javacard.kmdevice.KMComputedHmacKey; +import com.android.javacard.kmdevice.KMDeviceUniqueKey; +import com.android.javacard.kmdevice.KMException; +import com.android.javacard.kmdevice.KMMasterKey; +import com.android.javacard.kmdevice.KMOperation; +import com.android.javacard.kmdevice.KMPreSharedKey; +import com.android.javacard.kmdevice.KMSEProvider; + import javacard.framework.JCSystem; import javacard.framework.Util; import javacard.security.AESKey; @@ -140,12 +149,12 @@ public KMAndroidSEProvider() { // Re-usable AES,DES and HMAC keys in persisted memory. aesKeys = new AESKey[2]; aesKeys[KEYSIZE_128_OFFSET] = (AESKey) KeyBuilder.buildKey( - KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); + KeyBuilder.TYPE_AES_TRANSIENT_RESET, KeyBuilder.LENGTH_AES_128, false); aesKeys[KEYSIZE_256_OFFSET] = (AESKey) KeyBuilder.buildKey( - KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false); - triDesKey = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, + KeyBuilder.TYPE_AES_TRANSIENT_RESET, KeyBuilder.LENGTH_AES_256, false); + triDesKey = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES_TRANSIENT_RESET, KeyBuilder.LENGTH_DES3_3KEY, false); - hmacKey = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, (short) 512, + hmacKey = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC_TRANSIENT_RESET, (short) 512, false); rsaKeyPair = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048); ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); @@ -167,8 +176,6 @@ public KMAndroidSEProvider() { //Allocate buffer for certificate chain. if (!isUpgrading()) { certificateChain = new byte[CERT_CHAIN_MAX_SIZE]; - additionalCertChain = new byte[ADDITIONAL_CERT_CHAIN_MAX_SIZE]; - //Allocate buffer for certificate chain. //Allocate buffer for certificate chain and cert parameters. // First 2 bytes is reserved for length for all the 3 buffers. short totalLen = (short) (6 + KMConfigurations.CERT_CHAIN_MAX_SIZE + @@ -186,9 +193,10 @@ public KMAndroidSEProvider() { createComputedHmacKey(tmpArray, (short)0, (short) 32); } androidSEProvider = this; - resetFlag = JCSystem.makeTransientByteArray((short) 1, + resetFlag = JCSystem.makeTransientByteArray((short) 2, JCSystem.CLEAR_ON_DESELECT); resetFlag[0] = (byte) POWER_RESET_FALSE; + resetFlag[1] = (byte) POWER_RESET_FALSE; } public static void initStatics() { @@ -908,9 +916,7 @@ public short cmacKDF(KMPreSharedKey pSharedKey, byte[] label, } public void clearCertificateChain() { - JCSystem.beginTransaction(); - Util.arrayFillNonAtomic(certificateChain, (short) 0, CERT_CHAIN_MAX_SIZE, (byte) 0); - JCSystem.commitTransaction(); + Util.arrayFill(certificateChain, (short) 0, CERT_CHAIN_MAX_SIZE, (byte) 0); } //This function supports multi-part request data. @@ -931,9 +937,9 @@ public void persistPartialCertificateChain(byte[] buf, short offset, short len, } JCSystem.beginTransaction(); Util.setShort(certificateChain, (short) 0, (short) (len + persistedLen)); - Util.arrayCopyNonAtomic(buf, offset, certificateChain, - (short) (persistedLen + 2), len); JCSystem.commitTransaction(); + Util.arrayCopy(buf, offset, certificateChain, + (short) (persistedLen + 2), len); } public short readCertificateChain(byte[] buf, short offset) { @@ -949,6 +955,9 @@ public short getCertificateChainLength() { @Override public void onSave(Element element) { element.write(certificateChain); + element.write(provisionData); + element.write(additionalCertChain); + element.write(bcc); KMAESKey.onSave(element, masterKey); KMECPrivateKey.onSave(element, attestationKey); KMHmacKey.onSave(element, preSharedKey); @@ -957,6 +966,9 @@ public void onSave(Element element) { @Override public void onRestore(Element element) { certificateChain = (byte[]) element.readObject(); + provisionData = (byte[]) element.readObject(); + additionalCertChain = (byte[]) element.readObject(); + bcc = (byte[]) element.readObject(); masterKey = KMAESKey.onRestore(element); attestationKey = KMECPrivateKey.onRestore(element); preSharedKey = KMHmacKey.onRestore(element); @@ -1183,59 +1195,43 @@ public void setAttestationId(short tag, byte[] buffer, short start, short length switch (tag) { // Attestation Id Brand case KMType.ATTESTATION_ID_BRAND: - JCSystem.beginTransaction(); attIdBrand = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short) start, attIdBrand, (short) 0, length); - JCSystem.commitTransaction(); + Util.arrayCopy(buffer, (short) start, attIdBrand, (short) 0, length); break; // Attestation Id Device case KMType.ATTESTATION_ID_DEVICE: - JCSystem.beginTransaction(); attIdDevice = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short) start, attIdDevice, (short) 0, length); - JCSystem.commitTransaction(); + Util.arrayCopy(buffer, (short) start, attIdDevice, (short) 0, length); break; // Attestation Id Product case KMType.ATTESTATION_ID_PRODUCT: - JCSystem.beginTransaction(); attIdProduct = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short) start, attIdProduct, (short) 0, length); - JCSystem.commitTransaction(); + Util.arrayCopy(buffer, (short) start, attIdProduct, (short) 0, length); break; // Attestation Id Serial case KMType.ATTESTATION_ID_SERIAL: - JCSystem.beginTransaction(); attIdSerial = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short) start, attIdSerial, (short) 0, length); - JCSystem.commitTransaction(); + Util.arrayCopy(buffer, (short) start, attIdSerial, (short) 0, length); break; // Attestation Id IMEI case KMType.ATTESTATION_ID_IMEI: - JCSystem.beginTransaction(); attIdImei = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short) start, attIdImei, (short) 0, length); - JCSystem.commitTransaction(); + Util.arrayCopy(buffer, (short) start, attIdImei, (short) 0, length); break; // Attestation Id MEID case KMType.ATTESTATION_ID_MEID: - JCSystem.beginTransaction(); attIdMeId = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short) start, attIdMeId, (short) 0, length); - JCSystem.commitTransaction(); + Util.arrayCopy(buffer, (short) start, attIdMeId, (short) 0, length); break; // Attestation Id Manufacturer case KMType.ATTESTATION_ID_MANUFACTURER: - JCSystem.beginTransaction(); attIdManufacturer = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short) start, attIdManufacturer, (short) 0, length); - JCSystem.commitTransaction(); + Util.arrayCopy(buffer, (short) start, attIdManufacturer, (short) 0, length); break; // Attestation Id Model case KMType.ATTESTATION_ID_MODEL: - JCSystem.beginTransaction(); attIdModel = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short) start, attIdModel, (short) 0, length); - JCSystem.commitTransaction(); + Util.arrayCopy(buffer, (short) start, attIdModel, (short) 0, length); break; } } @@ -1252,13 +1248,21 @@ public void deleteAttestationIds() { attIdModel = null; } - public boolean isPowerReset() { + @Override + public boolean isPowerReset(boolean isForStatusUpdate) { boolean flag = false; - if (resetFlag[0] == POWER_RESET_TRUE) { - resetFlag[0] = POWER_RESET_FALSE; - flag = true; - if (poolMgr != null) { - poolMgr.powerReset(); + if(isForStatusUpdate == false) { + if (resetFlag[0] == POWER_RESET_TRUE) { + resetFlag[0] = POWER_RESET_FALSE; + flag = true; + if (poolMgr != null) { + poolMgr.powerReset(); + } + } + } else { + if (resetFlag[1] == POWER_RESET_TRUE) { + resetFlag[1] = POWER_RESET_FALSE; + flag = true; } } return flag; @@ -1328,7 +1332,7 @@ public void setBootPatchLevel(byte[] buffer, short start, short length) { if (length > 4 || length < 0) { KMException.throwIt(KMError.UNKNOWN_ERROR); } - Util.arrayCopyNonAtomic(buffer, start, bootPatchLevel, (short) 0, (short) 4); + Util.arrayCopyNonAtomic(buffer, start, bootPatchLevel, (short) 0, length); } @Override @@ -1481,14 +1485,15 @@ public void persistAdditionalCertChain(byte[] buf, short offset, short len) { // // self-signed cert, leaf contains DK_pu b // ] // Certificate = COSE_Sign1 of a public key - if ((short) (len + 2) >= ADDITIONAL_CERT_CHAIN_MAX_SIZE) { + if ((short) (len + 2) > ADDITIONAL_CERT_CHAIN_MAX_SIZE) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); } JCSystem.beginTransaction(); Util.setShort(additionalCertChain, (short) 0, (short) len); - Util.arrayCopyNonAtomic(buf, offset, additionalCertChain, - (short) 2, len); JCSystem.commitTransaction(); + Util.arrayCopy(buf, offset, additionalCertChain, + (short) 2, len); + } @@ -1514,9 +1519,10 @@ public void persistBootCertificateChain(byte[] buf, short offset, short len) { } JCSystem.beginTransaction(); Util.setShort(bcc, (short) 0, (short) len); - Util.arrayCopyNonAtomic(buf, offset, bcc, - (short) 2, len); JCSystem.commitTransaction(); + Util.arrayCopy(buf, offset, bcc, + (short) 2, len); + } public void setProvisionLocked(boolean locked) { @@ -1550,20 +1556,6 @@ public short messageDigest256(byte[] inBuff, short inOffset, public KMComputedHmacKey getComputedHmacKey() { return computedHmacKey; } - - private byte mapPurpose(short purpose) { - switch (purpose) { - case KMType.ENCRYPT: - return Cipher.MODE_ENCRYPT; - case KMType.DECRYPT: - return Cipher.MODE_DECRYPT; - case KMType.SIGN: - return Signature.MODE_SIGN; - case KMType.VERIFY: - return Signature.MODE_VERIFY; - } - return -1; - } private short getProvisionDataBufferOffset(byte dataType) { switch(dataType) { @@ -1583,9 +1575,7 @@ private void persistProvisionData(byte[] buf, short off, short len, short maxSiz if (len > maxSize) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); } - JCSystem.beginTransaction(); - Util.arrayCopyNonAtomic(buf, off, provisionData, Util.setShort(provisionData, copyToOff, len), len); - JCSystem.commitTransaction(); + Util.arrayCopy(buf, off, provisionData, Util.setShort(provisionData, copyToOff, len), len); } private void persistCertificateChain(byte[] certChain, short certChainOff, short certChainLen) { @@ -1616,9 +1606,7 @@ public void persistProvisionData(byte[] buffer, short certChainOff, short certCh // Next single byte holds the byte string header. // Next 3 bytes holds the total length of the certificate chain. // clear buffer. - JCSystem.beginTransaction(); - Util.arrayFillNonAtomic(provisionData, (short) 0, (short) provisionData.length, (byte) 0); - JCSystem.commitTransaction(); + Util.arrayFill(provisionData, (short) 0, (short) provisionData.length, (byte) 0); // Persist data. persistCertificateChain(buffer, certChainOff, certChainLen); persistCertficateIssuer(buffer, certIssuerOff, certIssuerLen); diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMConfigurations.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMConfigurations.java similarity index 96% rename from Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMConfigurations.java rename to Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMConfigurations.java index 6e5090a1..8373c87f 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMConfigurations.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMConfigurations.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.seprovider; public class KMConfigurations { // Machine types diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java similarity index 96% rename from Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java rename to Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java index 0f68de61..cdf0b48b 100644 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java @@ -14,6 +14,8 @@ * limitations under the License. */ package com.android.javacard.seprovider; +import com.android.javacard.kmdevice.KMDeviceUniqueKey; + import javacard.security.ECPrivateKey; import javacard.security.ECPublicKey; import javacard.security.KeyPair; diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECPrivateKey.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMECPrivateKey.java similarity index 97% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECPrivateKey.java rename to Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMECPrivateKey.java index 33372f97..75825c01 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECPrivateKey.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMECPrivateKey.java @@ -17,6 +17,8 @@ import org.globalplatform.upgrade.Element; +import com.android.javacard.kmdevice.KMAttestationKey; + import javacard.security.AESKey; import javacard.security.ECPrivateKey; import javacard.security.KeyPair; diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMEcdsa256NoDigestSignature.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMEcdsa256NoDigestSignature.java similarity index 100% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMEcdsa256NoDigestSignature.java rename to Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMEcdsa256NoDigestSignature.java diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMError.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMError.java similarity index 100% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMError.java rename to Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMError.java diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMHmacKey.java similarity index 93% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java rename to Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMHmacKey.java index a863bf88..58829ea9 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMHmacKey.java @@ -17,6 +17,9 @@ import org.globalplatform.upgrade.Element; +import com.android.javacard.kmdevice.KMComputedHmacKey; +import com.android.javacard.kmdevice.KMPreSharedKey; + import javacard.security.HMACKey; public class KMHmacKey implements KMPreSharedKey, KMComputedHmacKey { diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMKeymasterProvision.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMKeymasterProvision.java new file mode 100644 index 00000000..c34cd24a --- /dev/null +++ b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMKeymasterProvision.java @@ -0,0 +1,340 @@ +package com.android.javacard.seprovider; + +import org.globalplatform.upgrade.Element; + +import com.android.javacard.kmdevice.KMArray; +import com.android.javacard.kmdevice.KMInteger; +import com.android.javacard.kmdevice.KMKeyParameters; +import com.android.javacard.kmdevice.KMKeymasterDevice; +import com.android.javacard.kmdevice.KMRepository; +import com.android.javacard.kmdevice.KMSEProvider; +import com.android.javacard.kmdevice.KMTag; +import com.android.javacard.kmdevice.KMByteBlob; +import com.android.javacard.kmdevice.KMByteTag; +import com.android.javacard.kmdevice.KMDecoder; +import com.android.javacard.kmdevice.KMEnum; +import com.android.javacard.kmdevice.KMEnumArrayTag; +import com.android.javacard.kmdevice.KMEnumTag; +import com.android.javacard.kmdevice.KMException; + +import javacard.framework.APDU; +import javacard.framework.Util; + +public class KMKeymasterProvision { + +//Provision reporting status + private static final byte NOT_PROVISIONED = 0x00; + private static final byte PROVISION_STATUS_ATTESTATION_KEY = 0x01; + private static final byte PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x02; + private static final byte PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x04; + private static final byte PROVISION_STATUS_ATTEST_IDS = 0x08; + private static final byte PROVISION_STATUS_PRESHARED_SECRET = 0x10; + private static final byte PROVISION_STATUS_PROVISIONING_LOCKED = 0x20; + private static final byte PROVISION_STATUS_DEVICE_UNIQUE_KEY = 0x40; + private static final byte PROVISION_STATUS_ADDITIONAL_CERT_CHAIN = (byte) 0x80; + private static final short POWER_RESET_MASK_FLAG = (short) 0x4000; + + public static final byte BOOT_KEY_MAX_SIZE = 32; + public static final byte BOOT_HASH_MAX_SIZE = 32; + public static final short SHARED_SECRET_KEY_SIZE = 32; + protected static byte provisionStatus = NOT_PROVISIONED; + + protected KMKeymasterDevice kmDeviceInst; + protected KMSEProvider seProvider; + protected KMDecoder kmDecoder; + protected KMRepository kmRepositroyInst; + + public short getBackupPrimitiveByteCount() { + // provisionStatus + return (short) 1; + } + + public short getBackupObjectCount() { + return (short) 0; + } + + public void onSave(Element ele) { + ele.write(provisionStatus); + } + + public void onRestore(Element ele) { + provisionStatus = ele.readByte(); + } + + public KMKeymasterProvision(KMKeymasterDevice deviceInst, KMSEProvider provider, KMDecoder decoder, KMRepository repoInst){ + kmDeviceInst = deviceInst; + seProvider = provider; + kmDecoder = decoder; + kmRepositroyInst = repoInst; + } + + public void processSetBootParamsCmd(APDU apdu) { + short argsProto = KMArray.instance((short) 5); + + byte[] scratchPad = apdu.getBuffer(); + // Array of 4 expected arguments + // Argument 0 Boot Patch level + KMArray.add(argsProto, (short) 0, KMInteger.exp()); + // Argument 1 Verified Boot Key + KMArray.add(argsProto, (short) 1, KMByteBlob.exp()); + // Argument 2 Verified Boot Hash + KMArray.add(argsProto, (short) 2, KMByteBlob.exp()); + // Argument 3 Verified Boot State + KMArray.add(argsProto, (short) 3, KMEnum.instance(KMType.VERIFIED_BOOT_STATE)); + // Argument 4 Device Locked + KMArray.add(argsProto, (short) 4, KMEnum.instance(KMType.DEVICE_LOCKED)); + + short args = kmDeviceInst.receiveIncoming(apdu, argsProto); + + short bootParam = KMArray.get(args, (short) 0); + + ((KMAndroidSEProvider) seProvider).setBootPatchLevel(KMInteger.getBuffer(bootParam), + KMInteger.getStartOff(bootParam), + KMInteger.length(bootParam)); + + bootParam = KMArray.get(args, (short) 1); + if (KMByteBlob.length(bootParam) > BOOT_KEY_MAX_SIZE) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + ((KMAndroidSEProvider) seProvider).setBootKey(KMByteBlob.getBuffer(bootParam), + KMByteBlob.getStartOff(bootParam), + KMByteBlob.length(bootParam)); + + bootParam = KMArray.get(args, (short) 2); + if (KMByteBlob.length(bootParam) > BOOT_HASH_MAX_SIZE) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + ((KMAndroidSEProvider) seProvider).setVerifiedBootHash(KMByteBlob.getBuffer(bootParam), + KMByteBlob.getStartOff(bootParam), + KMByteBlob.length(bootParam)); + + bootParam = KMArray.get(args, (short) 3); + byte enumVal = KMEnum.getVal(bootParam); + ((KMAndroidSEProvider) seProvider).setBootState(enumVal); + + bootParam = KMArray.get(args, (short) 4); + enumVal = KMEnum.getVal(bootParam); + ((KMAndroidSEProvider) seProvider).setDeviceLocked(enumVal == KMType.DEVICE_LOCKED_TRUE); + + + // Clear the Computed SharedHmac and Hmac nonce from persistent memory. + Util.arrayFillNonAtomic(scratchPad, (short) 0, KMRepository.COMPUTED_HMAC_KEY_SIZE, (byte) 0); + seProvider.createComputedHmacKey(scratchPad, (short) 0, KMRepository.COMPUTED_HMAC_KEY_SIZE); + + kmDeviceInst.reboot(); + kmDeviceInst.sendError(apdu, KMError.OK); + } + + public void processProvisionAttestationKey(APDU apdu) { + // Arguments + short keyparams = KMKeyParameters.exp(); + short keyFormatPtr = KMEnum.instance(KMType.KEY_FORMAT); + short blob = KMByteBlob.exp(); + short argsProto = KMArray.instance((short) 3); + KMArray.add(argsProto, (short) 0, keyparams); + KMArray.add(argsProto, (short) 1, keyFormatPtr); + KMArray.add(argsProto, (short) 2, blob); + + // Re-purpose the apdu buffer as scratch pad. + byte[] scratchPad = apdu.getBuffer(); + + short args = kmDeviceInst.receiveIncoming(apdu, argsProto); + + // key params should have os patch, os version and verified root of trust + short keyParams = KMArray.get(args, (short) 0); + keyFormatPtr = KMArray.get(args, (short) 1); + short rawBlob = KMArray.get(args, (short) 2); + // Key format must be RAW format + short keyFormat = KMEnum.getVal(keyFormatPtr); + if (keyFormat != KMType.RAW) { + KMException.throwIt(KMError.UNIMPLEMENTED); + } + //byte origin = KMType.IMPORTED; + + // get algorithm - only EC keys expected + KMTag.assertPresence(keyParams, KMType.ENUM_TAG, KMType.ALGORITHM, KMError.INVALID_ARGUMENT); + short alg = KMEnumTag.getValue(KMType.ALGORITHM, keyParams); + if (alg != KMType.EC) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + // get digest - only SHA256 supported + KMTag.assertPresence(keyParams, KMType.ENUM_ARRAY_TAG, KMType.DIGEST, KMError.INVALID_ARGUMENT); + short len = KMEnumArrayTag.getValues(KMType.DIGEST, keyParams, scratchPad, (short) 0); + if (len != 1) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + if (scratchPad[0] != KMType.SHA2_256) { + KMException.throwIt(KMError.INCOMPATIBLE_DIGEST); + } + // Purpose should be ATTEST_KEY + KMTag.assertPresence(keyParams, KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, + KMError.INVALID_ARGUMENT); + len = KMEnumArrayTag.getValues(KMType.PURPOSE, keyParams, scratchPad, (short) 0); + if (len != 1) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + if (scratchPad[0] != KMType.ATTEST_KEY) { + KMException.throwIt(KMError.INCOMPATIBLE_PURPOSE); + } + // validate Curve + KMTag.assertPresence(keyParams, KMType.ENUM_TAG, KMType.ECCURVE, KMError.INVALID_ARGUMENT); + short curve = KMEnumTag.getValue(KMType.ECCURVE, keyParams); + if (curve != KMType.P_256) { + KMException.throwIt(KMError.UNSUPPORTED_EC_CURVE); + } + // Decode EC Key + short arrPtr = kmDeviceInst.decodeRawECKey(rawBlob); + short secret = KMArray.get(arrPtr, (short) 0); + short pubKey = KMArray.get(arrPtr, (short) 1); + // Check whether key can be created + seProvider.importAsymmetricKey( + KMType.EC, + KMByteBlob.getBuffer(secret), + KMByteBlob.getStartOff(secret), + KMByteBlob.length(secret), + KMByteBlob.getBuffer(pubKey), + KMByteBlob.getStartOff(pubKey), + KMByteBlob.length(pubKey)); + + // persist key + seProvider.createAttestationKey( + KMByteBlob.getBuffer(secret), + KMByteBlob.getStartOff(secret), + KMByteBlob.length(secret)); + + provisionStatus |= PROVISION_STATUS_ATTESTATION_KEY; + kmDeviceInst.sendError(apdu, KMError.OK); + } + + public void processProvisionAttestationCertDataCmd(APDU apdu) { + // Buffer holds the corresponding offsets and lengths of the certChain, certIssuer and certExpiry + // in the bufferRef[0] buffer. + short var = KMByteBlob.instance((short) 12); + // These variables point to the appropriate positions in the var buffer. + short certChainPos = KMByteBlob.getStartOff(var); + short certIssuerPos = (short) (KMByteBlob.getStartOff(var) + 4); + short certExpiryPos = (short) (KMByteBlob.getStartOff(var) + 8); + short recvLen = apdu.setIncomingAndReceive(); + short bufferLength = apdu.getIncomingLength(); + short bufferStartOffset = kmRepositroyInst.allocReclaimableMemory(bufferLength); + byte[] buffer = kmRepositroyInst.getHeap(); + kmDeviceInst.receiveIncomingCertData(apdu, buffer, bufferLength, + bufferStartOffset, recvLen, KMByteBlob.getBuffer(var), KMByteBlob.getStartOff(var)); + // persist data + seProvider.persistProvisionData( + (byte[]) buffer, + Util.getShort(KMByteBlob.getBuffer(var), certChainPos), // offset + Util.getShort(KMByteBlob.getBuffer(var), (short) (certChainPos + 2)), // length + Util.getShort(KMByteBlob.getBuffer(var), certIssuerPos), // offset + Util.getShort(KMByteBlob.getBuffer(var), (short) (certIssuerPos + 2)), // length + Util.getShort(KMByteBlob.getBuffer(var), certExpiryPos), // offset + Util.getShort(KMByteBlob.getBuffer(var), (short) (certExpiryPos + 2))); // length + + // reclaim memory + kmRepositroyInst.reclaimMemory(bufferLength); + provisionStatus |= (PROVISION_STATUS_ATTESTATION_CERT_CHAIN | + PROVISION_STATUS_ATTESTATION_CERT_PARAMS); + kmDeviceInst.sendError(apdu, KMError.OK); + } + + public void processProvisionAttestIdsCmd(APDU apdu) { + short keyparams = KMKeyParameters.exp(); + short cmd = KMArray.instance((short) 1); + KMArray.add(cmd, (short) 0, keyparams); + short args = kmDeviceInst.receiveIncoming(apdu, cmd); + + short attData = KMArray.get(args, (short) 0); + // persist attestation Ids - if any is missing then exception occurs + setAttestationIds(attData); + provisionStatus |= PROVISION_STATUS_ATTEST_IDS; + kmDeviceInst.sendError(apdu, KMError.OK); + } + + public void processProvisionPreSharedSecretCmd(APDU apdu) { + short blob = KMByteBlob.exp(); + short argsProto = KMArray.instance((short) 1); + KMArray.add(argsProto, (short) 0, blob); + short args = kmDeviceInst.receiveIncoming(apdu, argsProto); + + short val = KMArray.get(args, (short) 0); + + if (val != KMType.INVALID_VALUE + && KMByteBlob.length(val) != SHARED_SECRET_KEY_SIZE) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + // Persist shared Hmac. + ((KMAndroidSEProvider) seProvider).createPresharedKey( + KMByteBlob.getBuffer(val), + KMByteBlob.getStartOff(val), + KMByteBlob.length(val)); + provisionStatus |= PROVISION_STATUS_PRESHARED_SECRET; + kmDeviceInst.sendError(apdu, KMError.OK); + + } + + public void processGetProvisionStatusCmd(APDU apdu) { + short resp = KMArray.instance((short) 2); + KMArray.add(resp, (short) 0, kmDeviceInst.buildErrorStatus(KMError.OK)); + KMArray.add(resp, (short) 1, KMInteger.uint_16(provisionStatus)); + kmDeviceInst.sendOutgoing(apdu, resp); + } + + public void processLockProvisioningCmd(APDU apdu) { + ((KMAndroidSEProvider) seProvider).setProvisionLocked(true); + kmDeviceInst.sendError(apdu, KMError.OK); + } + + public void processProvisionDeviceUniqueKey(APDU apdu) { + kmDeviceInst.sendError(apdu, KMError.CMD_NOT_ALLOWED); + } + + public void processProvisionAdditionalCertChain(APDU apdu) { + kmDeviceInst.sendError(apdu, KMError.CMD_NOT_ALLOWED); + } + + protected void setAttestationIds(short attIdVals) { + short vals = KMKeyParameters.getVals(attIdVals); + short index = 0; + short length = KMArray.length(vals); + short key; + short type; + short obj; + while (index < length) { + obj = KMArray.get(vals, index); + key = KMTag.getKMTagKey(obj); + type = KMTag.getKMTagType(obj); + + if (KMType.BYTES_TAG != type) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + obj = KMByteTag.getValue(obj); + ((KMAndroidSEProvider) seProvider).setAttestationId(key, KMByteBlob.getBuffer(obj), + KMByteBlob.getStartOff(obj),KMByteBlob.length(obj)); + index++; + } + } + +//This function masks the error code with POWER_RESET_MASK_FLAG + // in case if card reset event occurred. The clients of the Applet + // has to extract the power reset status from the error code and + // process accordingly. + public short buildErrorStatus(short err) { + short int32Ptr = KMInteger.instance((short) 4); + short powerResetStatus = 0; + if (((KMAndroidSEProvider) seProvider).isPowerReset(true)) { + powerResetStatus = POWER_RESET_MASK_FLAG; + } + + Util.setShort(KMInteger.getBuffer(int32Ptr), + KMInteger.getStartOff(int32Ptr), + powerResetStatus); + + Util.setShort(KMInteger.getBuffer(int32Ptr), + (short) (KMInteger.getStartOff(int32Ptr) + 2), + err); + // reset power reset status flag to its default value. + //repository.restorePowerResetStatus(); //TODO + return int32Ptr; + } + +} diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMKeymintProvision.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMKeymintProvision.java new file mode 100644 index 00000000..52cca58e --- /dev/null +++ b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMKeymintProvision.java @@ -0,0 +1,111 @@ +package com.android.javacard.seprovider; + +import com.android.javacard.kmdevice.KMArray; +import com.android.javacard.kmdevice.KMByteBlob; +import com.android.javacard.kmdevice.KMCose; +import com.android.javacard.kmdevice.KMCoseHeaders; +import com.android.javacard.kmdevice.KMCoseKey; +import com.android.javacard.kmdevice.KMDecoder; +import com.android.javacard.kmdevice.KMDeviceUniqueKey; +import com.android.javacard.kmdevice.KMException; +import com.android.javacard.kmdevice.KMInteger; +import com.android.javacard.kmdevice.KMKeymasterDevice; +import com.android.javacard.kmdevice.KMMap; +import com.android.javacard.kmdevice.KMRepository; +import com.android.javacard.kmdevice.KMSEProvider; +import com.android.javacard.kmdevice.KMTextString; + +import javacard.framework.APDU; +import javacard.framework.Util; + +public class KMKeymintProvision extends KMKeymasterProvision{ + + public KMKeymintProvision(KMKeymasterDevice deviceInst, KMSEProvider provider, KMDecoder decoder, KMRepository repoInst){ + super(deviceInst, provider, decoder, repoInst); + } + + @Override + public void processProvisionAttestationKey(APDU apdu) { + kmDeviceInst.sendError(apdu, KMError.CMD_NOT_ALLOWED); + } + + @Override + public void processProvisionAttestationCertDataCmd(APDU apdu) { + kmDeviceInst.sendError(apdu, KMError.CMD_NOT_ALLOWED); + } + + @Override + public void processProvisionDeviceUniqueKey(APDU apdu) { + // Re-purpose the apdu buffer as scratch pad. + byte[] scratchPad = apdu.getBuffer(); + short arr = KMArray.instance((short) 1); + short coseKeyExp = KMCoseKey.exp(); + KMArray.add(arr, (short) 0, coseKeyExp); //[ CoseKey ] + arr = kmDeviceInst.receiveIncoming(apdu, arr); + // Get cose key. + short coseKey = KMArray.get(arr, (short) 0); + short pubKeyLen = KMCoseKey.cast(coseKey).getEcdsa256PublicKey(scratchPad, (short) 0); + short privKeyLen = KMCoseKey.cast(coseKey).getPrivateKey(scratchPad, pubKeyLen); + //Store the Device unique Key. + seProvider.createDeviceUniqueKey(false, scratchPad, (short) 0, pubKeyLen, scratchPad, + pubKeyLen, privKeyLen); + short bcc = kmDeviceInst.generateBcc(false, scratchPad); + short len = KMKeymasterDevice.encodeToApduBuffer(bcc, scratchPad, (short) 0, + kmDeviceInst.MAX_COSE_BUF_SIZE); + ((KMAndroidSEProvider) seProvider).persistBootCertificateChain(scratchPad, (short) 0, len); + kmDeviceInst.sendError(apdu, KMError.OK); + } + + @Override + public void processProvisionAdditionalCertChain(APDU apdu) { + // Prepare the expression to decode + short headers = KMCoseHeaders.exp(); + short arrInst = KMArray.instance((short) 4); + KMArray.add(arrInst, (short) 0, KMByteBlob.exp()); + KMArray.add(arrInst, (short) 1, headers); + KMArray.add(arrInst, (short) 2, KMByteBlob.exp()); + KMArray.add(arrInst, (short) 3, KMByteBlob.exp()); + short coseSignArr = KMArray.exp(arrInst); + short map = KMMap.instance((short) 1); + KMMap.add(map, (short) 0, KMTextString.exp(), coseSignArr); + // receive incoming data and decode it. + byte[] srcBuffer = apdu.getBuffer(); + short recvLen = apdu.setIncomingAndReceive(); + short bufferLength = apdu.getIncomingLength(); + short bufferStartOffset = kmRepositroyInst.allocReclaimableMemory(bufferLength); + byte[] buffer = kmRepositroyInst.getHeap(); + map = kmDeviceInst.receiveIncoming(apdu, map, buffer, bufferLength, bufferStartOffset, recvLen); + arrInst = KMMap.getKeyValue(map, (short) 0); + // Validate Additional certificate chain. + short leafCoseKey = + kmDeviceInst.validateCertChain(false, KMCose.COSE_ALG_ES256, KMCose.COSE_ALG_ES256, arrInst, + srcBuffer, null); + // Compare the DK_Pub. + short pubKeyLen = KMCoseKey.cast(leafCoseKey).getEcdsa256PublicKey(srcBuffer, (short) 0); + KMDeviceUniqueKey uniqueKey = seProvider.getDeviceUniqueKey(false); + if (uniqueKey == null) { + KMException.throwIt(KMError.STATUS_FAILED); + } + short uniqueKeyLen = uniqueKey.getPublicKey(srcBuffer, pubKeyLen); + if ((pubKeyLen != uniqueKeyLen) || + (0 != Util.arrayCompare(srcBuffer, (short) 0, srcBuffer, pubKeyLen, pubKeyLen))) { + KMException.throwIt(KMError.STATUS_FAILED); + } + seProvider.persistAdditionalCertChain(buffer, bufferStartOffset, bufferLength); + //reclaim memory + kmRepositroyInst.reclaimMemory(bufferLength); + kmDeviceInst.sendError(apdu, KMError.OK); + } + + @Override + public short buildErrorStatus(short err) { + short int32Ptr = KMInteger.instance((short) 2); + + Util.setShort(KMInteger.getBuffer(int32Ptr), + (short) (KMInteger.getStartOff(int32Ptr)), + err); + + return int32Ptr; + } + +} diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMOperationImpl.java similarity index 99% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java rename to Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMOperationImpl.java index baa8a0f9..4a96131d 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMOperationImpl.java @@ -15,8 +15,9 @@ */ package com.android.javacard.seprovider; +import com.android.javacard.kmdevice.KMException; +import com.android.javacard.kmdevice.KMOperation; import com.android.javacard.seprovider.KMError; -import com.android.javacard.seprovider.KMException; import com.android.javacard.seprovider.KMType; import javacard.framework.JCSystem; import javacard.framework.Util; diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMPoolManager.java similarity index 99% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java rename to Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMPoolManager.java index e3baf610..6d162079 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMPoolManager.java @@ -14,6 +14,9 @@ * limitations under the License. */ package com.android.javacard.seprovider; +import com.android.javacard.kmdevice.KMException; +import com.android.javacard.kmdevice.KMOperation; + import javacard.framework.JCSystem; import javacard.security.KeyAgreement; import javacard.security.Signature; diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsa2048NoDigestSignature.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMRsa2048NoDigestSignature.java similarity index 98% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsa2048NoDigestSignature.java rename to Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMRsa2048NoDigestSignature.java index 303e2b98..89c390bd 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsa2048NoDigestSignature.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMRsa2048NoDigestSignature.java @@ -15,6 +15,8 @@ */ package com.android.javacard.seprovider; +import com.android.javacard.kmdevice.KMException; + import javacard.framework.Util; import javacard.security.CryptoException; import javacard.security.Key; diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsaOAEPEncoding.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMRsaOAEPEncoding.java similarity index 100% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsaOAEPEncoding.java rename to Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMRsaOAEPEncoding.java diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMType.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMType.java similarity index 100% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMType.java rename to Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMType.java diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java deleted file mode 100644 index 0f68de61..00000000 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright(C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; -import javacard.security.ECPrivateKey; -import javacard.security.ECPublicKey; -import javacard.security.KeyPair; - -public class KMECDeviceUniqueKey implements KMDeviceUniqueKey { - - private KeyPair ecKeyPair; - - @Override - public short getPublicKey(byte[] buf, short offset) { - ECPublicKey publicKey = getPublicKey(); - return publicKey.getW(buf, offset); - } - - public KMECDeviceUniqueKey(KeyPair ecPair) { - ecKeyPair = ecPair; - } - - public void setS(byte[] buffer, short offset, short length) { - ECPrivateKey ecPriv = (ECPrivateKey) ecKeyPair.getPrivate(); - ecPriv.setS(buffer, offset, length); - } - - public void setW(byte[] buffer, short offset, short length) { - ECPublicKey ecPublicKey = (ECPublicKey) ecKeyPair.getPublic(); - ecPublicKey.setW(buffer, offset, length); - } - - public ECPrivateKey getPrivateKey() { - return (ECPrivateKey) ecKeyPair.getPrivate(); - } - - public ECPublicKey getPublicKey() { - return (ECPublicKey) ecKeyPair.getPublic(); - } - -} diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMException.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMException.java deleted file mode 100644 index c0b2431f..00000000 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMException.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.seprovider; - -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 { - - private static short[] reason; - private static KMException exception; - - private KMException() { - } - public static short reason(){ - return reason[0]; - } - public static void throwIt(short e) { - if(reason == null) { - reason = JCSystem.makeTransientShortArray((short)1,JCSystem.CLEAR_ON_DESELECT); - } - if(exception == null){ - exception = new KMException(); - } - reason[0] = e; - throw exception; - } -/* - public static KMException instance() { - if (exception == null) { - exception = new KMException(); - } - return exception; - } -*/ -} - - diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java deleted file mode 100644 index 7dbef4d6..00000000 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ /dev/null @@ -1,1083 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.keymaster; - -import com.android.javacard.seprovider.KMAESKey; -import com.android.javacard.seprovider.KMAttestationCert; -import com.android.javacard.seprovider.KMAttestationKey; -import com.android.javacard.seprovider.KMException; -import com.android.javacard.seprovider.KMJCardSimulator; -import com.android.javacard.seprovider.KMMasterKey; -import com.android.javacard.seprovider.KMSEProvider; -import javacard.framework.JCSystem; -import javacard.framework.Util; - -// The class encodes strongbox generated amd signed attestation certificate. This only encodes -// required fields of the certificates. It is not meant to be generic X509 cert encoder. -// Whatever fields that are fixed are added as byte arrays. The Extensions are encoded as per -// the values. -// The certificate is assembled with leafs first and then the sequences. - -public class KMAttestationCertImpl implements KMAttestationCert { - - private static final byte MAX_PARAMS = 30; - // DER encoded object identifiers required by the cert. - // rsaEncryption - 1.2.840.113549.1.1.1 - private static final byte[] rsaEncryption = { - 0x06, 0x09, 0x2A, (byte) 0x86, 0x48, (byte) 0x86, (byte) 0xF7, 0x0D, 0x01, 0x01, 0x01 - }; - // ecPublicKey - 1.2.840.10045.2.1 - private static final byte[] eccPubKey = { - 0x06, 0x07, 0x2A, (byte) 0x86, 0x48, (byte) 0xCE, 0x3D, 0x02, 0x01 - }; - // prime256v1 curve - 1.2.840.10045.3.1.7 - private static final byte[] prime256v1 = { - 0x06, 0x08, 0x2A, (byte) 0x86, 0x48, (byte) 0xCE, 0x3D, 0x03, 0x01, 0x07 - }; - // Key Usage Extn - 2.5.29.15 - private static final byte[] keyUsageExtn = {0x06, 0x03, 0x55, 0x1D, 0x0F}; - // Android Extn - 1.3.6.1.4.1.11129.2.1.17 - private static final byte[] androidExtn = { - 0x06, 0x0A, 0X2B, 0X06, 0X01, 0X04, 0X01, (byte) 0XD6, 0X79, 0X02, 0X01, 0X11 - }; - private static final short RSA_SIG_LEN = 256; - private static final short ECDSA_MAX_SIG_LEN = 72; - //Signature algorithm identifier - ecdsaWithSha256 - 1.2.840.10045.4.3.2 - //SEQUENCE of alg OBJ ID and parameters = NULL. - private static final byte[] X509EcdsaSignAlgIdentifier = { - 0x30, - 0x0A, - 0x06, - 0x08, - 0x2A, - (byte) 0x86, - 0x48, - (byte) 0xCE, - (byte) 0x3D, - 0x04, - 0x03, - 0x02 - }; - // Signature algorithm identifier - sha256WithRSAEncryption - 1.2.840.113549.1.1.11 - // SEQUENCE of alg OBJ ID and parameters = NULL. - private static final byte[] X509RsaSignAlgIdentifier = { - 0x30, - 0x0D, - 0x06, - 0x09, - 0x2A, - (byte) 0x86, - 0x48, - (byte) 0x86, - (byte) 0xF7, - 0x0D, - 0x01, - 0x01, - 0x0B, - 0x05, - 0x00 - }; - // Validity is not fixed field - // Subject is a fixed field with only CN= Android Keystore Key - same for all the keys - private static final byte[] X509Subject = { - 0x30, 0x1F, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x14, 0x41, 0x6e, - 0x64, - 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4B, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x4B, - 0x65, - 0x79 - }; - - private static final byte keyUsageSign = (byte) 0x80; // 0 bit - private static final byte keyUsageKeyEncipher = (byte) 0x20; // 2nd- bit - private static final byte keyUsageDataEncipher = (byte) 0x10; // 3rd- bit - private static final byte keyUsageKeyAgreement = (byte) 0x08; // 4th- bit - private static final byte keyUsageCertSign = (byte) 0x04; // 5th- bit - - private static final byte KEYMASTER_VERSION = 100; - private static final byte ATTESTATION_VERSION = 100; - private static final byte[] pubExponent = {0x01, 0x00, 0x01}; - private static final byte SERIAL_NUM = (byte) 0x01; - private static final byte X509_VERSION = (byte) 0x02; - - private static short certStart; - private static short certLength; - private static short tbsStart; - private static short tbsLength; - private static byte[] stack; - private static short stackPtr; - private static short bufStart; - private static short bufLength; - private static KMSEProvider seProvider; - - private static short uniqueId; - private static short attChallenge; - private static short notBefore; - - private static short notAfter; - private static short pubKey; - private static short[] swParams; - private static short swParamsIndex; - private static short[] hwParams; - private static short hwParamsIndex; - private static byte keyUsage; - private static byte unusedBits; - private static KMAttestationCert inst; - private static boolean rsaCert; - private static byte deviceLocked; - private static short verifiedBootKey; - private static byte verifiedState; - private static short verifiedHash; - private static short issuer; - private static short subjectName; - private static short signPriv; - private static short serialNum; - - private static byte certMode; - private static short certAttestKeySecret; - private static short certAttestKeyRsaPubModulus; - private static KMAttestationKey factoryAttestKey; - private static boolean certRsaSign; - private static final byte SERIAL_NUM_MAX_LEN = 20; - private static final byte SUBJECT_NAME_MAX_LEN = 32; - - private KMAttestationCertImpl() { - } - - public static KMAttestationCert instance(boolean rsaCert, KMSEProvider provider) { - if (inst == null) { - inst = new KMAttestationCertImpl(); - seProvider = provider; - } - init(); - KMAttestationCertImpl.rsaCert = rsaCert; - return inst; - } - - private static void init() { - stack = null; - stackPtr = 0; - certStart = 0; - certLength = 0; - bufStart = 0; - bufLength = 0; - tbsLength = 0; - if (swParams == null) { - swParams = JCSystem.makeTransientShortArray((short) MAX_PARAMS, JCSystem.CLEAR_ON_RESET); - } - if (hwParams == null) { - hwParams = JCSystem.makeTransientShortArray((short) MAX_PARAMS, JCSystem.CLEAR_ON_RESET); - } - - swParamsIndex = 0; - hwParamsIndex = 0; - keyUsage = 0; - unusedBits = 8; - attChallenge = 0; - notBefore = 0; - notAfter = 0; - pubKey = 0; - uniqueId = 0; - verifiedBootKey = 0; - verifiedHash = 0; - verifiedState = 0; - rsaCert = true; - deviceLocked = 0; - signPriv = 0; - certMode = KMType.NO_CERT; - certAttestKeySecret = KMType.INVALID_VALUE; - certRsaSign = true; - issuer = KMType.INVALID_VALUE; - subjectName = KMType.INVALID_VALUE; - serialNum = KMType.INVALID_VALUE; - factoryAttestKey = null; - } - - @Override - public KMAttestationCert verifiedBootHash(short obj) { - verifiedHash = obj; - return this; - } - - @Override - public KMAttestationCert verifiedBootKey(short obj) { - verifiedBootKey = obj; - return this; - } - - @Override - public KMAttestationCert verifiedBootState(byte val) { - verifiedState = val; - return this; - } - - private KMAttestationCert uniqueId(short obj) { - uniqueId = obj; - return this; - } - - @Override - public KMAttestationCert notBefore(short obj, boolean derEncoded, byte[] scratchpad) { - if(!derEncoded) { - // convert milliseconds to UTC date - notBefore = KMUtils.convertToDate(obj, scratchpad, true); - }else{ - notBefore = KMByteBlob.instance(KMByteBlob.cast(obj).getBuffer(), - KMByteBlob.cast(obj).getStartOff(), KMByteBlob.cast(obj).length()); - } - return this; - } - - @Override - public KMAttestationCert notAfter(short usageExpiryTimeObj, boolean derEncoded, - byte[] scratchPad) { - if (!derEncoded) { - if (usageExpiryTimeObj != KMType.INVALID_VALUE) { - // compare if the expiry time is greater then 2051 then use generalized - // time format else use utc time format. - short tmpVar = KMInteger.uint_64(KMUtils.firstJan2051, (short) 0); - if (KMInteger.compare(usageExpiryTimeObj, tmpVar) >= 0) { - usageExpiryTimeObj = KMUtils.convertToDate(usageExpiryTimeObj, scratchPad, - false); - } else { - usageExpiryTimeObj = KMUtils - .convertToDate(usageExpiryTimeObj, scratchPad, true); - } - notAfter = usageExpiryTimeObj; - } else { - //notAfter = certExpirtyTimeObj; - } - } else { - // notAfter = KMByteBlob.instance(KMByteBlob.cast(usageExpiryTimeObj).getBuffer(), - // KMByteBlob.cast(usageExpiryTimeObj).getStartOff(), - // KMByteBlob.cast(usageExpiryTimeObj).length()); - notAfter = usageExpiryTimeObj; - } - return this; - } - - @Override - public KMAttestationCert deviceLocked(boolean val) { - if (val) { - deviceLocked = (byte) 0xFF; - } else { - deviceLocked = 0; - } - return this; - } - - @Override - public KMAttestationCert publicKey(short obj) { - pubKey = obj; - return this; - } - - @Override - public KMAttestationCert attestationChallenge(short obj) { - attChallenge = obj; - return this; - } - - @Override - public KMAttestationCert extensionTag(short tag, boolean hwEnforced) { - if (hwEnforced) { - hwParams[hwParamsIndex] = tag; - hwParamsIndex++; - } else { - swParams[swParamsIndex] = tag; - swParamsIndex++; - } - if (KMTag.getKey(tag) == KMType.PURPOSE) { - createKeyUsage(tag); - } - return this; - } - - @Override - public KMAttestationCert issuer(short obj) { - issuer = obj; - return this; - } - - private void createKeyUsage(short tag) { - short len = KMEnumArrayTag.cast(tag).length(); - byte index = 0; - while (index < len) { - if (KMEnumArrayTag.cast(tag).get(index) == KMType.SIGN) { - keyUsage = (byte) (keyUsage | keyUsageSign); - } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.WRAP_KEY) { - keyUsage = (byte) (keyUsage | keyUsageKeyEncipher); - } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.DECRYPT) { - keyUsage = (byte) (keyUsage | keyUsageDataEncipher); - } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.AGREE_KEY){ - keyUsage = (byte) (keyUsage | keyUsageKeyAgreement); - }else if (KMEnumArrayTag.cast(tag).get(index) == KMType.ATTEST_KEY){ - keyUsage = (byte) (keyUsage | keyUsageCertSign); - } - index++; - } - index = keyUsage; - while (index != 0) { - index = (byte) (index << 1); - unusedBits--; - } - } - -//TODO Serial number, X509Version needa to be passed as parameter - private static void pushTbsCert(boolean rsaCert, boolean rsa) { - short last = stackPtr; - if(certMode == KMType.ATTESTATION_CERT || certMode == KMType.FACTORY_PROVISIONED_ATTEST_CERT) { - pushExtensions(); - } - // subject public key info - if (rsaCert) { - pushRsaSubjectKeyInfo(); - } else { - pushEccSubjectKeyInfo(); - } - // subject - pushBytes(KMByteBlob.cast(subjectName).getBuffer(), KMByteBlob.cast(subjectName).getStartOff(), - KMByteBlob.cast(subjectName).length()); - pushValidity(); - // issuer - der encoded - pushBytes( - KMByteBlob.cast(issuer).getBuffer(), - KMByteBlob.cast(issuer).getStartOff(), - KMByteBlob.cast(issuer).length()); - // Algorithm Id - if(rsa) { - pushAlgorithmId(X509RsaSignAlgIdentifier); - }else{ - pushAlgorithmId(X509EcdsaSignAlgIdentifier); - } - // Serial Number - pushBytes(KMByteBlob.cast(serialNum).getBuffer(), KMByteBlob.cast(serialNum).getStartOff(), - KMByteBlob.cast(serialNum).length()); - pushIntegerHeader(KMByteBlob.cast(serialNum).length()); - // Version - pushByte(X509_VERSION); - pushIntegerHeader((short) 1); - pushByte((byte) 0x03); - pushByte((byte) 0xA0); - // Finally sequence header. - pushSequenceHeader((short) (last - stackPtr)); - } - - private static void pushExtensions() { - short last = stackPtr; - if (keyUsage != 0) { - pushKeyUsage(keyUsage, unusedBits); - } - pushKeyDescription(); - pushSequenceHeader((short) (last - stackPtr)); - // Extensions have explicit tag of [3] - pushLength((short) (last - stackPtr)); - pushByte((byte) 0xA3); - } - - // Time SEQUENCE{UTCTime, UTC or Generalized Time) - private static void pushValidity() { - short last = stackPtr; - if (notAfter != 0) { - pushBytes( - KMByteBlob.cast(notAfter).getBuffer(), - KMByteBlob.cast(notAfter).getStartOff(), - KMByteBlob.cast(notAfter).length()); - } else { - KMException.throwIt(KMError.INVALID_DATA); - } - pushTimeHeader(KMByteBlob.cast(notAfter).length()); - pushBytes( - KMByteBlob.cast(notBefore).getBuffer(), - KMByteBlob.cast(notBefore).getStartOff(), - KMByteBlob.cast(notBefore).length()); - pushTimeHeader(KMByteBlob.cast(notBefore).length()); - pushSequenceHeader((short) (last - stackPtr)); - } - - private static void pushTimeHeader(short len) { - if (len == 13) { // UTC Time - pushLength((short) 0x0D); - pushByte((byte) 0x17); - } else if (len == 15) { // Generalized Time - pushLength((short) 0x0F); - pushByte((byte) 0x18); - } else { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - } - - // SEQUENCE{SEQUENCE{algId, NULL}, bitString{SEQUENCE{ modulus as positive integer, public - // exponent - // as positive integer} - private static void pushRsaSubjectKeyInfo() { - short last = stackPtr; - pushBytes(pubExponent, (short) 0, (short) pubExponent.length); - pushIntegerHeader((short) pubExponent.length); - pushBytes( - KMByteBlob.cast(pubKey).getBuffer(), - KMByteBlob.cast(pubKey).getStartOff(), - KMByteBlob.cast(pubKey).length()); - - // encode modulus as positive if the MSB is 1. - if (KMByteBlob.cast(pubKey).get((short) 0) < 0) { - pushByte((byte) 0x00); - pushIntegerHeader((short) (KMByteBlob.cast(pubKey).length() + 1)); - } else { - pushIntegerHeader(KMByteBlob.cast(pubKey).length()); - } - pushSequenceHeader((short) (last - stackPtr)); - pushBitStringHeader((byte) 0x00, (short) (last - stackPtr)); - pushRsaEncryption(); - pushSequenceHeader((short) (last - stackPtr)); - } - - // SEQUENCE{SEQUENCE{ecPubKey, prime256v1}, bitString{pubKey}} - private static void pushEccSubjectKeyInfo() { - short last = stackPtr; - pushBytes( - KMByteBlob.cast(pubKey).getBuffer(), - KMByteBlob.cast(pubKey).getStartOff(), - KMByteBlob.cast(pubKey).length()); - pushBitStringHeader((byte) 0x00, KMByteBlob.cast(pubKey).length()); - pushEcDsa(); - pushSequenceHeader((short) (last - stackPtr)); - } - - private static void pushEcDsa() { - short last = stackPtr; - pushBytes(prime256v1, (short) 0, (short) prime256v1.length); - pushBytes(eccPubKey, (short) 0, (short) eccPubKey.length); - pushSequenceHeader((short) (last - stackPtr)); - } - - private static void pushRsaEncryption() { - short last = stackPtr; - pushNullHeader(); - pushBytes(rsaEncryption, (short) 0, (short) rsaEncryption.length); - pushSequenceHeader((short) (last - stackPtr)); - } - - // KeyDescription ::= SEQUENCE { - // attestationVersion INTEGER, # Value 3 - // attestationSecurityLevel SecurityLevel, # See below - // keymasterVersion INTEGER, # Value 4 - // keymasterSecurityLevel SecurityLevel, # See below - // attestationChallenge OCTET_STRING, # Tag::ATTESTATION_CHALLENGE from attestParams - // uniqueId OCTET_STRING, # Empty unless key has Tag::INCLUDE_UNIQUE_ID - // softwareEnforced AuthorizationList, # See below - // hardwareEnforced AuthorizationList, # See below - // } - private static void pushKeyDescription() { - short last = stackPtr; - pushHWParams(); - pushSWParams(); - if (uniqueId != 0) { - pushOctetString( - KMByteBlob.cast(uniqueId).getBuffer(), - KMByteBlob.cast(uniqueId).getStartOff(), - KMByteBlob.cast(uniqueId).length()); - } else { - pushOctetStringHeader((short) 0); - } - pushOctetString( - KMByteBlob.cast(attChallenge).getBuffer(), - KMByteBlob.cast(attChallenge).getStartOff(), - KMByteBlob.cast(attChallenge).length()); - pushEnumerated(KMType.STRONGBOX); - pushByte(KEYMASTER_VERSION); - pushIntegerHeader((short) 1); - pushEnumerated(KMType.STRONGBOX); - pushByte(ATTESTATION_VERSION); - pushIntegerHeader((short) 1); - pushSequenceHeader((short) (last - stackPtr)); - pushOctetStringHeader((short) (last - stackPtr)); - pushBytes(androidExtn, (short) 0, (short) androidExtn.length); - pushSequenceHeader((short) (last - stackPtr)); - } - - private static void pushSWParams() { - short last = stackPtr; - // Below are the allowed softwareEnforced Authorization tags inside the attestation certificate's extension. - short[] tagIds = { - KMType.ATTESTATION_APPLICATION_ID, KMType.CREATION_DATETIME, - KMType.USAGE_EXPIRE_DATETIME, KMType.ORIGINATION_EXPIRE_DATETIME, - KMType.ACTIVE_DATETIME, KMType.UNLOCKED_DEVICE_REQUIRED}; - byte index = 0; - do { - pushParams(swParams, swParamsIndex, tagIds[index]); - } while (++index < tagIds.length); - pushSequenceHeader((short) (last - stackPtr)); - } - - private static void pushHWParams() { - short last = stackPtr; - // Below are the allowed hardwareEnforced Authorization tags inside the attestation certificate's extension. - short[] tagIds = { - KMType.BOOT_PATCH_LEVEL, KMType.VENDOR_PATCH_LEVEL, - KMType.ATTESTATION_ID_MODEL, KMType.ATTESTATION_ID_MANUFACTURER, - KMType.ATTESTATION_ID_MEID, KMType.ATTESTATION_ID_IMEI, - KMType.ATTESTATION_ID_SERIAL, KMType.ATTESTATION_ID_PRODUCT, - KMType.ATTESTATION_ID_DEVICE, KMType.ATTESTATION_ID_BRAND, - KMType.OS_PATCH_LEVEL, KMType.OS_VERSION, KMType.ROOT_OF_TRUST, - KMType.ORIGIN, KMType.AUTH_TIMEOUT, KMType.USER_AUTH_TYPE, - KMType.NO_AUTH_REQUIRED, KMType.USER_SECURE_ID, - KMType.RSA_PUBLIC_EXPONENT, KMType.ECCURVE, KMType.MIN_MAC_LENGTH, - KMType.CALLER_NONCE, KMType.PADDING, KMType.DIGEST, KMType.BLOCK_MODE, - KMType.KEYSIZE, KMType.ALGORITHM, KMType.PURPOSE}; - - byte index = 0; - do { - if (tagIds[index] == KMType.ROOT_OF_TRUST) { - pushRoT(); - continue; - } - if (pushParams(hwParams, hwParamsIndex, tagIds[index])) { - continue; - } - } while (++index < tagIds.length); - pushSequenceHeader((short) (last - stackPtr)); - } - - private static boolean pushParams(short[] params, short len, short tagId) { - short index = 0; - while (index < len) { - if (tagId == KMTag.getKey(params[index])) { - pushTag(params[index]); - return true; - } - index++; - } - return false; - } - - private static void pushTag(short tag) { - short type = KMTag.getTagType(tag); - short tagId = KMTag.getKey(tag); - short val; - switch (type) { - case KMType.BYTES_TAG: - val = KMByteTag.cast(tag).getValue(); - pushBytesTag( - tagId, - KMByteBlob.cast(val).getBuffer(), - KMByteBlob.cast(val).getStartOff(), - KMByteBlob.cast(val).length()); - break; - case KMType.ENUM_TAG: - val = KMEnumTag.cast(tag).getValue(); - pushEnumTag(tagId, (byte) val); - break; - case KMType.ENUM_ARRAY_TAG: - val = KMEnumArrayTag.cast(tag).getValues(); - pushEnumArrayTag( - tagId, - KMByteBlob.cast(val).getBuffer(), - KMByteBlob.cast(val).getStartOff(), - KMByteBlob.cast(val).length()); - break; - case KMType.UINT_TAG: - case KMType.ULONG_TAG: - case KMType.DATE_TAG: - val = KMIntegerTag.cast(tag).getValue(); - pushIntegerTag( - tagId, - KMInteger.cast(val).getBuffer(), - KMInteger.cast(val).getStartOff(), - KMInteger.cast(val).length()); - break; - case KMType.UINT_ARRAY_TAG: - case KMType.ULONG_ARRAY_TAG: - // According to keymaster hal only one user secure id is used but this conflicts with - // tag type which is ULONG-REP. Currently this is encoded as SET OF INTEGERS - val = KMIntegerArrayTag.cast(tag).getValues(); - pushIntegerArrayTag(tagId, val); - break; - case KMType.BOOL_TAG: - val = KMBoolTag.cast(tag).getVal(); - pushBoolTag(tagId); - break; - default: - KMException.throwIt(KMError.INVALID_TAG); - break; - } - } - - // RootOfTrust ::= SEQUENCE { - // verifiedBootKey OCTET_STRING, - // deviceLocked BOOLEAN, - // verifiedBootState VerifiedBootState, - // verifiedBootHash OCTET_STRING, - // } - // VerifiedBootState ::= ENUMERATED { - // Verified (0), - // SelfSigned (1), - // Unverified (2), - // Failed (3), - // } - private static void pushRoT() { - short last = stackPtr; - // verified boot hash - pushOctetString( - KMByteBlob.cast(verifiedHash).getBuffer(), - KMByteBlob.cast(verifiedHash).getStartOff(), - KMByteBlob.cast(verifiedHash).length()); - - pushEnumerated(verifiedState); - - pushBoolean(deviceLocked); - // verified boot Key - pushOctetString( - KMByteBlob.cast(verifiedBootKey).getBuffer(), - KMByteBlob.cast(verifiedBootKey).getStartOff(), - KMByteBlob.cast(verifiedBootKey).length()); - - // Finally sequence header - pushSequenceHeader((short) (last - stackPtr)); - // ... and tag Id - pushTagIdHeader(KMType.ROOT_OF_TRUST, (short) (last - stackPtr)); - } - - private static void pushOctetString(byte[] buf, short start, short len) { - pushBytes(buf, start, len); - pushOctetStringHeader(len); - } - - private static void pushBoolean(byte val) { - pushByte(val); - pushBooleanHeader((short) 1); - } - - private static void pushBooleanHeader(short len) { - pushLength(len); - pushByte((byte) 0x01); - } - - // Only SET of INTEGERS supported are padding, digest, purpose and blockmode - // All of these are enum array tags i.e. byte long values - private static void pushEnumArrayTag(short tagId, byte[] buf, short start, short len) { - short last = stackPtr; - short index = 0; - while (index < len) { - pushByte(buf[(short) (start + index)]); - pushIntegerHeader((short) 1); - index++; - } - pushSetHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); - } - - // Only SET of INTEGERS supported are padding, digest, purpose and blockmode - // All of these are enum array tags i.e. byte long values - private static void pushIntegerArrayTag(short tagId, short arr) { - short last = stackPtr; - short index = 0; - short len = KMArray.cast(arr).length(); - short ptr; - while (index < len) { - ptr = KMArray.cast(arr).get(index); - pushInteger( - KMInteger.cast(ptr).getBuffer(), - KMInteger.cast(ptr).getStartOff(), - KMInteger.cast(ptr).length()); - index++; - } - pushSetHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); - } - - private static void pushSetHeader(short len) { - pushLength(len); - pushByte((byte) 0x31); - } - - private static void pushEnumerated(byte val) { - short last = stackPtr; - pushByte(val); - pushEnumeratedHeader((short) (last - stackPtr)); - } - - private static void pushEnumeratedHeader(short len) { - pushLength(len); - pushByte((byte) 0x0A); - } - - private static void pushBoolTag(short tagId) { - short last = stackPtr; - pushNullHeader(); - pushTagIdHeader(tagId, (short) (last - stackPtr)); - } - - private static void pushNullHeader() { - pushByte((byte) 0); - pushByte((byte) 0x05); - } - - private static void pushEnumTag(short tagId, byte val) { - short last = stackPtr; - pushByte(val); - pushIntegerHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); - } - - private static void pushIntegerTag(short tagId, byte[] buf, short start, short len) { - short last = stackPtr; - pushInteger(buf, start, len); - // pushIntegerHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); - } - - // Ignore leading zeros. Only Unsigned Integers are required hence if MSB is set then add 0x00 - // as most significant byte. - private static void pushInteger(byte[] buf, short start, short len) { - short last = stackPtr; - byte index = 0; - while (index < (byte) len) { - if (buf[(short) (start + index)] != 0) { - break; - } - index++; - } - if (index == (byte) len) { - pushByte((byte) 0x00); - } else { - pushBytes(buf, (short) (start + index), (short) (len - index)); - if (buf[(short) (start + index)] < 0) { // MSB is 1 - pushByte((byte) 0x00); // always unsigned int - } - } - pushIntegerHeader((short) (last - stackPtr)); - } - - // Bytes Tag is a octet string and tag id is added explicitly - private static void pushBytesTag(short tagId, byte[] buf, short start, short len) { - short last = stackPtr; - pushBytes(buf, start, len); - pushOctetStringHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); - } - - // tag id <= 30 ---> 0xA0 | {tagId} - // 30 < tagId < 128 ---> 0xBF 0x{tagId} - // tagId >= 128 ---> 0xBF 0x80+(tagId/128) 0x{tagId - (128*(tagId/128))} - private static void pushTagIdHeader(short tagId, short len) { - pushLength(len); - short count = (short) (tagId / 128); - if (count > 0) { - pushByte((byte) (tagId - (128 * count))); - pushByte((byte) (0x80 + count)); - pushByte((byte) 0xBF); - } else if (tagId > 30) { - pushByte((byte) tagId); - pushByte((byte) 0xBF); - } else { - pushByte((byte) (0xA0 | (byte) tagId)); - } - } - - // SEQUENCE {ObjId, OCTET STRING{BIT STRING{keyUsage}}} - private static void pushKeyUsage(byte keyUsage, byte unusedBits) { - short last = stackPtr; - pushByte(keyUsage); - pushBitStringHeader(unusedBits, (short) (last - stackPtr)); - pushOctetStringHeader((short) (last - stackPtr)); - pushBytes(keyUsageExtn, (short) 0, (short) keyUsageExtn.length); - pushSequenceHeader((short) (last - stackPtr)); - } - - private static void pushAlgorithmId(byte[] algId) { - pushBytes(algId, (short) 0, (short) algId.length); - } - - private static void pushIntegerHeader(short len) { - pushLength(len); - pushByte((byte) 0x02); - } - - private static void pushOctetStringHeader(short len) { - pushLength(len); - pushByte((byte) 0x04); - } - - private static void pushSequenceHeader(short len) { - pushLength(len); - pushByte((byte) 0x30); - } - - private static void pushBitStringHeader(byte unusedBits, short len) { - pushByte(unusedBits); - pushLength((short) (len + 1)); // 1 extra byte for unused bits byte - pushByte((byte) 0x03); - } - - private static void pushLength(short len) { - if (len < 128) { - pushByte((byte) len); - } else if (len < 256) { - pushByte((byte) len); - pushByte((byte) 0x81); - } else { - pushShort(len); - pushByte((byte) 0x82); - } - } - - private static void pushShort(short val) { - decrementStackPtr((short) 2); - Util.setShort(stack, stackPtr, val); - } - - private static void pushByte(byte val) { - decrementStackPtr((short) 1); - stack[stackPtr] = val; - } - - private static void pushBytes(byte[] buf, short start, short len) { - decrementStackPtr(len); - if (buf != null) { - Util.arrayCopyNonAtomic(buf, start, stack, stackPtr, len); - } - } - - private static void decrementStackPtr(short cnt) { - stackPtr = (short) (stackPtr - cnt); - if (bufStart > stackPtr) { - KMException.throwIt(KMError.UNKNOWN_ERROR); - } - } - - @Override - public KMAttestationCert buffer(byte[] buf, short start, short maxLen) { - stack = buf; - bufStart = start; - bufLength = maxLen; - stackPtr = (short) (bufStart + bufLength); - return this; - } - - @Override - public short getCertStart() { - return certStart; - } - - @Override - public short getCertLength() { - return certLength; - } - - - public void build(KMAttestationKey factoryAttestKey, short attSecret, short attMod, - boolean rsaSign, boolean fakeCert) { - stackPtr = (short)(bufStart + bufLength); - short last = stackPtr; - short sigLen = 0; - if(fakeCert){ - rsaSign = true; - pushByte((byte)0); - sigLen = 1; - } - // Push placeholder signature Bit string header - // This will potentially change at the end - else if (rsaSign) { - decrementStackPtr(RSA_SIG_LEN); - } else { - decrementStackPtr(ECDSA_MAX_SIG_LEN); - } - short signatureOffset = stackPtr; - pushBitStringHeader((byte) 0, (short) (last - stackPtr)); - if (rsaSign) { - pushAlgorithmId(X509RsaSignAlgIdentifier); - } else { - pushAlgorithmId(X509EcdsaSignAlgIdentifier); - } - tbsLength = stackPtr; - pushTbsCert(rsaCert, rsaSign); - tbsStart = stackPtr; - tbsLength = (short) (tbsLength - tbsStart); - KMJCardSimulator provider = KMJCardSimulator.getInstance(); - if(attSecret != KMType.INVALID_VALUE || factoryAttestKey != null) { - // Sign with the attestation key - // The pubKey is the modulus. - if (rsaSign) { - sigLen = provider - .rsaSign256Pkcs1( - KMByteBlob.cast(attSecret).getBuffer(), - KMByteBlob.cast(attSecret).getStartOff(), - KMByteBlob.cast(attSecret).length(), - KMByteBlob.cast(attMod).getBuffer(), - KMByteBlob.cast(attMod).getStartOff(), - KMByteBlob.cast(attMod).length(), - stack, - tbsStart, - tbsLength, - stack, - signatureOffset); - if(sigLen > RSA_SIG_LEN) KMException.throwIt(KMError.UNKNOWN_ERROR); - } else if (factoryAttestKey != null) { - sigLen = provider - .ecSign256( - factoryAttestKey, - stack, - tbsStart, - tbsLength, - stack, - signatureOffset); - if (sigLen > ECDSA_MAX_SIG_LEN) KMException.throwIt(KMError.UNKNOWN_ERROR); - } else { - sigLen = provider - .ecSign256( - KMByteBlob.cast(attSecret).getBuffer(), - KMByteBlob.cast(attSecret).getStartOff(), - KMByteBlob.cast(attSecret).length(), - stack, - tbsStart, - tbsLength, - stack, - signatureOffset); - if (sigLen > ECDSA_MAX_SIG_LEN) KMException.throwIt(KMError.UNKNOWN_ERROR); - } - // Adjust signature length - stackPtr = signatureOffset; - pushBitStringHeader((byte) 0, sigLen); - } else if(!fakeCert) { // no attestation key provisioned in the factory - KMException.throwIt(KMError.ATTESTATION_KEYS_NOT_PROVISIONED); - } - last = (short)(signatureOffset+sigLen); - // Add certificate sequence header - stackPtr = tbsStart; - pushSequenceHeader((short) (last - stackPtr)); - certStart = stackPtr; - certLength = (short)(last - certStart); - print(stack, getCertStart(), getCertLength()); - } - - - @Override - public void build() { - if (certMode == KMType.FAKE_CERT) { - build(null, KMType.INVALID_VALUE, KMType.INVALID_VALUE, true, true); - } else if (certMode == KMType.FACTORY_PROVISIONED_ATTEST_CERT) { - build(factoryAttestKey, KMType.INVALID_VALUE, KMType.INVALID_VALUE, false, false); - } else { - build(null, certAttestKeySecret, certAttestKeyRsaPubModulus, certRsaSign, false); - } - } - - @Override - public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, - byte[] creationTime, short timeOffset, short creationTimeLen, - byte[] attestAppId, short appIdOff, short attestAppIdLen, - byte resetSinceIdRotation, KMMasterKey masterKey) { - // Concatenate T||C||R - // temporal count T - short temp = KMUtils.countTemporalCount(creationTime, timeOffset, - creationTimeLen, scratchPad, scratchPadOff); - Util.setShort(scratchPad, (short) scratchPadOff, temp); - temp = scratchPadOff; - scratchPadOff += 2; - - // Application Id C - Util.arrayCopyNonAtomic(attestAppId, appIdOff, scratchPad, scratchPadOff, - attestAppIdLen); - scratchPadOff += attestAppIdLen; - - // Reset After Rotation R - scratchPad[scratchPadOff] = resetSinceIdRotation; - scratchPadOff++; - - //Get the key data from the master key - KMAESKey aesKey = (KMAESKey) masterKey; - short mKeyData = KMByteBlob.instance((short) (aesKey.getKeySizeBits() / 8)); - aesKey.getKey( - KMByteBlob.cast(mKeyData).getBuffer(), /* Key */ - KMByteBlob.cast(mKeyData).getStartOff()); /* Key start*/ - timeOffset = KMByteBlob.instance((short) 32); - appIdOff = KMJCardSimulator.getInstance().hmacSign( - KMByteBlob.cast(mKeyData).getBuffer(), /* Key */ - KMByteBlob.cast(mKeyData).getStartOff(), /* Key start*/ - KMByteBlob.cast(mKeyData).length(), /* Key length*/ - scratchPad, /* data */ - temp, /* data start */ - scratchPadOff, /* data length */ - KMByteBlob.cast(timeOffset).getBuffer(), /* signature buffer */ - KMByteBlob.cast(timeOffset).getStartOff()); /* signature start */ - if (appIdOff != 32) { - KMException.throwIt(KMError.UNKNOWN_ERROR); - } - return uniqueId(timeOffset); - } - - @Override - public boolean serialNumber(short number){ - short length = KMByteBlob.cast(number).length(); - if(length > SERIAL_NUM_MAX_LEN){ - return false; - } - byte msb = KMByteBlob.cast(number).get((short)0); - if(msb < 0 && length > (SERIAL_NUM_MAX_LEN -1)){ - return false; - } - serialNum = number; - return true; - } - - @Override - public boolean subjectName(short sub){ - /* - short length = KMByteBlob.cast(sub).length(); - if(length > SUBJECT_NAME_MAX_LEN){ - return false; - } - Util.arrayCopyNonAtomic(KMByteBlob.cast(sub).getBuffer(), KMByteBlob.cast(sub).getStartOff(), - subjectName,(short)0,length); - subjectLen = length; - */ - if(sub == KMType.INVALID_VALUE || KMByteBlob.cast(sub).length() == 0) return false; - subjectName = sub; - return true; - } - - @Override - public KMAttestationCert ecAttestKey(short attestKey, byte mode){ - certMode = mode; - certAttestKeySecret = attestKey; - certAttestKeyRsaPubModulus = KMType.INVALID_VALUE; - certRsaSign = false; - return this; - } - - @Override - public KMAttestationCert rsaAttestKey(short attestPrivExp, short attestMod, byte mode){ - certMode = mode; - certAttestKeySecret = attestPrivExp; - certAttestKeyRsaPubModulus = attestMod; - certRsaSign = true; - return this; - } - - public KMAttestationCert factoryAttestKey(KMAttestationKey key, byte mode) { - certMode = mode; - factoryAttestKey = key; - return this; - } - - private void print(byte[] buf, short start, short length){ - StringBuilder sb = new StringBuilder(length * 2); - for(short i = start; i < (start+length); i ++){ - sb.append(String.format("%02x", buf[i])); - } - System.out.println( sb.toString()); - } -} diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java deleted file mode 100644 index f6af7ab2..00000000 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java +++ /dev/null @@ -1,550 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.keymaster; - -import com.android.javacard.seprovider.KMDeviceUniqueKey; -import com.android.javacard.seprovider.KMException; -import com.android.javacard.seprovider.KMJCardSimulator; -import javacard.framework.APDU; -import javacard.framework.ISO7816; -import javacard.framework.Util; - -public class KMJCardSimApplet extends KMKeymasterApplet { - - // Provider specific Commands - private static final byte INS_KEYMINT_PROVIDER_APDU_START = 0x00; - private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = - INS_KEYMINT_PROVIDER_APDU_START + 1; //0x01 - private static final byte INS_PROVISION_ATTESTATION_CERT_DATA_CMD = - INS_KEYMINT_PROVIDER_APDU_START + 2; //0x02 - private static final byte INS_PROVISION_ATTEST_IDS_CMD = - INS_KEYMINT_PROVIDER_APDU_START + 3; //0x03 - private static final byte INS_PROVISION_PRESHARED_SECRET_CMD = - INS_KEYMINT_PROVIDER_APDU_START + 4; //0x04 - private static final byte INS_SET_BOOT_PARAMS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 5; //0x05 - private static final byte INS_LOCK_PROVISIONING_CMD = INS_KEYMINT_PROVIDER_APDU_START + 6; //0x06 - private static final byte INS_GET_PROVISION_STATUS_CMD = - INS_KEYMINT_PROVIDER_APDU_START + 7; //0x07 - private static final byte INS_SET_VERSION_PATCHLEVEL_CMD = - INS_KEYMINT_PROVIDER_APDU_START + 8; //0x08 - private static final byte INS_SET_BOOT_ENDED_CMD = INS_KEYMINT_PROVIDER_APDU_START + 9; //0x09 - - // private static final byte INS_PROVISION_ATTEST_IDS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 1; - // private static final byte INS_PROVISION_PRESHARED_SECRET_CMD = - // INS_KEYMINT_PROVIDER_APDU_START + 2; - // private static final byte INS_LOCK_PROVISIONING_CMD = INS_KEYMINT_PROVIDER_APDU_START + 3; - // private static final byte INS_GET_PROVISION_STATUS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 4; - // private static final byte INS_SET_BOOT_PARAMS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 5; - private static final byte INS_PROVISION_DEVICE_UNIQUE_KEY_CMD = - INS_KEYMINT_PROVIDER_APDU_START + 10; - private static final byte INS_PROVISION_ADDITIONAL_CERT_CHAIN_CMD = - INS_KEYMINT_PROVIDER_APDU_START + 11; - private static final byte INS_KEYMINT_PROVIDER_APDU_END = 0x1F; - - //Provision reporting status - private static final byte NOT_PROVISIONED = 0x00; - private static final byte PROVISION_STATUS_ATTESTATION_KEY = 0x01; - private static final byte PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x02; - private static final byte PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x04; - private static final byte PROVISION_STATUS_ATTEST_IDS = 0x08; - private static final byte PROVISION_STATUS_PRESHARED_SECRET = 0x10; - private static final byte PROVISION_STATUS_PROVISIONING_LOCKED = 0x20; - private static final byte PROVISION_STATUS_DEVICE_UNIQUE_KEY = 0x40; - private static final byte PROVISION_STATUS_ADDITIONAL_CERT_CHAIN = (byte) 0x80; - private static final short POWER_RESET_MASK_FLAG = (short) 0x4000; - public static final short SHARED_SECRET_KEY_SIZE = 32; - public static final byte BOOT_KEY_MAX_SIZE = 32; - public static final byte BOOT_HASH_MAX_SIZE = 32; - - private static byte provisionStatus = NOT_PROVISIONED; - private static byte kmSpecification; - - KMJCardSimApplet() { - super(new KMJCardSimulator(), kmSpecification); - } - - /** - * Installs this applet. - * - * @param bArray the array containing installation parameters - * @param bOffset the starting offset in bArray - * @param bLength the length in bytes of the parameter data in bArray - */ - public static void install(byte[] bArray, short bOffset, byte bLength) { - kmSpecification = bArray[(short) (bOffset + 1)]; - new KMJCardSimApplet().register(); - } - - @Override - public void process(APDU apdu) { - try { - // If this is select applet apdu which is selecting this applet then return - if (apdu.isISOInterindustryCLA()) { - if (selectingApplet()) { - return; - } - } - short apduIns = validateApdu(apdu); - if (((KMJCardSimulator) seProvider).isPowerReset()) { - super.powerReset(); - } - if (((KMJCardSimulator) seProvider).isProvisionLocked()) { - switch (apduIns) { - case INS_SET_BOOT_PARAMS_CMD: - processSetBootParamsCmd(apdu); - break; - default: - super.process(apdu); - break; - } - return; - } - if (apduIns == KMType.INVALID_VALUE) { - return; - } - switch (apduIns) { - case INS_PROVISION_ATTESTATION_KEY_CMD: - processProvisionAttestationKey(apdu); - provisionStatus |= PROVISION_STATUS_ATTESTATION_KEY; - sendError(apdu, KMError.OK); - break; - case INS_PROVISION_ATTESTATION_CERT_DATA_CMD: - processProvisionAttestationCertDataCmd(apdu); - provisionStatus |= (PROVISION_STATUS_ATTESTATION_CERT_CHAIN | - PROVISION_STATUS_ATTESTATION_CERT_PARAMS); - sendError(apdu, KMError.OK); - break; - case INS_PROVISION_ATTEST_IDS_CMD: - processProvisionAttestIdsCmd(apdu); - provisionStatus |= PROVISION_STATUS_ATTEST_IDS; - sendError(apdu, KMError.OK); - break; - case INS_PROVISION_PRESHARED_SECRET_CMD: - processProvisionPreSharedSecretCmd(apdu); - provisionStatus |= PROVISION_STATUS_PRESHARED_SECRET; - sendError(apdu, KMError.OK); - break; - case INS_GET_PROVISION_STATUS_CMD: - processGetProvisionStatusCmd(apdu); - break; - case INS_LOCK_PROVISIONING_CMD: - processLockProvisioningCmd(apdu); - break; - case INS_SET_BOOT_PARAMS_CMD: - processSetBootParamsCmd(apdu); - break; - case INS_PROVISION_DEVICE_UNIQUE_KEY_CMD: - processProvisionDeviceUniqueKey(apdu); - provisionStatus |= PROVISION_STATUS_DEVICE_UNIQUE_KEY; - break; - case INS_PROVISION_ADDITIONAL_CERT_CHAIN_CMD: - processProvisionAdditionalCertChain(apdu); - provisionStatus |= PROVISION_STATUS_ADDITIONAL_CERT_CHAIN; - break; - default: - super.process(apdu); - break; - } - } finally { - repository.clean(); - } - } - - private void processProvisionAttestationCertDataCmd(APDU apdu) { - // TODO Handle this function properly - processAttestationCertDataCmd(apdu); - } - - private void processProvisionAttestationKey(APDU apdu) { - // Arguments - short keyparams = KMKeyParameters.exp(); - short keyFormatPtr = KMEnum.instance(KMType.KEY_FORMAT); - short blob = KMByteBlob.exp(); - short argsProto = KMArray.instance((short) 3); - KMArray.cast(argsProto).add((short) 0, keyparams); - KMArray.cast(argsProto).add((short) 1, keyFormatPtr); - KMArray.cast(argsProto).add((short) 2, blob); - - short args = receiveIncoming(apdu, argsProto); - // Re-purpose the apdu buffer as scratch pad. - byte[] scratchPad = apdu.getBuffer(); - - // key params should have os patch, os version and verified root of trust - short keyParams = KMArray.cast(args).get((short) 0); - keyFormatPtr = KMArray.cast(args).get((short) 1); - short rawBlob = KMArray.cast(args).get((short) 2); - // Key format must be RAW format - short keyFormat = KMEnum.cast(keyFormatPtr).getVal(); - if (keyFormat != KMType.RAW) { - KMException.throwIt(KMError.UNIMPLEMENTED); - } - //byte origin = KMType.IMPORTED; - - // get algorithm - only EC keys expected - KMTag.assertPresence(keyParams, KMType.ENUM_TAG, KMType.ALGORITHM, KMError.INVALID_ARGUMENT); - short alg = KMEnumTag.getValue(KMType.ALGORITHM, keyParams); - if (alg != KMType.EC) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - // get digest - only SHA256 supported - KMTag.assertPresence(keyParams, KMType.ENUM_ARRAY_TAG, KMType.DIGEST, KMError.INVALID_ARGUMENT); - short len = KMEnumArrayTag.getValues(KMType.DIGEST, keyParams, scratchPad, (short) 0); - if (len != 1) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - if (scratchPad[0] != KMType.SHA2_256) { - KMException.throwIt(KMError.INCOMPATIBLE_DIGEST); - } - // Purpose should be ATTEST_KEY - KMTag.assertPresence(keyParams, KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, - KMError.INVALID_ARGUMENT); - len = KMEnumArrayTag.getValues(KMType.PURPOSE, keyParams, scratchPad, (short) 0); - if (len != 1) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - if (scratchPad[0] != KMType.ATTEST_KEY) { - KMException.throwIt(KMError.INCOMPATIBLE_PURPOSE); - } - // validate Curve - KMTag.assertPresence(keyParams, KMType.ENUM_TAG, KMType.ECCURVE, KMError.INVALID_ARGUMENT); - short curve = KMEnumTag.getValue(KMType.ECCURVE, keyParams); - if (curve != KMType.P_256) { - KMException.throwIt(KMError.UNSUPPORTED_EC_CURVE); - } - // Decode EC Key - short arrPtr = decodeRawECKey(rawBlob); - short secret = KMArray.cast(arrPtr).get((short) 0); - short pubKey = KMArray.cast(arrPtr).get((short) 1); - // Check whether key can be created - seProvider.importAsymmetricKey( - KMType.EC, - KMByteBlob.cast(secret).getBuffer(), - KMByteBlob.cast(secret).getStartOff(), - KMByteBlob.cast(secret).length(), - KMByteBlob.cast(pubKey).getBuffer(), - KMByteBlob.cast(pubKey).getStartOff(), - KMByteBlob.cast(pubKey).length()); - - // persist key - seProvider.createAttestationKey( - KMByteBlob.cast(secret).getBuffer(), - KMByteBlob.cast(secret).getStartOff(), - KMByteBlob.cast(secret).length()); - } - - private void processProvisionAttestIdsCmd(APDU apdu) { - - short keyparams = KMKeyParameters.exp(); - short cmd = KMArray.instance((short) 1); - KMArray.cast(cmd).add((short) 0, keyparams); - short args = receiveIncoming(apdu, cmd); - short attData = KMArray.cast(args).get((short) 0); - // persist attestation Ids - if any is missing then exception occurs - setAttestationIds(attData); - } - - public void setAttestationIds(short attIdVals) { - KMKeyParameters instParam = KMKeyParameters.cast(attIdVals); - KMArray vals = KMArray.cast(instParam.getVals()); - short index = 0; - short length = vals.length(); - short key; - short type; - short obj; - while (index < length) { - obj = vals.get(index); - key = KMTag.getKey(obj); - type = KMTag.getTagType(obj); - - if (KMType.BYTES_TAG != type) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - obj = KMByteTag.cast(obj).getValue(); - ((KMJCardSimulator) seProvider).setAttestationId(key, KMByteBlob.cast(obj).getBuffer(), - KMByteBlob.cast(obj).getStartOff(), KMByteBlob.cast(obj).length()); - index++; - } - } - - private void processProvisionPreSharedSecretCmd(APDU apdu) { - - short blob = KMByteBlob.exp(); - short argsProto = KMArray.instance((short) 1); - KMArray.cast(argsProto).add((short) 0, blob); - short args = receiveIncoming(apdu, argsProto); - - short val = KMArray.cast(args).get((short) 0); - - if (val != KMType.INVALID_VALUE - && KMByteBlob.cast(val).length() != SHARED_SECRET_KEY_SIZE) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - // Persist shared Hmac. - ((KMJCardSimulator) seProvider).createPresharedKey( - KMByteBlob.cast(val).getBuffer(), - KMByteBlob.cast(val).getStartOff(), - KMByteBlob.cast(val).length()); - } - - private void processGetProvisionStatusCmd(APDU apdu) { - short resp = KMArray.instance((short) 2); - KMArray.cast(resp).add((short) 0, buildErrorStatus(KMError.OK)); - KMArray.cast(resp).add((short) 1, KMInteger.uint_16(provisionStatus)); - sendOutgoing(apdu, resp); - - } - - private void processSetBootParamsCmd(APDU apdu) { - short argsProto = KMArray.instance((short) 5); - // Array of 4 expected arguments - // Argument 0 Boot Patch level - KMArray.cast(argsProto).add((short) 0, KMInteger.exp()); - // Argument 1 Verified Boot Key - KMArray.cast(argsProto).add((short) 1, KMByteBlob.exp()); - // Argument 2 Verified Boot Hash - KMArray.cast(argsProto).add((short) 2, KMByteBlob.exp()); - // Argument 3 Verified Boot State - KMArray.cast(argsProto).add((short) 3, KMEnum.instance(KMType.VERIFIED_BOOT_STATE)); - // Argument 4 Device Locked - KMArray.cast(argsProto).add((short) 4, KMEnum.instance(KMType.DEVICE_LOCKED)); - - short args = receiveIncoming(apdu, argsProto); - short bootParam = KMArray.cast(args).get((short) 0); - - ((KMJCardSimulator) seProvider).setBootPatchLevel(KMInteger.cast(bootParam).getBuffer(), - KMInteger.cast(bootParam).getStartOff(), - KMInteger.cast(bootParam).length()); - - bootParam = KMArray.cast(args).get((short) 1); - if (KMByteBlob.cast(bootParam).length() > BOOT_KEY_MAX_SIZE) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - ((KMJCardSimulator) seProvider).setBootKey(KMByteBlob.cast(bootParam).getBuffer(), - KMByteBlob.cast(bootParam).getStartOff(), - KMByteBlob.cast(bootParam).length()); - - bootParam = KMArray.cast(args).get((short) 2); - if (KMByteBlob.cast(bootParam).length() > BOOT_HASH_MAX_SIZE) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - ((KMJCardSimulator) seProvider).setVerifiedBootHash(KMByteBlob.cast(bootParam).getBuffer(), - KMByteBlob.cast(bootParam).getStartOff(), - KMByteBlob.cast(bootParam).length()); - - bootParam = KMArray.cast(args).get((short) 3); - byte enumVal = KMEnum.cast(bootParam).getVal(); - ((KMJCardSimulator) seProvider).setBootState(enumVal); - - bootParam = KMArray.cast(args).get((short) 4); - enumVal = KMEnum.cast(bootParam).getVal(); - ((KMJCardSimulator) seProvider).setDeviceLocked(enumVal == KMType.DEVICE_LOCKED_TRUE); - - super.reboot(); - sendError(apdu, KMError.OK); - } - - private void processLockProvisioningCmd(APDU apdu) { - ((KMJCardSimulator) seProvider).setProvisionLocked(true); - sendError(apdu, KMError.OK); - } - - private short validateApdu(APDU apdu) { - // Read the apdu header and buffer. - byte[] apduBuffer = apdu.getBuffer(); - byte apduClass = apduBuffer[ISO7816.OFFSET_CLA]; - - // Validate APDU Header. - if ((apduClass != CLA_ISO7816_NO_SM_NO_CHAN)) { - sendError(apdu, KMError.UNSUPPORTED_CLA); - return KMType.INVALID_VALUE; - } - - short err = specification.validateApduHeader(apdu); - if (err != KMError.OK) { - sendError(apdu, err); - return KMType.INVALID_VALUE; - } - return apduBuffer[ISO7816.OFFSET_INS]; - } - - private void setDummyBootParams() { - short osVersion = KMInteger.uint_16(((short) 0)); - short osPatchLevel = KMInteger.uint_16((short) 0); - short vendorPatchLevel = KMInteger.uint_16((short) 0); - short bootPatchLevel = KMInteger.uint_16((short) 0); - - super.setOsVersion(osVersion); - super.setOsPatchLevel(osPatchLevel); - super.setVendorPatchLevel(vendorPatchLevel); - - byte[] bootBlob = new byte[32]; - short bootKey = KMByteBlob.instance(bootBlob, (short) 0, - (short) bootBlob.length); - short verifiedHash = KMByteBlob.instance(bootBlob, (short) 0, - (short) bootBlob.length); - short bootState = KMType.UNVERIFIED_BOOT; - - ((KMJCardSimulator) seProvider).setBootPatchLevel( - KMInteger.cast(bootPatchLevel).getBuffer(), - KMInteger.cast(bootPatchLevel).getStartOff(), - KMInteger.cast(bootPatchLevel).length()); - - ((KMJCardSimulator) seProvider).setBootKey( - KMByteBlob.cast(bootKey).getBuffer(), - KMByteBlob.cast(bootKey).getStartOff(), - KMByteBlob.cast(bootKey).length()); - - ((KMJCardSimulator) seProvider).setVerifiedBootHash( - KMByteBlob.cast(verifiedHash).getBuffer(), - KMByteBlob.cast(verifiedHash).getStartOff(), - KMByteBlob.cast(verifiedHash).length()); - - ((KMJCardSimulator) seProvider).setBootState((byte) bootState); - ((KMJCardSimulator) seProvider).setDeviceLocked(true); - super.reboot(); - } - - private void setDummyPresharedKey() { - final byte[] presharedKey = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - ((KMJCardSimulator) seProvider) - .createPresharedKey(presharedKey, (short) 0, (short) presharedKey.length); - } - - private void setDummyAttestationIds() { - final byte[] brand = {'g', 'e', 'n', 'e', 'r', 'i', 'c'}; - final byte[] device = {'v', 's', 'o', 'c', '_', 'x', '8', '6', '_', '6', '4'};//vsoc_x86_64 - final byte[] product = //aosp_cf_x86_64_phone - {'a', 'o', 's', 'p', '_', 'c', 'f', '_', 'x', '8', '6', '_', '6', '4', '_', 'p', 'h', 'o', - 'n', 'e'}; - final byte[] serial = {}; - final byte[] imei = {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'}; - final byte[] meid = {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'}; - final byte[] manufacturer = {'G', 'o', 'o', 'g', 'l', 'e'}; - final byte[] model = //"Cuttlefish x86_64 phone" - {'C', 'u', 't', 't', 'l', 'e', 'f', 'i', 's', 'h', ' ', 'x', '8', '6', '_', '6', '4', - ' ', 'p', 'h', 'o', 'n', 'e'}; - ((KMJCardSimulator) seProvider) - .setAttestationId(KMType.ATTESTATION_ID_BRAND, brand, (short) 0, (short) brand.length); - ((KMJCardSimulator) seProvider) - .setAttestationId(KMType.ATTESTATION_ID_IMEI, imei, (short) 0, (short) imei.length); - ((KMJCardSimulator) seProvider) - .setAttestationId(KMType.ATTESTATION_ID_DEVICE, device, (short) 0, (short) device.length); - ((KMJCardSimulator) seProvider) - .setAttestationId(KMType.ATTESTATION_ID_MEID, meid, (short) 0, (short) meid.length); - ((KMJCardSimulator) seProvider) - .setAttestationId(KMType.ATTESTATION_ID_MODEL, model, (short) 0, (short) model.length); - ((KMJCardSimulator) seProvider) - .setAttestationId(KMType.ATTESTATION_ID_MANUFACTURER, manufacturer, (short) 0, - (short) manufacturer.length); - ((KMJCardSimulator) seProvider) - .setAttestationId(KMType.ATTESTATION_ID_PRODUCT, product, (short) 0, - (short) product.length); - ((KMJCardSimulator) seProvider) - .setAttestationId(KMType.ATTESTATION_ID_SERIAL, serial, (short) 0, (short) serial.length); - } - - private static void processProvisionDeviceUniqueKey(APDU apdu) { - // Re-purpose the apdu buffer as scratch pad. - byte[] scratchPad = apdu.getBuffer(); - short arr = KMArray.instance((short) 1); - short coseKeyExp = KMCoseKey.exp(); - KMArray.cast(arr).add((short) 0, coseKeyExp); //[ CoseKey ] - arr = receiveIncoming(apdu, arr); - // Get cose key. - short coseKey = KMArray.cast(arr).get((short) 0); - short pubKeyLen = KMCoseKey.cast(coseKey).getEcdsa256PublicKey(scratchPad, (short) 0); - short privKeyLen = KMCoseKey.cast(coseKey).getPrivateKey(scratchPad, pubKeyLen); - //Store the Device unique Key. - seProvider.createDeviceUniqueKey(false, scratchPad, (short) 0, pubKeyLen, scratchPad, - pubKeyLen, privKeyLen); - // Newly added code 30/07/2021 - short bcc = generateBcc(false, scratchPad); - short len = KMKeymasterApplet.encodeToApduBuffer(bcc, scratchPad, (short) 0, - MAX_COSE_BUF_SIZE); - ((KMJCardSimulator) seProvider).persistBootCertificateChain(scratchPad, (short) 0, len); - sendError(apdu, KMError.OK); - } - - private static void processProvisionAdditionalCertChain(APDU apdu) { - // Prepare the expression to decode - short headers = KMCoseHeaders.exp(); - short arrInst = KMArray.instance((short) 4); - KMArray.cast(arrInst).add((short) 0, KMByteBlob.exp()); - KMArray.cast(arrInst).add((short) 1, headers); - KMArray.cast(arrInst).add((short) 2, KMByteBlob.exp()); - KMArray.cast(arrInst).add((short) 3, KMByteBlob.exp()); - short coseSignArr = KMArray.exp(arrInst); - short map = KMMap.instance((short) 1); - KMMap.cast(map).add((short) 0, KMTextString.exp(), coseSignArr); - // TODO duplicate code. - // receive incoming data and decode it. - byte[] srcBuffer = apdu.getBuffer(); - short recvLen = apdu.setIncomingAndReceive(); - short srcOffset = apdu.getOffsetCdata(); - short bufferLength = apdu.getIncomingLength(); - short bufferStartOffset = repository.allocReclaimableMemory(bufferLength); - short index = bufferStartOffset; - byte[] buffer = repository.getHeap(); - while (recvLen > 0 && ((short) (index - bufferStartOffset) < bufferLength)) { - Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, index, recvLen); - index += recvLen; - recvLen = apdu.receiveBytes(srcOffset); - } - // decode - map = decoder.decode(map, buffer, bufferStartOffset, bufferLength); - arrInst = KMMap.cast(map).getKeyValue((short) 0); - // Validate Additional certificate chain. - short leafCoseKey = - validateCertChain(false, KMCose.COSE_ALG_ES256, KMCose.COSE_ALG_ES256, arrInst, - srcBuffer, null); - // Compare the DK_Pub. - short pubKeyLen = KMCoseKey.cast(leafCoseKey).getEcdsa256PublicKey(srcBuffer, (short) 0); - KMDeviceUniqueKey uniqueKey = seProvider.getDeviceUniqueKey(false); - if (uniqueKey == null) { - KMException.throwIt(KMError.STATUS_FAILED); - } - short uniqueKeyLen = uniqueKey.getPublicKey(srcBuffer, pubKeyLen); - if ((pubKeyLen != uniqueKeyLen) || - (0 != Util.arrayCompare(srcBuffer, (short) 0, srcBuffer, pubKeyLen, pubKeyLen))) { - KMException.throwIt(KMError.STATUS_FAILED); - } - seProvider.persistAdditionalCertChain(buffer, bufferStartOffset, bufferLength); - //reclaim memory - repository.reclaimMemory(bufferLength); - sendError(apdu, KMError.OK); - } - - private static short buildErrorStatus(short err) { - short int32Ptr = KMInteger.instance((short) 4); - short powerResetStatus = 0; - if (((KMJCardSimulator) seProvider).isPowerReset()) { - powerResetStatus = POWER_RESET_MASK_FLAG; - } - - Util.setShort(KMInteger.cast(int32Ptr).getBuffer(), - KMInteger.cast(int32Ptr).getStartOff(), - powerResetStatus); - - Util.setShort(KMInteger.cast(int32Ptr).getBuffer(), - (short) (KMInteger.cast(int32Ptr).getStartOff() + 2), - err); - // reset power reset status flag to its default value. - //repository.restorePowerResetStatus(); //TODO - return int32Ptr; - } - -} diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java deleted file mode 100644 index 3e9002e2..00000000 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.keymaster; - -import com.android.javacard.seprovider.KMException; -import javacard.framework.Util; - -public class KMUtils { - - // 64 bit unsigned calculations for time - public static final byte[] oneSecMsec = { - 0, 0, 0, 0, 0, 0, 0x03, (byte) 0xE8}; // 1000 msec - public static final byte[] oneMinMsec = { - 0, 0, 0, 0, 0, 0, (byte) 0xEA, 0x60}; // 60000 msec - public static final byte[] oneHourMsec = { - 0, 0, 0, 0, 0, 0x36, (byte) 0xEE, (byte) 0x80}; // 3600000 msec - public static final byte[] oneDayMsec = { - 0, 0, 0, 0, 0x05, 0x26, 0x5C, 0x00}; // 86400000 msec - public static final byte[] oneMonthMsec = { - 0, 0, 0, 0, (byte) 0x9C, (byte) 0xBE, (byte) 0xBD, 0x50}; // 2629746000 msec - public static final byte[] leapYearMsec = { - 0, 0, 0, 0x07, (byte) 0x5C, (byte) 0xD7, (byte) 0x88, 0x00}; //31622400000; - public static final byte[] yearMsec = { - 0, 0, 0, 0x07, 0x57, (byte) 0xB1, 0x2C, 0x00}; //31536000000 - //Leap year(366) + 3 * 365 - public static final byte[] fourYrsMsec = { - 0, 0, 0, 0x1D, 0x63, (byte) 0xEB, 0x0C, 0x00};//126230400000 - public static final byte[] firstJan2020 = { - 0, 0, 0x01, 0x6F, 0x5E, 0x66, (byte) 0xE8, 0x00}; // 1577836800000 msec - public static final byte[] firstJan2051 = { - 0, 0, 0x02, 0x53, 0x26, (byte) 0x0E, (byte) 0x1C, 0x00}; // 2556144000000 - // msec - public static final byte[] febMonthLeapMSec = { - 0, 0, 0, 0, (byte) 0x95, 0x58, 0x6C, 0x00}; //2505600000 - public static final byte[] febMonthMsec = { - 0, 0, 0, 0, (byte) 0x90, 0x32, 0x10, 0x00}; //2419200000 - public static final byte[] ThirtyOneDaysMonthMsec = { - 0, 0, 0, 0, (byte) 0x9F, (byte) 0xA5, 0x24, 0x00};//2678400000 - public static final byte[] ThirtDaysMonthMsec = { - 0, 0, 0, 0, (byte) 0x9A, 0x7E, (byte) 0xC8, 0x00};//2592000000 - public static final short year2051 = 2051; - public static final short year2020 = 2020; - // Convert to milliseconds constants - public static final byte[] SEC_TO_MILLIS_SHIFT_POS = {9, 8, 7, 6, 5, 3}; - - // -------------------------------------- - public static short convertToDate(short time, byte[] scratchPad, - boolean utcFlag) { - - short yrsCount = 0; - short monthCount = 1; - short dayCount = 1; - short hhCount = 0; - short mmCount = 0; - short ssCount = 0; - byte Z = 0x5A; - boolean from2020 = true; - Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); - Util.arrayCopyNonAtomic(KMInteger.cast(time).getBuffer(), - KMInteger.cast(time).getStartOff(), scratchPad, - (short) (8 - KMInteger.cast(time).length()), KMInteger.cast(time) - .length()); - // If the time is less then 1 Jan 2020 then it is an error - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2020, (short) 0, - (short) 8) < 0) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - if (utcFlag - && KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, - (short) 0, (short) 8) >= 0) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, - (short) 8) < 0) { - Util.arrayCopyNonAtomic(firstJan2020, (short) 0, scratchPad, (short) 8, - (short) 8); - subtract(scratchPad, (short) 0, (short) 8, (short) 16, (byte) 8); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - } else { - from2020 = false; - Util.arrayCopyNonAtomic(firstJan2051, (short) 0, scratchPad, (short) 8, - (short) 8); - subtract(scratchPad, (short) 0, (short) 8, (short) 16, (byte) 8); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - } - // divide the given time with four yrs msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, - (short) 8) >= 0) { - Util.arrayCopyNonAtomic(fourYrsMsec, (short) 0, scratchPad, (short) 8, - (short) 8); - // quotient is multiple of 4. - yrsCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - yrsCount = (short) (yrsCount * 4); // number of yrs. - // copy reminder as new dividend - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - } - - //Get the leap year index starting from the (base Year + yrsCount) Year. - short leapYrIdx = getLeapYrIndex(from2020, yrsCount); - - // if leap year index is 0, then the number of days for the 1st year will be 366 days. - // if leap year index is not 0, then the number of days for the 1st year will be 365 days. - if (((leapYrIdx == 0) && - (KMInteger - .unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, (short) 0, (short) 8) - >= 0)) || - ((leapYrIdx != 0) && - (KMInteger - .unsignedByteArrayCompare(scratchPad, (short) 0, yearMsec, (short) 0, (short) 8) - >= 0))) { - for (short i = 0; i < 4; i++) { - yrsCount++; - if (i == leapYrIdx) { - Util.arrayCopyNonAtomic(leapYearMsec, (short) 0, scratchPad, - (short) 8, (short) 8); - } else { - Util.arrayCopyNonAtomic(yearMsec, (short) 0, scratchPad, (short) 8, - (short) 8); - } - subtract(scratchPad, (short) 0, (short) 8, (short) 16, (byte) 8); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - if (((short) (i + 1) == leapYrIdx)) { - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, - (short) 0, (short) 8) < 0) { - break; - } - } else { - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, yearMsec, - (short) 0, (short) 8) < 0) { - break; - } - } - } - } - - // total yrs from 1970 - if (from2020) { - yrsCount = (short) (year2020 + yrsCount); - } else { - yrsCount = (short) (year2051 + yrsCount); - } - - // divide the given time with one month msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneMonthMsec, (short) 0, - (short) 8) >= 0) { - for (short i = 0; i < 12; i++) { - if (i == 1) { - // Feb month - if (isLeapYear(yrsCount)) { - // Leap year 29 days - Util.arrayCopyNonAtomic(febMonthLeapMSec, (short) 0, scratchPad, - (short) 8, (short) 8); - } else { - // 28 days - Util.arrayCopyNonAtomic(febMonthMsec, (short) 0, scratchPad, - (short) 8, (short) 8); - } - } else if (((i <= 6) && ((i % 2 == 0))) || ((i > 6) && ((i % 2 == 1)))) { - Util.arrayCopyNonAtomic(ThirtyOneDaysMonthMsec, (short) 0, - scratchPad, (short) 8, (short) 8); - } else { - // 30 Days - Util.arrayCopyNonAtomic(ThirtDaysMonthMsec, (short) 0, scratchPad, - (short) 8, (short) 8); - } - - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, scratchPad, (short) 8, - (short) 8) >= 0) { - subtract(scratchPad, (short) 0, (short) 8, (short) 16, (byte) 8); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - } else { - break; - } - monthCount++; - } - } - - // divide the given time with one day msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneDayMsec, (short) 0, - (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneDayMsec, (short) 0, scratchPad, (short) 8, - (short) 8); - dayCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - dayCount++; - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - } - - // divide the given time with one hour msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneHourMsec, (short) 0, - (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneHourMsec, (short) 0, scratchPad, (short) 8, - (short) 8); - hhCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - } - - // divide the given time with one minute msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, - (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneMinMsec, (short) 0, scratchPad, (short) 8, - (short) 8); - mmCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - } - - // divide the given time with one second msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, - (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneSecMsec, (short) 0, scratchPad, (short) 8, - (short) 8); - ssCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - } - - // Now convert to ascii string YYMMDDhhmmssZ or YYYYMMDDhhmmssZ - Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); - short len = numberToString(yrsCount, scratchPad, (short) 0); // returns YYYY - len += numberToString(monthCount, scratchPad, len); - len += numberToString(dayCount, scratchPad, len); - len += numberToString(hhCount, scratchPad, len); - len += numberToString(mmCount, scratchPad, len); - len += numberToString(ssCount, scratchPad, len); - scratchPad[len] = Z; - len++; - if (utcFlag) { - return KMByteBlob.instance(scratchPad, (short) 2, (short) (len - 2)); // YY - } else { - return KMByteBlob.instance(scratchPad, (short) 0, len); // YYYY - } - } - - public static short numberToString(short number, byte[] scratchPad, - short offset) { - byte zero = 0x30; - byte len = 2; - byte digit; - if (number > 999) { - len = 4; - } - byte index = len; - while (index > 0) { - digit = (byte) (number % 10); - number = (short) (number / 10); - scratchPad[(short) (offset + index - 1)] = (byte) (digit + zero); - index--; - } - return len; - } - - // 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. - public static short divide(byte[] buf, short dividend, short divisor, - short remainder) { - short expCnt = 1; - short q = 0; - // first increase divisor so that it becomes greater then dividend. - while (compare(buf, divisor, dividend) < 0) { - shiftLeft(buf, divisor); - expCnt = (short) (expCnt << 1); - } - // Now subtract divisor from dividend if dividend is greater then divisor. - // Copy remainder in the dividend and repeat. - while (expCnt != 0) { - if (compare(buf, dividend, divisor) >= 0) { - subtract(buf, dividend, divisor, remainder, (byte) 8); - copy(buf, remainder, dividend); - q = (short) (q + expCnt); - } - expCnt = (short) (expCnt >> 1); - shiftRight(buf, divisor); - } - return q; - } - - public static void copy(byte[] buf, short from, short to) { - Util.arrayCopyNonAtomic(buf, from, buf, to, (short) 8); - } - - public static byte compare(byte[] buf, short lhs, short rhs) { - return KMInteger.unsignedByteArrayCompare(buf, lhs, buf, rhs, (short) 8); - } - - public static void shiftLeft(byte[] buf, short start, short count) { - short index = 0; - while (index < count) { - shiftLeft(buf, start); - index++; - } - } - - public static void shiftLeft(byte[] buf, short start) { - byte index = 7; - byte carry = 0; - byte tmp; - while (index >= 0) { - tmp = buf[(short) (start + index)]; - buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] << 1); - buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] + carry); - if (tmp < 0) { - carry = 1; - } else { - carry = 0; - } - index--; - } - } - - public static void shiftRight(byte[] buf, short start) { - byte index = 0; - byte carry = 0; - byte tmp; - while (index < 8) { - tmp = (byte) (buf[(short) (start + index)] & 0x01); - buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] >> 1); - buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] & 0x7F); - buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] | carry); - if (tmp == 1) { - carry = (byte) 0x80; - } else { - carry = 0; - } - index++; - } - } - - public static void add(byte[] buf, short op1, short op2, short result) { - byte index = 7; - byte carry = 0; - short tmp; - while (index >= 0) { - tmp = (short) (buf[(short) (op1 + index)] + buf[(short) (op2 + index)] + carry); - carry = 0; - if (tmp > 255) { - carry = 1; // max unsigned byte value is 255 - } - buf[(short) (result + index)] = (byte) (tmp & (byte) 0xFF); - index--; - } - } - - // subtraction by borrowing. - public static void subtract(byte[] buf, short op1, short op2, short result, byte sizeBytes) { - byte borrow = 0; - byte index = (byte) (sizeBytes - 1); - short r; - short x; - short y; - while (index >= 0) { - x = (short) (buf[(short) (op1 + index)] & 0xFF); - y = (short) (buf[(short) (op2 + index)] & 0xFF); - r = (short) (x - y - borrow); - borrow = 0; - if (r < 0) { - borrow = 1; - r = (short) (r + 256); // max unsigned byte value is 255 - } - buf[(short) (result + index)] = (byte) (r & 0xFF); - index--; - } - } - - public static short countTemporalCount(byte[] bufTime, short timeOff, - short timeLen, byte[] scratchPad, short offset) { - Util.arrayFillNonAtomic(scratchPad, (short) offset, (short) 24, (byte) 0); - Util.arrayCopyNonAtomic( - bufTime, - timeOff, - scratchPad, - (short) (offset + 8 - timeLen), - timeLen); - Util.arrayCopyNonAtomic(oneMonthMsec, (short) 0, scratchPad, (short) (offset + 8), - (short) 8); - return divide(scratchPad, (short) 0, (short) 8, (short) 16); - } - - public static boolean isLeapYear(short year) { - if ((short) (year % 4) == (short) 0) { - if (((short) (year % 100) == (short) 0) && - ((short) (year % 400)) != (short) 0) { - return false; - } - return true; - } - return false; - } - - public static short getLeapYrIndex(boolean from2020, short yrsCount) { - short newBaseYr = (short) (from2020 ? (year2020 + yrsCount) : (year2051 + yrsCount)); - for (short i = 0; i < 4; i++) { - if (isLeapYear((short) (newBaseYr + i))) { - return i; - } - } - return -1; - } - - public static void computeOnesCompliment(byte[] buf, short offset, short len) { - short index = offset; - // Compute 1s compliment - while (index < (short) (len + offset)) { - buf[index] = (byte) ~buf[index]; - index++; - } - } - - // i * 1000 = (i << 9) + (i << 8) + (i << 7) + (i << 6) + (i << 5) + ( i << 3) - public static void convertToMilliseconds(byte[] buf, short inputOff, short outputOff, - short scratchPadOff) { - short index = 0; - short length = (short) SEC_TO_MILLIS_SHIFT_POS.length; - while (index < length) { - Util.arrayCopyNonAtomic(buf, inputOff, buf, scratchPadOff, (short) 8); - shiftLeft(buf, scratchPadOff, SEC_TO_MILLIS_SHIFT_POS[index]); - Util.arrayCopyNonAtomic(buf, outputOff, buf, (short) (scratchPadOff + 8), (short) 8); - add(buf, scratchPadOff, (short) (8 + scratchPadOff), (short) (16 + scratchPadOff)); - Util.arrayCopyNonAtomic(buf, (short) (scratchPadOff + 16), buf, outputOff, (short) 8); - Util.arrayFillNonAtomic(buf, scratchPadOff, (short) 24, (byte) 0); - index++; - } - } -} diff --git a/Applet/JCardSimProviderLib/lib/gpapi-upgrade.jar b/Applet/JCardSimProviderLib/lib/gpapi-upgrade.jar deleted file mode 100644 index e4814bde..00000000 Binary files a/Applet/JCardSimProviderLib/lib/gpapi-upgrade.jar and /dev/null differ diff --git a/Applet/JCardSimProviderLib/lib/hamcrest-core-1.3.jar b/Applet/JCardSimProviderLib/lib/hamcrest-core-1.3.jar deleted file mode 100644 index 9d5fe16e..00000000 Binary files a/Applet/JCardSimProviderLib/lib/hamcrest-core-1.3.jar and /dev/null differ diff --git a/Applet/JCardSimProviderLib/lib/jcardsim-3.0.5-SNAPSHOT.jar b/Applet/JCardSimProviderLib/lib/jcardsim-3.0.5-SNAPSHOT.jar deleted file mode 100644 index d756d67b..00000000 Binary files a/Applet/JCardSimProviderLib/lib/jcardsim-3.0.5-SNAPSHOT.jar and /dev/null differ diff --git a/Applet/JCardSimProviderLib/lib/junit-4.13.jar b/Applet/JCardSimProviderLib/lib/junit-4.13.jar deleted file mode 100644 index acc3c432..00000000 Binary files a/Applet/JCardSimProviderLib/lib/junit-4.13.jar and /dev/null differ diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMAESKey.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMAESKey.java deleted file mode 100644 index bbbb27f2..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMAESKey.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -import javacard.security.AESKey; - -public class KMAESKey implements KMMasterKey { - - private AESKey aesKey; - - public KMAESKey(AESKey key) { - aesKey = key; - } - - public void setKey(byte[] keyData, short kOff) { - aesKey.setKey(keyData, kOff); - } - - public byte getKey(byte[] keyData, short kOff) { - return aesKey.getKey(keyData, kOff); - } - - public short getKeySizeBits() { - return aesKey.getSize(); - } -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMAttestationCert.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMAttestationCert.java deleted file mode 100644 index 78ac7123..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMAttestationCert.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -/** - * The KMAttestationCert interface represents a X509 compliant attestation certificate required to - * support keymaster's attestKey function. This cert will be created according to the specifications - * given in android keymaster hal documentation. KMSeProvider has to provide the instance of this - * certificate. This interface is designed based on builder pattern and hence each method returns - * instance of cert. - */ -public interface KMAttestationCert { - - /** - * Set verified boot hash. - * - * @param obj This is a KMByteBlob containing hash - * @return instance of KMAttestationCert - */ - KMAttestationCert verifiedBootHash(short obj); - - /** - * Set verified boot key received during booting up. - * - * @param obj This is a KMByteBlob containing verified boot key. - * @return instance of KMAttestationCert - */ - KMAttestationCert verifiedBootKey(short obj); - - /** - * Set verified boot state received during booting up. - * - * @param val This is a byte containing verified boot state value. - * @return instance of KMAttestationCert - */ - KMAttestationCert verifiedBootState(byte val); - - /** - * Set uniqueId received from CA certificate during provisioning. - * - * @param scratchpad Buffer to store intermediate results. - * @param scratchPadOff Start offset of the scratchpad buffer. - * @param creationTime This buffer contains the CREATION_TIME value. - * @param creationTimeOff Start offset of creattionTime buffer. - * @param creationTimeLen Length of the creationTime buffer. - * @param attestAppId This buffer contains the ATTESTATION_APPLICATION_ID value. - * @param attestAppIdOff Start offset of the attestAppId buffer. - * @param attestAppIdLen Length of the attestAppId buffer. - * @param resetSinceIdRotation This holds the information of RESET_SINCE_ID_ROTATION. - * @param masterKey - * @return instance of KMAttestationCert. - */ - KMAttestationCert makeUniqueId(byte[] scratchpad, short scratchPadOff, byte[] creationTime, - short creationTimeOff, short creationTimeLen, byte[] attestAppId, - short attestAppIdOff, short attestAppIdLen, byte resetSinceIdRotation, - KMMasterKey masterKey); - - /** - * Set start time received from creation/activation time tag. Used for certificate's valid - * period. - * - * @param obj This is a KMByteBlob object containing start time. - * @param scratchpad Buffer to store intermediate results. - * @return instance of KMAttestationCert. - */ - KMAttestationCert notBefore(short obj, boolean derEncoded, byte[] scratchpad); - - - /** - * Set expiry time received from expiry time tag or ca certificates expiry time. Used for - * certificate's valid period. - * - * @param usageExpiryTimeObj This is a KMByteBlob containing expiry time. - * certificate. - * @param scratchPad Buffer to store intermediate results. - * @return instance of KMAttestationCert - */ - KMAttestationCert notAfter(short usageExpiryTimeObj, boolean derEncoded, byte[] scratchPad); - - /** - * Set device lock status received during booting time or due to device lock command. - * - * @param val This is true if device is locked. - * @return instance of KMAttestationCert - */ - KMAttestationCert deviceLocked(boolean val); - - /** - * Set public key to be attested received from attestKey command. - * - * @param obj This is KMByteBlob containing the public key. - * @return instance of KMAttestationCert - */ - KMAttestationCert publicKey(short obj); - - /** - * Set attestation challenge received from attestKey command. - * - * @param obj This is KMByteBlob containing the attestation challenge. - * @return instance of KMAttestationCert - */ - KMAttestationCert attestationChallenge(short obj); - - /** - * Set extension tag received from key characteristics which needs to be added to android - * extension. This method will called once for each tag. - * - * @param tag is the KMByteBlob containing KMTag. - * @param hwEnforced is true if the tag has to be added to hw enforced list or else added to sw - * enforced list. - * @return instance of KMAttestationCert - */ - KMAttestationCert extensionTag(short tag, boolean hwEnforced); - - /** - * Set ASN.1 encoded X509 issuer field received from attestation key CA cert. - * - * @param obj This is KMByteBlob containing the issuer. - * @return instance of KMAttestationCert - */ - KMAttestationCert issuer(short obj); - - /** - * Set byte buffer to be used to generate certificate. - * - * @param buf This is byte[] buffer. - * @param bufStart This is short start offset. - * @param maxLen This is short length of the buffer. - * @return instance of KMAttestationCert - */ - KMAttestationCert buffer(byte[] buf, short bufStart, short maxLen); - - /** - * Get the start of the certificate - * - * @return start of the attestation cert. - */ - short getCertStart(); - - /** - * Get the length of the certificate - * - * @return length of the attestation cert. - */ - short getCertLength(); - - - /** - * Build a fake signed certificate. After this method executes the certificate is ready with the - * signature equal to 1 byte which is 0 and with rsa signature algorithm. - */ - void build(); - - /** - * Set the Serial number in the certificate. If no serial number is set then serial number is 1. - * - * @param serialNumber - */ - boolean serialNumber(short serialNumber); - - /** - * Set the Subject Name in the certificate. - * - * @param subject - */ - boolean subjectName(short subject); - - /** - * Set attestation key and mode. - * @param attestKey KMByteBlob of the key - * @param mode - */ - KMAttestationCert ecAttestKey(short attestKey, byte mode); - /** - * Set attestation key and mode. - * @param attestKey KMByteBlob of the key - * @param mode - */ - KMAttestationCert rsaAttestKey(short attestPrivExp, short attestMod, byte mode); - - KMAttestationCert factoryAttestKey(KMAttestationKey key, byte mode); - -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMAttestationKey.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMAttestationKey.java deleted file mode 100644 index 1b8e334e..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMAttestationKey.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -/** - * KMAttestationKey is a marker interface and the SE Provider has to implement this interface. - * Internally attestation key is stored as a Javacard EC key pair object, which will provide - * additional security. The attestation key is maintained by the SEProvider. - */ -public interface KMAttestationKey { -} - diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMCipher.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMCipher.java deleted file mode 100644 index 31389eee..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMCipher.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -public abstract class KMCipher { - - public static final short SUN_JCE = 0xE9; - - public abstract short doFinal(byte[] buffer, short startOff, short length, byte[] scratchPad, - short i); - - public abstract short update(byte[] buffer, short startOff, short length, byte[] scratchPad, - short i); - - public abstract void updateAAD(byte[] buffer, short startOff, short length); - - public abstract short getBlockMode(); - - public abstract void setBlockMode(short mode); - - public abstract short getPaddingAlgorithm(); - - public abstract short getCipherAlgorithm(); - - public abstract void setPaddingAlgorithm(short alg); - - public abstract void setCipherAlgorithm(short alg); - - public abstract short getCipherProvider(); - - public abstract short getAesGcmOutputSize(short len, short macLength); -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMCipherImpl.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMCipherImpl.java deleted file mode 100644 index 4340cd4b..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMCipherImpl.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -import javacard.framework.Util; -import javacard.security.CryptoException; -import javacardx.crypto.Cipher; -import javax.crypto.AEADBadTagException; -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.ShortBufferException; - - -public class KMCipherImpl extends KMCipher { - - private Cipher cipher; - private javax.crypto.Cipher sunCipher; - private short cipherAlg; - private short padding; - private short mode; - private short blockMode; - - KMCipherImpl(Cipher c) { - cipher = c; - } - - KMCipherImpl(javax.crypto.Cipher c) { - sunCipher = c; - } - - @Override - public short doFinal(byte[] buffer, short startOff, short length, byte[] scratchPad, short i) { - if (cipherAlg == KMType.RSA && padding == KMType.RSA_OAEP) { - try { - return (short) sunCipher.doFinal(buffer, startOff, length, scratchPad, i); - } catch (ShortBufferException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (IllegalBlockSizeException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (BadPaddingException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - } else if (cipherAlg == KMType.AES && blockMode == KMType.GCM) { - try { - return (short) sunCipher.doFinal(buffer, startOff, length, scratchPad, i); - } catch (AEADBadTagException e) { - e.printStackTrace(); - KMException.throwIt(KMError.VERIFICATION_FAILED); - } catch (ShortBufferException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (IllegalBlockSizeException e) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (BadPaddingException e) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - } else if (cipherAlg == KMType.AES && blockMode == KMType.CTR) { - try { - return (short) sunCipher.doFinal(buffer, startOff, length, scratchPad, i); - } catch (ShortBufferException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (IllegalBlockSizeException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (BadPaddingException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - } else { - if ((cipherAlg == KMType.DES || cipherAlg == KMType.AES) && padding == KMType.PKCS7 - && mode == KMType.ENCRYPT) { - byte blkSize = 16; - byte paddingBytes; - short len = length; - if (cipherAlg == KMType.DES) { - blkSize = 8; - } - // padding bytes - if (len % blkSize == 0) { - paddingBytes = blkSize; - } else { - paddingBytes = (byte) (blkSize - (len % blkSize)); - } - // final len with padding - len = (short) (len + paddingBytes); - // intermediate buffer to copy input data+padding - byte[] tmp = new byte[len]; - // fill in the padding - Util.arrayFillNonAtomic(tmp, (short) 0, len, paddingBytes); - // copy the input data - Util.arrayCopyNonAtomic(buffer, startOff, tmp, (short) 0, length); - buffer = tmp; - length = len; - startOff = 0; - } - short len = cipher.doFinal(buffer, startOff, length, scratchPad, i); - // JCard Sim removes leading zeros during decryption in case of no padding - so add that back. - if (cipherAlg == KMType.RSA && padding == KMType.PADDING_NONE && mode == KMType.DECRYPT - && len < 256) { - byte[] tempBuf = new byte[256]; - Util.arrayFillNonAtomic(tempBuf, (short) 0, (short) 256, (byte) 0); - Util.arrayCopyNonAtomic(scratchPad, (short) 0, tempBuf, (short) (i + 256 - len), len); - Util.arrayCopyNonAtomic(tempBuf, (short) 0, scratchPad, i, (short) 256); - len = 256; - } else if ((cipherAlg == KMType.AES || cipherAlg == KMType.DES) // PKCS7 - && padding == KMType.PKCS7 - && mode == KMType.DECRYPT) { - byte blkSize = 16; - if (cipherAlg == KMType.DES) { - blkSize = 8; - } - if (len > 0) { - //verify if padding is corrupted. - byte paddingByte = scratchPad[i + len - 1]; - //padding byte always should be <= block size - if ((short) paddingByte > blkSize || - (short) paddingByte <= 0) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - - for (short j = 1; j <= paddingByte; ++j) { - if (scratchPad[i + len - j] != paddingByte) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - } - len = (short) (len - (short) paddingByte);// remove the padding bytes - } - } - return len; - } - return KMType.INVALID_VALUE; - } - - @Override - public short getCipherAlgorithm() { - return cipherAlg; - } - - @Override - public void setCipherAlgorithm(short alg) { - cipherAlg = alg; - } - - @Override - public short update(byte[] buffer, short startOff, short length, byte[] scratchPad, short i) { - if (cipherAlg == KMType.AES && (blockMode == KMType.GCM || blockMode == KMType.CTR)) { - try { - return (short) sunCipher.update(buffer, startOff, length, scratchPad, i); - } catch (ShortBufferException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (IllegalStateException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - } else { - return cipher.update(buffer, startOff, length, scratchPad, i); - } - return KMType.INVALID_VALUE; - } - - @Override - public void updateAAD(byte[] buffer, short startOff, short length) { - try { - sunCipher.updateAAD(buffer, startOff, length); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (IllegalStateException e) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (UnsupportedOperationException e) { - CryptoException.throwIt(CryptoException.ILLEGAL_USE); - } - } - - @Override - public short getPaddingAlgorithm() { - return padding; - } - - @Override - public void setPaddingAlgorithm(short alg) { - padding = alg; - } - - @Override - public void setBlockMode(short mode) { - blockMode = mode; - } - - @Override - public short getBlockMode() { - return blockMode; - } - - public short getMode() { - return mode; - } - - public void setMode(short mode) { - this.mode = mode; - } - - @Override - public short getCipherProvider() { - return KMCipher.SUN_JCE; - } - - @Override - public short getAesGcmOutputSize(short len, short macLength) { - if (sunCipher != null) { - return (short) sunCipher.getOutputSize(len); - } else { - if (mode == KMType.ENCRYPT) { - return (short) (len + macLength); - } else { - return (short) (len - macLength); - } - } - } - -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMComputedHmacKey.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMComputedHmacKey.java deleted file mode 100644 index 3b0aa405..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMComputedHmacKey.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.android.javacard.seprovider; - - -public interface KMComputedHmacKey { -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMDeviceUniqueKey.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMDeviceUniqueKey.java deleted file mode 100644 index 08e60a3f..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMDeviceUniqueKey.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright(C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -public interface KMDeviceUniqueKey { - - short getPublicKey(byte[] buf, short offset); -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMECPrivateKey.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMECPrivateKey.java deleted file mode 100644 index f45c55ba..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMECPrivateKey.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -import javacard.security.ECPrivateKey; -import javacard.security.KeyPair; - -public class KMECPrivateKey implements KMAttestationKey { - - private KeyPair ecKeyPair; - - public KMECPrivateKey(KeyPair ecPair) { - ecKeyPair = ecPair; - } - - public void setS(byte[] buffer, short offset, short length) { - ECPrivateKey ecPriv = (ECPrivateKey) ecKeyPair.getPrivate(); - ecPriv.setS(buffer, offset, length); - } - - public ECPrivateKey getPrivateKey() { - return (ECPrivateKey) ecKeyPair.getPrivate(); - } - -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMEcdsa256NoDigestSignature.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMEcdsa256NoDigestSignature.java deleted file mode 100644 index e53a8963..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMEcdsa256NoDigestSignature.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -import java.math.BigInteger; -import java.security.AlgorithmParameters; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.SignatureException; -import java.security.interfaces.ECPrivateKey; -import java.security.spec.ECGenParameterSpec; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPrivateKeySpec; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.InvalidParameterSpecException; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.spec.ECGenParameterSpec; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; -import java.security.spec.ECPrivateKeySpec; -import java.security.spec.ECPublicKeySpec; -import javacard.framework.Util; -import javacard.security.CryptoException; -import javacard.security.Key; -import javacard.security.Signature; - - -public class KMEcdsa256NoDigestSignature extends Signature { - - private java.security.Signature sunSigner; - - public KMEcdsa256NoDigestSignature(byte mode, byte[] key, short keyStart, short keyLength) { - KeyFactory kf; - try { - sunSigner = java.security.Signature.getInstance("NONEwithECDSA", "SunEC"); - kf = KeyFactory.getInstance("EC"); - AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC", "SunEC"); - //Supported curve secp256r1 - parameters.init(new ECGenParameterSpec("secp256r1")); - ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class); - if (mode == Signature.MODE_SIGN) { - byte[] privKey = new byte[keyLength]; - for (short i = 0; i < keyLength; i++) { - privKey[i] = key[keyStart + i]; - } - BigInteger bI = new BigInteger(privKey); - ECPrivateKeySpec prikeyspec = new ECPrivateKeySpec(bI, ecParameters); - ECPrivateKey privkey = (ECPrivateKey) kf.generatePrivate(prikeyspec); - sunSigner.initSign(privkey); - } else { - //Check if the first byte is 04 and remove it. - if (key[keyStart] == 0x04) { - //uncompressed format. - keyStart++; - keyLength--; - } - short i = 0; - byte[] pubx = new byte[keyLength / 2]; - for (; i < keyLength / 2; i++) { - pubx[i] = key[keyStart + i]; - } - byte[] puby = new byte[keyLength / 2]; - for (i = 0; i < keyLength / 2; i++) { - puby[i] = key[keyStart + keyLength / 2 + i]; - } - BigInteger bIX = new BigInteger(pubx); - BigInteger bIY = new BigInteger(puby); - ECPoint point = new ECPoint(bIX, bIY); - ECPublicKeySpec pubkeyspec = new ECPublicKeySpec(point, ecParameters); - ECPublicKey pubkey = (ECPublicKey) kf.generatePublic(pubkeyspec); - sunSigner.initVerify(pubkey); - } - } catch (NoSuchAlgorithmException e) { - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - } catch (NoSuchProviderException e) { - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - } catch (InvalidParameterSpecException e) { - CryptoException.throwIt(CryptoException.INVALID_INIT); - } catch (InvalidKeySpecException e) { - CryptoException.throwIt(CryptoException.INVALID_INIT); - } catch (InvalidKeyException e) { - CryptoException.throwIt(CryptoException.INVALID_INIT); - } - } - - @Override - public void init(Key key, byte b) throws CryptoException { - - } - - @Override - public void init(Key key, byte b, byte[] bytes, short i, short i1) throws CryptoException { - - } - - @Override - public void setInitialDigest(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) - throws CryptoException { - - } - - @Override - public byte getAlgorithm() { - return 0; - } - - @Override - public byte getMessageDigestAlgorithm() { - return 0; - } - - @Override - public byte getCipherAlgorithm() { - return 0; - } - - @Override - public byte getPaddingAlgorithm() { - return 0; - } - - @Override - public short getLength() throws CryptoException { - return 0; - } - - @Override - public void update(byte[] message, short msgStart, short messageLength) throws CryptoException { - byte[] msgBytes = new byte[messageLength]; - for (int i = 0; i < messageLength; i++) { - msgBytes[i] = message[msgStart + i]; - } - try { - if (messageLength > 0) { - sunSigner.update(msgBytes); - } - } catch (SignatureException e) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - } - - @Override - public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) - throws CryptoException { - short len = 0; - try { - update(bytes, i, i1); - byte[] sig = sunSigner.sign(); - Util.arrayCopyNonAtomic(sig, (short) 0, bytes1, i2, (short) sig.length); - return (short) sig.length; - } catch (SignatureException e) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - return len; - } - - @Override - public short signPreComputedHash(byte[] bytes, short i, short i1, byte[] bytes1, short i2) - throws CryptoException { - return 0; - } - - @Override - public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) - throws CryptoException { - // Public key operations not handled here. - return false; - } - - @Override - public boolean verifyPreComputedHash(byte[] bytes, short i, short i1, byte[] bytes1, short i2, - short i3) throws CryptoException { - return false; - } -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMError.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMError.java deleted file mode 100644 index 5754abe9..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMError.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -/** - * KMError includes all the error codes from android keymaster hal specifications. The values are - * positive unlike negative values in keymaster hal. - */ -public class KMError { - - public static final short OK = 0; - public static final short UNSUPPORTED_PURPOSE = 2; - public static final short INCOMPATIBLE_PURPOSE = 3; - public static final short UNSUPPORTED_ALGORITHM = 4; - public static final short INCOMPATIBLE_ALGORITHM = 5; - public static final short UNSUPPORTED_KEY_SIZE = 6; - public static final short UNSUPPORTED_BLOCK_MODE = 7; - public static final short INCOMPATIBLE_BLOCK_MODE = 8; - public static final short UNSUPPORTED_MAC_LENGTH = 9; - public static final short UNSUPPORTED_PADDING_MODE = 10; - public static final short INCOMPATIBLE_PADDING_MODE = 11; - public static final short UNSUPPORTED_DIGEST = 12; - public static final short INCOMPATIBLE_DIGEST = 13; - - public static final short UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = 19; - - /** - * For PKCS8 & PKCS12 - */ - public static final short INVALID_INPUT_LENGTH = 21; - - - public static final short KEY_USER_NOT_AUTHENTICATED = 26; - public static final short INVALID_OPERATION_HANDLE = 28; - public static final short VERIFICATION_FAILED = 30; - public static final short TOO_MANY_OPERATIONS = 31; - public static final short INVALID_KEY_BLOB = 33; - - public static final short INVALID_ARGUMENT = 38; - public static final short UNSUPPORTED_TAG = 39; - public static final short INVALID_TAG = 40; - public static final short IMPORT_PARAMETER_MISMATCH = 44; - public static final short OPERATION_CANCELLED = 46; - - public static final short MISSING_NONCE = 51; - public static final short INVALID_NONCE = 52; - public static final short MISSING_MAC_LENGTH = 53; - public static final short CALLER_NONCE_PROHIBITED = 55; - public static final short INVALID_MAC_LENGTH = 57; - public static final short MISSING_MIN_MAC_LENGTH = 58; - public static final short UNSUPPORTED_MIN_MAC_LENGTH = 59; - public static final short UNSUPPORTED_EC_CURVE = 61; - public static final short KEY_REQUIRES_UPGRADE = 62; - - public static final short ATTESTATION_CHALLENGE_MISSING = 63; - public static final short ATTESTATION_APPLICATION_ID_MISSING = 65; - public static final short CANNOT_ATTEST_IDS = 66; - public static final short ROLLBACK_RESISTANCE_UNAVAILABLE = 67; - - public static final short DEVICE_LOCKED = 72; - public static final short EARLY_BOOT_ENDED = 73; - public static final short ATTESTATION_KEYS_NOT_PROVISIONED =74; - public static final short INCOMPATIBLE_MGF_DIGEST = 78; - public static final short UNSUPPORTED_MGF_DIGEST = 79; - public static final short MISSING_NOT_BEFORE = 80; - public static final short MISSING_NOT_AFTER = 81; - public static final short MISSING_ISSUER_SUBJECT_NAME = 82; - public static final short INVALID_ISSUER_SUBJECT_NAME = 83; - - public static final short UNIMPLEMENTED = 100; - public static final short UNKNOWN_ERROR = 1000; - - //Extended errors - public static final short SW_CONDITIONS_NOT_SATISFIED = 10001; - public static final short UNSUPPORTED_CLA = 10002; - public static final short INVALID_P1P2 = 10003; - public static final short UNSUPPORTED_INSTRUCTION = 10004; - public static final short CMD_NOT_ALLOWED = 10005; - public static final short SW_WRONG_LENGTH = 10006; - public static final short INVALID_DATA = 10007; - - //Crypto errors - public static final short CRYPTO_ILLEGAL_USE = 10008; - public static final short CRYPTO_ILLEGAL_VALUE = 10009; - public static final short CRYPTO_INVALID_INIT = 10010; - public static final short CRYPTO_NO_SUCH_ALGORITHM = 10011; - public static final short CRYPTO_UNINITIALIZED_KEY = 10012; - //Generic Unknown error. - public static final short GENERIC_UNKNOWN_ERROR = 10013; - - // Remote key provisioning error codes. - public static final short STATUS_FAILED = 32000; - public static final short STATUS_INVALID_MAC = 32001; - public static final short STATUS_PRODUCTION_KEY_IN_TEST_REQUEST = 32002; - public static final short STATUS_TEST_KEY_IN_PRODUCTION_REQUEST = 32003; - public static final short STATUS_INVALID_EEK = 32004; - public static final short INVALID_STATE = 32005; - - public static short translate(short err) { - switch(err) { - case SW_CONDITIONS_NOT_SATISFIED: - case UNSUPPORTED_CLA: - case INVALID_P1P2: - case INVALID_DATA: - case CRYPTO_ILLEGAL_USE: - case CRYPTO_ILLEGAL_VALUE: - case CRYPTO_INVALID_INIT: - case CRYPTO_UNINITIALIZED_KEY: - case GENERIC_UNKNOWN_ERROR: - case UNKNOWN_ERROR: - return UNKNOWN_ERROR; - case CRYPTO_NO_SUCH_ALGORITHM: - return UNSUPPORTED_ALGORITHM; - case UNSUPPORTED_INSTRUCTION: - case CMD_NOT_ALLOWED: - case SW_WRONG_LENGTH: - return UNIMPLEMENTED; - } - return err; - } -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java deleted file mode 100644 index eaa54962..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -import javacard.security.HMACKey; - -public class KMHmacKey implements KMPreSharedKey, KMComputedHmacKey { - - private HMACKey hmacKey; - - public KMHmacKey(HMACKey key) { - hmacKey = key; - } - - public void setKey(byte[] keyData, short kOff, short length) { - hmacKey.setKey(keyData, kOff, length); - } - - public byte getKey(byte[] keyData, short kOff) { - return hmacKey.getKey(keyData, kOff); - } - - public short getKeySizeBits() { - return hmacKey.getSize(); - } - - public HMACKey getKey() { - return hmacKey; - } -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java deleted file mode 100644 index f01e4637..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java +++ /dev/null @@ -1,1860 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.seprovider; - -import com.android.javacard.keymaster.KMConfigurations; -import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.MGF1ParameterSpec; -import java.security.spec.RSAPrivateKeySpec; -import java.security.spec.RSAPublicKeySpec; -import javacard.framework.ISO7816; -import javacard.framework.ISOException; -import javacard.framework.JCSystem; -import javacard.framework.Util; -import javacard.security.AESKey; -import javacard.security.CryptoException; -import javacard.security.DESKey; -import javacard.security.ECPrivateKey; -import javacard.security.ECPublicKey; -import javacard.security.HMACKey; -import javacard.security.Key; -import javacard.security.KeyBuilder; -import javacard.security.KeyPair; -import javacard.security.MessageDigest; -import javacard.security.RSAPrivateKey; -import javacard.security.KeyAgreement; -import javacard.security.RandomData; -import javacard.security.Signature; -import javacardx.crypto.AEADCipher; -import javacardx.crypto.Cipher; -import javax.crypto.AEADBadTagException; -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.ShortBufferException; -import javax.crypto.spec.GCMParameterSpec; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.OAEPParameterSpec; -import javax.crypto.spec.PSource; -import javax.crypto.spec.SecretKeySpec; -import org.globalplatform.upgrade.Element; - -/** - * Simulator only supports 512 bit RSA key pair, 128 AES Key, 128 bit 3Des key, less then 256 bit EC - * Key, and upto 512 bit HMAC key. Also simulator does not support TRNG, so this implementation just - * creates its own RNG using PRNG. - */ -public class KMJCardSimulator implements KMSEProvider { - public static final short AES_GCM_TAG_LENGTH = 16; - public static final short AES_GCM_NONCE_LENGTH = 12; - public static final short MAX_RND_NUM_SIZE = 64; - 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 short CERT_CHAIN_MAX_SIZE = 2500;//First 2 bytes for length. - private static final short ADDITIONAL_CERT_CHAIN_MAX_SIZE = 1024;//First 2 bytes for length. - private static final short BCC_MAX_SIZE = 512; - private static final short RSA_KEY_SIZE = 256; - public static final byte POWER_RESET_FALSE = (byte)0xAA; - public static final byte POWER_RESET_TRUE = (byte)0x00; - public static final byte AES_BLOCK_SIZE = 16; - private static final short CERT_CHAIN_OFFSET = 0; - private static final short CERT_ISSUER_OFFSET = KMConfigurations.CERT_CHAIN_MAX_SIZE; - private static final short CERT_EXPIRY_OFFSET = - (short) (CERT_ISSUER_OFFSET + KMConfigurations.CERT_ISSUER_MAX_SIZE); - private static final short COMPUTED_HMAC_KEY_SIZE = 32; - - public static byte[] resetFlag; - public static boolean jcardSim = false; - private static Signature kdf; - private static Signature hmacSignature; - private static KeyAgreement keyAgreement; - - private static byte[] rngCounter; - private static AESKey aesRngKey; - private static Cipher aesRngCipher; - private static byte[] entropyPool; - private static byte[] rndNum; - private byte[] additionalCertChain; - private byte[] bcc; - private byte[] provisionData; - private KMAESKey masterKey; - private KMECPrivateKey attestationKey; - private KMECDeviceUniqueKey testKey; - private KMECDeviceUniqueKey deviceUniqueKey; - private KMHmacKey preSharedKey; - private KMHmacKey computedHmacKey; - private boolean deviceReboot; - - // Data - originally was in repository - private byte[] attIdBrand; - private byte[] attIdDevice; - private byte[] attIdProduct; - private byte[] attIdSerial; - private byte[] attIdImei; - private byte[] attIdMeId; - private byte[] attIdManufacturer; - private byte[] attIdModel; - - // Boot parameters - private byte[] verifiedHash; - private byte[] bootKey; - private byte[] bootPatchLevel; - private boolean deviceBootLocked; - private short bootState; - private boolean isProvisionLocked; - - - private static KMJCardSimulator jCardSimulator = null; - - public static KMJCardSimulator getInstance() { - return jCardSimulator; - } - - // Implements Oracle Simulator based restricted crypto provider - public KMJCardSimulator() { - // Various Keys - kdf = Signature.getInstance(Signature.ALG_AES_CMAC_128, false); - hmacSignature = Signature.getInstance(Signature.ALG_HMAC_SHA_256, false); - keyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH_PLAIN, false); - // RNG - rndNum = JCSystem.makeTransientByteArray(MAX_RND_NUM_SIZE, JCSystem.CLEAR_ON_RESET); - entropyPool = JCSystem.makeTransientByteArray(ENTROPY_POOL_SIZE, JCSystem.CLEAR_ON_RESET); - rngCounter = JCSystem.makeTransientByteArray((short) 8, JCSystem.CLEAR_ON_RESET); - initEntropyPool(entropyPool); - try { - aesRngCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false); - } catch (CryptoException exp) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } - aesRngKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); - // various ciphers - //Allocate buffer for certificate chain. - //Allocate buffer for certificate chain and cert parameters. - // First 2 bytes is reserved for length for all the 3 buffers. - short totalLen = (short) (6 + KMConfigurations.CERT_CHAIN_MAX_SIZE + - KMConfigurations.CERT_ISSUER_MAX_SIZE + KMConfigurations.CERT_EXPIRY_MAX_SIZE); - provisionData = new byte[totalLen]; - additionalCertChain = new byte[ADDITIONAL_CERT_CHAIN_MAX_SIZE]; - bcc = new byte[BCC_MAX_SIZE]; - byte[] tmpArray = new byte[32]; - createAttestationKey(tmpArray, (short) 0, (short) 32); - // Pre-shared secret key length is 32 bytes. - createPresharedKey(tmpArray, (short) 0, (short) 32); - // Initialize the Computed Hmac Key object. - createComputedHmacKey(tmpArray, (short)0, (short) 32); - jCardSimulator = this; - resetFlag = new byte[1]; - resetFlag[0] = (byte) POWER_RESET_FALSE; - deviceReboot = false; - } - - - public KeyPair createRsaKeyPair() { - KeyPair rsaKeyPair = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048); - rsaKeyPair.genKeyPair(); - return rsaKeyPair; - } - - - public RSAPrivateKey createRsaKey(byte[] modBuffer, short modOff, short modLength, - byte[] privBuffer, short privOff, short privLength) { - KeyPair rsaKeyPair = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048); - RSAPrivateKey privKey = (RSAPrivateKey) rsaKeyPair.getPrivate(); - privKey.setExponent(privBuffer, privOff, privLength); - privKey.setModulus(modBuffer, modOff, modLength); - return privKey; - - } - - - public KeyPair createECKeyPair() { - KeyPair ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); - ecKeyPair.genKeyPair(); - return ecKeyPair; - } - - - public ECPrivateKey createEcKey(byte[] privBuffer, short privOff, short privLength) { - KeyPair ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); - ECPrivateKey privKey = (ECPrivateKey) ecKeyPair.getPrivate(); - privKey.setS(privBuffer, privOff, privLength); - return privKey; - } - - - public AESKey createAESKey(short keysize) { - byte[] rndNum = new byte[(short) (keysize / 8)]; - return createAESKey(rndNum, (short) 0, (short) rndNum.length); - } - - public AESKey createAESKey(byte[] buf, short startOff, short length) { - AESKey key = null; - short keysize = (short) (length * 8); - if (keysize == 128) { - key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); - key.setKey(buf, (short) startOff); - } else if (keysize == 256) { - key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false); - key.setKey(buf, (short) startOff); - } - return key; - } - - - public DESKey createTDESKey() { - byte[] rndNum = new byte[24]; - newRandomNumber(rndNum, (short) 0, (short) rndNum.length); - return createTDESKey(rndNum, (short) 0, (short) rndNum.length); - } - - - public DESKey createTDESKey(byte[] secretBuffer, short secretOff, short secretLength) { - DESKey triDesKey = - (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES3_3KEY, false); - triDesKey.setKey(secretBuffer, secretOff); - return triDesKey; - } - - - public HMACKey createHMACKey(short keysize) { - if ((keysize % 8 != 0) || !(keysize >= 64 && keysize <= 512)) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - byte[] rndNum = new byte[(short) (keysize / 8)]; - newRandomNumber(rndNum, (short) 0, (short) (keysize / 8)); - return createHMACKey(rndNum, (short) 0, (short) rndNum.length); - } - - @Override - public short createSymmetricKey(byte alg, short keysize, byte[] buf, short startOff) { - switch (alg) { - case KMType.AES: - AESKey aesKey = createAESKey(keysize); - return aesKey.getKey(buf, startOff); - case KMType.DES: - DESKey desKey = createTDESKey(); - return desKey.getKey(buf, startOff); - case KMType.HMAC: - HMACKey hmacKey = createHMACKey(keysize); - return hmacKey.getKey(buf, startOff); - default: - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - break; - } - return 0; - } - - @Override - public void createAsymmetricKey(byte alg, byte[] privKeyBuf, short privKeyStart, - short privKeyLength, - byte[] pubModBuf, short pubModStart, short pubModLength, short[] lengths) { - switch (alg) { - case KMType.RSA: - if (RSA_KEY_SIZE != privKeyLength || RSA_KEY_SIZE != pubModLength) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - KeyPair rsaKey = createRsaKeyPair(); - RSAPrivateKey privKey = (RSAPrivateKey) rsaKey.getPrivate(); - //Copy exponent. - byte[] exp = new byte[RSA_KEY_SIZE]; - lengths[0] = privKey.getExponent(exp, (short) 0); - if (lengths[0] > privKeyLength) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - Util.arrayFillNonAtomic(privKeyBuf, privKeyStart, privKeyLength, (byte) 0); - Util.arrayCopyNonAtomic(exp, (short) 0, - privKeyBuf, (short) (privKeyStart + privKeyLength - lengths[0]), lengths[0]); - //Copy modulus - byte[] mod = new byte[RSA_KEY_SIZE]; - lengths[1] = privKey.getModulus(mod, (short) 0); - if (lengths[1] > pubModLength) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - Util.arrayFillNonAtomic(pubModBuf, pubModStart, pubModLength, (byte) 0); - Util.arrayCopyNonAtomic(mod, (short) 0, - pubModBuf, (short) (pubModStart + pubModLength - lengths[1]), lengths[1]); - break; - case KMType.EC: - KeyPair ecKey = createECKeyPair(); - ECPublicKey ecPubKey = (ECPublicKey) ecKey.getPublic(); - ECPrivateKey ecPrivKey = (ECPrivateKey) ecKey.getPrivate(); - lengths[0] = ecPrivKey.getS(privKeyBuf, privKeyStart); - lengths[1] = ecPubKey.getW(pubModBuf, pubModStart); - if (lengths[0] > privKeyLength || lengths[1] > pubModLength) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - break; - default: - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - break; - } - } - - @Override - public boolean importSymmetricKey(byte alg, short keysize, byte[] buf, short startOff, - short length) { - switch (alg) { - case KMType.AES: - AESKey aesKey = createAESKey(buf, startOff, length); - break; - case KMType.DES: - DESKey desKey = createTDESKey(buf, startOff, length); - break; - case KMType.HMAC: - HMACKey hmacKey = createHMACKey(buf, startOff, length); - break; - default: - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - break; - } - return true; - } - - @Override - public boolean importAsymmetricKey(byte alg, byte[] privKeyBuf, short privKeyStart, - short privKeyLength, byte[] pubModBuf, short pubModStart, short pubModLength) { - switch (alg) { - case KMType.RSA: - RSAPrivateKey rsaKey = createRsaKey(pubModBuf, pubModStart, pubModLength, privKeyBuf, - privKeyStart, privKeyLength); - break; - case KMType.EC: - ECPrivateKey ecPrivKey = createEcKey(privKeyBuf, privKeyStart, privKeyLength); - break; - default: - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - break; - } - return true; - } - - - public HMACKey createHMACKey(byte[] secretBuffer, short secretOff, short secretLength) { - HMACKey key = null; - key = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, - KeyBuilder.LENGTH_HMAC_SHA_256_BLOCK_64, false); - key.setKey(secretBuffer, secretOff, secretLength); - return key; - } - - @Override - public short aesGCMEncrypt( - byte[] keyBuf, - short keyStart, - short keyLen, - byte[] secret, - short secretStart, - short secretLen, - byte[] encSecret, - short encSecretStart, - byte[] nonce, - short nonceStart, - short nonceLen, - byte[] authData, - short authDataStart, - short authDataLen, - byte[] authTag, - short authTagStart, - short authTagLen) { - //Create the sun jce compliant aes key - if (keyLen != 32 && keyLen != 16) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - java.security.Key aesKey = new SecretKeySpec(keyBuf, keyStart, keyLen, "AES"); - // Create the cipher - javax.crypto.Cipher cipher = null; - try { - cipher = javax.crypto.Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - } catch (NoSuchProviderException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.INVALID_INIT); - } catch (NoSuchPaddingException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - // Copy nonce - if (nonceLen != AES_GCM_NONCE_LENGTH) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - byte[] iv = new byte[AES_GCM_NONCE_LENGTH]; - Util.arrayCopyNonAtomic(nonce, nonceStart, iv, (short) 0, AES_GCM_NONCE_LENGTH); - // Init Cipher - GCMParameterSpec spec = new GCMParameterSpec(AES_GCM_TAG_LENGTH * 8, nonce, nonceStart, - AES_GCM_NONCE_LENGTH); - try { - cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, aesKey, spec); - } catch (InvalidKeyException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.INVALID_INIT); - } catch (InvalidAlgorithmParameterException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - } - // Create auth data - byte[] aad = new byte[authDataLen]; - Util.arrayCopyNonAtomic(authData, authDataStart, aad, (short) 0, authDataLen); - cipher.updateAAD(aad); - // Encrypt secret - short len = 0; - byte[] outputBuf = new byte[cipher.getOutputSize(secretLen)]; - try { - len = (short) (cipher.doFinal(secret, secretStart, secretLen, outputBuf, (short) 0)); - } catch (ShortBufferException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (IllegalBlockSizeException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (BadPaddingException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - // Extract Tag appended at the end. - Util.arrayCopyNonAtomic(outputBuf, (short) (len - AES_GCM_TAG_LENGTH), authTag, authTagStart, - AES_GCM_TAG_LENGTH); - //Copy the encrypted data - Util.arrayCopyNonAtomic(outputBuf, (short) 0, encSecret, encSecretStart, - (short) (len - AES_GCM_TAG_LENGTH)); - return (short) (len - AES_GCM_TAG_LENGTH); - } - - public boolean aesGCMDecrypt( - byte[] keyBuf, - short keyStart, - short keyLen, - byte[] encSecret, - short encSecretStart, - short encSecretLen, - byte[] secret, - short secretStart, - byte[] nonce, - short nonceStart, - short nonceLen, - byte[] authData, - short authDataStart, - short authDataLen, - byte[] authTag, - short authTagStart, - short authTagLen) { - // Create the sun jce compliant aes key - if (keyLen != 32 && keyLen != 16) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - java.security.Key aesKey = new SecretKeySpec(keyBuf, keyStart, keyLen, - "AES"); - // Create the cipher - javax.crypto.Cipher cipher = null; - try { - cipher = javax.crypto.Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - } catch (NoSuchProviderException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.INVALID_INIT); - } catch (NoSuchPaddingException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - // Copy nonce - if (nonceLen != AES_GCM_NONCE_LENGTH) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - byte[] iv = new byte[AES_GCM_NONCE_LENGTH]; - Util.arrayCopyNonAtomic(nonce, nonceStart, iv, (short) 0, - AES_GCM_NONCE_LENGTH); - // Init Cipher - GCMParameterSpec spec = new GCMParameterSpec(authTagLen * 8, nonce, - nonceStart, AES_GCM_NONCE_LENGTH); - try { - cipher.init(javax.crypto.Cipher.DECRYPT_MODE, aesKey, spec); - } catch (InvalidKeyException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.INVALID_INIT); - } catch (InvalidAlgorithmParameterException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - } - // Create auth data - byte[] aad = new byte[authDataLen]; - Util.arrayCopyNonAtomic(authData, authDataStart, aad, (short) 0, - authDataLen); - cipher.updateAAD(aad); - // Append the auth tag at the end of data - byte[] inputBuf = new byte[(short) (encSecretLen + authTagLen)]; - Util.arrayCopyNonAtomic(encSecret, encSecretStart, inputBuf, (short) 0, - encSecretLen); - Util.arrayCopyNonAtomic(authTag, authTagStart, inputBuf, encSecretLen, - authTagLen); - // Decrypt - short len = 0; - byte[] outputBuf = new byte[cipher.getOutputSize((short) inputBuf.length)]; - try { - len = (short) (cipher.doFinal(inputBuf, (short) 0, - (short) inputBuf.length, outputBuf, (short) 0)); - } catch (AEADBadTagException e) { - e.printStackTrace(); - return false; - } catch (ShortBufferException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (IllegalBlockSizeException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (BadPaddingException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - // Copy the decrypted data - Util.arrayCopyNonAtomic(outputBuf, (short) 0, secret, secretStart, len); - return true; - } - - @Override - public void getTrueRandomNumber(byte[] buf, short start, short length) { - Util.arrayCopy(entropyPool, (short) 0, buf, start, length); - } - - public HMACKey cmacKdf(byte[] keyMaterial, short keyMaterialStart, short keyMaterialLen, - byte[] label, - short labelStart, short labelLen, 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. - final byte[] zero = {0}; // byte - byte[] iBuf = new byte[]{0, 0, 0, 0}; // [i] counter - 32 bits - 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, keyMaterialStart); - prf.init(key, Signature.MODE_SIGN); - byte i = 1; - short pos = 0; - while (i <= n) { - iBuf[3] = i; - prf.update(iBuf, (short) 0, (short) 4); // 4 bytes of iBuf with counter in it - prf.update(label, labelStart, labelLen); // label - prf.update(zero, (short) 0, (short) 1); // 1 byte of 0x00 - prf.update(context, contextStart, contextLength); // context - pos = prf.sign(L, (short) 0, (short) 4, keyOut, pos); // 4 bytes of L - signature of 16 bytes - i++; - } - return createHMACKey(keyOut, (short) 0, (short) keyOut.length); - } - - @Override - public short cmacKDF(KMPreSharedKey pSharedKey, byte[] label, - short labelStart, short labelLen, byte[] context, short contextStart, short contextLength, - byte[] keyBuf, short keyStart) { - KMHmacKey key = (KMHmacKey) pSharedKey; - short keyMaterialLen = key.getKeySizeBits(); - keyMaterialLen = (short) (keyMaterialLen / 8); - short keyMaterialStart = 0; - byte[] keyMaterial = new byte[keyMaterialLen]; - key.getKey(keyMaterial, keyMaterialStart); - HMACKey hmacKey = cmacKdf(keyMaterial, keyMaterialStart, keyMaterialLen, label, labelStart, - labelLen, context, contextStart, contextLength); - return hmacKey.getKey(keyBuf, keyStart); - } - - - public short hmacSign(HMACKey key, byte[] data, short dataStart, short dataLength, byte[] mac, - short macStart) { - hmacSignature.init(key, Signature.MODE_SIGN); - return hmacSignature.sign(data, dataStart, dataLength, mac, macStart); - } - - @Override - public short hmacKDF(KMMasterKey masterkey, byte[] data, short dataStart, - short dataLength, byte[] signature, short signatureStart) { - KMAESKey aesKey = (KMAESKey) masterkey; - short keyLen = (short) (aesKey.getKeySizeBits() / 8); - byte[] keyData = new byte[keyLen]; - aesKey.getKey(keyData, (short) 0); - return hmacSign(keyData, (short) 0, keyLen, data, dataStart, dataLength, - signature, signatureStart); - } - - @Override - public short hkdf(byte[] ikm, short ikmOff, short ikmLen, byte[] salt, short saltOff, short saltLen, - byte[] info, short infoOff, short infoLen, byte[] out, short outOff, short outLen) { - // HMAC_extract - byte[] prk = new byte[32]; - hkdfExtract(ikm, ikmOff, ikmLen, salt, saltOff, saltLen, prk, (short) 0); - //HMAC_expand - return hkdfExpand(prk, (short) 0, (short) 32, info, infoOff, infoLen, out, outOff, outLen); - } - - private short hkdfExtract(byte[] ikm, short ikmOff, short ikmLen, byte[] salt, short saltOff, short saltLen, - byte[] out, short off) { - // https://tools.ietf.org/html/rfc5869#section-2.2 - HMACKey hmacKey = createHMACKey(salt, saltOff, saltLen); - hmacSignature.init(hmacKey, Signature.MODE_SIGN); - return hmacSignature.sign(ikm, ikmOff, ikmLen, out, off); - } - - private short hkdfExpand(byte[] prk, short prkOff, short prkLen, byte[] info, short infoOff, short infoLen, - byte[] out, short outOff, short outLen) { - // https://tools.ietf.org/html/rfc5869#section-2.3 - short digestLen = (short) 32; // SHA256 digest length. - // Calculate no of iterations N. - short n = (short) ((outLen + digestLen - 1) / digestLen); - if (n > 255) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - HMACKey hmacKey = createHMACKey(prk, prkOff, prkLen); - byte[] previousOutput = new byte[32]; // Length of output 32. - byte[] cnt = {(byte) 0}; - short bytesCopied = 0; - short len = 0; - for (short i = 0; i < n; i++) { - cnt[0]++; - hmacSignature.init(hmacKey, Signature.MODE_SIGN); - if (i != 0) - hmacSignature.update(previousOutput, (short) 0, (short) 32); - hmacSignature.update(info, infoOff, infoLen); - len = hmacSignature.sign(cnt, (short) 0, (short) 1, previousOutput, (short) 0); - if ((short) (bytesCopied + len) > outLen) { - len = (short) (outLen - bytesCopied); - } - Util.arrayCopyNonAtomic(previousOutput, (short) 0, out, (short) (outOff + bytesCopied), len); - bytesCopied += len; - } - return outLen; - } - - @Override - public short ecdhKeyAgreement(byte[] privKey, short privKeyOff, short privKeyLen, byte[] publicKey, short publicKeyOff, - short publicKeyLen, byte[] secret, short secretOff) { - keyAgreement.init(createEcKey(privKey, privKeyOff, privKeyLen)); - return keyAgreement.generateSecret(publicKey, publicKeyOff, publicKeyLen, secret, secretOff); - } - - @Override - public short hmacSign(byte[] keyBuf, short keyStart, short keyLength, byte[] data, - short dataStart, short dataLength, byte[] mac, short macStart) { - HMACKey key = createHMACKey(keyBuf, keyStart, keyLength); - return hmacSign(key, data, dataStart, dataLength, mac, macStart); - } - - @Override - public boolean hmacVerify(KMComputedHmacKey key, byte[] data, short dataStart, - short dataLength, byte[] mac, short macStart, short macLength) { - KMHmacKey hmacKey = (KMHmacKey) key; - hmacSignature.init(hmacKey.getKey(), Signature.MODE_VERIFY); - return hmacSignature.verify(data, dataStart, dataLength, mac, macStart, macLength); - } - - @Override - public short rsaDecipherOAEP256(byte[] secret, short secretStart, short secretLength, - byte[] modBuffer, short modOff, short modLength, - byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart) { - KMCipher cipher = createRsaDecipher( - KMType.RSA_OAEP, KMType.SHA1, secret, secretStart, secretLength, modBuffer, modOff, - modLength); - return cipher.doFinal( - inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart); - } - - @Override - public KMOperation initSymmetricOperation(byte purpose, byte alg, byte digest, byte padding, - byte blockMode, - byte[] keyBuf, short keyStart, short keyLength, - byte[] ivBuf, short ivStart, short ivLength, short macLength) { - switch (alg) { - case KMType.AES: - case KMType.DES: - if (blockMode != KMType.GCM) { - KMCipher cipher = createSymmetricCipher(alg, purpose, blockMode, padding, keyBuf, - keyStart, keyLength, - ivBuf, ivStart, ivLength); - return new KMOperationImpl(cipher); - } else { - KMCipher aesGcm = createAesGcmCipher(purpose, macLength, keyBuf, keyStart, keyLength, - ivBuf, ivStart, ivLength); - return new KMOperationImpl(aesGcm); - } - case KMType.HMAC: - Signature signerVerifier = createHmacSignerVerifier(purpose, digest, keyBuf, keyStart, - keyLength); - return new KMOperationImpl(signerVerifier); - default: - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - } - return null; - } - - @Override - public KMOperation initTrustedConfirmationSymmetricOperation(KMComputedHmacKey computedHmacKey) { - KMOperationImpl opr = null; - KMHmacKey key = (KMHmacKey) computedHmacKey; - Signature signerVerifier = createHmacSignerVerifier(KMType.VERIFY, KMType.SHA2_256, key.getKey()); - return new KMOperationImpl(signerVerifier); - } - - @Override - public KMOperation initAsymmetricOperation(byte purpose, byte alg, byte padding, byte digest, - byte mgfDigest, byte[] privKeyBuf, short privKeyStart, short privKeyLength, - byte[] pubModBuf, short pubModStart, short pubModLength) { - if (alg == KMType.RSA) { - switch (purpose) { - case KMType.SIGN: - Signature signer = - createRsaSigner( - digest, - padding, - privKeyBuf, - privKeyStart, - privKeyLength, - pubModBuf, - pubModStart, - pubModLength); - return new KMOperationImpl(signer); - case KMType.DECRYPT: - KMCipher decipher = - createRsaDecipher( - padding, mgfDigest, privKeyBuf, privKeyStart, privKeyLength, pubModBuf, pubModStart, - pubModLength); - return new KMOperationImpl(decipher); - default: - KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); - } - } else if (alg == KMType.EC) { - switch (purpose) { - case KMType.SIGN: - Signature signer = - createEcSigner(digest, privKeyBuf, privKeyStart, privKeyLength); - return new KMOperationImpl(signer); - case KMType.AGREE_KEY: - KeyAgreement keyAgreement = - createKeyAgreement(privKeyBuf, privKeyStart, privKeyLength); - return new KMOperationImpl(keyAgreement); - default: - KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); - } - } - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - return null; - } - - public KMCipher createRsaDecipher(short padding, short digest, byte[] secret, short secretStart, - short secretLength, byte[] modBuffer, short modOff, short modLength) { - byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0); - if (cipherAlg == Cipher.ALG_RSA_PKCS1_OAEP) { - return createRsaOAEP256Cipher(KMType.DECRYPT, (byte) digest, secret, secretStart, - secretLength, modBuffer, modOff, modLength); - } - Cipher rsaCipher = Cipher.getInstance(cipherAlg, false); - RSAPrivateKey key = (RSAPrivateKey) KeyBuilder - .buildKey(KeyBuilder.TYPE_RSA_PRIVATE, KeyBuilder.LENGTH_RSA_2048, false); - key.setExponent(secret, secretStart, secretLength); - key.setModulus(modBuffer, modOff, modLength); - rsaCipher.init(key, Cipher.MODE_DECRYPT); - KMCipherImpl inst = new KMCipherImpl(rsaCipher); - inst.setCipherAlgorithm(KMType.RSA); - inst.setMode(KMType.DECRYPT); - inst.setPaddingAlgorithm(padding); - return inst; - } - - private MGF1ParameterSpec getMGF1ParamSpec(byte mgfDigest) { - switch (mgfDigest) { - case KMType.SHA1: - return MGF1ParameterSpec.SHA1; - case KMType.SHA2_256: - return MGF1ParameterSpec.SHA256; - case KMType.SHA2_224: - return MGF1ParameterSpec.SHA224; - case KMType.SHA2_384: - return MGF1ParameterSpec.SHA384; - case KMType.SHA2_512: - return MGF1ParameterSpec.SHA512; - default: - KMException.throwIt(KMError.UNSUPPORTED_DIGEST); - } - return null; - } - - private KMCipher createRsaOAEP256Cipher(byte mode, byte mgfDigest, - byte[] secret, short secretStart, short secretLen, - byte[] modBuffer, short modOff, short modLength) { - // Convert byte arrays into keys - byte[] exp = null; - byte[] mod = new byte[modLength]; - if (secret != null) { - exp = new byte[secretLen]; - Util.arrayCopyNonAtomic(secret, secretStart, exp, (short) 0, secretLen); - } else { - exp = new byte[]{0x01, 0x00, 0x01}; - } - Util.arrayCopyNonAtomic(modBuffer, modOff, mod, (short) 0, modLength); - String modString = toHexString(mod); - String expString = toHexString(exp); - BigInteger modInt = new BigInteger(modString, 16); - BigInteger expInt = new BigInteger(expString, 16); - javax.crypto.Cipher rsaCipher = null; - try { - KeyFactory kf = KeyFactory.getInstance("RSA"); - // Create cipher with oaep padding - OAEPParameterSpec oaepSpec = new OAEPParameterSpec("SHA-256", "MGF1", - getMGF1ParamSpec(mgfDigest), PSource.PSpecified.DEFAULT); - rsaCipher = javax.crypto.Cipher.getInstance("RSA/ECB/OAEPPadding", "SunJCE"); - if (mode == KMType.ENCRYPT) { - RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(modInt, expInt); - java.security.interfaces.RSAPublicKey pubKey = (java.security.interfaces.RSAPublicKey) kf - .generatePublic(pubSpec); - rsaCipher.init(javax.crypto.Cipher.ENCRYPT_MODE, pubKey, oaepSpec); - } else { - RSAPrivateKeySpec privSpec = new RSAPrivateKeySpec(modInt, expInt); - java.security.interfaces.RSAPrivateKey privKey = (java.security.interfaces.RSAPrivateKey) kf - .generatePrivate(privSpec); - rsaCipher.init(javax.crypto.Cipher.DECRYPT_MODE, privKey, oaepSpec); - } - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - } catch (InvalidKeySpecException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (InvalidKeyException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.INVALID_INIT); - } catch (InvalidAlgorithmParameterException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (NoSuchPaddingException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (NoSuchProviderException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.INVALID_INIT); - } - KMCipherImpl ret = new KMCipherImpl(rsaCipher); - ret.setCipherAlgorithm(KMType.RSA); - ret.setPaddingAlgorithm(KMType.RSA_OAEP); - ret.setMode(mode); - return ret; - } - - private String toHexString(byte[] num) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < num.length; i++) { - sb.append(String.format("%02X", num[i])); - } - return sb.toString(); - } - - public Signature createRsaSigner(short digest, short padding, byte[] secret, - short secretStart, short secretLength, byte[] modBuffer, - short modOff, short modLength) { - short alg = mapSignature256Alg(KMType.RSA, (byte) padding); - if (padding == KMType.PADDING_NONE || - (padding == KMType.RSA_PKCS1_1_5_SIGN && digest == KMType.DIGEST_NONE)) { - return createNoDigestSigner(padding, secret, secretStart, secretLength, - modBuffer, modOff, modLength); - } - Signature rsaSigner = Signature.getInstance((byte) alg, false); - RSAPrivateKey key = (RSAPrivateKey) KeyBuilder - .buildKey(KeyBuilder.TYPE_RSA_PRIVATE, KeyBuilder.LENGTH_RSA_2048, false); - key.setExponent(secret, secretStart, secretLength); - key.setModulus(modBuffer, modOff, modLength); - rsaSigner.init(key, Signature.MODE_SIGN); - return rsaSigner; - } - - private Signature createNoDigestSigner(short padding, - byte[] secret, short secretStart, short secretLength, - byte[] modBuffer, short modOff, short modLength) { - Cipher rsaCipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false); - RSAPrivateKey key = (RSAPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PRIVATE, - KeyBuilder.LENGTH_RSA_2048, false); - key.setExponent(secret, secretStart, secretLength); - key.setModulus(modBuffer, modOff, modLength); - rsaCipher.init(key, Cipher.MODE_DECRYPT); - KMRsa2048NoDigestSignature inst = new KMRsa2048NoDigestSignature(rsaCipher, (byte) padding, - modBuffer, modOff, modLength); - return inst; - } - - public KeyAgreement createKeyAgreement(byte[] secret, short secretStart, - short secretLength) { - ECPrivateKey key = (ECPrivateKey) KeyBuilder - .buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, KeyBuilder.LENGTH_EC_FP_256, false); - key.setS(secret, secretStart, secretLength); - - KeyAgreement keyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH_PLAIN, - false); - keyAgreement.init(key); - return keyAgreement; - } - - public Signature createEcSigner(short digest, byte[] secret, short secretStart, - short secretLength) { - short alg = mapSignature256Alg(KMType.EC, (byte) 0); - Signature ecSigner; - if (digest == KMType.DIGEST_NONE) { - ecSigner = new KMEcdsa256NoDigestSignature(Signature.MODE_SIGN, secret, secretStart, - secretLength); - } else { - ECPrivateKey key = (ECPrivateKey) KeyBuilder - .buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, KeyBuilder.LENGTH_EC_FP_256, false); - key.setS(secret, secretStart, secretLength); - ecSigner = Signature.getInstance((byte) alg, false); - ecSigner.init(key, Signature.MODE_SIGN); - } - return ecSigner; - } - - - public KMCipher createSymmetricCipher( - short cipherAlg, short mode, short blockMode, short padding, byte[] secret, short secretStart, - short secretLength) { - return createSymmetricCipher(cipherAlg, mode, blockMode, padding, secret, secretStart, - secretLength, null, (short) 0, (short) 0); - } - - - public KMCipher createSymmetricCipher(short alg, short purpose, short blockMode, short padding, - byte[] secret, - short secretStart, short secretLength, - byte[] ivBuffer, short ivStart, short ivLength) { - Key key = null; - Cipher symmCipher = null; - short len = 0; - switch (secretLength) { - case 32: - len = KeyBuilder.LENGTH_AES_256; - break; - case 16: - len = KeyBuilder.LENGTH_AES_128; - break; - case 24: - len = KeyBuilder.LENGTH_DES3_3KEY; - break; - default: - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - break; - } - short cipherAlg = mapCipherAlg((byte) alg, (byte) padding, (byte) blockMode); - switch (cipherAlg) { - case Cipher.ALG_AES_BLOCK_128_CBC_NOPAD: - key = KeyBuilder.buildKey(KeyBuilder.TYPE_AES, len, false); - ((AESKey) key).setKey(secret, secretStart); - symmCipher = Cipher.getInstance((byte) cipherAlg, false); - symmCipher.init(key, mapPurpose(purpose), ivBuffer, ivStart, ivLength); - break; - case Cipher.ALG_AES_BLOCK_128_ECB_NOPAD: - key = KeyBuilder.buildKey(KeyBuilder.TYPE_AES, len, false); - ((AESKey) key).setKey(secret, secretStart); - symmCipher = Cipher.getInstance((byte) cipherAlg, false); - symmCipher.init(key, mapPurpose(purpose)); - break; - case Cipher.ALG_DES_CBC_NOPAD: - key = KeyBuilder.buildKey(KeyBuilder.TYPE_DES, len, false); - ((DESKey) key).setKey(secret, secretStart); - symmCipher = Cipher.getInstance((byte) cipherAlg, false); - //While sending back the iv send only 8 bytes. - symmCipher.init(key, mapPurpose(purpose), ivBuffer, ivStart, (short) 8); - break; - case Cipher.ALG_DES_ECB_NOPAD: - key = KeyBuilder.buildKey(KeyBuilder.TYPE_DES, len, false); - ((DESKey) key).setKey(secret, secretStart); - symmCipher = Cipher.getInstance((byte) cipherAlg, false); - symmCipher.init(key, mapPurpose(purpose)); - break; - case Cipher.ALG_AES_CTR: // uses SUNJCE - return createAesCtrCipherNoPad(purpose, secret, secretStart, secretLength, ivBuffer, - ivStart, ivLength); - default://This should never happen - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - break; - } - KMCipherImpl cipher = new KMCipherImpl(symmCipher); - cipher.setCipherAlgorithm(alg); - cipher.setPaddingAlgorithm(padding); - cipher.setMode(purpose); - cipher.setBlockMode(blockMode); - return cipher; - } - - private byte mapPurpose(short purpose) { - switch (purpose) { - case KMType.ENCRYPT: - return Cipher.MODE_ENCRYPT; - case KMType.DECRYPT: - return Cipher.MODE_DECRYPT; - case KMType.SIGN: - return Signature.MODE_SIGN; - case KMType.VERIFY: - return Signature.MODE_VERIFY; - } - return -1; - } - - private byte mapSignature256Alg(byte alg, byte padding) { - switch (alg) { - case KMType.RSA: - switch (padding) { - case KMType.RSA_PKCS1_1_5_SIGN: - return Signature.ALG_RSA_SHA_256_PKCS1; - case KMType.RSA_PSS: - return Signature.ALG_RSA_SHA_256_PKCS1_PSS; - } - break; - case KMType.EC: - return Signature.ALG_ECDSA_SHA_256; - case KMType.HMAC: - return Signature.ALG_HMAC_SHA_256; - } - return -1; - } - - private byte mapCipherAlg(byte alg, byte padding, byte blockmode) { - switch (alg) { - case KMType.AES: - switch (blockmode) { - case KMType.ECB: - return Cipher.ALG_AES_BLOCK_128_ECB_NOPAD; - case KMType.CBC: - return Cipher.ALG_AES_BLOCK_128_CBC_NOPAD; - case KMType.CTR: - return Cipher.ALG_AES_CTR; - case KMType.GCM: - return AEADCipher.ALG_AES_GCM; - } - break; - case KMType.DES: - switch (blockmode) { - case KMType.ECB: - return Cipher.ALG_DES_ECB_NOPAD; - case KMType.CBC: - return Cipher.ALG_DES_CBC_NOPAD; - } - break; - case KMType.RSA: - switch (padding) { - case KMType.PADDING_NONE: - return Cipher.ALG_RSA_NOPAD; - case KMType.RSA_PKCS1_1_5_ENCRYPT: - return Cipher.ALG_RSA_PKCS1; - case KMType.RSA_OAEP: - return Cipher.ALG_RSA_PKCS1_OAEP; - } - break; - } - return -1; - } - - private KMCipher createAesCtrCipherNoPad(short mode, byte[] secret, short secretStart, - short secretLength, byte[] ivBuffer, short ivStart, short ivLength) { - if (secretLength != 16 && secretLength != 32) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - if (ivLength != 16) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - if (mode != KMType.ENCRYPT && mode != KMType.DECRYPT) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - //Create the sun jce compliant aes key - byte[] keyMaterial = new byte[secretLength]; - Util.arrayCopyNonAtomic(secret, secretStart, keyMaterial, (short) 0, secretLength); - java.security.Key aesKey = new SecretKeySpec(keyMaterial, (short) 0, keyMaterial.length, "AES"); - // Create the cipher - javax.crypto.Cipher cipher = null; - try { - cipher = javax.crypto.Cipher.getInstance("AES/CTR/NoPadding", "SunJCE"); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - } catch (NoSuchProviderException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.INVALID_INIT); - } catch (NoSuchPaddingException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - // Copy nonce - byte[] iv = new byte[ivLength]; - Util.arrayCopyNonAtomic(ivBuffer, ivStart, iv, (short) 0, ivLength); - // Init Cipher - IvParameterSpec ivSpec = new IvParameterSpec(iv); - try { - if (mode == KMType.ENCRYPT) { - cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, aesKey, ivSpec); - } else { - cipher.init(javax.crypto.Cipher.DECRYPT_MODE, aesKey, ivSpec); - } - } catch (InvalidKeyException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.INVALID_INIT); - } catch (InvalidAlgorithmParameterException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - } - KMCipherImpl ret = new KMCipherImpl(cipher); - ret.setCipherAlgorithm(KMType.AES); - ret.setMode(mode); - ret.setPaddingAlgorithm((short) 0); - ret.setBlockMode(KMType.CTR); - return ret; - } - - - public Signature createHmacSignerVerifier(short purpose, short digest, byte[] secret, - short secretStart, short secretLength) { - short alg = Signature.ALG_HMAC_SHA_256; - if (digest != KMType.SHA2_256) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - Signature hmacSignerVerifier = Signature.getInstance((byte) alg, false); - HMACKey key = (HMACKey) KeyBuilder - .buildKey(KeyBuilder.TYPE_HMAC, (short) (secretLength * 8), false); - key.setKey(secret, secretStart, secretLength); - hmacSignerVerifier.init(key, (byte) purpose); - return hmacSignerVerifier; - } - - private Signature createHmacSignerVerifier(short purpose, short digest, HMACKey key) { - byte alg = Signature.ALG_HMAC_SHA_256; - if (digest != KMType.SHA2_256) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - Signature hmacSignerVerifier = Signature.getInstance((byte) alg, false); - hmacSignerVerifier.init(key, (byte) purpose); - return hmacSignerVerifier; - } - - public KMCipher createAesGcmCipher(short mode, short tagLen, byte[] secret, short secretStart, - short secretLength, - byte[] ivBuffer, short ivStart, short ivLength) { - if (secretLength != 16 && secretLength != 32) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - if (ivLength != AES_GCM_NONCE_LENGTH) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - if (mode != KMType.ENCRYPT && mode != KMType.DECRYPT) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - //Create the sun jce compliant aes key - byte[] keyMaterial = new byte[secretLength]; - Util.arrayCopyNonAtomic(secret, secretStart, keyMaterial, (short) 0, secretLength); - java.security.Key aesKey = new SecretKeySpec(keyMaterial, (short) 0, keyMaterial.length, "AES"); - // Create the cipher - javax.crypto.Cipher cipher = null; - try { - cipher = javax.crypto.Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - } catch (NoSuchProviderException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.INVALID_INIT); - } catch (NoSuchPaddingException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - // Copy nonce - byte[] iv = new byte[AES_GCM_NONCE_LENGTH]; - Util.arrayCopyNonAtomic(ivBuffer, ivStart, iv, (short) 0, AES_GCM_NONCE_LENGTH); - // Init Cipher - GCMParameterSpec spec = new GCMParameterSpec(tagLen, iv, (short) 0, AES_GCM_NONCE_LENGTH); - try { - if (mode == KMType.ENCRYPT) { - mode = javax.crypto.Cipher.ENCRYPT_MODE; - } else { - mode = javax.crypto.Cipher.DECRYPT_MODE; - } - cipher.init(mode, aesKey, spec); - } catch (InvalidKeyException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.INVALID_INIT); - } catch (InvalidAlgorithmParameterException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - } - KMCipherImpl ret = new KMCipherImpl(cipher); - ret.setCipherAlgorithm(KMType.AES); - ret.setMode(mode); - ret.setPaddingAlgorithm((short) 0); - ret.setBlockMode(KMType.GCM); - return ret; - } - - private void initEntropyPool(byte[] pool) { - byte index = 0; - RandomData trng; - while (index < rngCounter.length) { - rngCounter[index++] = 0; - } - try { - trng = RandomData.getInstance(RandomData.ALG_TRNG); - trng.nextBytes(pool, (short) 0, (short) pool.length); - } catch (CryptoException exp) { - if (exp.getReason() == CryptoException.NO_SUCH_ALGORITHM) { - // simulator does not support TRNG algorithm. So, PRNG algorithm (deprecated) is used. - trng = RandomData.getInstance(RandomData.ALG_PSEUDO_RANDOM); - trng.nextBytes(pool, (short) 0, (short) pool.length); - } else { - ISOException.throwIt(ISO7816.SW_UNKNOWN); - } - } - } - - // Generate a secure random number from existing entropy pool. This uses aes ecb algorithm with - // 8 byte rngCounter and 16 byte block size. - @Override - public void newRandomNumber(byte[] num, short startOff, short length) { - byte[] countBuf = new byte[AES_BLOCK_SIZE]; - byte[] randBuf = new byte[AES_BLOCK_SIZE]; - short len = AES_BLOCK_SIZE; - aesRngKey.setKey(entropyPool, (short) 0); - aesRngCipher.init(aesRngKey, Cipher.MODE_ENCRYPT, aesICV, (short) 0, (short) 16); - while (length > 0) { - if (length < len) { - len = length; - } - // increment rngCounter by one - incrementCounter(); - // copy the 8 byte rngCounter into the 16 byte rngCounter buffer. - Util.arrayCopy(rngCounter, (short) 0, countBuf, (short) 0, (short) rngCounter.length); - // encrypt the rngCounter buffer with existing entropy which forms the aes key. - aesRngCipher.doFinal( - countBuf, (short) 0, AES_BLOCK_SIZE, randBuf, (short) 0); - // copy the encrypted rngCounter block to buffer passed in the argument - Util.arrayCopy(randBuf, (short) 0, num, startOff, len); - length = (short) (length - len); - startOff = (short) (startOff + len); - } - } - - // increment 8 byte rngCounter by one - private void incrementCounter() { - // start with least significant byte - short index = (short) (rngCounter.length - 1); - while (index >= 0) { - // if the msb of current byte is set then it will be negative - if (rngCounter[index] < 0) { - // then increment the rngCounter - rngCounter[index]++; - // is the msb still set? i.e. no carry over - if (rngCounter[index] < 0) { - break; // then break - } else { - index--; // else go to the higher order byte - } - } else { - // if msb is not set then increment the rngCounter - rngCounter[index]++; - break; - } - } - } - - @Override - public void addRngEntropy(byte[] num, short offset, short length) { - // Maximum length can be 256 bytes. But currently we support max 32 bytes seed. - // Get existing entropy pool. - if (length > 32) { - length = 32; - } - // Create new temporary pool. - // Populate the new pool with the entropy which is derived from current entropy pool. - newRandomNumber(rndNum, (short) 0, (short) entropyPool.length); - // Copy the entropy to the current pool - updates the entropy pool. - Util.arrayCopy(rndNum, (short) 0, entropyPool, (short) 0, (short) entropyPool.length); - short index = 0; - short randIndex = 0; - // XOR the seed received from the master in the entropy pool - 16 bytes (entPool.length). - // at a time. - while (index < length) { - entropyPool[randIndex] = (byte) (entropyPool[randIndex] ^ num[(short) (offset + index)]); - randIndex++; - index++; - if (randIndex >= entropyPool.length) { - randIndex = 0; - } - } - } - - @Override - public short getAttestationKeyAlgorithm(){ - return KMType.INVALID_VALUE; - } - - @Override - public short getAdditionalCertChainLength() { - return Util.getShort(additionalCertChain, (short) 0); - } - - @Override - public byte[] getAdditionalCertChain() { - return additionalCertChain; - // short length = Util.getShort(additionalCertChain, (short) 0); - // Util.arrayCopyNonAtomic(additionalCertChain, (short) 2, buffer, start, length); - // return length; - } - - public void persistBootCertificateChain(byte[] buf, short offset, short len) { - if ((short) (len + 2) > BCC_MAX_SIZE) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - JCSystem.beginTransaction(); - Util.setShort(bcc, (short) 0, (short) len); - Util.arrayCopyNonAtomic(buf, offset, bcc, - (short) 2, len); - JCSystem.commitTransaction(); - } - - @Override - public byte[] getBootCertificateChain() { - return bcc; - } - - @Override - public short rsaSign256Pkcs1( - byte[] secret, - short secretStart, - short secretLength, - byte[] modBuf, - short modStart, - short modLength, - byte[] inputDataBuf, - short inputDataStart, - short inputDataLength, - byte[] outputDataBuf, - short outputDataStart){ - Signature signer = createRsaSigner(KMType.SHA2_256, KMType.RSA_PKCS1_1_5_SIGN,secret,secretStart,secretLength,modBuf,modStart,modLength); - return signer.sign(inputDataBuf, inputDataStart, inputDataLength, - outputDataBuf, outputDataStart); - } - - @Override - public short ecSign256(byte[] secret, short secretStart, short secretLength, - byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart){ - Signature signer = createEcSigner(KMType.SHA2_256, secret, secretStart, secretLength); - return signer.sign(inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart); - } - - @Override - public short ecSign256(KMAttestationKey attestationKey, - byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart) { - - ECPrivateKey key = ((KMECPrivateKey) attestationKey).getPrivateKey(); - - Signature signer = Signature - .getInstance(Signature.ALG_ECDSA_SHA_256, false); - signer.init(key, Signature.MODE_SIGN); - return signer.sign(inputDataBuf, inputDataStart, inputDataLength, - outputDataBuf, outputDataStart); - } - - - @Override - public short ecSign256(KMDeviceUniqueKey deviceUniqueKey, byte[] inputDataBuf, short inputDataStart, - short inputDataLength, byte[] outputDataBuf, short outputDataStart) { - ECPrivateKey key = ((KMECDeviceUniqueKey) deviceUniqueKey).getPrivateKey(); - Signature signer = Signature - .getInstance(Signature.ALG_ECDSA_SHA_256, false); - signer.init(key, Signature.MODE_SIGN); - return signer.sign(inputDataBuf, inputDataStart, inputDataLength, - outputDataBuf, outputDataStart); - } - - @Override - public boolean ecVerify256(byte[] pubKey, short pubKeyOffset, short pubKeyLen, byte[] inputDataBuf, - short inputDataStart, short inputDataLength, byte[] signatureDataBuf, - short signatureDataStart, short signatureDataLen) { - - KeyPair ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); - ECPublicKey ecPublicKey = (ECPublicKey) ecKeyPair.getPublic(); - ecPublicKey.setW(pubKey, pubKeyOffset, pubKeyLen); - - Signature signer = Signature - .getInstance(Signature.ALG_ECDSA_SHA_256, false); - signer.init(ecPublicKey, Signature.MODE_VERIFY); - return signer.verify(inputDataBuf, inputDataStart, inputDataLength, - signatureDataBuf, signatureDataStart, signatureDataLen); - } - - - @Override - public void persistAdditionalCertChain(byte[] buf, short offset, short len) { - // Input buffer contains encoded additional certificate chain as shown below. - // AdditionalDKSignatures = { - // + SignerName => DKCertChain - // } - // SignerName = tstr - // DKCertChain = [ - // 2* Certificate // Root -> Leaf. Root is the vendo r - // // self-signed cert, leaf contains DK_pu b - // ] - // Certificate = COSE_Sign1 of a public key - if (len > ADDITIONAL_CERT_CHAIN_MAX_SIZE) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - JCSystem.beginTransaction(); - Util.setShort(additionalCertChain, (short) 0, (short) len); - Util.arrayCopyNonAtomic(buf, offset, additionalCertChain, - (short) 2, len); - JCSystem.commitTransaction(); - } - - @Override - public void onSave(Element ele) { - } - - @Override - public void onRestore(Element ele) { - } - - @Override - public short getBackupPrimitiveByteCount() { - return 0; - } - - @Override - public short getBackupObjectCount() { - return 0; - } - - @Override - public boolean isUpgrading() { - return false; - } - - @Override - public KMComputedHmacKey createComputedHmacKey(byte[] keyData, short offset, short length) { - if (length != COMPUTED_HMAC_KEY_SIZE) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - if (computedHmacKey == null) { - HMACKey key = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, (short) (length * 8), - false); - computedHmacKey = new KMHmacKey(key); - } - computedHmacKey.setKey(keyData, offset, length); - return (KMComputedHmacKey) computedHmacKey; - } - - @Override - public KMMasterKey createMasterKey(short keySizeBits) { - if (masterKey == null) { - AESKey key = (AESKey) KeyBuilder.buildKey( - KeyBuilder.TYPE_AES, keySizeBits, false); - masterKey = new KMAESKey(key); - short keyLen = (short) (keySizeBits / 8); - byte[] keyData = new byte[keyLen]; - getTrueRandomNumber(keyData, (short) 0, keyLen); - masterKey.setKey(keyData, (short) 0); - } - return (KMMasterKey) masterKey; - } - - @Override - public boolean isAttestationKeyProvisioned(){ - return false; - } - /** - * This function creates an ECKey and initializes the ECPrivateKey with the provided input key - * data. The initialized Key is maintained by the SEProvider. This function should be called only - * while provisioning the attestation key. - * - * @param keyData buffer containing the ec private key. - * @param offset start of the buffer. - * @param length length of the buffer. - * @return An instance of KMAttestationKey. - */ - @Override - public KMAttestationKey createAttestationKey(byte[] keyData, short offset, short length){ - if (attestationKey == null) { - // Strongbox supports only P-256 curve for EC key. - KeyPair ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); - attestationKey = new KMECPrivateKey(ecKeyPair); - } - attestationKey.setS(keyData, offset, length); - return (KMAttestationKey) attestationKey; - } - - private KMDeviceUniqueKey createDeviceUniqueKey(KMECDeviceUniqueKey key, - byte[] pubKey, short pubKeyOff, short pubKeyLen, byte[] privKey, - short privKeyOff, short privKeyLen) { - if (key == null) { - KeyPair ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); - key = new KMECDeviceUniqueKey(ecKeyPair); - } - key.setS(privKey, privKeyOff, privKeyLen); - key.setW(pubKey, pubKeyOff, pubKeyLen); - return (KMDeviceUniqueKey) key; - } - - @Override - public KMDeviceUniqueKey createDeviceUniqueKey(boolean testMode, - byte[] pubKey, short pubKeyOff, short pubKeyLen, byte[] privKey, - short privKeyOff, short privKeyLen) { - KMDeviceUniqueKey key; - if (testMode) { - key = createDeviceUniqueKey(testKey, pubKey, pubKeyOff, - pubKeyLen, privKey, privKeyOff, privKeyLen); - if (testKey == null) testKey = (KMECDeviceUniqueKey) key; - } else { - key = createDeviceUniqueKey(deviceUniqueKey, pubKey, pubKeyOff, - pubKeyLen, privKey, privKeyOff, privKeyLen); - if (deviceUniqueKey == null) deviceUniqueKey = (KMECDeviceUniqueKey) key; - } - return key; - } - - @Override - public KMDeviceUniqueKey getDeviceUniqueKey(boolean testMode) { - return ((KMDeviceUniqueKey) (testMode ? testKey : deviceUniqueKey)); - } - - /** - * This function creates an HMACKey and initializes the key with the provided input key data. This - * created key is maintained by the SEProvider. This function should be called only while - * provisioing the pre-shared secret. - * - * @param keyData buffer containing the key data. - * @param offset start of the buffer. - * @param length length of the buffer. - * @return An instance of KMPreSharedKey. - */ - public KMPreSharedKey createPresharedKey(byte[] keyData, short offset, short length) { - short lengthInBits = (short) (length * 8); - if ((lengthInBits % 8 != 0) || !(lengthInBits >= 64 && lengthInBits <= 512)) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - if (preSharedKey == null) { - HMACKey key = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, lengthInBits, - false); - preSharedKey = new KMHmacKey(key); - } - preSharedKey.setKey(keyData, offset, length); - return (KMPreSharedKey) preSharedKey; - } - - @Override - public KMMasterKey getMasterKey() { - return (KMMasterKey) masterKey; - } - - /** - * Returns the factory provisioned attestation key if any. - * - * @return Instance of the KMAttestationKey. - */ - @Override - public KMAttestationKey getAttestationKey() { - return (KMAttestationKey) attestationKey; - } - - @Override - public KMPreSharedKey getPresharedKey() { - return (KMPreSharedKey) preSharedKey; - } - - @Override - public short getAttestationId(short tag, byte[] buffer, short start) { - switch(tag){ - // Attestation Id Brand - case KMType.ATTESTATION_ID_BRAND: - Util.arrayCopyNonAtomic(attIdBrand,(short)0,buffer, start,(short)attIdBrand.length); - return (short)attIdBrand.length; - // Attestation Id Device - case KMType.ATTESTATION_ID_DEVICE: - Util.arrayCopyNonAtomic(attIdDevice,(short)0,buffer, start,(short)attIdDevice.length); - return (short)attIdDevice.length; - // Attestation Id Product - case KMType.ATTESTATION_ID_PRODUCT: - Util.arrayCopyNonAtomic(attIdProduct,(short)0,buffer, start,(short)attIdProduct.length); - return (short)attIdProduct.length; - // Attestation Id Serial - case KMType.ATTESTATION_ID_SERIAL: - Util.arrayCopyNonAtomic(attIdSerial,(short)0,buffer, start,(short)attIdSerial.length); - return (short)attIdSerial.length; - // Attestation Id IMEI - case KMType.ATTESTATION_ID_IMEI: - Util.arrayCopyNonAtomic(attIdImei,(short)0,buffer, start,(short)attIdImei.length); - return (short)attIdImei.length; - // Attestation Id MEID - case KMType.ATTESTATION_ID_MEID: - Util.arrayCopyNonAtomic(attIdMeId,(short)0,buffer, start,(short)attIdMeId.length); - return (short)attIdMeId.length; - // Attestation Id Manufacturer - case KMType.ATTESTATION_ID_MANUFACTURER: - Util.arrayCopyNonAtomic(attIdManufacturer,(short)0,buffer, start,(short)attIdManufacturer.length); - return (short)attIdManufacturer.length; - // Attestation Id Model - case KMType.ATTESTATION_ID_MODEL: - Util.arrayCopyNonAtomic(attIdModel,(short)0,buffer, start,(short)attIdModel.length); - return (short)attIdModel.length; - } - return (short)0; - } - - public void setAttestationId(short tag, byte[] buffer, short start, short length) { - switch(tag){ - // Attestation Id Brand - case KMType.ATTESTATION_ID_BRAND: - attIdBrand = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short)start, attIdBrand,(short)0,length); - break; - // Attestation Id Device - case KMType.ATTESTATION_ID_DEVICE: - attIdDevice = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short)start, attIdDevice,(short)0,length); - break; - // Attestation Id Product - case KMType.ATTESTATION_ID_PRODUCT: - attIdProduct = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short)start, attIdProduct,(short)0,length); - break; - // Attestation Id Serial - case KMType.ATTESTATION_ID_SERIAL: - attIdSerial = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short)start, attIdSerial,(short)0,length); - break; - // Attestation Id IMEI - case KMType.ATTESTATION_ID_IMEI: - attIdImei = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short)start, attIdImei,(short)0,length); - break; - // Attestation Id MEID - case KMType.ATTESTATION_ID_MEID: - attIdMeId = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short)start, attIdMeId,(short)0,length); - break; - // Attestation Id Manufacturer - case KMType.ATTESTATION_ID_MANUFACTURER: - attIdManufacturer = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short)start, attIdManufacturer,(short)0,length); - break; - // Attestation Id Model - case KMType.ATTESTATION_ID_MODEL: - attIdModel = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short)start, attIdModel,(short)0,length); - break; - } - } - - @Override - public void deleteAttestationIds() { - attIdBrand = null; - attIdDevice = null; - attIdProduct = null; - attIdSerial = null; - attIdImei = null; - attIdMeId = null; - attIdManufacturer = null; - attIdModel = null; - } - - - public boolean isPowerReset(){ - boolean flag = false; - if(resetFlag[0] == POWER_RESET_TRUE){ - resetFlag[0] = POWER_RESET_FALSE; - flag = true; - } - return flag; - } - - @Override - public short getVerifiedBootHash(byte[] buffer, short start) { - Util.arrayCopyNonAtomic(verifiedHash,(short)0,buffer,start,(short)verifiedHash.length); - return (short)verifiedHash.length; - } - - @Override - public short getBootKey(byte[] buffer, short start) { - Util.arrayCopyNonAtomic(bootKey,(short) 0, buffer, start, (short)bootKey.length); - return (short)bootKey.length; - } - - @Override - public short getBootState() { - return bootState; - } - - @Override - public boolean isDeviceBootLocked() { - return deviceBootLocked; - } - - @Override - public short getBootPatchLevel(byte[] buffer, short start) { - Util.arrayCopyNonAtomic(bootPatchLevel, (short)0, buffer, start, (short)bootPatchLevel.length); - return (short)bootPatchLevel.length; - } - - public void setVerifiedBootHash(byte[] buffer, short start, short length) { - if(verifiedHash == null){ - verifiedHash = new byte[32]; - } - if(length != 32){ - KMException.throwIt(KMError.UNKNOWN_ERROR); - } - Util.arrayCopyNonAtomic(buffer, start, verifiedHash, (short)0, (short)32); - } - - public void setBootKey(byte[] buffer, short start, short length) { - if(bootKey == null){ - bootKey = new byte[32]; - } - if(length != 32){ - KMException.throwIt(KMError.UNKNOWN_ERROR); - } - Util.arrayCopyNonAtomic(buffer, start, bootKey, (short)0, (short)32); - } - - public void setBootState(short state) { - bootState = state; - } - - public void setDeviceLocked(boolean state) { - deviceBootLocked = state; - } - - public void setBootPatchLevel(byte[] buffer, short start, short length) { - if(bootPatchLevel == null){ - bootPatchLevel = new byte[4]; - } - if(length > 4 || length < 0){ - KMException.throwIt(KMError.UNKNOWN_ERROR); - } - Util.arrayCopyNonAtomic(buffer, start, bootPatchLevel, (short)0, (short) 4); - } - - public void setProvisionLocked(boolean locked) { - isProvisionLocked = locked; - } - - public boolean isProvisionLocked() { - return isProvisionLocked; - } - - @Override - public short messageDigest256(byte[] inBuff, short inOffset, - short inLength, byte[] outBuff, short outOffset) { - MessageDigest mDigest = null; - short len = 0; - try { - mDigest = MessageDigest.getInitializedMessageDigestInstance(MessageDigest.ALG_SHA_256, false); - len = mDigest.doFinal(inBuff, inOffset, inLength, outBuff, outOffset); - } catch (Exception e) { - - } - return len; - } - - private short getProvisionDataBufferOffset(byte dataType) { - switch(dataType) { - case CERTIFICATE_CHAIN: - return CERT_CHAIN_OFFSET; - case CERTIFICATE_ISSUER: - return CERT_ISSUER_OFFSET; - case CERTIFICATE_EXPIRY: - return CERT_EXPIRY_OFFSET; - default: - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - return 0; - } - - private void persistProvisionData(byte[] buf, short off, short len, short maxSize, short copyToOff) { - if (len > maxSize) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - JCSystem.beginTransaction(); - Util.setShort(provisionData, copyToOff, len); - Util.arrayCopyNonAtomic(buf, off, provisionData, (short) (copyToOff + 2), len); - JCSystem.commitTransaction(); - } - - private void persistCertificateChain(byte[] certChain, short certChainOff, short certChainLen) { - persistProvisionData(certChain, certChainOff, certChainLen, - KMConfigurations.CERT_CHAIN_MAX_SIZE, CERT_CHAIN_OFFSET); - } - - private void persistCertficateIssuer(byte[] certIssuer, short certIssuerOff, short certIssuerLen) { - persistProvisionData(certIssuer, certIssuerOff, certIssuerLen, - KMConfigurations.CERT_ISSUER_MAX_SIZE, CERT_ISSUER_OFFSET); - } - - private void persistCertificateExpiryTime(byte[] certExpiry, short certExpiryOff, short certExpiryLen) { - persistProvisionData(certExpiry, certExpiryOff, certExpiryLen, - KMConfigurations.CERT_EXPIRY_MAX_SIZE, CERT_EXPIRY_OFFSET); - } - - @Override - public void persistProvisionData(byte[] buffer, short certChainOff, short certChainLen, - short certIssuerOff, short certIssuerLen, short certExpiryOff ,short certExpiryLen) { - // All the buffers uses first two bytes for length. The certificate chain - // is stored as shown below. - // _____________________________________________________ - // | 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 byte string header. - // Next 3 bytes holds the total length of the certificate chain. - // clear buffer. - JCSystem.beginTransaction(); - Util.arrayFillNonAtomic(provisionData, (short) 0, (short) provisionData.length, (byte) 0); - JCSystem.commitTransaction(); - // Persist data. - persistCertificateChain(buffer, certChainOff, certChainLen); - persistCertficateIssuer(buffer, certIssuerOff, certIssuerLen); - persistCertificateExpiryTime(buffer, certExpiryOff, certExpiryLen); - } - - @Override - public short readProvisionedData(byte dataType, byte[] buf, short offset) { - short provisionBufOffset = getProvisionDataBufferOffset(dataType); - short len = Util.getShort(provisionData, provisionBufOffset); - Util.arrayCopyNonAtomic(provisionData, (short) (2 + provisionBufOffset), buf, offset, len); - return len; - } - - @Override - public KMComputedHmacKey getComputedHmacKey() { - return (KMComputedHmacKey) computedHmacKey; - } - - @Override - public short getProvisionedDataLength(byte dataType) { - short provisionBufOffset = getProvisionDataBufferOffset(dataType); - return Util.getShort(provisionData, provisionBufOffset); - } - -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMMasterKey.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMMasterKey.java deleted file mode 100644 index 6eab5e56..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMMasterKey.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -/** - * KMMasterKey is a marker interface and the SE Provider has to implement this interface. Internally - * Masterkey is stored as a Javacard AES key object, which will provide additional security. The - * master key is maintained by the SEProvider. - */ -public interface KMMasterKey { - -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMOperation.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMOperation.java deleted file mode 100644 index b73d58d1..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMOperation.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -/** - * KMOperation represents a persistent operation started by keymaster hal's beginOperation function. - * This operation is persistent i.e. it will be stored in non volatile memory of se card. It will be - * returned back to KMSEProvider for the reuse when the operation is finished. - */ -public interface KMOperation { - - // Used for cipher operations - short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart); - - // Used for signature operations - short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength); - - // Used for finishing cipher operations or ecdh keyAgreement. - short finish(byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart); - - // Used for finishing signing operations. - short sign(byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] signBuf, short signStart); - - // Used for finishing verifying operations. - boolean verify(byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] signBuf, short signStart, short signLength); - - // Used for aborting the ongoing operations. - void abort(); - - // Used for AES GCM cipher operation. - void updateAAD(byte[] dataBuf, short dataStart, short dataLength); - - // Used for getting output size before finishing a AES GCM cipher operation. For encryption this will - // include the auth tag which is appended at the end of the encrypted data. For decryption this will be - // size of the decrypted data only. - short getAESGCMOutputSize(short dataSize, short macLength); -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java deleted file mode 100644 index 715092af..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -import javacard.security.KeyAgreement; -import javacard.security.Signature; - -public class KMOperationImpl implements KMOperation { - - private KMCipher cipher; - private Signature signature; - private KeyAgreement keyAgreement; - - public KMOperationImpl(KMCipher cipher) { - this.cipher = cipher; - this.signature = null; - this.keyAgreement = null; - } - - public KMOperationImpl(Signature sign) { - this.cipher = null; - this.signature = sign; - this.keyAgreement = null; - } - - public KMOperationImpl(KeyAgreement keyAgreement) { - this.cipher = null; - this.signature = null; - this.keyAgreement = keyAgreement; - } - - @Override - public short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart) { - return cipher - .update(inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart); - } - - @Override - public short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength) { - signature.update(inputDataBuf, inputDataStart, inputDataLength); - return 0; - } - - @Override - public short finish(byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart) { - if (cipher != null) { - return cipher - .doFinal(inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart); - } else if (keyAgreement != null) { - return keyAgreement.generateSecret(inputDataBuf, inputDataStart, inputDataLength, - outputDataBuf, outputDataStart); - } else { - KMException.throwIt(KMError.UNKNOWN_ERROR); - } - return 0; - } - - @Override - public short sign(byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] signBuf, short signStart) { - return signature.sign(inputDataBuf, inputDataStart, inputDataLength, signBuf, signStart); - } - - @Override - public boolean verify(byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] signBuf, short signStart, short signLength) { - return signature - .verify(inputDataBuf, inputDataStart, inputDataLength, signBuf, signStart, signLength); - } - - @Override - public void abort() { - // do nothing - } - - @Override - public void updateAAD(byte[] dataBuf, short dataStart, short dataLength) { - cipher.updateAAD(dataBuf, dataStart, dataLength); - } - - @Override - public short getAESGCMOutputSize(short dataSize, short macLength) { - return cipher.getAesGcmOutputSize(dataSize, macLength); - } -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMPreSharedKey.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMPreSharedKey.java deleted file mode 100644 index 86bb1df9..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMPreSharedKey.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -/** - * KMPreSharedKey is a marker interface and the SE Provider has to implement this interface. - * Internally Preshared key is stored as a Javacard HMac key object, which will provide additional - * security. The pre-shared key is maintained by the SEProvider. - */ -public interface KMPreSharedKey { - -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMRsa2048NoDigestSignature.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMRsa2048NoDigestSignature.java deleted file mode 100644 index f9e8875d..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMRsa2048NoDigestSignature.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -import javacard.framework.Util; -import javacard.security.CryptoException; -import javacard.security.Key; -import javacard.security.Signature; -import javacardx.crypto.Cipher; - -public class KMRsa2048NoDigestSignature extends Signature { - - private Cipher inst; // ALG_RSA_NOPAD. - private byte padding; - private byte[] rsaModulus; // to compare with the data value - - public KMRsa2048NoDigestSignature(Cipher ciph, byte padding, byte[] mod, short start, short len) { - inst = ciph; - this.padding = padding; - if (len != 256) { - CryptoException.throwIt(CryptoException.INVALID_INIT); - } - rsaModulus = new byte[256]; - Util.arrayCopyNonAtomic(mod, start, rsaModulus, (short) 0, len); - } - - @Override - public void init(Key key, byte b) throws CryptoException { - - } - - @Override - public void init(Key key, byte b, byte[] bytes, short i, short i1) throws CryptoException { - } - - @Override - public void setInitialDigest(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) - throws CryptoException { - } - - @Override - public byte getAlgorithm() { - return 0; - } - - @Override - public byte getMessageDigestAlgorithm() { - return 0; - } - - @Override - public byte getCipherAlgorithm() { - return 0; - } - - @Override - public byte getPaddingAlgorithm() { - return 0; - } - - @Override - public short getLength() throws CryptoException { - return 0; - } - - @Override - public void update(byte[] bytes, short i, short i1) throws CryptoException { - } - - @Override - public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) - throws CryptoException { - byte[] inputData = padData(bytes, i, i1); - return inst.doFinal(inputData, (short) 0, (short) 256, bytes1, i2); - } - - @Override - public short signPreComputedHash(byte[] bytes, short i, short i1, byte[] bytes1, short i2) - throws CryptoException { - return 0; - } - - @Override - public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) - throws CryptoException { - // Public key operations not handled here. - return false; - } - - @Override - public boolean verifyPreComputedHash(byte[] bytes, short i, short i1, byte[] bytes1, short i2, - short i3) throws CryptoException { - return false; - } - - private byte[] padData(byte[] buf, short start, short len) { - byte[] inputData = new byte[256]; - if (!isValidData(buf, start, len)) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - Util.arrayFillNonAtomic(inputData, (short) 0, (short) 256, (byte) 0x00); - if (padding == KMType.PADDING_NONE) { // add zero to right - } else if (padding == KMType.RSA_PKCS1_1_5_SIGN) {// 0x00||0x01||PS||0x00 - inputData[0] = 0x00; - inputData[1] = 0x01; - Util.arrayFillNonAtomic(inputData, (short) 2, (short) (256 - len - 3), (byte) 0xFF); - inputData[(short) (256 - len - 1)] = 0x00; - } else { - CryptoException.throwIt(CryptoException.ILLEGAL_USE); - } - Util.arrayCopyNonAtomic(buf, start, inputData, (short) (256 - len), len); - return inputData; - } - - private boolean isValidData(byte[] buf, short start, short len) { - if (padding == KMType.PADDING_NONE) { - if (len > 256) { - return false; - } else if (len == 256) { - short v = unsignedByteArrayCompare(buf, start, rsaModulus, (short) 0, len); - if (v > 0) { - return false; - } - } - } else {//pkcs1 no digest - if (len > 245) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - return false; - } - } - return true; - } - - private byte unsignedByteArrayCompare(byte[] a1, short offset1, byte[] a2, short offset2, - short length) { - byte count = (byte) 0; - short val1 = (short) 0; - short val2 = (short) 0; - - for (; count < length; count++) { - val1 = (short) (a1[(short) (count + offset1)] & 0x00FF); - val2 = (short) (a2[(short) (count + offset2)] & 0x00FF); - - if (val1 < val2) { - return -1; - } - if (val1 > val2) { - return 1; - } - } - return 0; - } -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java deleted file mode 100644 index 8252ca7f..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java +++ /dev/null @@ -1,779 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -/** - * KMSEProvider is facade to use SE specific methods. The main intention of this interface is to - * abstract the cipher, signature and backup and restore related functions. The instance of this - * interface is created by the singleton KMSEProviderImpl class for each provider. At a time there - * can be only one provider in the applet package. - */ -public interface KMSEProvider extends KMUpgradable { - // Provision related constants. - public static final byte CERTIFICATE_CHAIN = 0; - public static final byte CERTIFICATE_EXPIRY = 1; - public static final byte CERTIFICATE_ISSUER = 2; - - /** - * Create a symmetric key instance. If the algorithm and/or keysize are not supported then it - * should throw a CryptoException. - * - * @param alg will be KMType.AES, KMType.DES or KMType.HMAC. - * @param keysize will be 128 or 256 for AES or DES. It can be 64 to 512 (multiple of 8) for - * HMAC. - * @param buf is the buffer in which key has to be returned - * @param startOff is the start offset. - * @return length of the data in the buf. This should match the keysize (in bytes). - */ - short createSymmetricKey(byte alg, short keysize, byte[] buf, short startOff); - - /** - * Create a asymmetric key pair. If the algorithms are not supported then it should throw a - * CryptoException. For RSA the public key exponent must always be 0x010001. The key size of RSA - * key pair must be 2048 bits and key size of EC key pair must be for p256 curve. - * - * @param alg will be KMType.RSA or KMType.EC. - * @param privKeyBuf is the buffer to return the private key exponent in case of RSA or private - * key in case of EC. - * @param privKeyStart is the start offset. - * @param privKeyMaxLength is the maximum length of this private key buffer. - * @param pubModBuf is the buffer to return the modulus in case of RSA or public key in case of - * EC. - * @param pubModStart is the start of offset. - * @param pubModMaxLength is the maximum length of this public key buffer. - * @param lengths is the actual length of the key pair - lengths[0] should be private key and - * lengths[1] should be public key. - */ - void createAsymmetricKey( - byte alg, - byte[] privKeyBuf, - short privKeyStart, - short privKeyMaxLength, - byte[] pubModBuf, - short pubModStart, - short pubModMaxLength, - short[] lengths); - - /** - * Initializes the trusted confirmation operation. - * - * @param computedHmacKey Instance of the computed Hmac key. - * @return instance of KMOperation. - */ - KMOperation initTrustedConfirmationSymmetricOperation(KMComputedHmacKey computedHmacKey); - - /** - * Verify that the imported key is valid. If the algorithm and/or keysize are not supported then - * it should throw a CryptoException. - * - * @param alg will be KMType.AES, KMType.DES or KMType.HMAC. - * @param keysize will be 128 or 256 for AES or DES. It can be 64 to 512 (multiple of 8) for - * HMAC. - * @param buf is the buffer that contains the symmetric key. - * @param startOff is the start offset. - * @param length of the data in the buf. This should match the keysize (in bytes). - * @return true if the symmetric key is supported and valid. - */ - boolean importSymmetricKey(byte alg, short keysize, byte[] buf, short startOff, short length); - - /** - * Validate that the imported asymmetric key pair is valid. For RSA the public key exponent must - * always be 0x010001. The key size of RSA key pair must be 2048 bits and key size of EC key pair - * must be for p256 curve. If the algorithms are not supported then it should throw a - * CryptoException. - * - * @param alg will be KMType.RSA or KMType.EC. - * @param privKeyBuf is the buffer that contains the private key exponent in case of RSA or - * private key in case of EC. - * @param privKeyStart is the start offset. - * @param privKeyLength is the length of this private key buffer. - * @param pubModBuf is the buffer that contains the modulus in case of RSA or public key in case - * of EC. - * @param pubModStart is the start of offset. - * @param pubModLength is the length of this public key buffer. - * @return true if the key pair is supported and valid. - */ - boolean importAsymmetricKey( - byte alg, - byte[] privKeyBuf, - short privKeyStart, - short privKeyLength, - byte[] pubModBuf, - short pubModStart, - short pubModLength); - - /** - * This is a oneshot operation that generates random number of desired length. - * - * @param num is the buffer in which random number is returned to the applet. - * @param offset is start of the buffer. - * @param length indicates the size of buffer and desired length of random number in bytes. - */ - void newRandomNumber(byte[] num, short offset, short length); - - /** - * This is a oneshot operation that adds the entropy to the entropy pool. This operation - * corresponds to addRndEntropy command. This method may ignore the added entropy value if the SE - * provider does not support it. - * - * @param num is the buffer in which entropy value is given. - * @param offset is start of the buffer. - * @param length length of the buffer. - */ - void addRngEntropy(byte[] num, short offset, short length); - - /** - * This is a oneshot operation that generates and returns back a true random number. - * - * @param num is the buffer in which entropy value is returned. - * @param offset is start of the buffer. - * @param length length of the buffer. - */ - void getTrueRandomNumber(byte[] num, short offset, short length); - - /** - * This is a oneshot operation that performs encryption operation using AES GCM algorithm. It - * throws CryptoException if algorithm is not supported or if tag length is not equal to 16 or - * nonce length is not equal to 12. - * - * @param aesKey is the buffer that contains 128 bit or 256 bit aes key used to encrypt. - * @param aesKeyStart is the start in aes key buffer. - * @param aesKeyLen is the length of aes key buffer in bytes (16 or 32 bytes). - * @param data is the buffer that contains data to encrypt. - * @param dataStart is the start of the data buffer. - * @param dataLen is the length of the data buffer. - * @param encData is the buffer of the output encrypted data. - * @param encDataStart is the start of the encrypted data buffer. - * @param nonce is the buffer of nonce. - * @param nonceStart is the start of the nonce buffer. - * @param nonceLen is the length of the nonce buffer. - * @param authData is the authentication data buffer. - * @param authDataStart is the start of the authentication buffer. - * @param authDataLen is the length of the authentication buffer. - * @param authTag is the buffer to output authentication tag. - * @param authTagStart is the start of the buffer. - * @param authTagLen is the length of the buffer. - * @return length of the encrypted data. - */ - short aesGCMEncrypt( - byte[] aesKey, - short aesKeyStart, - short aesKeyLen, - byte[] data, - short dataStart, - short dataLen, - byte[] encData, - short encDataStart, - byte[] nonce, - short nonceStart, - short nonceLen, - byte[] authData, - short authDataStart, - short authDataLen, - byte[] authTag, - short authTagStart, - short authTagLen); - - /** - * This is a oneshot operation that performs decryption operation using AES GCM algorithm. It - * throws CryptoException if algorithm is not supported. - * - * @param aesKey is the buffer that contains 128 bit or 256 bit aes key used to encrypt. - * @param aesKeyStart is the start in aes key buffer. - * @param aesKeyLen is the length of aes key buffer in bytes (16 or 32 bytes). - * @param encData is the buffer of the input encrypted data. - * @param encDataStart is the start of the encrypted data buffer. - * @param encDataLen is the length of the data buffer. - * @param data is the buffer that contains output decrypted data. - * @param dataStart is the start of the data buffer. - * @param nonce is the buffer of nonce. - * @param nonceStart is the start of the nonce buffer. - * @param nonceLen is the length of the nonce buffer. - * @param authData is the authentication data buffer. - * @param authDataStart is the start of the authentication buffer. - * @param authDataLen is the length of the authentication buffer. - * @param authTag is the buffer to output authentication tag. - * @param authTagStart is the start of the buffer. - * @param authTagLen is the length of the buffer. - * @return true if the authentication is valid. - */ - boolean aesGCMDecrypt( - byte[] aesKey, - short aesKeyStart, - short aesKeyLen, - byte[] encData, - short encDataStart, - short encDataLen, - byte[] data, - short dataStart, - byte[] nonce, - short nonceStart, - short nonceLen, - byte[] authData, - short authDataStart, - short authDataLen, - byte[] authTag, - short authTagStart, - short authTagLen); - - /** - * This is a oneshot operation that performs key derivation function using cmac kdf (CKDF) as - * defined in android keymaster hal definition. - * - * @param hmacKey of pre-shared key. - * @param label is the label to be used for ckdf. - * @param labelStart is the start of label. - * @param labelLen is the length of the label. - * @param context is the context to be used for ckdf. - * @param contextStart is the start of the context - * @param contextLength is the length of the context - * @param key is the output buffer to return the derived key - * @param keyStart is the start of the output buffer. - * @return length of the derived key buffer in bytes. - */ - short cmacKDF( - KMPreSharedKey hmacKey, - byte[] label, - short labelStart, - short labelLen, - byte[] context, - short contextStart, - short contextLength, - byte[] key, - short keyStart); - - /** - * This is a oneshot operation that signs the data using hmac algorithm. - * - * @param keyBuf is the buffer with hmac key. - * @param keyStart is the start of the buffer. - * @param keyLength is the length of the buffer which will be in bytes from 8 to 64. - * @param data is the buffer containing data to be signed. - * @param dataStart is the start of the data. - * @param dataLength is the length of the data. - * @param signature is the output signature buffer - * @param signatureStart is the start of the signature - * @return length of the signature buffer in bytes. - */ - short hmacSign( - byte[] keyBuf, - short keyStart, - short keyLength, - byte[] data, - short dataStart, - short dataLength, - byte[] signature, - short signatureStart); - - /** - * This is a oneshot operation that signs the data using hmac algorithm. This is used to derive - * the key, which is used to encrypt the keyblob. - * - * @param masterkey of masterkey. - * @param data is the buffer containing data to be signed. - * @param dataStart is the start of the data. - * @param dataLength is the length of the data. - * @param signature is the output signature buffer - * @param signatureStart is the start of the signature - * @return length of the signature buffer in bytes. - */ - short hmacKDF( - KMMasterKey masterkey, - byte[] data, - short dataStart, - short dataLength, - byte[] signature, - short signatureStart); - - /** - * This is a oneshot operation that verifies the signature using hmac algorithm. - * - * @param hmacKey is the computed hmac key. - * @param data is the buffer containing data. - * @param dataStart is the start of the data. - * @param dataLength is the length of the data. - * @param signature is the signature buffer. - * @param signatureStart is the start of the signature buffer. - * @param signatureLen is the length of the signature buffer in bytes. - * @return true if the signature matches. - */ - boolean hmacVerify( - KMComputedHmacKey hmacKey, - byte[] data, - short dataStart, - short dataLength, - byte[] signature, - short signatureStart, - short signatureLen); - - /** - * This is a oneshot operation that decrypts the data using RSA algorithm with oaep256 padding. - * The public exponent is always 0x010001. It throws CryptoException if OAEP encoding validation - * fails. - * - * @param privExp is the private exponent (2048 bit) buffer. - * @param privExpStart is the start of the private exponent buffer. - * @param privExpLength is the length of the private exponent buffer in bytes. - * @param modBuffer is the modulus (2048 bit) buffer. - * @param modOff is the start of the modulus buffer. - * @param modLength is the length of the modulus buffer in bytes. - * @param inputDataBuf is the buffer of the input data. - * @param inputDataStart is the start of the input data buffer. - * @param inputDataLength is the length of the input data buffer in bytes. - * @param outputDataBuf is the output buffer that contains the decrypted data. - * @param outputDataStart is the start of the output data buffer. - * @return length of the decrypted data. - */ - short rsaDecipherOAEP256( - byte[] privExp, - short privExpStart, - short privExpLength, - byte[] modBuffer, - short modOff, - short modLength, - byte[] inputDataBuf, - short inputDataStart, - short inputDataLength, - byte[] outputDataBuf, - short outputDataStart); - - /** - * This is a oneshot operation that signs the data using EC private key. - * - * @param ecPrivKey of KMAttestationKey. - * @param inputDataBuf is the buffer of the input data. - * @param inputDataStart is the start of the input data buffer. - * @param inputDataLength is the length of the inpur data buffer in bytes. - * @param outputDataBuf is the output buffer that contains the signature. - * @param outputDataStart is the start of the output data buffer. - * @return length of the decrypted data. - */ - short ecSign256( - KMAttestationKey ecPrivKey, - byte[] inputDataBuf, - short inputDataStart, - short inputDataLength, - byte[] outputDataBuf, - short outputDataStart); - - /** - * Implementation of HKDF as per RFC5869 https://datatracker.ietf.org/doc/html/rfc5869#section-2 - * - * @param ikm is the buffer containing input key material. - * @param ikmOff is the start of the input key. - * @param ikmLen is the length of the input key. - * @param salt is the buffer containing the salt. - * @param saltOff is the start of the salt buffer. - * @param saltLen is the length of the salt buffer. - * @param info is the buffer containing the application specific information - * @param infoOff is the start of the info buffer. - * @param infoLen is the length of the info buffer. - * @param out is the output buffer. - * @param outOff is the start of the output buffer. - * @param outLen is the length of the expected out buffer. - * @return Length of the out buffer which is outLen. - */ - short hkdf( - byte[] ikm, - short ikmOff, - short ikmLen, - byte[] salt, - short saltOff, - short saltLen, - byte[] info, - short infoOff, - short infoLen, - byte[] out, - short outOff, - short outLen); - - /** - * This function performs ECDH key agreement and generates a secret. - * - * @param privKey is the buffer containing the private key from first party. - * @param privKeyOff is the offset of the private key buffer. - * @param privKeyLen is the length of the private key buffer. - * @param publicKey is the buffer containing the public key from second party. - * @param publicKeyOff is the offset of the public key buffer. - * @param publicKeyLen is the length of the public key buffer. - * @param secret is the output buffer. - * @param secretOff is the offset of the output buffer. - * @return The length of the secret. - */ - short ecdhKeyAgreement( - byte[] privKey, - short privKeyOff, - short privKeyLen, - byte[] publicKey, - short publicKeyOff, - short publicKeyLen, - byte[] secret, - short secretOff); - - /** - * This is a oneshort operation that verifies the data using EC public key - * - * @param pubKey is the public key buffer. - * @param pubKeyOffset is the start of the public key buffer. - * @param pubKeyLen is the length of the public key. - * @param inputDataBuf is the buffer of the input data. - * @param inputDataStart is the start of the input data buffer. - * @param inputDataLength is the length of the input data buffer in bytes. - * @param signatureDataBuf is the buffer the signature input data. - * @param signatureDataStart is the start of the signature input data. - * @param signatureDataLen is the length of the signature input data. - * @return true if verification is successful, otherwise false. - */ - boolean ecVerify256( - byte[] pubKey, - short pubKeyOffset, - short pubKeyLen, - byte[] inputDataBuf, - short inputDataStart, - short inputDataLength, - byte[] signatureDataBuf, - short signatureDataStart, - short signatureDataLen); - - /** - * This is a oneshot operation that signs the data using device unique key. - * - * @param ecPrivKey instance of KMECDeviceUniqueKey to sign the input data. - * @param inputDataBuf is the buffer of the input data. - * @param inputDataStart is the start of the input data buffer. - * @param inputDataLength is the length of the input data buffer in bytes. - * @param outputDataBuf is the output buffer that contains the signature. - * @param outputDataStart is the start of the output data buffer. - * @return length of the decrypted data. - */ - short ecSign256( - KMDeviceUniqueKey ecPrivKey, - byte[] inputDataBuf, - short inputDataStart, - short inputDataLength, - byte[] outputDataBuf, - short outputDataStart); - - short ecSign256(byte[] secret, short secretStart, short secretLength, - byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart); - - short rsaSign256Pkcs1( - byte[] secret, - short secretStart, - short secretLength, - byte[] modBuf, - short modStart, - short modLength, - byte[] inputDataBuf, - short inputDataStart, - short inputDataLength, - byte[] outputDataBuf, - short outputDataStart); - - /** - * This creates a persistent operation for signing, verify, encryption and decryption using HMAC, - * AES and DES algorithms when keymaster hal's beginOperation function is executed. The - * KMOperation instance can be reclaimed by the seProvider when KMOperation is finished or - * aborted. It throws CryptoException if algorithm is not supported. - * - * @param purpose is KMType.ENCRYPT or KMType.DECRYPT for AES and DES algorithm. It will be - * KMType.SIGN and KMType.VERIFY for HMAC algorithm - * @param alg is KMType.HMAC, KMType.AES or KMType.DES. - * @param digest is KMType.SHA2_256 in case of HMAC else it will be KMType.DIGEST_NONE. - * @param padding is KMType.PADDING_NONE or KMType.PKCS7 (in case of AES and DES). - * @param blockMode is KMType.CTR, KMType.GCM. KMType.CBC or KMType.ECB for AES or DES else it is - * 0. - * @param keyBuf is aes, des or hmac key buffer. - * @param keyStart is the start of the key buffer. - * @param keyLength is the length of the key buffer. - * @param ivBuf is the iv buffer (in case on AES and DES algorithm without ECB mode) - * @param ivStart is the start of the iv buffer. - * @param ivLength is the length of the iv buffer. It will be zero in case of HMAC and AES/DES - * with ECB mode. - * @param macLength is the mac length in case of signing operation for hmac algorithm. - * @return KMOperation instance. - */ - KMOperation initSymmetricOperation( - byte purpose, - byte alg, - byte digest, - byte padding, - byte blockMode, - byte[] keyBuf, - short keyStart, - short keyLength, - byte[] ivBuf, - short ivStart, - short ivLength, - short macLength); - - /** - * This creates a persistent operation for signing, verify, encryption and decryption using RSA - * and EC algorithms when keymaster hal's beginOperation function is executed. For RSA the public - * exponent is always 0x0100101. For EC the curve is always p256. The KMOperation instance can be - * reclaimed by the seProvider when KMOperation is finished or aborted. It throws CryptoException - * if algorithm is not supported. - * - * @param purpose is KMType.ENCRYPT or KMType.DECRYPT for RSA. It will be * KMType.SIGN and - * KMType.VERIFY for RSA and EC algorithms. - * @param alg is KMType.RSA or KMType.EC algorithms. - * @param padding is KMType.PADDING_NONE or KMType.RSA_OAEP, KMType.RSA_PKCS1_1_5_ENCRYPT, - * KMType.RSA_PKCS1_1_5_SIGN or KMType.RSA_PSS. - * @param digest is KMType.DIGEST_NONE or KMType.SHA2_256. - * @param mgfDigest is the MGF digest. - * @param privKeyBuf is the private key in case of EC or private key exponent is case of RSA. - * @param privKeyStart is the start of the private key. - * @param privKeyLength is the length of the private key. - * @param pubModBuf is the modulus (in case of RSA) or public key (in case of EC). - * @param pubModStart is the start of the modulus. - * @param pubModLength is the length of the modulus. - * @return KMOperation instance that can be executed. - */ - KMOperation initAsymmetricOperation( - byte purpose, - byte alg, - byte padding, - byte digest, - byte mgfDigest, - byte[] privKeyBuf, - short privKeyStart, - short privKeyLength, - byte[] pubModBuf, - short pubModStart, - short pubModLength); - - /** - * This function tells if applet is upgrading or not. - * - * @return true if upgrading, otherwise false. - */ - boolean isUpgrading(); - - /** - * This function creates an HMACKey and initializes the key with the provided input key data. - * - * @param keyData buffer containing the key data. - * @param offset start of the buffer. - * @param length length of the buffer. - * @return An instance of the KMComputedHmacKey. - */ - KMComputedHmacKey createComputedHmacKey(byte[] keyData, short offset, short length); - - /** - * This function generates an AES Key of keySizeBits, which is used as an master key. This - * generated key is maintained by the SEProvider. This function should be called only once at the - * time of installation. - * - * @param keySizeBits key size in bits. - * @return An instance of KMMasterKey. - */ - KMMasterKey createMasterKey(short keySizeBits); - - /** - * Returns the master key. - * - * @return Instance of the KMMasterKey - */ - KMMasterKey getMasterKey(); - - /** - * Returns true if factory provisioned attestation key is supported. - */ - boolean isAttestationKeyProvisioned(); - - /** - * Returns algorithm type of the attestation key. It can be KMType.EC or KMType.RSA if the - * attestation key is provisioned in the factory. - */ - short getAttestationKeyAlgorithm(); - - /** - * Returns the preshared key. - * - * @return Instance of the KMPreSharedKey. - */ - KMPreSharedKey getPresharedKey(); - - /** - * Returns the value of the attestation id. - * - * @param tag - attestation id tag key as defined KMType. - * @param buffer - memorey buffer in which value of the id must be copied - * @param start - start offset in the buffer - * @return length - length of the returned attestation id value. - */ - short getAttestationId(short tag, byte[] buffer, short start); - - /** - * Delete the attestation ids permanently. - */ - void deleteAttestationIds(); - - /** - * Get Verified Boot hash. Part of RoT. Part of data sent by the aosp bootloader. - */ - short getVerifiedBootHash(byte[] buffer, short start); - - /** - * Get Boot Key. Part of RoT. Part of data sent by the aosp bootloader. - */ - short getBootKey(byte[] buffer, short start); - - /** - * Get Boot state. Part of RoT. Part of data sent by the aosp bootloader. - */ - short getBootState(); - - /** - * Returns true if device bootloader is locked. Part of RoT. Part of data sent by the aosp - * bootloader. - */ - boolean isDeviceBootLocked(); - - /** - * Get Boot patch level. Part of data sent by the aosp bootloader. - */ - short getBootPatchLevel(byte[] buffer, short start); - - /** - * Creates an ECKey instance and sets the public and private keys to it. - * - * @param testMode to indicate if current execution is for test or production. - * @param pubKey buffer containing the public key. - * @param pubKeyOff public key buffer start offset. - * @param pubKeyLen public key buffer length. - * @param privKey buffer containing the private key. - * @param privKeyOff private key buffer start offset. - * @param privKeyLen private key buffer length. - * @return instance of KMDeviceUniqueKey. - */ - KMDeviceUniqueKey createDeviceUniqueKey(boolean testMode, - byte[] pubKey, short pubKeyOff, short pubKeyLen, - byte[] privKey, short privKeyOff, short privKeyLen); - - /** - * Returns the instance KMDeviceUnique if it is created. - * - * @param testMode Indicates if current execution is for test or production. - * @return instance of KMDeviceUniqueKey if present; null otherwise. - */ - KMDeviceUniqueKey getDeviceUniqueKey(boolean testMode); - - /** - * Persists the additional certificate chain in persistent memory. - * - * @param buf buffer containing the cbor encoded additional certificate chain. - * @param offset start offset of the buffer. - * @param len length of the buffer. - */ - void persistAdditionalCertChain(byte[] buf, short offset, short len); - - /** - * Returns the additional certificate chain length. - * - * @return length of the encoded additional certificate chain. - */ - short getAdditionalCertChainLength(); - - /** - * Returns the additional certificate chain. - * - * @return additional cert chain. - */ - byte[] getAdditionalCertChain(); - - - /** - * Returns the boot certificate chain. - * - * @return boot certificate chain. - */ - byte[] getBootCertificateChain(); - - /** - * Returns the computed Hmac key. - * - * @return Instance of the computed hmac key. - */ - KMComputedHmacKey getComputedHmacKey(); - - /** - * This is a one-shot operation the does digest of the input mesage. - * - * @param inBuff input buffer to be digested. - * @param inOffset start offset of the input buffer. - * @param inLength length of the input buffer. - * @param outBuff is the output buffer that contains the digested data. - * @param outOffset start offset of the digested output buffer. - * @return length of the digested data. - */ - short messageDigest256(byte[] inBuff, short inOffset, short inLength, byte[] outBuff, - short outOffset); - - public boolean isProvisionLocked(); - -/** - * This function creates an ECKey and initializes the ECPrivateKey with the provided input key - * data. The initialized Key is maintained by the SEProvider. This function should be called only - * while provisioning the attestation key. - * - * @param keyData buffer containing the ec private key. - * @param offset start of the buffer. - * @param length length of the buffer. - * @return An instance of KMAttestationKey. - */ - KMAttestationKey createAttestationKey(byte[] keyData, short offset, short length); - /** - * This operation persists the provision data in the persistent memory. - * - * @param buf buffer which contains all the provision data. - * @param certChainOff is the start of the cert chain. - * @param certChainLen is the length of the cert chain. - * @param certIssuerOff is the start of the cert issuer. - * @param certIssuerLen is the length of the cert issuer. - * @param certExpiryOff is the start of the cert expiry. - * @param certExpiryLen is the length of the cert expiry. - */ - void persistProvisionData(byte[] buf, short certChainOff, short certChainLen, - short certIssuerOff, short certIssuerLen, short certExpiryOff, short certExpiryLen); - - /** - * The operation reads the provisioned data from persistent memory. - * - * @param dataType type of the provision data to read. - * @param buf is the start of data buffer. - * @param offset is the start of the data. - * @return the length of the data buffer in bytes. - */ - short readProvisionedData(byte dataType, byte[] buf, short offset); - - /** - * This function returns the provisioned data length. - * - * @param dataType type of the provision data to read. - * @return length of the certificate chain. - */ - short getProvisionedDataLength(byte dataType); - /** - * Returns the attestation key. - * - * @return Instance of the KMAttestationKey. - */ - KMAttestationKey getAttestationKey(); - - -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMType.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMType.java deleted file mode 100644 index acae1362..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMType.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.seprovider; - -/** - * This class declares all types, tag types, and tag keys. It also establishes basic structure of - * any KMType i.e. struct{byte type, short length, value} where value can any of the KMType. Also, - * KMType refers to transient memory heap in the repository. Finally KMType's subtypes are singleton - * prototype objects which just cast the structure over contiguous memory buffer. - */ -public abstract class KMType { - - public static final short INVALID_VALUE = (short) 0x8000; - protected static final byte TLV_HEADER_SIZE = 3; - - // Types - public static final byte BYTE_BLOB_TYPE = 0x01; - public static final byte INTEGER_TYPE = 0x02; - public static final byte ENUM_TYPE = 0x03; - public static final byte TAG_TYPE = 0x04; - public static final byte ARRAY_TYPE = 0x05; - public static final byte KEY_PARAM_TYPE = 0x06; - public static final byte KEY_CHAR_TYPE = 0x07; - public static final byte HW_AUTH_TOKEN_TYPE = 0x08; - public static final byte VERIFICATION_TOKEN_TYPE = 0x09; - public static final byte HMAC_SHARING_PARAM_TYPE = 0x0A; - public static final byte X509_CERT = 0x0B; - public static final byte NEG_INTEGER_TYPE = 0x0C; - public static final byte TEXT_STRING_TYPE = 0x0D; - public static final byte MAP_TYPE = 0x0E; - public static final byte COSE_KEY_TYPE = 0x0F; - public static final byte COSE_PAIR_TAG_TYPE = 0x10; - public static final byte COSE_PAIR_INT_TAG_TYPE = 0x20; - public static final byte COSE_PAIR_NEG_INT_TAG_TYPE = 0x30; - public static final byte COSE_PAIR_BYTE_BLOB_TAG_TYPE = 0x40; - public static final byte COSE_PAIR_COSE_KEY_TAG_TYPE = 0x60; - public static final byte COSE_PAIR_SIMPLE_VALUE_TAG_TYPE = 0x70; - public static final byte COSE_PAIR_TEXT_STR_TAG_TYPE = (byte) 0x80; - public static final byte SIMPLE_VALUE_TYPE = (byte) 0x90; - public static final byte COSE_HEADERS_TYPE = (byte) 0xA0; - public static final byte COSE_CERT_PAYLOAD_TYPE = (byte) 0xB0; - // Tag Types - public static final short INVALID_TAG = 0x0000; - public static final short ENUM_TAG = 0x1000; - public static final short ENUM_ARRAY_TAG = 0x2000; - public static final short UINT_TAG = 0x3000; - public static final short UINT_ARRAY_TAG = 0x4000; - public static final short ULONG_TAG = 0x5000; - public static final short DATE_TAG = 0x6000; - public static final short BOOL_TAG = 0x7000; - public static final short BIGNUM_TAG = (short) 0x8000; - public static final short BYTES_TAG = (short) 0x9000; - public static final short ULONG_ARRAY_TAG = (short) 0xA000; - public static final short TAG_TYPE_MASK = (short) 0xF000; - - // Enum Tag - // Internal tags - public static final short RULE = 0x7FFF; - public static final byte IGNORE_INVALID_TAGS = 0x00; - public static final byte FAIL_ON_INVALID_TAGS = 0x01; - - // Algorithm Enum Tag key and values - public static final short ALGORITHM = 0x0002; - public static final byte RSA = 0x01; - public static final byte DES = 0x21; - public static final byte EC = 0x03; - public static final byte AES = 0x20; - public static final byte HMAC = (byte) 0x80; - - // EcCurve Enum Tag key and values. - public static final short ECCURVE = 0x000A; - public static final byte P_224 = 0x00; - public static final byte P_256 = 0x01; - public static final byte P_384 = 0x02; - public static final byte P_521 = 0x03; - - // KeyBlobUsageRequirements Enum Tag key and values. - public static final short BLOB_USAGE_REQ = 0x012D; - public static final byte STANDALONE = 0x00; - public static final byte REQUIRES_FILE_SYSTEM = 0x01; - - // HardwareAuthenticatorType Enum Tag key and values. - public static final short USER_AUTH_TYPE = 0x01F8; - public static final byte USER_AUTH_NONE = 0x00; - public static final byte PASSWORD = 0x01; - public static final byte FINGERPRINT = 0x02; - public static final byte BOTH = 0x03; - // have to be power of 2 - public static final byte ANY = (byte) 0xFF; - - // Origin Enum Tag key and values. - public static final short ORIGIN = 0x02BE; - public static final byte GENERATED = 0x00; - public static final byte DERIVED = 0x01; - public static final byte IMPORTED = 0x02; - public static final byte UNKNOWN = 0x03; - public static final byte SECURELY_IMPORTED = 0x04; - - // Hardware Type tag key and values - public static final short HARDWARE_TYPE = 0x0130; - public static final byte SOFTWARE = 0x00; - public static final byte TRUSTED_ENVIRONMENT = 0x01; - public static final byte STRONGBOX = 0x02; - - // No Tag - // Derivation Function - No Tag defined - public static final short KEY_DERIVATION_FUNCTION = (short) 0xF001; - public static final byte DERIVATION_NONE = 0x00; - public static final byte RFC5869_SHA256 = 0x01; - public static final byte ISO18033_2_KDF1_SHA1 = 0x02; - public static final byte ISO18033_2_KDF1_SHA256 = 0x03; - public static final byte ISO18033_2_KDF2_SHA1 = 0x04; - public static final byte ISO18033_2_KDF2_SHA256 = 0x05; - - // KeyFormat - No Tag defined. - public static final short KEY_FORMAT = (short) 0xF002; - public static final byte X509 = 0x00; - public static final byte PKCS8 = 0x01; - public static final byte RAW = 0x03; - - // Verified Boot State - public static final short VERIFIED_BOOT_STATE = (short) 0xF003; - public static final byte VERIFIED_BOOT = 0x00; - public static final byte SELF_SIGNED_BOOT = 0x01; - public static final byte UNVERIFIED_BOOT = 0x02; - public static final byte FAILED_BOOT = 0x03; - - // Verified Boot Key - public static final short VERIFIED_BOOT_KEY = (short) 0xF004; - - // Verified Boot Hash - public static final short VERIFIED_BOOT_HASH = (short) 0xF005; - - // Device Locked - public static final short DEVICE_LOCKED = (short) 0xF006; - public static final byte DEVICE_LOCKED_TRUE = 0x01; - public static final byte DEVICE_LOCKED_FALSE = 0x00; - - // Enum Array Tag - // Purpose - public static final short PURPOSE = 0x0001; - public static final byte ENCRYPT = 0x00; - public static final byte DECRYPT = 0x01; - public static final byte SIGN = 0x02; - public static final byte VERIFY = 0x03; - public static final byte DERIVE_KEY = 0x04; - public static final byte WRAP_KEY = 0x05; - public static final byte AGREE_KEY = 0x06; - public static final byte ATTEST_KEY = (byte) 0x07; - // Block mode - public static final short BLOCK_MODE = 0x0004; - public static final byte ECB = 0x01; - public static final byte CBC = 0x02; - public static final byte CTR = 0x03; - public static final byte GCM = 0x20; - - // Digest - public static final short DIGEST = 0x0005; - public static final byte DIGEST_NONE = 0x00; - public static final byte MD5 = 0x01; - public static final byte SHA1 = 0x02; - public static final byte SHA2_224 = 0x03; - public static final byte SHA2_256 = 0x04; - public static final byte SHA2_384 = 0x05; - public static final byte SHA2_512 = 0x06; - - // Padding mode - public static final short PADDING = 0x0006; - public static final byte PADDING_NONE = 0x01; - public static final byte RSA_OAEP = 0x02; - public static final byte RSA_PSS = 0x03; - public static final byte RSA_PKCS1_1_5_ENCRYPT = 0x04; - public static final byte RSA_PKCS1_1_5_SIGN = 0x05; - public static final byte PKCS7 = 0x40; - - // OAEP MGF Digests - only SHA-1 is supported in Javacard - public static final short RSA_OAEP_MGF_DIGEST = 0xCB; - - // Integer Tag - UINT, ULONG and DATE - // UINT tags - // Keysize - public static final short KEYSIZE = 0x0003; - // Min Mac Length - public static final short MIN_MAC_LENGTH = 0x0008; - // Min Seconds between OPS - public static final short MIN_SEC_BETWEEN_OPS = 0x0193; - // Max Uses per Boot - public static final short MAX_USES_PER_BOOT = 0x0194; - // UserId - public static final short USERID = 0x01F5; - // Auth Timeout - public static final short AUTH_TIMEOUT = 0x01F9; - // OS Version - public static final short OS_VERSION = 0x02C1; - // OS Patch Level - public static final short OS_PATCH_LEVEL = 0x02C2; - // Vendor Patch Level - public static final short VENDOR_PATCH_LEVEL = 0x02CE; - // Boot Patch Level - public static final short BOOT_PATCH_LEVEL = 0x02CF; - // Mac Length - public static final short MAC_LENGTH = 0x03EB; - // Usage Count Limit - public static final short USAGE_COUNT_LIMIT = 0x195; - - // ULONG tags - // RSA Public Exponent - public static final short RSA_PUBLIC_EXPONENT = 0x00C8; - - // DATE tags - public static final short ACTIVE_DATETIME = 0x0190; - public static final short ORIGINATION_EXPIRE_DATETIME = 0x0191; - public static final short USAGE_EXPIRE_DATETIME = 0x0192; - public static final short CREATION_DATETIME = 0x02BD;; - public static final short CERTIFICATE_NOT_BEFORE = 0x03F0; - public static final short CERTIFICATE_NOT_AFTER = 0x03F1; - // Integer Array Tags - ULONG_REP and UINT_REP. - // User Secure Id - public static final short USER_SECURE_ID = (short) 0x01F6; - - // Boolean Tag - // Caller Nonce - public static final short CALLER_NONCE = (short) 0x0007; - // Include Unique Id - public static final short INCLUDE_UNIQUE_ID = (short) 0x00CA; - // Bootloader Only - public static final short BOOTLOADER_ONLY = (short) 0x012E; - // Rollback Resistance - public static final short ROLLBACK_RESISTANCE = (short) 0x012F; - // No Auth Required - public static final short NO_AUTH_REQUIRED = (short) 0x01F7; - // Allow While On Body - public static final short ALLOW_WHILE_ON_BODY = (short) 0x01FA; - // Trusted User Presence Required - public static final short TRUSTED_USER_PRESENCE_REQUIRED = (short) 0x01FB; - // Trusted Confirmation Required - public static final short TRUSTED_CONFIRMATION_REQUIRED = (short) 0x01FC; - // Unlocked Device Required - 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_ONLY = (short) 0x0131; - //Device unique attestation. - public static final short DEVICE_UNIQUE_ATTESTATION = (short) 0x02D0; - - // Byte Tag - // Application Id - public static final short APPLICATION_ID = (short) 0x0259; - // Application Data - public static final short APPLICATION_DATA = (short) 0x02BC; - // Root Of Trust - public static final short ROOT_OF_TRUST = (short) 0x02C0; - // Unique Id - public static final short UNIQUE_ID = (short) 0x02C3; - // Attestation Challenge - public static final short ATTESTATION_CHALLENGE = (short) 0x02C4; - // Attestation Application Id - public static final short ATTESTATION_APPLICATION_ID = (short) 0x02C5; - // Attestation Id Brand - public static final short ATTESTATION_ID_BRAND = (short) 0x02C6; - // Attestation Id Device - public static final short ATTESTATION_ID_DEVICE = (short) 0x02C7; - // Attestation Id Product - public static final short ATTESTATION_ID_PRODUCT = (short) 0x02C8; - // Attestation Id Serial - public static final short ATTESTATION_ID_SERIAL = (short) 0x02C9; - // Attestation Id IMEI - public static final short ATTESTATION_ID_IMEI = (short) 0x02CA; - // Attestation Id MEID - public static final short ATTESTATION_ID_MEID = (short) 0x02CB; - // Attestation Id Manufacturer - public static final short ATTESTATION_ID_MANUFACTURER = (short) 0x02CC; - // Attestation Id Model - public static final short ATTESTATION_ID_MODEL = (short) 0x02CD; - // Associated Data - public static final short ASSOCIATED_DATA = (short) 0x03E8; - // Nonce - public static final short NONCE = (short) 0x03E9; - // Confirmation Token - public static final short CONFIRMATION_TOKEN = (short) 0x03ED; - // Serial Number - this is a big num but in applet we handle it as byte blob - public static final short CERTIFICATE_SERIAL_NUM = (short) 0x03EE; - // Subject Name - public static final short CERTIFICATE_SUBJECT_NAME = (short) 0x03EF; - - public static final short LENGTH_FROM_PDU = (short) 0xFFFF; - - public static final byte NO_VALUE = (byte) 0xff; - // Support Curves for Eek Chain validation. - public static final byte RKP_CURVE_P256 = 1; - // 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; - public static final byte KM_NEG_INTEGER_OFFSET = KM_TYPE_BASE_OFFSET + 15; - public static final byte KM_TEXT_STRING_OFFSET = KM_TYPE_BASE_OFFSET + 16; - public static final byte KM_MAP_OFFSET = KM_TYPE_BASE_OFFSET + 17; - public static final byte KM_COSE_KEY_OFFSET = KM_TYPE_BASE_OFFSET + 18; - public static final byte KM_COSE_KEY_INT_VAL_OFFSET = KM_TYPE_BASE_OFFSET + 19; - public static final byte KM_COSE_KEY_NINT_VAL_OFFSET = KM_TYPE_BASE_OFFSET + 20; - public static final byte KM_COSE_KEY_BYTE_BLOB_VAL_OFFSET = KM_TYPE_BASE_OFFSET + 21; - public static final byte KM_COSE_KEY_COSE_KEY_VAL_OFFSET = KM_TYPE_BASE_OFFSET + 22; - public static final byte KM_COSE_KEY_SIMPLE_VAL_OFFSET = KM_TYPE_BASE_OFFSET + 23; - public static final byte KM_SIMPLE_VALUE_OFFSET = KM_TYPE_BASE_OFFSET + 24; - public static final byte KM_COSE_HEADERS_OFFSET = KM_TYPE_BASE_OFFSET + 25; - public static final byte KM_COSE_KEY_TXT_STR_VAL_OFFSET = KM_TYPE_BASE_OFFSET + 26; - public static final byte KM_COSE_CERT_PAYLOAD_OFFSET = KM_TYPE_BASE_OFFSET + 27; - public static final byte KM_BIGNUM_TAG_OFFSET = KM_TYPE_BASE_OFFSET + 28; - - // Attestation types - public static final byte NO_CERT = 0; - public static final byte ATTESTATION_CERT = 1; - public static final byte SELF_SIGNED_CERT = 2; - public static final byte FAKE_CERT = 3; - // Buffering Mode - public static final byte BUF_NONE = 0; - public static final byte BUF_RSA_NO_DIGEST = 1; - public static final byte BUF_EC_NO_DIGEST = 2; - public static final byte BUF_BLOCK_ALIGN = 3; -} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMUpgradable.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMUpgradable.java deleted file mode 100644 index 9bca1c8c..00000000 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMUpgradable.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" (short)0IS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.javacard.seprovider; - -import org.globalplatform.upgrade.Element; - -public interface KMUpgradable { - - void onSave(Element ele); - - void onRestore(Element ele); - - short getBackupPrimitiveByteCount(); - - short getBackupObjectCount(); - -} diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterSpecification.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterSpecification.java deleted file mode 100644 index 8001d767..00000000 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterSpecification.java +++ /dev/null @@ -1,301 +0,0 @@ -package com.android.javacard.keymaster; - -import static com.android.javacard.keymaster.KMKeymasterApplet.seProvider; - -import com.android.javacard.seprovider.KMAttestationCert; -import com.android.javacard.seprovider.KMException; -import com.android.javacard.seprovider.KMSEProvider; -import javacard.framework.APDU; -import javacard.framework.ISO7816; -import javacard.framework.Util; - -public class KMKeymasterSpecification implements KMSpecification { - - // getHardwareInfo constants. - private static final byte[] JAVACARD_KEYMASTER_DEVICE = { - 0x4A, 0x61, 0x76, 0x61, 0x63, 0x61, 0x72, 0x64, 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, - 0x65, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - }; - private static final byte[] GOOGLE = {0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65}; - private static final byte[] X509Subject = { - 0x30, 0x1F, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x14, 0x41, 0x6e, - 0x64, - 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4B, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x4B, - 0x65, - 0x79 - }; - private static final byte SERIAL_NUM = (byte) 0x01; - - - @Override - public short getHardwareInfo() { - short respPtr = KMArray.instance((short) 4); - KMArray resp = KMArray.cast(respPtr); - resp.add((short) 0, KMInteger.uint_16(KMError.OK)); - resp.add((short) 1, KMEnum.instance(KMType.HARDWARE_TYPE, KMType.STRONGBOX)); - resp.add( - (short) 2, - KMByteBlob.instance( - JAVACARD_KEYMASTER_DEVICE, (short) 0, (short) JAVACARD_KEYMASTER_DEVICE.length)); - resp.add((short) 3, KMByteBlob.instance(GOOGLE, (short) 0, (short) GOOGLE.length)); - return respPtr; - } - - @Override - public short makeKeyCharacteristics(short keyParams, short osVersion, short osPatch, - short vendorPatch, short bootPatch, short origin, byte[] scratchPad) { - short strongboxParams = KMKeyParameters.makeSbEnforced( - keyParams, (byte) origin, osVersion, osPatch, vendorPatch, bootPatch, scratchPad); - short teeParams = KMKeyParameters.makeTeeEnforced(keyParams, scratchPad); - short swParams = KMKeyParameters.makeKeystoreEnforced(keyParams, scratchPad); - short hwParams = KMKeyParameters.makeHwEnforced(strongboxParams, teeParams); - short arr = KMArray.instance((short) 0); - short emptyParams = KMKeyParameters.instance(arr); - short keyCharacteristics = KMKeyCharacteristics.instance(); - KMKeyCharacteristics.cast(keyCharacteristics).setStrongboxEnforced(hwParams); - KMKeyCharacteristics.cast(keyCharacteristics).setKeystoreEnforced(swParams); - KMKeyCharacteristics.cast(keyCharacteristics).setTeeEnforced(emptyParams); - return keyCharacteristics; - } - - @Override - public short makeKeyCharacteristicsForKeyblob(short swParams, short sbParams, short teeParams) { - short keyChars = KMKeyCharacteristics.instance(); - KMKeyCharacteristics.cast(keyChars).setStrongboxEnforced(sbParams); - KMKeyCharacteristics.cast(keyChars).setKeystoreEnforced(swParams); - KMKeyCharacteristics.cast(keyChars).setTeeEnforced(teeParams); - return keyChars; - } - - @Override - public boolean canCreateEarlyBootKeys() { - return false; - } - - @Override - public short getHardwareParamters(short sbParams, short teeParams) { - return sbParams; - } - - @Override - public short concatParamsForAuthData(short keyBlobPtr, short hwParams, short swParams, - short hiddenParams, short pubKey) { - short arrayLen = 3; - if (pubKey != KMType.INVALID_VALUE) { - arrayLen = 4; - } - short params = KMArray.instance((short) arrayLen); - KMArray.cast(params).add((short) 0, KMKeyParameters.cast(hwParams).getVals()); - KMArray.cast(params).add((short) 1, KMKeyParameters.cast(swParams).getVals()); - KMArray.cast(params).add((short) 2, KMKeyParameters.cast(hiddenParams).getVals()); - if (4 == arrayLen) { - KMArray.cast(params).add((short) 3, pubKey); - } - return params; - } - - @Override - public boolean isFactoryAttestationSupported() { - return true; - } - - @Override - public KMAttestationCert makeCommonCert(short swParams, short hwParams, short keyParams, - byte[] scratchPad, KMSEProvider seProvider) { - boolean rsaCert = (KMEnumTag.getValue(KMType.ALGORITHM, hwParams) == KMType.RSA); - KMAttestationCert cert = KMAttestationCertImpl.instance(rsaCert, seProvider); - // notBefore - short notBefore = - KMKeyParameters.findTag(KMType.DATE_TAG, KMType.ACTIVE_DATETIME, swParams); - if (notBefore == KMType.INVALID_VALUE) { - notBefore = - KMKeyParameters.findTag(KMType.DATE_TAG, KMType.CREATION_DATETIME, swParams); - if (notBefore == KMType.INVALID_VALUE) { - KMException.throwIt(KMError.INVALID_KEY_BLOB); - } - } - notBefore = KMIntegerTag.cast(notBefore).getValue(); - cert.notBefore(notBefore, false, scratchPad); - // notAfter - // expiry time - byte blob - boolean derEncoded = false; - short notAfter = - KMKeyParameters.findTag(KMType.DATE_TAG, KMType.USAGE_EXPIRE_DATETIME, swParams); - if (notAfter == KMType.INVALID_VALUE) { - notAfter = getProvisionedCertificateData(seProvider, KMSEProvider.CERTIFICATE_EXPIRY); - derEncoded = true; - } - cert.notAfter(notAfter, derEncoded, scratchPad); - // SubjectName - cert.subjectName(KMByteBlob.instance(X509Subject, (short) 0, (short) X509Subject.length)); - // Serial - short serialNumber = KMByteBlob.instance((short) 1); - KMByteBlob.cast(serialNumber).add((short) 0, SERIAL_NUM); - cert.serialNumber(serialNumber); - // Issuer. - cert.issuer(getProvisionedCertificateData(seProvider, KMSEProvider.CERTIFICATE_ISSUER)); - return cert; - } - - @Override - public boolean isKeyAgreementSupported() { - return false; - } - - private short getProvisionedCertificateData(KMSEProvider kmseProvider, byte dataType) { - short len = seProvider.getProvisionedDataLength(dataType); - if (len == 0) { - KMException.throwIt(KMError.INVALID_DATA); - } - short ptr = KMByteBlob.instance(len); - seProvider.readProvisionedData( - dataType, - KMByteBlob.cast(ptr).getBuffer(), - KMByteBlob.cast(ptr).getStartOff()); - return ptr; - } - - @Override - public short getConfirmationToken(short confToken, short keyParams) { - short cToken = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.CONFIRMATION_TOKEN, keyParams); - if (cToken == KMType.INVALID_VALUE) { - KMException.throwIt(KMError.NO_USER_CONFIRMATION); - } - return KMByteTag.cast(cToken).getValue(); - } - - @Override - public short getKMVerificationTokenExp() { - return KMVerificationToken.exp2(); - } - - @Override - public short getMacFromVerificationToken(short verToken) { - return KMVerificationToken.cast(verToken).getMac((short) 0x04); - } - - @Override - public short getMgf1Digest(short keyParams, short hwParams) { - return KMType.SHA1; - } - - @Override - public short generateAttestKeyExp() { - // Arguments - short keyParams = KMKeyParameters.expAny(); - short keyBlob = KMByteBlob.exp(); - short argsProto = KMArray.instance((short) 2); - KMArray.cast(argsProto).add((short) 0, keyBlob); - KMArray.cast(argsProto).add((short) 1, keyParams); - return argsProto; - } - - @Override - public void getAttestKeyInputParameters(short arrPtr, short[] data, byte keyBlobOff, - byte keyParametersOff, - byte attestKeyBlobOff, byte attestKeyParamsOff, byte attestKeyIssuerOff) { - data[keyBlobOff] = KMArray.cast(arrPtr).get((short) 0); - data[keyParametersOff] = KMArray.cast(arrPtr).get((short) 1); - data[attestKeyBlobOff] = KMType.INVALID_VALUE; - data[attestKeyParamsOff] = KMType.INVALID_VALUE; - data[attestKeyIssuerOff] = KMType.INVALID_VALUE; - } - - @Override - public short prepareBeginResp(short paramsPtr, short opHandlePtr, short bufModPtr, - short macLengthPtr) { - short resp = KMArray.instance((short) 3); - KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(resp).add((short) 1, paramsPtr); - KMArray.cast(resp).add((short) 2, opHandlePtr); - return resp; - } - - @Override - public short prepareFinishExp() { - short byteBlob = KMByteBlob.exp(); - short cmd = KMArray.instance((short) 6); - KMArray.cast(cmd).add((short) 0, KMInteger.exp());//op handle - short keyParam = KMKeyParameters.exp(); - KMArray.cast(cmd).add((short) 1, keyParam);// Key Parameters - KMArray.cast(cmd).add((short) 2, byteBlob);// input data - KMArray.cast(cmd).add((short) 3, byteBlob); // signature - short authToken = KMHardwareAuthToken.exp(); - KMArray.cast(cmd).add((short) 4, authToken); // auth token - short verToken = getKMVerificationTokenExp(); - KMArray.cast(cmd).add((short) 5, verToken); // time stamp token - return cmd; - } - - @Override - public short prepareUpdateExp() { - short cmd = KMArray.instance((short) 5); - // Arguments - short keyParams = KMKeyParameters.exp(); - KMArray.cast(cmd).add((short) 0, KMInteger.exp()); - KMArray.cast(cmd).add((short) 1, keyParams); - KMArray.cast(cmd).add((short) 2, KMByteBlob.exp()); - short authToken = KMHardwareAuthToken.exp(); - KMArray.cast(cmd).add((short) 3, authToken); - short verToken = getKMVerificationTokenExp(); - KMArray.cast(cmd).add((short) 4, verToken); - return cmd; - } - - @Override - public void getUpdateInputParameters(short arrPtr, short[] data, byte opHandleOff, - byte keyParametersOff, byte inputDataOff, byte hwTokenOff, - byte verToken) { - data[opHandleOff] = KMArray.cast(arrPtr).get((short) 0); - data[keyParametersOff] = KMArray.cast(arrPtr).get((short) 1); - data[inputDataOff] = KMArray.cast(arrPtr).get((short) 2); - data[hwTokenOff] = KMArray.cast(arrPtr).get((short) 3); - data[verToken] = KMArray.cast(arrPtr).get((short) 4); - } - - @Override - public void getFinishInputParameters(short arrPtr, short[] data, byte opHandleOff, - byte keyParametersOff, byte inputDataOff, byte signDataOff, byte hwTokenOff, byte verToken, - byte confToken) { - data[opHandleOff] = KMArray.cast(arrPtr).get((short) 0); - data[keyParametersOff] = KMArray.cast(arrPtr).get((short) 1); - data[inputDataOff] = KMArray.cast(arrPtr).get((short) 2); - data[signDataOff] = KMArray.cast(arrPtr).get((short) 3); - data[hwTokenOff] = KMArray.cast(arrPtr).get((short) 4); - data[verToken] = KMArray.cast(arrPtr).get((short) 5); - data[confToken] = KMType.INVALID_VALUE; - } - - @Override - public short prepareFinishResp(short outputPtr) { - short keyParam = KMArray.instance((short) 0); - keyParam = KMKeyParameters.instance(keyParam); - short resp = KMArray.instance((short) 3); - KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(resp).add((short) 1, keyParam); - KMArray.cast(resp).add((short) 2, outputPtr); - return resp; - } - - @Override - public short prepareUpdateResp(short outputPtr, short inputConsumedPtr) { - short resp = KMArray.instance((short) 4); - KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(resp).add((short) 1, inputConsumedPtr); - short keyParm = KMKeyParameters.instance(KMArray.instance((short) 0)); - KMArray.cast(resp).add((short) 2, keyParm); - KMArray.cast(resp).add((short) 3, outputPtr); - return resp; - } - - @Override - public short validateApduHeader(APDU apdu) { - return KMError.OK; - } - - @Override - public boolean isAssociatedDataTagSupported() { - return true; - } -} diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymintSpecification.java b/Applet/src/com/android/javacard/keymaster/KMKeymintSpecification.java deleted file mode 100644 index eef71995..00000000 --- a/Applet/src/com/android/javacard/keymaster/KMKeymintSpecification.java +++ /dev/null @@ -1,328 +0,0 @@ -package com.android.javacard.keymaster; - -import com.android.javacard.seprovider.KMAttestationCert; -import com.android.javacard.seprovider.KMException; -import com.android.javacard.seprovider.KMSEProvider; -import javacard.framework.APDU; -import javacard.framework.ISO7816; -import javacard.framework.ISOException; -import javacard.framework.Util; - -public class KMKeymintSpecification implements KMSpecification { - - public static final byte[] JAVACARD_KEYMINT_DEVICE = { - 0x4a, 0x61, 0x76, 0x61, 0x63, 0x61, 0x72, 0x64, - 0x4b, 0x65, 0x79, 0x6d, 0x69, 0x6e, 0x74, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - }; - private static final byte[] GOOGLE = {0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65}; - - private static final byte[] dec319999Ms = {(byte) 0, (byte) 0, (byte) 0xE6, (byte) 0x77, - (byte) 0xD2, (byte) 0x1F, (byte) 0xD8, (byte) 0x18}; - - private static final byte[] dec319999 = { - 0x39, 0x39, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, - 0x39, 0x35, 0x39, 0x5a, - }; - - private static final byte[] jan01970 = { - 0x37, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x5a, - }; - - @Override - public short getHardwareInfo() { - final byte version = 1; - // Make the response - short respPtr = KMArray.instance((short) 6); - KMArray resp = KMArray.cast(respPtr); - resp.add((short) 0, KMInteger.uint_16(KMError.OK)); - resp.add((short) 1, KMInteger.uint_8(version)); - resp.add((short) 2, KMEnum.instance(KMType.HARDWARE_TYPE, KMType.STRONGBOX)); - resp.add( - (short) 3, - KMByteBlob.instance( - JAVACARD_KEYMINT_DEVICE, (short) 0, (short) JAVACARD_KEYMINT_DEVICE.length)); - resp.add((short) 4, KMByteBlob.instance(GOOGLE, (short) 0, (short) GOOGLE.length)); - resp.add((short) 5, KMInteger.uint_8((byte) 1)); - return respPtr; - } - - @Override - public short makeKeyCharacteristics(short keyParams, short osVersion, short osPatch, - short vendorPatch, short bootPatch, short origin, byte[] scratchPad) { - short strongboxParams = KMKeyParameters.makeSbEnforced( - keyParams, (byte) origin, osVersion, osPatch, vendorPatch, bootPatch, scratchPad); - short teeParams = KMKeyParameters.makeTeeEnforced(keyParams, scratchPad); - short swParams = KMKeyParameters.makeKeystoreEnforced(keyParams, scratchPad); - //short emptyParam = KMArray.instance((short) 0); - short keyCharacteristics = KMKeyCharacteristics.instance(); - KMKeyCharacteristics.cast(keyCharacteristics).setStrongboxEnforced(strongboxParams); - KMKeyCharacteristics.cast(keyCharacteristics).setKeystoreEnforced(swParams); - KMKeyCharacteristics.cast(keyCharacteristics).setTeeEnforced(teeParams); - return keyCharacteristics; - } - - @Override - public short makeKeyCharacteristicsForKeyblob(short swParams, short sbParams, short teeParams) { - short keyChars = KMKeyCharacteristics.instance(); - short emptyParam = KMArray.instance((short) 0); - emptyParam = KMKeyParameters.instance(emptyParam); - KMKeyCharacteristics.cast(keyChars).setStrongboxEnforced(sbParams); - KMKeyCharacteristics.cast(keyChars).setKeystoreEnforced(emptyParam); - KMKeyCharacteristics.cast(keyChars).setTeeEnforced(teeParams); - return keyChars; - } - - @Override - public boolean canCreateEarlyBootKeys() { - return true; - } - - @Override - public short getHardwareParamters(short sbParams, short teeParams) { - return KMKeyParameters.makeHwEnforced(sbParams, teeParams); - } - - @Override - public short concatParamsForAuthData(short keyBlobPtr, short hwParams, short swParams, - short hiddenParams, short pubKey) { - short arrayLen = 2; - if (pubKey != KMType.INVALID_VALUE) { - arrayLen = 3; - } - short params = KMArray.instance((short) arrayLen); - KMArray.cast(params).add((short) 0, KMKeyParameters.cast(hwParams).getVals()); - KMArray.cast(params).add((short) 1, KMKeyParameters.cast(hiddenParams).getVals()); - if (3 == arrayLen) { - KMArray.cast(params).add((short) 2, pubKey); - } - return params; - } - - @Override - public boolean isFactoryAttestationSupported() { - return false; - } - - @Override - public KMAttestationCert makeCommonCert(short swParams, short hwParams, short keyParams, - byte[] scratchPad, KMSEProvider seProvider) { - short alg = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, keyParams); - boolean rsaCert = KMEnumTag.cast(alg).getValue() == KMType.RSA; - KMAttestationCert cert = KMAttestationCertImpl.instance(rsaCert, seProvider); - - // Validity period must be specified - short notBefore = KMKeyParameters.findTag(KMType.DATE_TAG, KMType.CERTIFICATE_NOT_BEFORE, - keyParams); - if (notBefore == KMType.INVALID_VALUE) { - KMException.throwIt(KMError.MISSING_NOT_BEFORE); - } - notBefore = KMIntegerTag.cast(notBefore).getValue(); - short notAfter = KMKeyParameters.findTag(KMType.DATE_TAG, KMType.CERTIFICATE_NOT_AFTER, - keyParams); - if (notAfter == KMType.INVALID_VALUE) { - KMException.throwIt(KMError.MISSING_NOT_AFTER); - } - notAfter = KMIntegerTag.cast(notAfter).getValue(); - // VTS sends notBefore == Epoch. - Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 8, (byte) 0); - short epoch = KMInteger.instance(scratchPad, (short) 0, (short) 8); - short end = KMInteger.instance(dec319999Ms, (short) 0, (short) dec319999Ms.length); - if (KMInteger.compare(notBefore, epoch) == 0) { - cert.notBefore(KMByteBlob.instance(jan01970, (short) 0, (short) jan01970.length), - true, scratchPad); - } else { - cert.notBefore(notBefore, false, scratchPad); - } - // VTS sends notAfter == Dec 31st 9999 - if (KMInteger.compare(notAfter, end) == 0) { - cert.notAfter(KMByteBlob.instance(dec319999, (short) 0, (short) dec319999.length), - true, scratchPad); - } else { - cert.notAfter(notAfter, false, scratchPad); - } - // Serial number - short serialNum = - KMKeyParameters.findTag(KMType.BIGNUM_TAG, KMType.CERTIFICATE_SERIAL_NUM, keyParams); - if (serialNum != KMType.INVALID_VALUE) { - serialNum = KMBignumTag.cast(serialNum).getValue(); - } else { - serialNum = KMByteBlob.instance((short) 1); - KMByteBlob.cast(serialNum).add((short) 0, (byte) 1); - } - cert.serialNumber(serialNum); - return cert; - } - - @Override - public short getMgf1Digest(short keyParams, short hwParams) { - short mgfDigest = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, - KMType.RSA_OAEP_MGF_DIGEST, keyParams); - if (mgfDigest != KMType.INVALID_VALUE) { - if (KMEnumArrayTag.cast(mgfDigest).length() != 1) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - mgfDigest = KMEnumArrayTag.cast(mgfDigest).get((short) 0); - if (mgfDigest == KMType.DIGEST_NONE) { - KMException.throwIt(KMError.UNSUPPORTED_MGF_DIGEST); - } - if (!KMEnumArrayTag - .contains(KMType.RSA_OAEP_MGF_DIGEST, mgfDigest, hwParams)) { - KMException.throwIt(KMError.INCOMPATIBLE_MGF_DIGEST); - } - if (mgfDigest != KMType.SHA1 && mgfDigest != KMType.SHA2_256) { - KMException.throwIt(KMError.UNSUPPORTED_MGF_DIGEST); - } - } - return mgfDigest; - } - - @Override - public short generateAttestKeyExp() { - short params = KMKeyParameters.expAny(); - short blob = KMByteBlob.exp(); - // Array of expected arguments - short cmd = KMArray.instance((short) 5); - KMArray.cast(cmd).add((short) 0, blob); //key blob - KMArray.cast(cmd).add((short) 1, params); //keyparamters to be attested. - KMArray.cast(cmd).add((short) 2, blob); //attest key blob - KMArray.cast(cmd).add((short) 3, params); //attest key params - KMArray.cast(cmd).add((short) 4, blob); //attest issuer - return cmd; - } - - @Override - public void getAttestKeyInputParameters(short arrPtr, short[] data, byte keyBlobOff, - byte keyParametersOff, - byte attestKeyBlobOff, byte attestKeyParamsOff, byte attestKeyIssuerOff) { - data[keyBlobOff] = KMArray.cast(arrPtr).get((short) 0); - data[keyParametersOff] = KMArray.cast(arrPtr).get((short) 1); - data[attestKeyBlobOff] = KMArray.cast(arrPtr).get((short) 2); - data[attestKeyParamsOff] = KMArray.cast(arrPtr).get((short) 3); - data[attestKeyIssuerOff] = KMArray.cast(arrPtr).get((short) 4); - } - - @Override - public short prepareBeginResp(short paramsPtr, short opHandlePtr, short bufModePtr, - short macLengthPtr) { - short resp = KMArray.instance((short) 5); - KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(resp).add((short) 1, paramsPtr); - KMArray.cast(resp).add((short) 2, opHandlePtr); - KMArray.cast(resp).add((short) 3, bufModePtr); - KMArray.cast(resp).add((short) 4, macLengthPtr); - return resp; - } - - @Override - public short prepareFinishExp() { - short byteBlob = KMByteBlob.exp(); - short cmd = KMArray.instance((short) 6); - KMArray.cast(cmd).add((short) 0, KMInteger.exp());//op handle - KMArray.cast(cmd).add((short) 1, byteBlob);// input data - KMArray.cast(cmd).add((short) 2, byteBlob); // signature - short authToken = KMHardwareAuthToken.exp(); - KMArray.cast(cmd).add((short) 3, authToken); // auth token - short verToken = getKMVerificationTokenExp(); - KMArray.cast(cmd).add((short) 4, verToken); // time stamp token - KMArray.cast(cmd).add((short) 5, byteBlob); // confirmation token - return cmd; - } - - @Override - public short prepareUpdateExp() { - short cmd = KMArray.instance((short) 4); - // Arguments - KMArray.cast(cmd).add((short) 0, KMInteger.exp()); - KMArray.cast(cmd).add((short) 1, KMByteBlob.exp()); - short authToken = KMHardwareAuthToken.exp(); - KMArray.cast(cmd).add((short) 2, authToken); - short verToken = getKMVerificationTokenExp(); - KMArray.cast(cmd).add((short) 3, verToken); - return cmd; - } - - @Override - public void getUpdateInputParameters(short arrPtr, short[] data, byte opHandleOff, - byte keyParametersOff, byte inputDataOff, byte hwTokenOff, - byte verToken) { - data[opHandleOff] = KMArray.cast(arrPtr).get((short) 0); - data[inputDataOff] = KMArray.cast(arrPtr).get((short) 1); - data[hwTokenOff] = KMArray.cast(arrPtr).get((short) 2); - data[verToken] = KMArray.cast(arrPtr).get((short) 3); - } - - @Override - public void getFinishInputParameters(short arrPtr, short[] data, byte opHandleOff, - byte keyParametersOff, byte inputDataOff, byte signDataOff, byte hwTokenOff, byte verToken, - byte confToken) { - data[opHandleOff] = KMArray.cast(arrPtr).get((short) 0); - data[inputDataOff] = KMArray.cast(arrPtr).get((short) 1); - data[signDataOff] = KMArray.cast(arrPtr).get((short) 2); - data[hwTokenOff] = KMArray.cast(arrPtr).get((short) 3); - data[verToken] = KMArray.cast(arrPtr).get((short) 4); - data[confToken] = KMArray.cast(arrPtr).get((short) 5); - } - - @Override - public short prepareFinishResp(short outputPtr) { - short resp = KMArray.instance((short) 2); - KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(resp).add((short) 1, outputPtr); - return resp; - } - - @Override - public short prepareUpdateResp(short outputPtr, short inputConsumedPtr) { - short resp = KMArray.instance((short) 2); - KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(resp).add((short) 1, outputPtr); - return resp; - } - - - @Override - public short validateApduHeader(APDU apdu) { - byte[] apduBuffer = apdu.getBuffer(); - short P1P2 = Util.getShort(apduBuffer, ISO7816.OFFSET_P1); - byte ins = apduBuffer[ISO7816.OFFSET_INS]; - switch (ins) { - case KMKeymasterApplet.INS_GET_CERT_CHAIN_CMD: - return KMError.UNSUPPORTED_INSTRUCTION; - } - if (P1P2 != KMKeymasterApplet.KM_HAL_VERSION) { - return KMError.INVALID_P1P2; - } - return KMError.OK; - } - - @Override - public boolean isAssociatedDataTagSupported() { - return false; - } - - @Override - public boolean isKeyAgreementSupported() { - return true; - } - - @Override - public short getConfirmationToken(short confToken, short keyParams) { - if (0 == KMByteBlob.cast(confToken).length()) { - KMException.throwIt(KMError.NO_USER_CONFIRMATION); - } - return confToken; - } - - @Override - public short getKMVerificationTokenExp() { - return KMVerificationToken.exp1(); - } - - @Override - public short getMacFromVerificationToken(short verToken) { - return KMVerificationToken.cast(verToken).getMac((short) 0x02); - } - -} diff --git a/Applet/src/com/android/javacard/keymaster/KMSpecification.java b/Applet/src/com/android/javacard/keymaster/KMSpecification.java deleted file mode 100644 index 2300331c..00000000 --- a/Applet/src/com/android/javacard/keymaster/KMSpecification.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.android.javacard.keymaster; - -import com.android.javacard.seprovider.KMAttestationCert; -import com.android.javacard.seprovider.KMSEProvider; -import javacard.framework.APDU; - -public interface KMSpecification { - - short getHardwareInfo(); - - short makeKeyCharacteristics(short keyParams, short osVersion, short osPatch, short vendorPatch, - short bootPatch, short origin, byte[] scratchPad); - - short makeKeyCharacteristicsForKeyblob(short swParams, short sbParams, short teeParams); - - boolean canCreateEarlyBootKeys(); - - short getHardwareParamters(short sbParams, short teeParams); - - short concatParamsForAuthData(short arrPtr, short hwParams, short swParams, short hiddenParams, - short pubKey); - - boolean isFactoryAttestationSupported(); - - KMAttestationCert makeCommonCert(short swParams, short hwParams, short keyParams, - byte[] scratchPad, KMSEProvider seProvider); - - boolean isKeyAgreementSupported(); - - short getConfirmationToken(short confToken, short keyParams); - - short getKMVerificationTokenExp(); - - short getMacFromVerificationToken(short verToken); - - short getMgf1Digest(short keyParams, short hwParams); - - short generateAttestKeyExp(); - - void getAttestKeyInputParameters(short arrPtr, short[] data, byte keyBlobOff, - byte keyParametersOff, - byte attestKeyBlobOff, byte attestKeyParamsOff, byte attestKeyIssuerOff); - - short prepareBeginResp(short paramsPtr, short opHandlePtr, short bufModePtr, short macLengthPtr); - - short prepareFinishExp(); - - short prepareUpdateExp(); - - void getUpdateInputParameters(short arrPtr, short[] data, byte opHandleOff, - byte keyParametersOff, byte inputDataOff, byte hwTokenOff, - byte verToken); - - void getFinishInputParameters(short arrPtr, short[] data, byte opHandleOff, - byte keyParametersOff, byte inputDataOff, byte signDataOff, byte hwTokenOff, - byte verToken, byte confToken); - - short prepareFinishResp(short outputPtr); - - short prepareUpdateResp(short outputPtr, short inputConsumedPtr); - - short validateApduHeader(APDU apdu); - - boolean isAssociatedDataTagSupported(); -} diff --git a/Applet/src/com/android/javacard/keymaster/KMArray.java b/Applet/src/com/android/javacard/kmdevice/KMArray.java similarity index 80% rename from Applet/src/com/android/javacard/keymaster/KMArray.java rename to Applet/src/com/android/javacard/kmdevice/KMArray.java index a468e924..4c6b0c98 100644 --- a/Applet/src/com/android/javacard/keymaster/KMArray.java +++ b/Applet/src/com/android/javacard/kmdevice/KMArray.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -75,14 +75,14 @@ public static short instance(short length, byte type) { return ptr; } - public static KMArray cast(short ptr) { + private static KMArray cast(short ptr) { if (heap[ptr] != ARRAY_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } return proto(ptr); } - public void add(short index, short objPtr) { + private void add(short index, short objPtr) { short len = length(); if (index >= len) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); @@ -93,7 +93,7 @@ public void add(short index, short objPtr) { objPtr); } - public short get(short index) { + private short get(short index) { short len = length(); if (index >= len) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); @@ -102,7 +102,7 @@ public short get(short index) { heap, (short) (getStartOff() + (short) (index * 2))); } - public void swap(short index1, short index2) { + private void swap(short index1, short index2) { short len = length(); if (index1 >= len || index2 >= len) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); @@ -125,25 +125,58 @@ public void swap(short index1, short index2) { indexPtr1); } - public short containedType() { + private short containedType() { return Util.getShort(heap, (short) (KMType.instanceTable[KM_ARRAY_OFFSET] + TLV_HEADER_SIZE)); } - public short getStartOff() { + private short getStartOff() { return (short) (KMType.instanceTable[KM_ARRAY_OFFSET] + TLV_HEADER_SIZE + ARRAY_HEADER_SIZE); } - public short length() { + private short length() { return Util.getShort(heap, (short) (KMType.instanceTable[KM_ARRAY_OFFSET] + TLV_HEADER_SIZE + 2)); } - public byte[] getBuffer() { + private byte[] getBuffer() { return heap; } - public void deleteLastEntry() { + private void deleteLastEntry() { short len = length(); Util.setShort(heap, (short) (instanceTable[KM_ARRAY_OFFSET] + TLV_HEADER_SIZE + 2), (short) (len - 1)); } + + public static void add(short bPtr, short index, short objPtr) { + KMArray.cast(bPtr).add(index, objPtr); + } + + public static short get(short bPtr, short index) { + return KMArray.cast(bPtr).get(index); + } + + public static void swap(short bPtr, short index1, short index2) { + KMArray.cast(bPtr).swap(index1, index2); + } + + public static short containedType(short bPtr) { + return KMArray.cast(bPtr).containedType(); + } + + public static short getStartOff(short bPtr) { + return KMArray.cast(bPtr).getStartOff(); + } + + public static short length(short bPtr) { + return KMArray.cast(bPtr).length(); + } + + public static byte[] getBuffer(short bPtr) { + return KMArray.cast(bPtr).getBuffer(); + } + + public static void deleteLastEntry(short bPtr) { + KMArray.cast(bPtr).deleteLastEntry(); + } + } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAttestationCert.java b/Applet/src/com/android/javacard/kmdevice/KMAttestationCert.java similarity index 99% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAttestationCert.java rename to Applet/src/com/android/javacard/kmdevice/KMAttestationCert.java index 78ac7123..029191ee 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAttestationCert.java +++ b/Applet/src/com/android/javacard/kmdevice/KMAttestationCert.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.javacard.seprovider; +package com.android.javacard.kmdevice; /** * The KMAttestationCert interface represents a X509 compliant attestation certificate required to diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/src/com/android/javacard/kmdevice/KMAttestationCertImpl.java similarity index 75% rename from Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java rename to Applet/src/com/android/javacard/kmdevice/KMAttestationCertImpl.java index 961dc1d7..ae478e16 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/src/com/android/javacard/kmdevice/KMAttestationCertImpl.java @@ -13,14 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.javacard.keymaster; - -import com.android.javacard.seprovider.KMAESKey; -import com.android.javacard.seprovider.KMAttestationCert; -import com.android.javacard.seprovider.KMAttestationKey; -import com.android.javacard.seprovider.KMException; -import com.android.javacard.seprovider.KMMasterKey; -import com.android.javacard.seprovider.KMSEProvider; +package com.android.javacard.kmdevice; import javacard.framework.JCSystem; import javacard.framework.Util; @@ -36,95 +29,33 @@ public class KMAttestationCertImpl implements KMAttestationCert { private static final byte MAX_PARAMS = 30; // DER encoded object identifiers required by the cert. // rsaEncryption - 1.2.840.113549.1.1.1 - private static final byte[] rsaEncryption = { - 0x06, 0x09, 0x2A, (byte) 0x86, 0x48, (byte) 0x86, (byte) 0xF7, 0x0D, 0x01, 0x01, 0x01 - }; + private static byte[] rsaEncryption; // ecPublicKey - 1.2.840.10045.2.1 - private static final byte[] eccPubKey = { - 0x06, 0x07, 0x2A, (byte) 0x86, 0x48, (byte) 0xCE, 0x3D, 0x02, 0x01 - }; + private static byte[] eccPubKey; // prime256v1 curve - 1.2.840.10045.3.1.7 - private static final byte[] prime256v1 = { - 0x06, 0x08, 0x2A, (byte) 0x86, 0x48, (byte) 0xCE, 0x3D, 0x03, 0x01, 0x07 - }; + private static byte[] prime256v1; // Key Usage Extn - 2.5.29.15 - private static final byte[] keyUsageExtn = {0x06, 0x03, 0x55, 0x1D, 0x0F}; + private static byte[] keyUsageExtn; // Android Extn - 1.3.6.1.4.1.11129.2.1.17 - private static final byte[] androidExtn = { - 0x06, 0x0A, 0X2B, 0X06, 0X01, 0X04, 0X01, (byte) 0XD6, 0X79, 0X02, 0X01, 0X11 - }; + private static byte[] androidExtn; private static final short RSA_SIG_LEN = 256; private static final short ECDSA_MAX_SIG_LEN = 72; //Signature algorithm identifier - ecdsaWithSha256 - 1.2.840.10045.4.3.2 //SEQUENCE of alg OBJ ID and parameters = NULL. - private static final byte[] X509EcdsaSignAlgIdentifier = { - 0x30, - 0x0A, - 0x06, - 0x08, - 0x2A, - (byte) 0x86, - 0x48, - (byte) 0xCE, - (byte) 0x3D, - 0x04, - 0x03, - 0x02 - }; + private static byte[] X509EcdsaSignAlgIdentifier; // Signature algorithm identifier - sha256WithRSAEncryption - 1.2.840.113549.1.1.11 // SEQUENCE of alg OBJ ID and parameters = NULL. - private static final byte[] X509RsaSignAlgIdentifier = { - 0x30, - 0x0D, - 0x06, - 0x09, - 0x2A, - (byte) 0x86, - 0x48, - (byte) 0x86, - (byte) 0xF7, - 0x0D, - 0x01, - 0x01, - 0x0B, - 0x05, - 0x00 - }; - + private static byte[] X509RsaSignAlgIdentifier; // Below are the allowed softwareEnforced Authorization tags inside the attestation certificate's extension. - private static final short[] swTagIds = { - KMType.ATTESTATION_APPLICATION_ID, - KMType.CREATION_DATETIME, - KMType.USAGE_EXPIRE_DATETIME, - KMType.ORIGINATION_EXPIRE_DATETIME, - KMType.ACTIVE_DATETIME, - KMType.UNLOCKED_DEVICE_REQUIRED - }; + private static short[] swTagIds; // Below are the allowed hardwareEnforced Authorization tags inside the attestation certificate's extension. - private static final short[] hwTagIds = { - KMType.BOOT_PATCH_LEVEL, KMType.VENDOR_PATCH_LEVEL, - KMType.ATTESTATION_ID_MODEL, KMType.ATTESTATION_ID_MANUFACTURER, - KMType.ATTESTATION_ID_MEID, KMType.ATTESTATION_ID_IMEI, - KMType.ATTESTATION_ID_SERIAL, KMType.ATTESTATION_ID_PRODUCT, - KMType.ATTESTATION_ID_DEVICE, KMType.ATTESTATION_ID_BRAND, - KMType.OS_PATCH_LEVEL, KMType.OS_VERSION, KMType.ROOT_OF_TRUST, - KMType.ORIGIN, KMType.AUTH_TIMEOUT, KMType.USER_AUTH_TYPE, - KMType.NO_AUTH_REQUIRED, KMType.USER_SECURE_ID, - KMType.RSA_PUBLIC_EXPONENT, KMType.ECCURVE, KMType.MIN_MAC_LENGTH, - KMType.CALLER_NONCE, KMType.PADDING, KMType.DIGEST, KMType.BLOCK_MODE, - KMType.KEYSIZE, KMType.ALGORITHM, KMType.PURPOSE}; + private static short[] hwTagIds; // Validity is not fixed field // Subject is a fixed field with only CN= Android Keystore Key - same for all the keys - private static final byte[] X509Subject = { - 0x30, 0x1F, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x14, 0x41, 0x6e, - 0x64, - 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4B, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x4B, - 0x65, - 0x79 - }; + private static byte[] X509Subject; private static final byte keyUsageSign = (byte) 0x80; // 0 bit private static final byte keyUsageKeyEncipher = (byte) 0x20; // 2nd- bit @@ -134,7 +65,7 @@ public class KMAttestationCertImpl implements KMAttestationCert { private static final byte KEYMASTER_VERSION = 100; private static final byte ATTESTATION_VERSION = 100; - private static final byte[] pubExponent = {0x01, 0x00, 0x01}; + private static byte[] pubExponent; private static final byte SERIAL_NUM = (byte) 0x01; private static final byte X509_VERSION = (byte) 0x02; @@ -179,6 +110,81 @@ public class KMAttestationCertImpl implements KMAttestationCert { private static final byte SERIAL_NUM_MAX_LEN = 20; private static final byte SUBJECT_NAME_MAX_LEN = 32; + public static void initStatics() { + rsaEncryption = new byte[]{ + 0x06, 0x09, 0x2A, (byte) 0x86, 0x48, (byte) 0x86, (byte) 0xF7, 0x0D, 0x01, 0x01, 0x01 + }; + eccPubKey = new byte[] { + 0x06, 0x07, 0x2A, (byte) 0x86, 0x48, (byte) 0xCE, 0x3D, 0x02, 0x01 + }; + prime256v1 = new byte[] { + 0x06, 0x08, 0x2A, (byte) 0x86, 0x48, (byte) 0xCE, 0x3D, 0x03, 0x01, 0x07 + }; + keyUsageExtn = new byte[]{0x06, 0x03, 0x55, 0x1D, 0x0F}; + androidExtn = new byte[]{ + 0x06, 0x0A, 0X2B, 0X06, 0X01, 0X04, 0X01, (byte) 0XD6, 0X79, 0X02, 0X01, 0X11 + }; + X509EcdsaSignAlgIdentifier = new byte[] { + 0x30, + 0x0A, + 0x06, + 0x08, + 0x2A, + (byte) 0x86, + 0x48, + (byte) 0xCE, + (byte) 0x3D, + 0x04, + 0x03, + 0x02 + }; + X509RsaSignAlgIdentifier = new byte[]{ + 0x30, + 0x0D, + 0x06, + 0x09, + 0x2A, + (byte) 0x86, + 0x48, + (byte) 0x86, + (byte) 0xF7, + 0x0D, + 0x01, + 0x01, + 0x0B, + 0x05, + 0x00 + }; + swTagIds = new short[]{ + KMType.ATTESTATION_APPLICATION_ID, + KMType.CREATION_DATETIME, + KMType.USAGE_EXPIRE_DATETIME, + KMType.ORIGINATION_EXPIRE_DATETIME, + KMType.ACTIVE_DATETIME, + KMType.UNLOCKED_DEVICE_REQUIRED + }; + hwTagIds = new short[]{ + KMType.BOOT_PATCH_LEVEL, KMType.VENDOR_PATCH_LEVEL, + KMType.ATTESTATION_ID_MODEL, KMType.ATTESTATION_ID_MANUFACTURER, + KMType.ATTESTATION_ID_MEID, KMType.ATTESTATION_ID_IMEI, + KMType.ATTESTATION_ID_SERIAL, KMType.ATTESTATION_ID_PRODUCT, + KMType.ATTESTATION_ID_DEVICE, KMType.ATTESTATION_ID_BRAND, + KMType.OS_PATCH_LEVEL, KMType.OS_VERSION, KMType.ROOT_OF_TRUST, + KMType.ORIGIN, KMType.AUTH_TIMEOUT, KMType.USER_AUTH_TYPE, + KMType.NO_AUTH_REQUIRED, KMType.USER_SECURE_ID, + KMType.RSA_PUBLIC_EXPONENT, KMType.ECCURVE, KMType.MIN_MAC_LENGTH, + KMType.CALLER_NONCE, KMType.PADDING, KMType.DIGEST, KMType.BLOCK_MODE, + KMType.KEYSIZE, KMType.ALGORITHM, KMType.PURPOSE}; + X509Subject = new byte[]{ + 0x30, 0x1F, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x14, 0x41, 0x6e, + 0x64, + 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4B, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x4B, + 0x65, + 0x79 + }; + pubExponent = new byte[]{0x01, 0x00, 0x01}; + } + private KMAttestationCertImpl() { } @@ -260,8 +266,8 @@ public KMAttestationCert notBefore(short obj, boolean derEncoded, byte[] scratch // convert milliseconds to UTC date notBefore = KMUtils.convertToDate(obj, scratchpad, true); }else{ - notBefore = KMByteBlob.instance(KMByteBlob.cast(obj).getBuffer(), - KMByteBlob.cast(obj).getStartOff(), KMByteBlob.cast(obj).length()); + notBefore = KMByteBlob.instance(KMByteBlob.getBuffer(obj), + KMByteBlob.getStartOff(obj), KMByteBlob.length(obj)); } return this; } @@ -285,9 +291,9 @@ public KMAttestationCert notAfter(short usageExpiryTimeObj, boolean derEncoded, //notAfter = certExpirtyTimeObj; } } else { - // notAfter = KMByteBlob.instance(KMByteBlob.cast(usageExpiryTimeObj).getBuffer(), - // KMByteBlob.cast(usageExpiryTimeObj).getStartOff(), - // KMByteBlob.cast(usageExpiryTimeObj).length()); + // notAfter = KMKeymasterApplet.instance(KMKeymasterApplet.cast(usageExpiryTimeObj).getBuffer(), + // KMKeymasterApplet.cast(usageExpiryTimeObj).getStartOff(), + // KMKeymasterApplet.cast(usageExpiryTimeObj).length()); notAfter = usageExpiryTimeObj; } return this; @@ -324,7 +330,7 @@ public KMAttestationCert extensionTag(short tag, boolean hwEnforced) { swParams[swParamsIndex] = tag; swParamsIndex++; } - if (KMTag.getKey(tag) == KMType.PURPOSE) { + if (KMTag.getKMTagKey(tag) == KMType.PURPOSE) { createKeyUsage(tag); } return this; @@ -337,18 +343,18 @@ public KMAttestationCert issuer(short obj) { } private void createKeyUsage(short tag) { - short len = KMEnumArrayTag.cast(tag).length(); + short len = KMEnumArrayTag.length(tag); byte index = 0; while (index < len) { - if (KMEnumArrayTag.cast(tag).get(index) == KMType.SIGN) { + if (KMEnumArrayTag.get(tag, index) == KMType.SIGN) { keyUsage = (byte) (keyUsage | keyUsageSign); - } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.WRAP_KEY) { + } else if (KMEnumArrayTag.get(tag, index) == KMType.WRAP_KEY) { keyUsage = (byte) (keyUsage | keyUsageKeyEncipher); - } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.DECRYPT) { + } else if (KMEnumArrayTag.get(tag, index) == KMType.DECRYPT) { keyUsage = (byte) (keyUsage | keyUsageDataEncipher); - } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.AGREE_KEY){ + } else if (KMEnumArrayTag.get(tag, index)== KMType.AGREE_KEY){ keyUsage = (byte) (keyUsage | keyUsageKeyAgreement); - }else if (KMEnumArrayTag.cast(tag).get(index) == KMType.ATTEST_KEY){ + }else if (KMEnumArrayTag.get(tag, index)== KMType.ATTEST_KEY){ keyUsage = (byte) (keyUsage | keyUsageCertSign); } index++; @@ -361,7 +367,7 @@ private void createKeyUsage(short tag) { } //TODO Serial number, X509Version needa to be passed as parameter - private static void pushTbsCert(boolean rsaCert, boolean rsa) { + private void pushTbsCert(boolean rsaCert, boolean rsa) { short last = stackPtr; if(certMode == KMType.ATTESTATION_CERT || certMode == KMType.FACTORY_PROVISIONED_ATTEST_CERT) { pushExtensions(); @@ -373,14 +379,14 @@ private static void pushTbsCert(boolean rsaCert, boolean rsa) { pushEccSubjectKeyInfo(); } // subject - pushBytes(KMByteBlob.cast(subjectName).getBuffer(), KMByteBlob.cast(subjectName).getStartOff(), - KMByteBlob.cast(subjectName).length()); + pushBytes(KMByteBlob.getBuffer(subjectName), KMByteBlob.getStartOff(subjectName), + KMByteBlob.length(subjectName)); pushValidity(); // issuer - der encoded pushBytes( - KMByteBlob.cast(issuer).getBuffer(), - KMByteBlob.cast(issuer).getStartOff(), - KMByteBlob.cast(issuer).length()); + KMByteBlob.getBuffer(issuer), + KMByteBlob.getStartOff(issuer), + KMByteBlob.length(issuer)); // Algorithm Id if(rsa) { pushAlgorithmId(X509RsaSignAlgIdentifier); @@ -388,9 +394,9 @@ private static void pushTbsCert(boolean rsaCert, boolean rsa) { pushAlgorithmId(X509EcdsaSignAlgIdentifier); } // Serial Number - pushBytes(KMByteBlob.cast(serialNum).getBuffer(), KMByteBlob.cast(serialNum).getStartOff(), - KMByteBlob.cast(serialNum).length()); - pushIntegerHeader(KMByteBlob.cast(serialNum).length()); + pushBytes(KMByteBlob.getBuffer(serialNum), KMByteBlob.getStartOff(serialNum), + KMByteBlob.length(serialNum)); + pushIntegerHeader(KMByteBlob.length(serialNum)); // Version pushByte(X509_VERSION); pushIntegerHeader((short) 1); @@ -400,7 +406,7 @@ private static void pushTbsCert(boolean rsaCert, boolean rsa) { pushSequenceHeader((short) (last - stackPtr)); } - private static void pushExtensions() { + private void pushExtensions() { short last = stackPtr; if (keyUsage != 0) { pushKeyUsage(keyUsage, unusedBits); @@ -413,22 +419,22 @@ private static void pushExtensions() { } // Time SEQUENCE{UTCTime, UTC or Generalized Time) - private static void pushValidity() { + private void pushValidity() { short last = stackPtr; if (notAfter != 0) { pushBytes( - KMByteBlob.cast(notAfter).getBuffer(), - KMByteBlob.cast(notAfter).getStartOff(), - KMByteBlob.cast(notAfter).length()); + KMByteBlob.getBuffer(notAfter), + KMByteBlob.getStartOff(notAfter), + KMByteBlob.length(notAfter)); } else { KMException.throwIt(KMError.INVALID_DATA); } - pushTimeHeader(KMByteBlob.cast(notAfter).length()); + pushTimeHeader(KMByteBlob.length(notAfter)); pushBytes( - KMByteBlob.cast(notBefore).getBuffer(), - KMByteBlob.cast(notBefore).getStartOff(), - KMByteBlob.cast(notBefore).length()); - pushTimeHeader(KMByteBlob.cast(notBefore).length()); + KMByteBlob.getBuffer(notBefore), + KMByteBlob.getStartOff(notBefore), + KMByteBlob.length(notBefore)); + pushTimeHeader(KMByteBlob.length(notBefore)); pushSequenceHeader((short) (last - stackPtr)); } @@ -447,21 +453,21 @@ private static void pushTimeHeader(short len) { // SEQUENCE{SEQUENCE{algId, NULL}, bitString{SEQUENCE{ modulus as positive integer, public // exponent // as positive integer} - private static void pushRsaSubjectKeyInfo() { + private void pushRsaSubjectKeyInfo() { short last = stackPtr; pushBytes(pubExponent, (short) 0, (short) pubExponent.length); pushIntegerHeader((short) pubExponent.length); pushBytes( - KMByteBlob.cast(pubKey).getBuffer(), - KMByteBlob.cast(pubKey).getStartOff(), - KMByteBlob.cast(pubKey).length()); + KMByteBlob.getBuffer(pubKey), + KMByteBlob.getStartOff(pubKey), + KMByteBlob.length(pubKey)); // encode modulus as positive if the MSB is 1. - if (KMByteBlob.cast(pubKey).get((short) 0) < 0) { + if (KMByteBlob.get(pubKey, (short) 0) < 0) { pushByte((byte) 0x00); - pushIntegerHeader((short) (KMByteBlob.cast(pubKey).length() + 1)); + pushIntegerHeader((short) (KMByteBlob.length(pubKey) + 1)); } else { - pushIntegerHeader(KMByteBlob.cast(pubKey).length()); + pushIntegerHeader(KMByteBlob.length(pubKey)); } pushSequenceHeader((short) (last - stackPtr)); pushBitStringHeader((byte) 0x00, (short) (last - stackPtr)); @@ -470,13 +476,13 @@ private static void pushRsaSubjectKeyInfo() { } // SEQUENCE{SEQUENCE{ecPubKey, prime256v1}, bitString{pubKey}} - private static void pushEccSubjectKeyInfo() { + private void pushEccSubjectKeyInfo() { short last = stackPtr; pushBytes( - KMByteBlob.cast(pubKey).getBuffer(), - KMByteBlob.cast(pubKey).getStartOff(), - KMByteBlob.cast(pubKey).length()); - pushBitStringHeader((byte) 0x00, KMByteBlob.cast(pubKey).length()); + KMByteBlob.getBuffer(pubKey), + KMByteBlob.getStartOff(pubKey), + KMByteBlob.length(pubKey)); + pushBitStringHeader((byte) 0x00, KMByteBlob.length(pubKey)); pushEcDsa(); pushSequenceHeader((short) (last - stackPtr)); } @@ -505,22 +511,22 @@ private static void pushRsaEncryption() { // softwareEnforced AuthorizationList, # See below // hardwareEnforced AuthorizationList, # See below // } - private static void pushKeyDescription() { + private void pushKeyDescription() { short last = stackPtr; pushHWParams(); pushSWParams(); if (uniqueId != 0) { pushOctetString( - KMByteBlob.cast(uniqueId).getBuffer(), - KMByteBlob.cast(uniqueId).getStartOff(), - KMByteBlob.cast(uniqueId).length()); + KMByteBlob.getBuffer(uniqueId), + KMByteBlob.getStartOff(uniqueId), + KMByteBlob.length(uniqueId)); } else { pushOctetStringHeader((short) 0); } pushOctetString( - KMByteBlob.cast(attChallenge).getBuffer(), - KMByteBlob.cast(attChallenge).getStartOff(), - KMByteBlob.cast(attChallenge).length()); + KMByteBlob.getBuffer(attChallenge), + KMByteBlob.getStartOff(attChallenge), + KMByteBlob.length(attChallenge)); pushEnumerated(KMType.STRONGBOX); pushByte(KEYMASTER_VERSION); pushIntegerHeader((short) 1); @@ -533,7 +539,7 @@ private static void pushKeyDescription() { pushSequenceHeader((short) (last - stackPtr)); } - private static void pushSWParams() { + private void pushSWParams() { short last = stackPtr; byte index = 0; short length = (short) swTagIds.length; @@ -543,7 +549,7 @@ private static void pushSWParams() { pushSequenceHeader((short) (last - stackPtr)); } - private static void pushHWParams() { + private void pushHWParams() { short last = stackPtr; byte index = 0; short length = (short) hwTagIds.length; @@ -559,10 +565,10 @@ private static void pushHWParams() { pushSequenceHeader((short) (last - stackPtr)); } - private static boolean pushParams(short[] params, short len, short tagId) { + private boolean pushParams(short[] params, short len, short tagId) { short index = 0; while (index < len) { - if (tagId == KMTag.getKey(params[index])) { + if (tagId == KMTag.getKMTagKey(params[index])) { pushTag(params[index]); return true; } @@ -571,50 +577,50 @@ private static boolean pushParams(short[] params, short len, short tagId) { return false; } - private static void pushTag(short tag) { - short type = KMTag.getTagType(tag); - short tagId = KMTag.getKey(tag); + private void pushTag(short tag) { + short type = KMTag.getKMTagType(tag); + short tagId = KMTag.getKMTagKey(tag); short val; switch (type) { case KMType.BYTES_TAG: - val = KMByteTag.cast(tag).getValue(); + val = KMByteTag.getValue(tag); pushBytesTag( tagId, - KMByteBlob.cast(val).getBuffer(), - KMByteBlob.cast(val).getStartOff(), - KMByteBlob.cast(val).length()); + KMByteBlob.getBuffer(val), + KMByteBlob.getStartOff(val), + KMByteBlob.length(val)); break; case KMType.ENUM_TAG: - val = KMEnumTag.cast(tag).getValue(); + val = KMEnumTag.getValue(tag); pushEnumTag(tagId, (byte) val); break; case KMType.ENUM_ARRAY_TAG: - val = KMEnumArrayTag.cast(tag).getValues(); + val = KMEnumArrayTag.getValues(tag); pushEnumArrayTag( tagId, - KMByteBlob.cast(val).getBuffer(), - KMByteBlob.cast(val).getStartOff(), - KMByteBlob.cast(val).length()); + KMByteBlob.getBuffer(val), + KMByteBlob.getStartOff(val), + KMByteBlob.length(val)); break; case KMType.UINT_TAG: case KMType.ULONG_TAG: case KMType.DATE_TAG: - val = KMIntegerTag.cast(tag).getValue(); + val = KMIntegerTag.getValue(tag); pushIntegerTag( tagId, - KMInteger.cast(val).getBuffer(), - KMInteger.cast(val).getStartOff(), - KMInteger.cast(val).length()); + KMInteger.getBuffer(val), + KMInteger.getStartOff(val), + KMInteger.length(val)); break; case KMType.UINT_ARRAY_TAG: case KMType.ULONG_ARRAY_TAG: // According to keymaster hal only one user secure id is used but this conflicts with // tag type which is ULONG-REP. Currently this is encoded as SET OF INTEGERS - val = KMIntegerArrayTag.cast(tag).getValues(); + val = KMIntegerArrayTag.getValues(tag); pushIntegerArrayTag(tagId, val); break; case KMType.BOOL_TAG: - val = KMBoolTag.cast(tag).getVal(); + KMBoolTag.validate(tag); pushBoolTag(tagId); break; default: @@ -635,22 +641,22 @@ private static void pushTag(short tag) { // Unverified (2), // Failed (3), // } - private static void pushRoT() { + private void pushRoT() { short last = stackPtr; // verified boot hash pushOctetString( - KMByteBlob.cast(verifiedHash).getBuffer(), - KMByteBlob.cast(verifiedHash).getStartOff(), - KMByteBlob.cast(verifiedHash).length()); + KMByteBlob.getBuffer(verifiedHash), + KMByteBlob.getStartOff(verifiedHash), + KMByteBlob.length(verifiedHash)); pushEnumerated(verifiedState); pushBoolean(deviceLocked); // verified boot Key pushOctetString( - KMByteBlob.cast(verifiedBootKey).getBuffer(), - KMByteBlob.cast(verifiedBootKey).getStartOff(), - KMByteBlob.cast(verifiedBootKey).length()); + KMByteBlob.getBuffer(verifiedBootKey), + KMByteBlob.getStartOff(verifiedBootKey), + KMByteBlob.length(verifiedBootKey)); // Finally sequence header pushSequenceHeader((short) (last - stackPtr)); @@ -689,17 +695,17 @@ private static void pushEnumArrayTag(short tagId, byte[] buf, short start, short // Only SET of INTEGERS supported are padding, digest, purpose and blockmode // All of these are enum array tags i.e. byte long values - private static void pushIntegerArrayTag(short tagId, short arr) { + private void pushIntegerArrayTag(short tagId, short arr) { short last = stackPtr; short index = 0; - short len = KMArray.cast(arr).length(); + short len = KMArray.length(arr); short ptr; while (index < len) { - ptr = KMArray.cast(arr).get(index); + ptr = KMArray.get(arr, index); pushInteger( - KMInteger.cast(ptr).getBuffer(), - KMInteger.cast(ptr).getStartOff(), - KMInteger.cast(ptr).length()); + KMInteger.getBuffer(ptr), + KMInteger.getStartOff(ptr), + KMInteger.length(ptr)); index++; } pushSetHeader((short) (last - stackPtr)); @@ -920,12 +926,12 @@ else if (rsaSign) { if (rsaSign) { sigLen = seProvider .rsaSign256Pkcs1( - KMByteBlob.cast(attSecret).getBuffer(), - KMByteBlob.cast(attSecret).getStartOff(), - KMByteBlob.cast(attSecret).length(), - KMByteBlob.cast(attMod).getBuffer(), - KMByteBlob.cast(attMod).getStartOff(), - KMByteBlob.cast(attMod).length(), + KMByteBlob.getBuffer(attSecret), + KMByteBlob.getStartOff(attSecret), + KMByteBlob.length(attSecret), + KMByteBlob.getBuffer(attMod), + KMByteBlob.getStartOff(attMod), + KMByteBlob.length(attMod), stack, tbsStart, tbsLength, @@ -945,9 +951,9 @@ else if (rsaSign) { } else { sigLen = seProvider .ecSign256( - KMByteBlob.cast(attSecret).getBuffer(), - KMByteBlob.cast(attSecret).getStartOff(), - KMByteBlob.cast(attSecret).length(), + KMByteBlob.getBuffer(attSecret), + KMByteBlob.getStartOff(attSecret), + KMByteBlob.length(attSecret), stack, tbsStart, tbsLength, @@ -1004,21 +1010,21 @@ public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, scratchPadOff++; //Get the key data from the master key - KMAESKey aesKey = (KMAESKey) masterKey; + KMMasterKey aesKey = masterKey; short mKeyData = KMByteBlob.instance((short) (aesKey.getKeySizeBits() / 8)); aesKey.getKey( - KMByteBlob.cast(mKeyData).getBuffer(), /* Key */ - KMByteBlob.cast(mKeyData).getStartOff()); /* Key start*/ + KMByteBlob.getBuffer(mKeyData), /* Key */ + KMByteBlob.getStartOff(mKeyData)); /* Key start*/ timeOffset = KMByteBlob.instance((short) 32); appIdOff = seProvider.hmacSign( - KMByteBlob.cast(mKeyData).getBuffer(), /* Key */ - KMByteBlob.cast(mKeyData).getStartOff(), /* Key start*/ - KMByteBlob.cast(mKeyData).length(), /* Key length*/ + KMByteBlob.getBuffer(mKeyData), /* Key */ + KMByteBlob.getStartOff(mKeyData), /* Key start*/ + KMByteBlob.length(mKeyData), /* Key length*/ scratchPad, /* data */ temp, /* data start */ scratchPadOff, /* data length */ - KMByteBlob.cast(timeOffset).getBuffer(), /* signature buffer */ - KMByteBlob.cast(timeOffset).getStartOff()); /* signature start */ + KMByteBlob.getBuffer(timeOffset), /* signature buffer */ + KMByteBlob.getStartOff(timeOffset)); /* signature start */ if (appIdOff != 32) { KMException.throwIt(KMError.UNKNOWN_ERROR); } @@ -1027,11 +1033,11 @@ public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, @Override public boolean serialNumber(short number){ - short length = KMByteBlob.cast(number).length(); + short length = KMByteBlob.length(number); if(length > SERIAL_NUM_MAX_LEN){ return false; } - byte msb = KMByteBlob.cast(number).get((short)0); + byte msb = KMByteBlob.get(number, (short)0); if(msb < 0 && length > (SERIAL_NUM_MAX_LEN -1)){ return false; } @@ -1042,15 +1048,15 @@ public boolean serialNumber(short number){ @Override public boolean subjectName(short sub){ /* - short length = KMByteBlob.cast(sub).length(); + short length = KMKeymasterApplet.cast(sub).length(); if(length > SUBJECT_NAME_MAX_LEN){ return false; } - Util.arrayCopyNonAtomic(KMByteBlob.cast(sub).getBuffer(), KMByteBlob.cast(sub).getStartOff(), + Util.arrayCopyNonAtomic(KMKeymasterApplet.cast(sub).getBuffer(), KMKeymasterApplet.cast(sub).getStartOff(), subjectName,(short)0,length); subjectLen = length; */ - if(sub == KMType.INVALID_VALUE || KMByteBlob.cast(sub).length() == 0) return false; + if(sub == KMType.INVALID_VALUE || KMByteBlob.length(sub) == 0) return false; subjectName = sub; return true; } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAttestationKey.java b/Applet/src/com/android/javacard/kmdevice/KMAttestationKey.java similarity index 95% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAttestationKey.java rename to Applet/src/com/android/javacard/kmdevice/KMAttestationKey.java index 1b8e334e..76054a7b 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAttestationKey.java +++ b/Applet/src/com/android/javacard/kmdevice/KMAttestationKey.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.javacard.seprovider; +package com.android.javacard.kmdevice; /** * KMAttestationKey is a marker interface and the SE Provider has to implement this interface. diff --git a/Applet/src/com/android/javacard/keymaster/KMBignumTag.java b/Applet/src/com/android/javacard/kmdevice/KMBignumTag.java similarity index 84% rename from Applet/src/com/android/javacard/keymaster/KMBignumTag.java rename to Applet/src/com/android/javacard/kmdevice/KMBignumTag.java index 7b020314..c3a53004 100644 --- a/Applet/src/com/android/javacard/keymaster/KMBignumTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMBignumTag.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -31,10 +31,14 @@ public class KMBignumTag extends KMTag { private static KMBignumTag prototype; // The allowed tag keys of type bool tag - private static final short[] tags = { - CERTIFICATE_SERIAL_NUM, - }; + private static short[] tags; + public static void initStatics() { + tags = new short[]{ + CERTIFICATE_SERIAL_NUM, + }; + } + private KMBignumTag() { } @@ -77,7 +81,7 @@ public static short instance(short key, short byteBlob) { return ptr; } - public static KMBignumTag cast(short ptr) { + private static KMBignumTag cast(short ptr) { if (heap[ptr] != TAG_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -101,9 +105,25 @@ public short getValue() { public short length() { short blobPtr = Util.getShort(heap, (short) (KMType.instanceTable[KM_BIGNUM_TAG_OFFSET] + TLV_HEADER_SIZE + 4)); - return KMByteBlob.cast(blobPtr).length(); + return KMByteBlob.length(blobPtr); + } + + public static short getKey(short bPtr) { + return KMBignumTag.cast(bPtr).getKey(); + } + + public static short getTagType(short bPtr) { + return KMBignumTag.cast(bPtr).getTagType(); + } + + public static short getValue(short bPtr) { + return KMBignumTag.cast(bPtr).getValue(); } + public static short length(short bPtr) { + return KMBignumTag.cast(bPtr).length(); + } + private static boolean validateKey(short key) { short index = (short) tags.length; while (--index >= 0) { diff --git a/Applet/src/com/android/javacard/keymaster/KMBoolTag.java b/Applet/src/com/android/javacard/kmdevice/KMBoolTag.java similarity index 76% rename from Applet/src/com/android/javacard/keymaster/KMBoolTag.java rename to Applet/src/com/android/javacard/kmdevice/KMBoolTag.java index d1e277a0..2886c3ab 100644 --- a/Applet/src/com/android/javacard/keymaster/KMBoolTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMBoolTag.java @@ -14,9 +14,8 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; -import com.android.javacard.seprovider.KMException; import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.Util; @@ -33,24 +32,29 @@ public class KMBoolTag extends KMTag { private static KMBoolTag prototype; // 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 - }; + private static short[] tags; private KMBoolTag() { } + public static void initStatics() { + // The allowed tag keys of type bool tag. + tags = new short[] { + 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 static KMBoolTag proto(short ptr) { if (prototype == null) { prototype = new KMBoolTag(); @@ -78,16 +82,20 @@ public static short instance(short key) { return ptr; } - public static KMBoolTag cast(short ptr) { + private static KMBoolTag cast(short ptr) { + validate(ptr); + return proto(ptr); + } + + public static void validate(short ptr) { if (heap[ptr] != TAG_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } if (Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)) != BOOL_TAG) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } - return proto(ptr); } - + public short getKey() { return Util.getShort(heap, (short) (KMType.instanceTable[KM_BOOL_TAG_OFFSET] + TLV_HEADER_SIZE + 2)); } @@ -99,7 +107,19 @@ public short getTagType() { public byte getVal() { return heap[(short) (KMType.instanceTable[KM_BOOL_TAG_OFFSET] + TLV_HEADER_SIZE + 4)]; } + + public static short getKey(short bPtr) { + return KMBoolTag.cast(bPtr).getKey(); + } + + public static short getTagType(short bPtr) { + return KMBoolTag.cast(bPtr).getTagType(); + } + public static byte getVal(short bPtr) { + return KMBoolTag.cast(bPtr).getVal(); + } + // validate the tag key. private static boolean validateKey(short key) { short index = (short) tags.length; diff --git a/Applet/src/com/android/javacard/keymaster/KMByteBlob.java b/Applet/src/com/android/javacard/kmdevice/KMByteBlob.java similarity index 74% rename from Applet/src/com/android/javacard/keymaster/KMByteBlob.java rename to Applet/src/com/android/javacard/kmdevice/KMByteBlob.java index 0d2627d9..9348c6b7 100644 --- a/Applet/src/com/android/javacard/keymaster/KMByteBlob.java +++ b/Applet/src/com/android/javacard/kmdevice/KMByteBlob.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -47,7 +47,7 @@ public static short exp() { // return an empty byte blob instance public static short instance(short length) { - short ptr = KMType.instance(BYTE_BLOB_TYPE, (short)(length+2)); + short ptr = KMType.instance(BYTE_BLOB_TYPE, (short)(length + OFFSET_SIZE)); Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE), (short)(ptr+TLV_HEADER_SIZE+OFFSET_SIZE)); Util.setShort(heap, (short)(ptr + 1), length); return ptr; @@ -61,16 +61,20 @@ public static short instance(byte[] buf, short startOff, short length) { } // cast the ptr to KMByteBlob - public static KMByteBlob cast(short ptr) { + private static KMByteBlob cast(short ptr) { + validate(ptr); + return proto(ptr); + } + + public static void validate(short ptr) { if (heap[ptr] != BYTE_BLOB_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } if (Util.getShort(heap, (short) (ptr + 1)) == INVALID_VALUE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } - return proto(ptr); } - + // Add the byte public void add(short index, byte val) { short len = length(); @@ -137,4 +141,49 @@ protected short getBaseOffset() { public void setLength(short len){ Util.setShort(heap, (short)(getBaseOffset() + 1), len); } + + + public static void add(short bPtr, short index, byte val) { + cast(bPtr).add(index, val); + } + + public static byte get(short bPtr, short index) { + return cast(bPtr).get(index); + } + + public static short getStartOff(short bPtr) { + return cast(bPtr).getStartOff(); + } + + public static short length(short bPtr) { + return cast(bPtr).length(); + } + + public static byte[] getBuffer(short bPtr) { + return cast(bPtr).getBuffer(); + } + + public static void getValue(short bPtr, byte[] destBuf, short destStart, short destLength) { + cast(bPtr).getValue(destBuf, destStart, destLength); + } + + public static short getValues(short bPtr, byte[] destBuf, short destStart) { + return cast(bPtr).getValues(destBuf, destStart); + } + + public static void setValue(short bPtr, byte[] srcBuf, short srcStart, short srcLength) { + cast(bPtr).setValue(srcBuf, srcStart, srcLength); + } + + public static boolean isValid(short bPtr) { + return cast(bPtr).isValid(); + } + + public static void setStartOff(short bPtr, short offset){ + cast(bPtr).setStartOff(offset); + } + + public static void setLength(short bPtr, short len){ + cast(bPtr).setLength(len); + } } diff --git a/Applet/src/com/android/javacard/keymaster/KMByteTag.java b/Applet/src/com/android/javacard/kmdevice/KMByteTag.java similarity index 74% rename from Applet/src/com/android/javacard/keymaster/KMByteTag.java rename to Applet/src/com/android/javacard/kmdevice/KMByteTag.java index 1677a744..06bf8c4c 100644 --- a/Applet/src/com/android/javacard/keymaster/KMByteTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMByteTag.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -31,33 +31,37 @@ public class KMByteTag extends KMTag { private static KMByteTag prototype; // 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, - CERTIFICATE_SERIAL_NUM, - CERTIFICATE_SUBJECT_NAME, - }; + private static short[] tags; private KMByteTag() { } - + + public static void initStatics() { + tags = new short[]{ + 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, + CERTIFICATE_SERIAL_NUM, + CERTIFICATE_SUBJECT_NAME, + }; + } + private static KMByteTag proto(short ptr) { if (prototype == null) { prototype = new KMByteTag(); @@ -97,7 +101,7 @@ public static short instance(short key, short byteBlob) { return ptr; } - public static KMByteTag cast(short ptr) { + private static KMByteTag cast(short ptr) { if (heap[ptr] != TAG_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -121,7 +125,23 @@ public short getValue() { public short length() { short blobPtr = Util.getShort(heap, (short) (KMType.instanceTable[KM_BYTE_TAG_OFFSET] + TLV_HEADER_SIZE + 4)); - return KMByteBlob.cast(blobPtr).length(); + return KMByteBlob.length(blobPtr); + } + + public static short getKey(short bPtr) { + return KMByteTag.cast(bPtr).getKey(); + } + + public static short getTagType(short bPtr) { + return KMByteTag.cast(bPtr).getTagType(); + } + + public static short getValue(short bPtr) { + return KMByteTag.cast(bPtr).getValue(); + } + + public static short length(short bPtr) { + return KMByteTag.cast(bPtr).length(); } private static boolean validateKey(short key) { diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMComputedHmacKey.java b/Applet/src/com/android/javacard/kmdevice/KMComputedHmacKey.java similarity index 50% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMComputedHmacKey.java rename to Applet/src/com/android/javacard/kmdevice/KMComputedHmacKey.java index 3b0aa405..7988e592 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMComputedHmacKey.java +++ b/Applet/src/com/android/javacard/kmdevice/KMComputedHmacKey.java @@ -1,4 +1,4 @@ -package com.android.javacard.seprovider; +package com.android.javacard.kmdevice; public interface KMComputedHmacKey { diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMConfigurations.java b/Applet/src/com/android/javacard/kmdevice/KMConfigurations.java similarity index 96% rename from Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMConfigurations.java rename to Applet/src/com/android/javacard/kmdevice/KMConfigurations.java index 6e5090a1..b6414ed7 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMConfigurations.java +++ b/Applet/src/com/android/javacard/kmdevice/KMConfigurations.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; public class KMConfigurations { // Machine types diff --git a/Applet/src/com/android/javacard/keymaster/KMCose.java b/Applet/src/com/android/javacard/kmdevice/KMCose.java similarity index 72% rename from Applet/src/com/android/javacard/keymaster/KMCose.java rename to Applet/src/com/android/javacard/kmdevice/KMCose.java index 6720d8df..494130ec 100644 --- a/Applet/src/com/android/javacard/keymaster/KMCose.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCose.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -84,42 +84,76 @@ public class KMCose { public static final byte COSE_KEY_PUBKEY_X = -2; public static final byte COSE_KEY_PUBKEY_Y = -3; public static final byte COSE_KEY_PRIV_KEY = -4; - public static final byte[] COSE_TEST_KEY = {(byte) 0xFF, (byte) 0xFE, (byte) 0xEE, (byte) 0x90}; // -70000 + public static byte[] COSE_TEST_KEY; // -70000 public static final short COSE_KEY_MAX_SIZE = 4; // kdfcontext strings - public static final byte[] client = {0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74}; - public static final byte[] server = {0x73, 0x65, 0x72, 0x76, 0x65, 0x72}; + public static byte[] client; + public static byte[] server; //Context strings - public static final byte[] MAC_CONTEXT = {0x4d, 0x41, 0x43, 0x30}; // MAC0 - public static final byte[] SIGNATURE1_CONTEXT = - {0x53, 0x69, 0x67, 0x6E, 0x61, 0x74, 0x75, 0x72, 0x65, 0x31}; // Signature1 - public static final byte[] ENCRYPT_CONTEXT = - {0x45, 0x6E, 0x63, 0x72, 0x79, 0x70, 0x74}; // Encrypt + public static byte[] MAC_CONTEXT; // MAC0 + public static byte[] SIGNATURE1_CONTEXT; // Signature1 + public static byte[] ENCRYPT_CONTEXT; // Encrypt //Empty strings - public static final byte[] EMPTY_MAC_KEY = - {0x45, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x4d, 0x41, 0x43, 0x20, 0x6b, 0x65, 0x79}; // "Empty MAC key" + public static byte[] EMPTY_MAC_KEY; // "Empty MAC key" // Certificate payload supported keys public static final byte ISSUER = (byte) 0x01; public static final byte SUBJECT = (byte) 0x02; - public static final byte[] CODE_HASH = {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xAF}; - public static final byte[] CODE_DESCRIPTOR = {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xAE}; - public static final byte[] CONFIG_HASH = {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xAD}; - public static final byte[] CONFIG_DESCRIPTOR = {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xAC}; - public static final byte[] AUTHORITY_HASH = {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xAB}; - public static final byte[] AUTHORITY_DESCRIPTOR = {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xAA}; - public static final byte[] MODE = {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xA9}; - public static final byte[] SUBJECT_PUBLIC_KEY = {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xA8}; - public static final byte[] KEY_USAGE = {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xA7}; + public static byte[] CODE_HASH; + public static byte[] CODE_DESCRIPTOR; + public static byte[] CONFIG_HASH; + public static byte[] CONFIG_DESCRIPTOR; + public static byte[] AUTHORITY_HASH; + public static byte[] AUTHORITY_DESCRIPTOR; + public static byte[] MODE; + public static byte[] SUBJECT_PUBLIC_KEY; + public static byte[] KEY_USAGE; // text strings - public static final byte[] TEST_ISSUER_NAME = {(byte) 0x49, 0x73, 0x73, 0x75, 0x65, 0x72}; // "Issuer" - public static final byte[] TEST_SUBJECT_NAME = {0x53, 0x75, 0x62, 0x6A, 0x65, 0x63, 0x74}; // "Subject" - public static final byte[] KEY_USAGE_SIGN = {0x20}; // Key usage sign - public static final byte[] MAC_DERIVE_KEY_CTX = - {0x4B, 0x65, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x4D, 0x41, 0x43, 0x20, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, - 0x20, 0x6B, 0x65, 0x79, 0x73}; // "Key to MAC public keys" + public static byte[] TEST_ISSUER_NAME; // "Issuer" + public static byte[] TEST_SUBJECT_NAME; // "Subject" + public static byte[] KEY_USAGE_SIGN; // Key usage sign + public static byte[] MAC_DERIVE_KEY_CTX; // "Key to MAC public keys" + private static KMCose prototype; + + public static void initStatics() { + COSE_TEST_KEY = new byte[] {(byte) 0xFF, (byte) 0xFE, (byte) 0xEE, (byte) 0x90}; // -70000 + client = new byte[] {0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74}; + server = new byte[] {0x73, 0x65, 0x72, 0x76, 0x65, 0x72}; + MAC_CONTEXT = new byte[] {0x4d, 0x41, 0x43, 0x30}; // MAC0 + SIGNATURE1_CONTEXT = new byte[] + {0x53, 0x69, 0x67, 0x6E, 0x61, 0x74, 0x75, 0x72, 0x65, 0x31}; // Signature1 + ENCRYPT_CONTEXT = new byte[] {0x45, 0x6E, 0x63, 0x72, 0x79, 0x70, 0x74}; // Encrypt + EMPTY_MAC_KEY = new byte[] + {0x45, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x4d, 0x41, 0x43, 0x20, 0x6b, 0x65, 0x79}; // "Empty MAC key" + + + CODE_HASH = new byte[] {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xAF}; + CODE_DESCRIPTOR = new byte[] {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xAE}; + CONFIG_HASH = new byte[] {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xAD}; + CONFIG_DESCRIPTOR = new byte[] {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xAC}; + AUTHORITY_HASH = new byte[] {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xAB}; + AUTHORITY_DESCRIPTOR = new byte[] {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xAA}; + MODE = new byte[] {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xA9}; + SUBJECT_PUBLIC_KEY = new byte[] {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xA8}; + KEY_USAGE = new byte[] {(byte) 0xFF, (byte) 0xB8, (byte) 0xBB, (byte) 0xA7}; + // text strings + TEST_ISSUER_NAME = new byte[] {(byte) 0x49, 0x73, 0x73, 0x75, 0x65, 0x72}; // "Issuer" + TEST_SUBJECT_NAME = new byte[] {0x53, 0x75, 0x62, 0x6A, 0x65, 0x63, 0x74}; // "Subject" + KEY_USAGE_SIGN = new byte[] {0x20}; // Key usage sign + MAC_DERIVE_KEY_CTX = new byte[] + {0x4B, 0x65, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x4D, 0x41, 0x43, 0x20, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, + 0x20, 0x6B, 0x65, 0x79, 0x73}; // "Key to MAC public keys" + + } + + public static KMCose getInstance() { + if (prototype == null) { + prototype = new KMCose(); + } + return prototype; + } /** * Constructs the Cose MAC structure. * @@ -128,7 +162,7 @@ public class KMCose { * @param payload Bstr pointer which holds the payload of the MAC structure. * @return KMArray instance of MAC structure. */ - public static short constructCoseMacStructure(short protectedHeader, short extAad, short payload) { + public short constructCoseMacStructure(short protectedHeader, short extAad, short payload) { // Create MAC Structure and compute HMAC as per https://tools.ietf.org/html/rfc8152#section-6.3 // MAC_structure = [ // context : "MAC" / "MAC0", @@ -138,14 +172,14 @@ public static short constructCoseMacStructure(short protectedHeader, short extAa // ] short arrPtr = KMArray.instance(KMCose.COSE_MAC0_ENTRY_COUNT); // 1 - Context - KMArray.cast(arrPtr).add((short) 0, KMTextString.instance(KMCose.MAC_CONTEXT, (short) 0, + KMArray.add(arrPtr, (short) 0, KMTextString.instance(KMCose.MAC_CONTEXT, (short) 0, (short) KMCose.MAC_CONTEXT.length)); // 2 - Protected headers. - KMArray.cast(arrPtr).add((short) 1, protectedHeader); + KMArray.add(arrPtr, (short) 1, protectedHeader); // 3 - external aad - KMArray.cast(arrPtr).add((short) 2, extAad); + KMArray.add(arrPtr, (short) 2, extAad); // 4 - payload. - KMArray.cast(arrPtr).add((short) 3, payload); + KMArray.add(arrPtr, (short) 3, payload); return arrPtr; } @@ -158,8 +192,8 @@ public static short constructCoseMacStructure(short protectedHeader, short extAa * @param tag Bstr pointer which holds the tag value. * @return KMArray instance of COSE_MAC0 object. */ - public static short constructCoseMac0(short protectedHeader, short unprotectedHeader, short payload, short tag) { - // Construct Cose_MAC0 + public short constructCoseMac0(short protectedHeader, short unprotectedHeader, short payload, short tag) { + // Construct Cose_MAC0 // COSE_Mac0 = [ // protectedHeader, // unprotectedHeader, @@ -168,13 +202,13 @@ public static short constructCoseMac0(short protectedHeader, short unprotectedHe // ] short arrPtr = KMArray.instance(KMCose.COSE_MAC0_ENTRY_COUNT); // 1 - protected headers - KMArray.cast(arrPtr).add((short) 0, protectedHeader); + KMArray.add(arrPtr, (short) 0, protectedHeader); // 2 - unprotected headers - KMArray.cast(arrPtr).add((short) 1, unprotectedHeader); + KMArray.add(arrPtr, (short) 1, unprotectedHeader); // 2 - payload - KMArray.cast(arrPtr).add((short) 2, payload); + KMArray.add(arrPtr, (short) 2, payload); // 3 - tag - KMArray.cast(arrPtr).add((short) 3, tag); + KMArray.add(arrPtr, (short) 3, tag); // Do encode. return arrPtr; } @@ -187,7 +221,7 @@ public static short constructCoseMac0(short protectedHeader, short unprotectedHe * @param payload Bstr pointer which holds the payload. * @return KMArray instance of COSE_Signature object. */ - public static short constructCoseSignStructure(short protectedHeader, short extAad, short payload) { + public short constructCoseSignStructure(short protectedHeader, short extAad, short payload) { // Sig_structure = [ // context : "Signature" / "Signature1" / "CounterSignature", // body_protected : empty_or_serialized_map, @@ -197,14 +231,14 @@ public static short constructCoseSignStructure(short protectedHeader, short extA // ] short arrPtr = KMArray.instance(KMCose.COSE_SIGN1_ENTRY_COUNT); // 1 - Context - KMArray.cast(arrPtr).add((short) 0, KMTextString.instance(KMCose.SIGNATURE1_CONTEXT, (short) 0, + KMArray.add(arrPtr, (short) 0, KMTextString.instance(KMCose.SIGNATURE1_CONTEXT, (short) 0, (short) KMCose.SIGNATURE1_CONTEXT.length)); // 2 - Protected headers. - KMArray.cast(arrPtr).add((short) 1, protectedHeader); + KMArray.add(arrPtr, (short) 1, protectedHeader); // 3 - external aad - KMArray.cast(arrPtr).add((short) 2, extAad); + KMArray.add(arrPtr, (short) 2, extAad); // 4 - payload. - KMArray.cast(arrPtr).add((short) 3, payload); + KMArray.add(arrPtr, (short) 3, payload); return arrPtr; } @@ -217,7 +251,7 @@ public static short constructCoseSignStructure(short protectedHeader, short extA * @param signature Bstr pointer which holds the signature. * @return KMArray instance of COSE_Sign1 object. */ - public static short constructCoseSign1(short protectedHeader, short unProtectedHeader, short payload, + public short constructCoseSign1(short protectedHeader, short unProtectedHeader, short payload, short signature) { // COSE_Sign = [ // protectedHeader, @@ -227,13 +261,13 @@ public static short constructCoseSign1(short protectedHeader, short unProtectedH // ] short arrPtr = KMArray.instance(KMCose.COSE_SIGN1_ENTRY_COUNT); // 1 - protected headers - KMArray.cast(arrPtr).add((short) 0, protectedHeader); + KMArray.add(arrPtr, (short) 0, protectedHeader); // 2 - unprotected headers - KMArray.cast(arrPtr).add((short) 1, unProtectedHeader); + KMArray.add(arrPtr, (short) 1, unProtectedHeader); // 2 - payload - KMArray.cast(arrPtr).add((short) 2, payload); + KMArray.add(arrPtr, (short) 2, payload); // 3 - tag - KMArray.cast(arrPtr).add((short) 3, signature); + KMArray.add(arrPtr, (short) 3, signature); return arrPtr; } @@ -244,7 +278,7 @@ public static short constructCoseSign1(short protectedHeader, short unProtectedH * @param includeTestMode flag which indicates if TEST_COSE_KEY should be included or not. * @return instance of KMArray. */ - private static short handleCosePairTags(short[] tags, boolean includeTestMode) { + private short handleCosePairTags(short[] tags, boolean includeTestMode) { short index = 0; // var is used to calculate the length of the array. short var = 0; @@ -263,7 +297,7 @@ private static short handleCosePairTags(short[] tags, boolean includeTestMode) { var = 0; while (index < tags.length) { if (tags[(short) (index + 2)] != KMType.INVALID_VALUE) { - KMArray.cast(arrPtr).add(var++, tags[(short) (index + 2)]); + KMArray.add(arrPtr, var++, tags[(short) (index + 2)]); } index += 3; } @@ -279,12 +313,12 @@ private static short handleCosePairTags(short[] tags, boolean includeTestMode) { * @param keyUsage instance of KMCosePairByteBlobTag which contains key usage value. * @return instance of KMArray. */ - public static short constructCoseCertPayload(short issuer, short subject, short subPublicKey, short keyUsage) { + public short constructCoseCertPayload(short issuer, short subject, short subPublicKey, short keyUsage) { short certPayload = KMArray.instance((short) 4); - KMArray.cast(certPayload).add((short) 0, issuer); - KMArray.cast(certPayload).add((short) 1, subject); - KMArray.cast(certPayload).add((short) 2, subPublicKey); - KMArray.cast(certPayload).add((short) 3, keyUsage); + KMArray.add(certPayload, (short) 0, issuer); + KMArray.add(certPayload, (short) 1, subject); + KMArray.add(certPayload, (short) 2, subPublicKey); + KMArray.add(certPayload, (short) 3, keyUsage); certPayload = KMCoseCertPayload.instance(certPayload); KMCoseCertPayload.cast(certPayload).canonicalize(); return certPayload; @@ -300,7 +334,7 @@ public static short constructCoseCertPayload(short issuer, short subject, short * @param ephemeralKey instance of KMCoseKey. * @return instance of KMCoseHeaders. */ - public static short constructHeaders(short alg, short keyId, short iv, short ephemeralKey) { + public short constructHeaders(short alg, short keyId, short iv, short ephemeralKey) { short[] coseHeaderTags = { KMCose.COSE_LABEL_ALGORITHM, alg, KMType.INVALID_VALUE, KMCose.COSE_LABEL_KEYID, keyId, KMType.INVALID_VALUE, @@ -321,7 +355,7 @@ public static short constructHeaders(short alg, short keyId, short iv, short eph * @param cipherText instance of KMSimple * @return instance of KMArray. */ - public static short constructRecipientsStructure(short protectedHeaders, short unprotectedHeaders, + public short constructRecipientsStructure(short protectedHeaders, short unprotectedHeaders, short cipherText) { // recipients : [+COSE_recipient] // COSE_recipient = [ @@ -331,14 +365,14 @@ public static short constructRecipientsStructure(short protectedHeaders, short u // ] short arrPtr = KMArray.instance(COSE_ENCRYPT_RECIPIENT_ENTRY_COUNT); // 1 - protected headers - KMArray.cast(arrPtr).add((short) 0, protectedHeaders); + KMArray.add(arrPtr, (short) 0, protectedHeaders); // 2 - unprotected headers - KMArray.cast(arrPtr).add((short) 1, unprotectedHeaders); + KMArray.add(arrPtr, (short) 1, unprotectedHeaders); // 2 - payload - KMArray.cast(arrPtr).add((short) 2, cipherText); + KMArray.add(arrPtr, (short) 2, cipherText); short recipientsArrayPtr = KMArray.instance((short) 1); - KMArray.cast(recipientsArrayPtr).add((short) 0, arrPtr); + KMArray.add(recipientsArrayPtr, (short) 0, arrPtr); return recipientsArrayPtr; } @@ -349,7 +383,7 @@ public static short constructRecipientsStructure(short protectedHeaders, short u * @param aad instance of KMByteBlob. * @return instance of KMArray. */ - public static short constructCoseEncryptStructure(short protectedHeader, short aad) { + public short constructCoseEncryptStructure(short protectedHeader, short aad) { // Enc_structure = [ // context : "Encrypt" / "Encrypt0" / "Enc_Recipient" / // "Mac_Recipient" / "Rec_Recipient", @@ -358,12 +392,12 @@ public static short constructCoseEncryptStructure(short protectedHeader, short a // ] short arrPtr = KMArray.instance(COSE_ENCRYPT_STRUCTURE_ENTRY_COUNT); // 1 - protected headers - KMArray.cast(arrPtr).add((short) 0, KMTextString.instance(KMCose.ENCRYPT_CONTEXT, (short) 0, + KMArray.add(arrPtr, (short) 0, KMTextString.instance(KMCose.ENCRYPT_CONTEXT, (short) 0, (short) KMCose.ENCRYPT_CONTEXT.length)); // 2 - unprotected headers - KMArray.cast(arrPtr).add((short) 1, protectedHeader); + KMArray.add(arrPtr, (short) 1, protectedHeader); // 2 - payload - KMArray.cast(arrPtr).add((short) 2, aad); + KMArray.add(arrPtr, (short) 2, aad); return arrPtr; } @@ -376,7 +410,7 @@ public static short constructCoseEncryptStructure(short protectedHeader, short a * @param recipients instance of KMArray containing the recipients instance * @return instance of KMArray. */ - public static short constructCoseEncrypt(short protectedHeader, short unProtectedHeader, short cipherText, + public short constructCoseEncrypt(short protectedHeader, short unProtectedHeader, short cipherText, short recipients) { // COSE_Encrypt = [ // protectedHeader, @@ -386,13 +420,13 @@ public static short constructCoseEncrypt(short protectedHeader, short unProtecte // ] short arrPtr = KMArray.instance(KMCose.COSE_ENCRYPT_ENTRY_COUNT); // 1 - protected headers - KMArray.cast(arrPtr).add((short) 0, protectedHeader); + KMArray.add(arrPtr, (short) 0, protectedHeader); // 2 - unprotected headers - KMArray.cast(arrPtr).add((short) 1, unProtectedHeader); + KMArray.add(arrPtr, (short) 1, unProtectedHeader); // 2 - payload - KMArray.cast(arrPtr).add((short) 2, cipherText); + KMArray.add(arrPtr, (short) 2, cipherText); // 3 - tag - KMArray.cast(arrPtr).add((short) 3, recipients); + KMArray.add(arrPtr, (short) 3, recipients); return arrPtr; } @@ -403,8 +437,8 @@ public static short constructCoseEncrypt(short protectedHeader, short unProtecte * @param valuePtr instance of one of KMType. * @return instance of KMCosePair*Value object. */ - public static short buildCosePairTag(byte key, short valuePtr) { - short type = KMType.getType(valuePtr); + public short buildCosePairTag(byte key, short valuePtr) { + short type = KMType.getKMType(valuePtr); short keyPtr; if (key < 0) { keyPtr = KMNInteger.uint_8(key); @@ -443,7 +477,7 @@ public static short buildCosePairTag(byte key, short valuePtr) { * @param testMode Represents if key is used in test mode or production mode. * @return Instance of the CoseKey structure. */ - public static short constructCoseKey(short keyType, short keyId, short keyAlg, short keyOps, + public short constructCoseKey(short keyType, short keyId, short keyAlg, short keyOps, short curve, byte[] pubKey, short pubKeyOff, short pubKeyLen, short privKeyPtr, boolean testMode) { if (pubKey[pubKeyOff] == 0x04) { // uncompressed format @@ -473,7 +507,7 @@ public static short constructCoseKey(short keyType, short keyId, short keyAlg, s * @param includeTestKey flag which identifies whether to construct test key or production key. * @return instance of the KMCoseKey object. */ - public static short constructCoseKey(short keyType, short keyId, short keyAlg, short keyOps, short curve, + public short constructCoseKey(short keyType, short keyId, short keyAlg, short keyOps, short curve, short pubX, short pubY, short priv, boolean includeTestKey) { short[] coseKeyTags = { KMCose.COSE_KEY_KEY_TYPE, keyType, KMType.INVALID_VALUE, @@ -490,7 +524,7 @@ public static short constructCoseKey(short keyType, short keyId, short keyAlg, s short testKey = KMCosePairSimpleValueTag.instance(KMNInteger.uint_32(KMCose.COSE_TEST_KEY, (short) 0), KMSimpleValue.instance(KMSimpleValue.NULL)); - KMArray.cast(arrPtr).add((short) (KMArray.cast(arrPtr).length() - 1), testKey); + KMArray.add(arrPtr, (short) (KMArray.length(arrPtr) - 1), testKey); } arrPtr = KMCoseKey.instance(arrPtr); KMCoseKey.cast(arrPtr).canonicalize(); @@ -509,41 +543,41 @@ public static short constructCoseKey(short keyType, short keyId, short keyAlg, s * @param senderIsA true if caller is first party, false if caller is second party. * @return instance of KMArray. */ - public static short constructKdfContext(byte[] publicKeyA, short publicKeyAOff, short publicKeyALen, + public short constructKdfContext(byte[] publicKeyA, short publicKeyAOff, short publicKeyALen, byte[] publicKeyB, short publicKeyBOff, short publicKeyBLen, boolean senderIsA) { short index = 0; // Prepare sender info short senderInfo = KMArray.instance((short) 3); - KMArray.cast(senderInfo).add(index++, KMByteBlob.instance(client, (short) 0, (short) client.length)); - KMArray.cast(senderInfo).add(index++, KMByteBlob.instance((short) 0)); - KMArray.cast(senderInfo).add(index, senderIsA ? + KMArray.add(senderInfo, index++, KMByteBlob.instance(client, (short) 0, (short) client.length)); + KMArray.add(senderInfo, index++, KMByteBlob.instance((short) 0)); + KMArray.add(senderInfo, index, senderIsA ? KMByteBlob.instance(publicKeyA, publicKeyAOff, publicKeyALen) : KMByteBlob.instance(publicKeyB, publicKeyBOff, publicKeyBLen)); // Prepare recipient info index = 0; short recipientInfo = KMArray.instance((short) 3); - KMArray.cast(recipientInfo).add(index++, KMByteBlob.instance(server, (short) 0, (short) server.length)); - KMArray.cast(recipientInfo).add(index++, KMByteBlob.instance((short) 0)); - KMArray.cast(recipientInfo).add(index, senderIsA ? + KMArray.add(recipientInfo, index++, KMByteBlob.instance(server, (short) 0, (short) server.length)); + KMArray.add(recipientInfo, index++, KMByteBlob.instance((short) 0)); + KMArray.add(recipientInfo, index, senderIsA ? KMByteBlob.instance(publicKeyB, publicKeyBOff, publicKeyBLen) : KMByteBlob.instance(publicKeyA, publicKeyAOff, publicKeyALen)); // supply public info index = 0; short publicInfo = KMArray.instance((short) 2); - KMArray.cast(publicInfo).add(index++, KMInteger.uint_16(AES_GCM_KEY_SIZE_BITS)); - KMArray.cast(publicInfo).add(index, KMByteBlob.instance((short) 0)); + KMArray.add(publicInfo, index++, KMInteger.uint_16(AES_GCM_KEY_SIZE_BITS)); + KMArray.add(publicInfo, index, KMByteBlob.instance((short) 0)); // construct kdf context index = 0; short arrPtr = KMArray.instance((short) 4); - KMArray.cast(arrPtr).add(index++, KMInteger.uint_8(COSE_ALG_AES_GCM_256)); - KMArray.cast(arrPtr).add(index++, senderInfo); - KMArray.cast(arrPtr).add(index++, recipientInfo); - KMArray.cast(arrPtr).add(index, publicInfo); + KMArray.add(arrPtr, index++, KMInteger.uint_8(COSE_ALG_AES_GCM_256)); + KMArray.add(arrPtr, index++, senderInfo); + KMArray.add(arrPtr, index++, recipientInfo); + KMArray.add(arrPtr, index, publicInfo); return arrPtr; } -} \ No newline at end of file +} diff --git a/Applet/src/com/android/javacard/keymaster/KMCoseCertPayload.java b/Applet/src/com/android/javacard/kmdevice/KMCoseCertPayload.java similarity index 84% rename from Applet/src/com/android/javacard/keymaster/KMCoseCertPayload.java rename to Applet/src/com/android/javacard/kmdevice/KMCoseCertPayload.java index 76535416..0860cf0f 100644 --- a/Applet/src/com/android/javacard/keymaster/KMCoseCertPayload.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCoseCertPayload.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -43,9 +43,8 @@ private static KMCoseCertPayload proto(short ptr) { public static short exp() { short arrPtr = KMArray.instance((short) 2); - KMArray arr = KMArray.cast(arrPtr); - arr.add((short) 0, KMCosePairTextStringTag.exp()); - arr.add((short) 1, KMCosePairByteBlobTag.exp()); + KMArray.add(arrPtr, (short) 0, KMCosePairTextStringTag.exp()); + KMArray.add(arrPtr, (short) 1, KMCosePairByteBlobTag.exp()); return KMCoseCertPayload.instance(arrPtr); } @@ -74,7 +73,7 @@ public short getVals() { @Override public short length() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).length(); + return KMArray.length(arrPtr); } @Override @@ -91,20 +90,20 @@ private short getValueType(short key, short significantKey) { short tagType; boolean found = false; while (index < length) { - tagType = KMCosePairTagType.getTagValueType(KMArray.cast(arr).get(index)); + tagType = KMCosePairTagType.getTagValueType(KMArray.get(arr, index)); switch (tagType) { case KMType.COSE_PAIR_BYTE_BLOB_TAG_TYPE: - keyPtr = KMCosePairByteBlobTag.cast(KMArray.cast(arr).get(index)).getKeyPtr(); + keyPtr = KMCosePairByteBlobTag.cast(KMArray.get(arr, index)).getKeyPtr(); if (key == KMCosePairTagType.getKeyValueShort(keyPtr) && significantKey == KMCosePairTagType.getKeyValueSignificantShort(keyPtr)) { - valPtr = KMCosePairByteBlobTag.cast(KMArray.cast(arr).get(index)).getValuePtr(); + valPtr = KMCosePairByteBlobTag.cast(KMArray.get(arr, index)).getValuePtr(); found = true; } break; case KMType.COSE_PAIR_TEXT_STR_TAG_TYPE: - keyPtr = KMCosePairTextStringTag.cast(KMArray.cast(arr).get(index)).getKeyPtr(); + keyPtr = KMCosePairTextStringTag.cast(KMArray.get(arr, index)).getKeyPtr(); if (key == (byte) KMCosePairTagType.getKeyValueShort(keyPtr)) { - valPtr = KMCosePairTextStringTag.cast(KMArray.cast(arr).get(index)).getValuePtr(); + valPtr = KMCosePairTextStringTag.cast(KMArray.get(arr, index)).getValuePtr(); found = true; } break; diff --git a/Applet/src/com/android/javacard/keymaster/KMCoseHeaders.java b/Applet/src/com/android/javacard/kmdevice/KMCoseHeaders.java similarity index 74% rename from Applet/src/com/android/javacard/keymaster/KMCoseHeaders.java rename to Applet/src/com/android/javacard/kmdevice/KMCoseHeaders.java index 0b82d6cb..d765e46b 100644 --- a/Applet/src/com/android/javacard/keymaster/KMCoseHeaders.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCoseHeaders.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -45,11 +45,10 @@ public static short exp() { short arrPtr = KMArray.instance((short) 4); // CoseKey is internally an Array so evaluate it separately. short coseKeyValueExp = KMCosePairCoseKeyTag.exp(); - KMArray arr = KMArray.cast(arrPtr); - arr.add((short) 0, KMCosePairIntegerTag.exp()); - arr.add((short) 1, KMCosePairNegIntegerTag.exp()); - arr.add((short) 2, KMCosePairByteBlobTag.exp()); - arr.add((short) 3, coseKeyValueExp); + KMArray.add(arrPtr, (short) 0, KMCosePairIntegerTag.exp()); + KMArray.add(arrPtr, (short) 1, KMCosePairNegIntegerTag.exp()); + KMArray.add(arrPtr, (short) 2, KMCosePairByteBlobTag.exp()); + KMArray.add(arrPtr, (short) 3, coseKeyValueExp); return KMCoseHeaders.instance(arrPtr); } @@ -79,7 +78,7 @@ public short getVals() { @Override public short length() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).length(); + return KMArray.length(arrPtr); } @Override @@ -96,33 +95,33 @@ private short getValueType(short key) { short keyPtr; boolean found = false; while (index < len) { - tagType = KMCosePairTagType.getTagValueType(KMArray.cast(arr).get(index)); + tagType = KMCosePairTagType.getTagValueType(KMArray.get(arr, index)); switch (tagType) { case KMType.COSE_PAIR_BYTE_BLOB_TAG_TYPE: - keyPtr = KMCosePairByteBlobTag.cast(KMArray.cast(arr).get(index)).getKeyPtr(); + keyPtr = KMCosePairByteBlobTag.cast(KMArray.get(arr, index)).getKeyPtr(); if (key == (byte) KMCosePairTagType.getKeyValueShort(keyPtr)) { - valPtr = KMCosePairByteBlobTag.cast(KMArray.cast(arr).get(index)).getValuePtr(); + valPtr = KMCosePairByteBlobTag.cast(KMArray.get(arr, index)).getValuePtr(); found = true; } break; case KMType.COSE_PAIR_COSE_KEY_TAG_TYPE: - keyPtr = KMCosePairCoseKeyTag.cast(KMArray.cast(arr).get(index)).getKeyPtr(); + keyPtr = KMCosePairCoseKeyTag.cast(KMArray.get(arr, index)).getKeyPtr(); if (key == (byte) KMCosePairTagType.getKeyValueShort(keyPtr)) { - valPtr = KMCosePairCoseKeyTag.cast(KMArray.cast(arr).get(index)).getValuePtr(); + valPtr = KMCosePairCoseKeyTag.cast(KMArray.get(arr, index)).getValuePtr(); found = true; } break; case KMType.COSE_PAIR_INT_TAG_TYPE: - keyPtr = KMCosePairIntegerTag.cast(KMArray.cast(arr).get(index)).getKeyPtr(); + keyPtr = KMCosePairIntegerTag.cast(KMArray.get(arr, index)).getKeyPtr(); if (key == (byte) KMCosePairTagType.getKeyValueShort(keyPtr)) { - valPtr = KMCosePairIntegerTag.cast(KMArray.cast(arr).get(index)).getValuePtr(); + valPtr = KMCosePairIntegerTag.cast(KMArray.get(arr, index)).getValuePtr(); found = true; } break; case KMType.COSE_PAIR_NEG_INT_TAG_TYPE: - keyPtr = KMCosePairNegIntegerTag.cast(KMArray.cast(arr).get(index)).getKeyPtr(); + keyPtr = KMCosePairNegIntegerTag.cast(KMArray.get(arr, index)).getKeyPtr(); if (key == (byte) KMCosePairTagType.getKeyValueShort(keyPtr)) { - valPtr = KMCosePairNegIntegerTag.cast(KMArray.cast(arr).get(index)).getValuePtr(); + valPtr = KMCosePairNegIntegerTag.cast(KMArray.get(arr, index)).getValuePtr(); found = true; } break; @@ -166,25 +165,25 @@ public boolean isDataValid(short alg, short keyIdPtr) { if (value != KMType.INVALID_VALUE) { valid = false; ptr = getValueType(headerTags[tagIndex]); - switch (KMType.getType(ptr)) { + switch (KMType.getKMType(ptr)) { case KMType.BYTE_BLOB_TYPE: - if ((KMByteBlob.cast(value).length() == KMByteBlob.cast(ptr).length()) && + if ((KMByteBlob.length(value) == KMByteBlob.length(ptr)) && (0 == - Util.arrayCompare(KMByteBlob.cast(value).getBuffer(), - KMByteBlob.cast(value).getStartOff(), - KMByteBlob.cast(ptr).getBuffer(), - KMByteBlob.cast(ptr).getStartOff(), - KMByteBlob.cast(ptr).length()))) { + Util.arrayCompare(KMByteBlob.getBuffer(value), + KMByteBlob.getStartOff(value), + KMByteBlob.getBuffer(ptr), + KMByteBlob.getStartOff(ptr), + KMByteBlob.length(ptr)))) { valid = true; } break; case KMType.INTEGER_TYPE: - if (value == KMInteger.cast(ptr).getShort()) { + if (value == KMInteger.getShort(ptr)) { valid = true; } break; case KMType.NEG_INTEGER_TYPE: - if ((byte) value == (byte) KMNInteger.cast(ptr).getShort()) { + if ((byte) value == (byte) KMNInteger.getShort(ptr)) { valid = true; } break; diff --git a/Applet/src/com/android/javacard/keymaster/KMCoseKey.java b/Applet/src/com/android/javacard/kmdevice/KMCoseKey.java similarity index 69% rename from Applet/src/com/android/javacard/keymaster/KMCoseKey.java rename to Applet/src/com/android/javacard/kmdevice/KMCoseKey.java index eafa3006..96df5583 100644 --- a/Applet/src/com/android/javacard/keymaster/KMCoseKey.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCoseKey.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -23,7 +23,7 @@ /** * KMCoseKey represents COSE_Key section from the Cose standard https://datatracker.ietf.org/doc/html/rfc8152#section-7 * The supported key types are KMNInteger, KMInteger and the supported value types are KMInteger, KMNInteger, - * KMByteBlob, KMSimpleValue. It corresponds to a CBOR Map type. struct{byte TAG_TYPE; short length; short arrayPtr } + * KMKeymasterApplet, KMSimpleValue. It corresponds to a CBOR Map type. struct{byte TAG_TYPE; short length; short arrayPtr } * where arrayPtr is a pointer to array with any KMTag subtype instances. */ public class KMCoseKey extends KMCoseMap { @@ -43,11 +43,10 @@ private static KMCoseKey proto(short ptr) { public static short exp() { short arrPtr = KMArray.instance((short) 4); - KMArray arr = KMArray.cast(arrPtr); - arr.add((short) 0, KMCosePairIntegerTag.exp()); - arr.add((short) 1, KMCosePairNegIntegerTag.exp()); - arr.add((short) 2, KMCosePairByteBlobTag.exp()); - arr.add((short) 3, KMCosePairSimpleValueTag.exp()); + KMArray.add(arrPtr, (short) 0, KMCosePairIntegerTag.exp()); + KMArray.add(arrPtr, (short) 1, KMCosePairNegIntegerTag.exp()); + KMArray.add(arrPtr, (short) 2, KMCosePairByteBlobTag.exp()); + KMArray.add(arrPtr, (short) 3, KMCosePairSimpleValueTag.exp()); return KMCoseKey.instance(arrPtr); } @@ -77,7 +76,7 @@ public short getVals() { @Override public short length() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).length(); + return KMArray.length(arrPtr); } private short getValueType(short key, short significantKey) { @@ -89,34 +88,34 @@ private short getValueType(short key, short significantKey) { short tagType; boolean found = false; while (index < length) { - tagType = KMCosePairTagType.getTagValueType(KMArray.cast(arr).get(index)); + tagType = KMCosePairTagType.getTagValueType(KMArray.get(arr, index)); switch (tagType) { case KMType.COSE_PAIR_BYTE_BLOB_TAG_TYPE: - keyPtr = KMCosePairByteBlobTag.cast(KMArray.cast(arr).get(index)).getKeyPtr(); + keyPtr = KMCosePairByteBlobTag.cast(KMArray.get(arr, index)).getKeyPtr(); if (key == (byte) KMCosePairTagType.getKeyValueShort(keyPtr)) { - valPtr = KMCosePairByteBlobTag.cast(KMArray.cast(arr).get(index)).getValuePtr(); + valPtr = KMCosePairByteBlobTag.cast(KMArray.get(arr, index)).getValuePtr(); found = true; } break; case KMType.COSE_PAIR_INT_TAG_TYPE: - keyPtr = KMCosePairIntegerTag.cast(KMArray.cast(arr).get(index)).getKeyPtr(); + keyPtr = KMCosePairIntegerTag.cast(KMArray.get(arr, index)).getKeyPtr(); if (key == (byte) KMCosePairTagType.getKeyValueShort(keyPtr)) { - valPtr = KMCosePairIntegerTag.cast(KMArray.cast(arr).get(index)).getValuePtr(); + valPtr = KMCosePairIntegerTag.cast(KMArray.get(arr, index)).getValuePtr(); found = true; } break; case KMType.COSE_PAIR_NEG_INT_TAG_TYPE: - keyPtr = KMCosePairNegIntegerTag.cast(KMArray.cast(arr).get(index)).getKeyPtr(); + keyPtr = KMCosePairNegIntegerTag.cast(KMArray.get(arr, index)).getKeyPtr(); if (key == (byte) KMCosePairTagType.getKeyValueShort(keyPtr)) { - valPtr = KMCosePairNegIntegerTag.cast(KMArray.cast(arr).get(index)).getValuePtr(); + valPtr = KMCosePairNegIntegerTag.cast(KMArray.get(arr, index)).getValuePtr(); found = true; } break; case KMType.COSE_PAIR_SIMPLE_VALUE_TAG_TYPE: - keyPtr = KMCosePairSimpleValueTag.cast(KMArray.cast(arr).get(index)).getKeyPtr(); + keyPtr = KMCosePairSimpleValueTag.cast(KMArray.get(arr, index)).getKeyPtr(); if (key == KMCosePairTagType.getKeyValueShort(keyPtr) && significantKey == KMCosePairTagType.getKeyValueSignificantShort(keyPtr)) { - valPtr = KMCosePairSimpleValueTag.cast(KMArray.cast(arr).get(index)).getValuePtr(); + valPtr = KMCosePairSimpleValueTag.cast(KMArray.get(arr, index)).getValuePtr(); found = true; } break; @@ -140,21 +139,21 @@ public short getEcdsa256PublicKey(byte[] pubKey, short pubKeyOff) { pubKey[pubKeyOff] = (byte) 0x04; // uncompressed. pubKeyOff++; short ptr = getValueType(KMCose.COSE_KEY_PUBKEY_X, KMType.INVALID_VALUE); - Util.arrayCopy(KMByteBlob.cast(ptr).getBuffer(), KMByteBlob.cast(ptr).getStartOff(), - pubKey, pubKeyOff, KMByteBlob.cast(ptr).length()); - pubKeyOff += KMByteBlob.cast(ptr).length(); + Util.arrayCopy(KMByteBlob.getBuffer(ptr), KMByteBlob.getStartOff(ptr), + pubKey, pubKeyOff, KMByteBlob.length(ptr)); + pubKeyOff += KMByteBlob.length(ptr); ptr = getValueType(KMCose.COSE_KEY_PUBKEY_Y, KMType.INVALID_VALUE); - Util.arrayCopy(KMByteBlob.cast(ptr).getBuffer(), KMByteBlob.cast(ptr).getStartOff(), - pubKey, pubKeyOff, KMByteBlob.cast(ptr).length()); - pubKeyOff += KMByteBlob.cast(ptr).length(); + Util.arrayCopy(KMByteBlob.getBuffer(ptr), KMByteBlob.getStartOff(ptr), + pubKey, pubKeyOff, KMByteBlob.length(ptr)); + pubKeyOff += KMByteBlob.length(ptr); return (short) (pubKeyOff - baseOffset); } public short getPrivateKey(byte[] priv, short privOff) { short ptr = getValueType(KMCose.COSE_KEY_PRIV_KEY, KMType.INVALID_VALUE); - Util.arrayCopy(KMByteBlob.cast(ptr).getBuffer(), KMByteBlob.cast(ptr).getStartOff(), - priv, privOff, KMByteBlob.cast(ptr).length()); - return KMByteBlob.cast(ptr).length(); + Util.arrayCopy(KMByteBlob.getBuffer(ptr), KMByteBlob.getStartOff(ptr), + priv, privOff, KMByteBlob.length(ptr)); + return KMByteBlob.length(ptr); } public boolean isTestKey() { @@ -165,7 +164,7 @@ public boolean isTestKey() { ); boolean isTestKey = false; if (ptr != 0) - isTestKey = (KMSimpleValue.cast(ptr).getValue() == KMSimpleValue.NULL); + isTestKey = (KMSimpleValue.getValue(ptr) == KMSimpleValue.NULL); return isTestKey; } @@ -173,7 +172,7 @@ public boolean isTestKey() { * Verifies the KMCoseKey values against the input values. * * @param keyType value of the key type - * @param keyIdPtr instance of KMByteBlob containing the key id. + * @param keyIdPtr instance of KMKeymasterApplet containing the key id. * @param keyAlg value of the algorithm. * @param keyOps value of the key operations. * @param curve value of the curve. @@ -196,25 +195,25 @@ public boolean isDataValid(short keyType, short keyIdPtr, short keyAlg, short ke if (value != KMType.INVALID_VALUE) { valid = false; ptr = getValueType(coseKeyTags[tagIndex], KMType.INVALID_VALUE); - switch (KMType.getType(ptr)) { + switch (KMType.getKMType(ptr)) { case KMType.BYTE_BLOB_TYPE: - if ((KMByteBlob.cast(value).length() == KMByteBlob.cast(ptr).length()) && + if ((KMByteBlob.length(value) == KMByteBlob.length(ptr)) && (0 == - Util.arrayCompare(KMByteBlob.cast(value).getBuffer(), - KMByteBlob.cast(value).getStartOff(), - KMByteBlob.cast(ptr).getBuffer(), - KMByteBlob.cast(ptr).getStartOff(), - KMByteBlob.cast(ptr).length()))) { + Util.arrayCompare(KMByteBlob.getBuffer(value), + KMByteBlob.getStartOff(value), + KMByteBlob.getBuffer(ptr), + KMByteBlob.getStartOff(ptr), + KMByteBlob.length(ptr)))) { valid = true; } break; case KMType.INTEGER_TYPE: - if (value == KMInteger.cast(ptr).getShort()) { + if (value == KMInteger.getShort(ptr)) { valid = true; } break; case KMType.NEG_INTEGER_TYPE: - if ((byte) value == (byte) KMNInteger.cast(ptr).getShort()) { + if ((byte) value == (byte) KMNInteger.getShort(ptr)) { valid = true; } break; diff --git a/Applet/src/com/android/javacard/keymaster/KMCoseMap.java b/Applet/src/com/android/javacard/kmdevice/KMCoseMap.java similarity index 86% rename from Applet/src/com/android/javacard/keymaster/KMCoseMap.java rename to Applet/src/com/android/javacard/kmdevice/KMCoseMap.java index ceb67fb2..c5ebf405 100644 --- a/Applet/src/com/android/javacard/keymaster/KMCoseMap.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCoseMap.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -41,7 +41,7 @@ public abstract class KMCoseMap extends KMType { * @return instance type of either KMCoseHeaders or KMCoseKey. */ public static short createInstanceFromType(short typePtr, short arrPtr) { - short mapType = KMType.getType(typePtr); + short mapType = KMType.getKMType(typePtr); switch (mapType) { case KMType.COSE_HEADERS_TYPE: return KMCoseHeaders.instance(arrPtr); @@ -56,7 +56,7 @@ public static short createInstanceFromType(short typePtr, short arrPtr) { } public static short getVals(short ptr) { - short mapType = KMType.getType(ptr); + short mapType = KMType.getKMType(ptr); switch (mapType) { case KMType.COSE_HEADERS_TYPE: return KMCoseHeaders.cast(ptr).getVals(); @@ -104,14 +104,14 @@ private static void createScratchBuffer() { } protected static void canonicalize(short arr) { - canonicalize(arr, KMArray.cast(arr).length()); + canonicalize(arr, KMArray.length(arr)); } private static void swap(short ptr, short firstIndex, short secondIndex) { - if (KMType.getType(ptr) == KMType.ARRAY_TYPE) { - KMArray.cast(ptr).swap(firstIndex, secondIndex); + if (KMType.getKMType(ptr) == KMType.ARRAY_TYPE) { + KMArray.swap(ptr, firstIndex, secondIndex); } else { - KMMap.cast(ptr).swap(firstIndex, secondIndex); + KMMap.swap(ptr, firstIndex, secondIndex); } } @@ -120,15 +120,15 @@ private static boolean compareAndSwap(short ptr, short index) { short secondKey; short firstKeyLen; short secondKeyLen; - if (KMType.getType(ptr) == KMType.ARRAY_TYPE) { - firstKey = getKey(KMArray.cast(ptr).get(index)); - secondKey = getKey(KMArray.cast(ptr).get((short) (index + 1))); + if (KMType.getKMType(ptr) == KMType.ARRAY_TYPE) { + firstKey = getKey(KMArray.get(ptr, index)); + secondKey = getKey(KMArray.get(ptr, (short) (index + 1))); } else { // Map - firstKey = KMMap.cast(ptr).getKey(index); - secondKey = KMMap.cast(ptr).getKey((short) (index + 1)); + firstKey = KMMap.getKey(ptr, index); + secondKey = KMMap.getKey(ptr, (short) (index + 1)); } - firstKeyLen = KMKeymasterApplet.encoder.encode(firstKey, scratchpad, (short) 0); - secondKeyLen = KMKeymasterApplet.encoder.encode(secondKey, scratchpad, firstKeyLen); + firstKeyLen = KMKeymasterDevice.encoder.encode(firstKey, scratchpad, (short) 0); + secondKeyLen = KMKeymasterDevice.encoder.encode(secondKey, scratchpad, firstKeyLen); if ((firstKeyLen > secondKeyLen) || ((firstKeyLen == secondKeyLen) && (0 < Util.arrayCompare(scratchpad, (short) 0, scratchpad, firstKeyLen, firstKeyLen)))) { diff --git a/Applet/src/com/android/javacard/keymaster/KMCosePairByteBlobTag.java b/Applet/src/com/android/javacard/kmdevice/KMCosePairByteBlobTag.java similarity index 93% rename from Applet/src/com/android/javacard/keymaster/KMCosePairByteBlobTag.java rename to Applet/src/com/android/javacard/kmdevice/KMCosePairByteBlobTag.java index 4a03295e..451985d6 100644 --- a/Applet/src/com/android/javacard/keymaster/KMCosePairByteBlobTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCosePairByteBlobTag.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -54,7 +54,7 @@ public static short instance(short keyPtr, short valuePtr) { if (!isKeyValueValid(keyPtr)) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } - if (KMType.getType(valuePtr) != BYTE_BLOB_TYPE) { + if (KMType.getKMType(valuePtr) != BYTE_BLOB_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } short ptr = KMType.instance(COSE_PAIR_TAG_TYPE, (short) 6); @@ -71,7 +71,7 @@ public static KMCosePairByteBlobTag cast(short ptr) { } // Validate the value pointer. short valuePtr = Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE + 4)); - if (KMType.getType(valuePtr) != BYTE_BLOB_TYPE) { + if (KMType.getKMType(valuePtr) != BYTE_BLOB_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } return proto(ptr); @@ -108,12 +108,12 @@ private static void createKeys() { public static boolean isKeyValueValid(short keyPtr) { createKeys(); - short type = KMType.getType(keyPtr); + short type = KMType.getKMType(keyPtr); short offset = 0; if (type == INTEGER_TYPE) { - offset = KMInteger.cast(keyPtr).getStartOff(); + offset = KMInteger.getStartOff(keyPtr); } else if (type == NEG_INTEGER_TYPE) { - offset = KMNInteger.cast(keyPtr).getStartOff(); + offset = KMNInteger.getStartOff(keyPtr); } else { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } diff --git a/Applet/src/com/android/javacard/keymaster/KMCosePairCoseKeyTag.java b/Applet/src/com/android/javacard/kmdevice/KMCosePairCoseKeyTag.java similarity index 90% rename from Applet/src/com/android/javacard/keymaster/KMCosePairCoseKeyTag.java rename to Applet/src/com/android/javacard/kmdevice/KMCosePairCoseKeyTag.java index 7eb1251e..8f38ac3b 100644 --- a/Applet/src/com/android/javacard/keymaster/KMCosePairCoseKeyTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCosePairCoseKeyTag.java @@ -1,4 +1,4 @@ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -10,11 +10,15 @@ */ public class KMCosePairCoseKeyTag extends KMCosePairTagType { - public static final byte[] keys = { - KMCose.COSE_LABEL_COSE_KEY - }; + public static byte[] keys; private static KMCosePairCoseKeyTag prototype; + public static void initStatics() { + keys = new byte[]{ + KMCose.COSE_LABEL_COSE_KEY + }; + } + private KMCosePairCoseKeyTag() { } @@ -39,7 +43,7 @@ public static short instance(short keyPtr, short valuePtr) { if (!isKeyValueValid(KMCosePairTagType.getKeyValueShort(keyPtr))) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } - if (KMType.getType(valuePtr) != COSE_KEY_TYPE) { + if (KMType.getKMType(valuePtr) != COSE_KEY_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } short ptr = KMType.instance(COSE_PAIR_TAG_TYPE, (short) 6); @@ -56,7 +60,7 @@ public static KMCosePairCoseKeyTag cast(short ptr) { } // Validate the value pointer. short valuePtr = Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE + 4)); - if (KMType.getType(valuePtr) != COSE_KEY_TYPE) { + if (KMType.getKMType(valuePtr) != COSE_KEY_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } return proto(ptr); diff --git a/Applet/src/com/android/javacard/keymaster/KMCosePairIntegerTag.java b/Applet/src/com/android/javacard/kmdevice/KMCosePairIntegerTag.java similarity index 95% rename from Applet/src/com/android/javacard/keymaster/KMCosePairIntegerTag.java rename to Applet/src/com/android/javacard/kmdevice/KMCosePairIntegerTag.java index d5fe47b9..84bff2b1 100644 --- a/Applet/src/com/android/javacard/keymaster/KMCosePairIntegerTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCosePairIntegerTag.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -52,7 +52,7 @@ public static short exp() { public static short instance(short keyPtr, short valuePtr) { short offset = KMCosePairTagType.getKeyStartOffset(keyPtr); if (!KMCosePairTagType.isKeyPairValid(heap, offset, KMCose.COSE_KEY_MAX_SIZE, - KMInteger.cast(valuePtr).getShort())) { + KMInteger.getShort(valuePtr))) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } short ptr = KMType.instance(COSE_PAIR_TAG_TYPE, (short) 6); @@ -69,7 +69,7 @@ public static KMCosePairIntegerTag cast(short ptr) { } // Validate the value ptr. short valuePtr = Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE + 4)); - if (INTEGER_TYPE != getType(valuePtr)) { + if (INTEGER_TYPE != getKMType(valuePtr)) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } return proto(ptr); diff --git a/Applet/src/com/android/javacard/keymaster/KMCosePairNegIntegerTag.java b/Applet/src/com/android/javacard/kmdevice/KMCosePairNegIntegerTag.java similarity index 95% rename from Applet/src/com/android/javacard/keymaster/KMCosePairNegIntegerTag.java rename to Applet/src/com/android/javacard/kmdevice/KMCosePairNegIntegerTag.java index b2abb95d..248c08f3 100644 --- a/Applet/src/com/android/javacard/keymaster/KMCosePairNegIntegerTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCosePairNegIntegerTag.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -56,7 +56,7 @@ public static KMCosePairNegIntegerTag cast(short ptr) { } // Validate the value ptr. short valuePtr = Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE + 4)); - if (NEG_INTEGER_TYPE != getType(valuePtr)) { + if (NEG_INTEGER_TYPE != getKMType(valuePtr)) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } return proto(ptr); @@ -65,7 +65,7 @@ public static KMCosePairNegIntegerTag cast(short ptr) { public static short instance(short keyPtr, short valuePtr) { short offset = KMCosePairTagType.getKeyStartOffset(keyPtr); if (!KMCosePairTagType.isKeyPairValid(heap, offset, KMCose.COSE_KEY_MAX_SIZE, - KMNInteger.cast(valuePtr).getShort())) { + KMNInteger.getShort(valuePtr))) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } short ptr = KMType.instance(COSE_PAIR_TAG_TYPE, (short) 6); diff --git a/Applet/src/com/android/javacard/keymaster/KMCosePairSimpleValueTag.java b/Applet/src/com/android/javacard/kmdevice/KMCosePairSimpleValueTag.java similarity index 94% rename from Applet/src/com/android/javacard/keymaster/KMCosePairSimpleValueTag.java rename to Applet/src/com/android/javacard/kmdevice/KMCosePairSimpleValueTag.java index 6aea5e30..454be097 100644 --- a/Applet/src/com/android/javacard/keymaster/KMCosePairSimpleValueTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCosePairSimpleValueTag.java @@ -1,4 +1,4 @@ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -35,7 +35,7 @@ public static short exp() { public static short instance(short keyPtr, short valuePtr) { short offset = KMCosePairTagType.getKeyStartOffset(keyPtr); if (!KMCosePairTagType.isKeyPairValid(heap, offset, KMCose.COSE_KEY_MAX_SIZE, - KMSimpleValue.cast(valuePtr).getValue())) { + KMSimpleValue.getValue(valuePtr))) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } short ptr = KMType.instance(COSE_PAIR_TAG_TYPE, (short) 6); @@ -52,7 +52,7 @@ public static KMCosePairSimpleValueTag cast(short ptr) { } // Validate the value pointer. short valuePtr = Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE + 4)); - if (KMType.getType(valuePtr) != SIMPLE_VALUE_TYPE) { + if (KMType.getKMType(valuePtr) != SIMPLE_VALUE_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } return proto(ptr); diff --git a/Applet/src/com/android/javacard/keymaster/KMCosePairTagType.java b/Applet/src/com/android/javacard/kmdevice/KMCosePairTagType.java similarity index 90% rename from Applet/src/com/android/javacard/keymaster/KMCosePairTagType.java rename to Applet/src/com/android/javacard/kmdevice/KMCosePairTagType.java index 053fc633..2f5b99db 100644 --- a/Applet/src/com/android/javacard/keymaster/KMCosePairTagType.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCosePairTagType.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -126,12 +126,12 @@ private static boolean isEqual(byte[] key1, short offset1, short length1, byte[] * @return value of the key as short. */ public static short getKeyValueShort(short keyPtr) { - short type = KMType.getType(keyPtr); + short type = KMType.getKMType(keyPtr); short value = 0; if (type == INTEGER_TYPE) { - value = KMInteger.cast(keyPtr).getShort(); + value = KMInteger.getShort(keyPtr); } else if (type == NEG_INTEGER_TYPE) { - value = KMNInteger.cast(keyPtr).getShort(); + value = KMNInteger.getShort(keyPtr); } else { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -145,12 +145,12 @@ public static short getKeyValueShort(short keyPtr) { * @return value of the key as short. */ public static short getKeyValueSignificantShort(short keyPtr) { - short type = KMType.getType(keyPtr); + short type = KMType.getKMType(keyPtr); short value = 0; if (type == INTEGER_TYPE) { - value = KMInteger.cast(keyPtr).getSignificantShort(); + value = KMInteger.getSignificantShort(keyPtr); } else if (type == NEG_INTEGER_TYPE) { - value = KMNInteger.cast(keyPtr).getSignificantShort(); + value = KMNInteger.getSignificantShort(keyPtr); } else { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -158,11 +158,11 @@ public static short getKeyValueSignificantShort(short keyPtr) { } public static void getKeyValue(short keyPtr, byte[] dest, short offset, short len) { - short type = KMType.getType(keyPtr); + short type = KMType.getKMType(keyPtr); if (type == INTEGER_TYPE) { - KMInteger.cast(keyPtr).getValue(dest, offset, len); + KMInteger.getValue(keyPtr, dest, offset, len); } else if (type == NEG_INTEGER_TYPE) { - KMNInteger.cast(keyPtr).getValue(dest, offset, len); + KMNInteger.getValue(keyPtr, dest, offset, len); } else { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -175,12 +175,12 @@ public static void getKeyValue(short keyPtr, byte[] dest, short offset, short le * @return offset from where the key starts. */ public static short getKeyStartOffset(short keyPtr) { - short type = KMType.getType(keyPtr); + short type = KMType.getKMType(keyPtr); short offset = 0; if (type == INTEGER_TYPE) { - offset = KMInteger.cast(keyPtr).getStartOff(); + offset = KMInteger.getStartOff(keyPtr); } else if (type == NEG_INTEGER_TYPE) { - offset = KMNInteger.cast(keyPtr).getStartOff(); + offset = KMNInteger.getStartOff(keyPtr); } else { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -194,12 +194,12 @@ public static short getKeyStartOffset(short keyPtr) { * @return length of the key. */ public static short getKeyLength(short keyPtr) { - short type = KMType.getType(keyPtr); + short type = KMType.getKMType(keyPtr); short len = 0; if (type == INTEGER_TYPE) { - len = KMInteger.cast(keyPtr).length(); + len = KMInteger.length(keyPtr); } else if (type == NEG_INTEGER_TYPE) { - len = KMNInteger.cast(keyPtr).length(); + len = KMNInteger.length(keyPtr); } else { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } diff --git a/Applet/src/com/android/javacard/keymaster/KMCosePairTextStringTag.java b/Applet/src/com/android/javacard/kmdevice/KMCosePairTextStringTag.java similarity index 90% rename from Applet/src/com/android/javacard/keymaster/KMCosePairTextStringTag.java rename to Applet/src/com/android/javacard/kmdevice/KMCosePairTextStringTag.java index 165e3d15..bfee89bf 100644 --- a/Applet/src/com/android/javacard/keymaster/KMCosePairTextStringTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCosePairTextStringTag.java @@ -1,4 +1,4 @@ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -12,11 +12,15 @@ public class KMCosePairTextStringTag extends KMCosePairTagType { private static KMCosePairTextStringTag prototype; - public static final byte[] keys = { - KMCose.ISSUER, - KMCose.SUBJECT, - }; + public static byte[] keys; + public static void initStatics() { + keys = new byte[]{ + KMCose.ISSUER, + KMCose.SUBJECT, + }; + } + private KMCosePairTextStringTag() { } @@ -41,7 +45,7 @@ public static short instance(short keyPtr, short valuePtr) { if (!isKeyValueValid(KMCosePairTagType.getKeyValueShort(keyPtr))) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } - if (KMType.getType(valuePtr) != TEXT_STRING_TYPE) { + if (KMType.getKMType(valuePtr) != TEXT_STRING_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } short ptr = KMType.instance(COSE_PAIR_TAG_TYPE, (short) 6); @@ -58,7 +62,7 @@ public static KMCosePairTextStringTag cast(short ptr) { } // Validate the value pointer. short valuePtr = Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE + 4)); - if (KMType.getType(valuePtr) != TEXT_STRING_TYPE) { + if (KMType.getKMType(valuePtr) != TEXT_STRING_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } return proto(ptr); diff --git a/Applet/src/com/android/javacard/keymaster/KMDecoder.java b/Applet/src/com/android/javacard/kmdevice/KMDecoder.java similarity index 89% rename from Applet/src/com/android/javacard/keymaster/KMDecoder.java rename to Applet/src/com/android/javacard/kmdevice/KMDecoder.java index 923a93e4..b37740e7 100644 --- a/Applet/src/com/android/javacard/keymaster/KMDecoder.java +++ b/Applet/src/com/android/javacard/kmdevice/KMDecoder.java @@ -14,9 +14,8 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; -import com.android.javacard.seprovider.KMException; import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.JCSystem; @@ -70,7 +69,7 @@ public short decodeArray(short exp, byte[] buffer, short startOff, short length) scratchBuf[START_OFFSET] = startOff; scratchBuf[LEN_OFFSET] = (short) (startOff + length); short payloadLength = readMajorTypeWithPayloadLength(ARRAY_TYPE); - short expLength = KMArray.cast(exp).length(); + short expLength = KMArray.length(exp); if (payloadLength > expLength) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } @@ -79,16 +78,16 @@ public short decodeArray(short exp, byte[] buffer, short startOff, short length) short type; short arrPtr = KMArray.instance(payloadLength); while (index < payloadLength) { - type = KMArray.cast(exp).get(index); + type = KMArray.get(exp, index); obj = decode(type); - KMArray.cast(arrPtr).add(index, obj); + KMArray.add(arrPtr, index, obj); index++; } return arrPtr; } private short decode(short exp) { - byte type = KMType.getType(exp); + byte type = KMType.getKMType(exp); switch (type) { case KMType.BYTE_BLOB_TYPE: return decodeByteBlob(exp); @@ -124,7 +123,7 @@ private short decode(short exp) { short tagValueType = KMCosePairTagType.getTagValueType(exp); return decodeCosePairTag(tagValueType, exp); case KMType.TAG_TYPE: - short tagType = KMTag.getTagType(exp); + short tagType = KMTag.getKMTagType(exp); return decodeTag(tagType, exp); default: ISOException.throwIt(ISO7816.SW_DATA_INVALID); @@ -158,22 +157,22 @@ private short decodeTag(short tagType, short exp) { } private short decodeVerificationToken(short exp) { - short vals = decode(KMVerificationToken.cast(exp).getVals()); + short vals = decode(KMVerificationToken.getVals(exp)); return KMVerificationToken.instance(vals); } private short decodeHwAuthToken(short exp) { - short vals = decode(KMHardwareAuthToken.cast(exp).getVals()); + short vals = decode(KMHardwareAuthToken.getVals(exp)); return KMHardwareAuthToken.instance(vals); } private short decodeHmacSharingParam(short exp) { - short vals = decode(KMHmacSharingParameters.cast(exp).getVals()); + short vals = decode(KMHmacSharingParameters.getVals(exp)); return KMHmacSharingParameters.instance(vals); } private short decodeKeyChar(short exp) { - short vals = decode(KMKeyCharacteristics.cast(exp).getVals()); + short vals = decode(KMKeyCharacteristics.getVals(exp)); return KMKeyCharacteristics.instance(vals); } @@ -295,7 +294,7 @@ private short decodeCoseMap(short exp) { // get allowed key pairs short allowedKeyPairs = KMCoseMap.getVals(exp); short vals = KMArray.instance(payloadLength); - short length = KMArray.cast(allowedKeyPairs).length(); + short length = KMArray.length(allowedKeyPairs); short index = 0; boolean tagFound; short tagInd; @@ -311,11 +310,11 @@ private short decodeCoseMap(short exp) { cosePairTagType = peekCosePairTagType(); // Check against the allowed tags ... while (tagInd < length) { - tagClass = KMArray.cast(allowedKeyPairs).get(tagInd); + tagClass = KMArray.get(allowedKeyPairs, tagInd); allowedType = KMCosePairTagType.getTagValueType(tagClass); if (allowedType == cosePairTagType) { obj = decode(tagClass); - KMArray.cast(vals).add(index, obj); + KMArray.add(vals, index, obj); tagFound = true; break; } @@ -333,11 +332,11 @@ private short decodeCoseMap(short exp) { private short decodeKeyParam(short exp) { short payloadLength = readMajorTypeWithPayloadLength(MAP_TYPE); // allowed tags - short allowedTags = KMKeyParameters.cast(exp).getVals(); - short tagRule = KMArray.cast(allowedTags).get((short)0); - boolean ignoreInvalidTags = KMEnum.cast(tagRule).getVal() == KMType.IGNORE_INVALID_TAGS; + short allowedTags = KMKeyParameters.getVals(exp); + short tagRule = KMArray.get(allowedTags, (short)0); + boolean ignoreInvalidTags = KMEnum.getVal(tagRule) == KMType.IGNORE_INVALID_TAGS; short vals = KMArray.instance(payloadLength); - short length = KMArray.cast(allowedTags).length(); + short length = KMArray.length(allowedTags); short index = 0; boolean tagFound; short tagInd; @@ -352,15 +351,15 @@ private short decodeKeyParam(short exp) { tagType = peekTagType(); // Check against the allowed tags ... while (tagInd < length) { - tagClass = KMArray.cast(allowedTags).get(tagInd); - allowedType = KMTag.getTagType(tagClass); + tagClass = KMArray.get(allowedTags, tagInd); + allowedType = KMTag.getKMTagType(tagClass); // If it is part of allowed tags ... if (tagType == allowedType) { // then decodeByteBlob and add that to the array. try { tagFound = true; obj = decode(tagClass); - KMArray.cast(vals).add(index, obj); + KMArray.add(vals, index, obj); break; }catch(KMException e){ if(KMException.reason() == KMError.INVALID_TAG && @@ -381,34 +380,34 @@ private short decodeKeyParam(short exp) { } private short decodeEnumArrayTag(short exp) { - readTagKey(KMEnumArrayTag.cast(exp).getTagType()); - return KMEnumArrayTag.instance(scratchBuf[TAG_KEY_OFFSET], decode(KMEnumArrayTag.cast(exp).getValues())); + readTagKey(KMEnumArrayTag.getTagType(exp)); + return KMEnumArrayTag.instance(scratchBuf[TAG_KEY_OFFSET], decode(KMEnumArrayTag.getValues(exp))); } private short decodeIntegerArrayTag(short exp) { - readTagKey(KMIntegerArrayTag.cast(exp).getTagType()); + readTagKey(KMIntegerArrayTag.getTagType(exp)); // the values are array of integers. - return KMIntegerArrayTag.instance(KMIntegerArrayTag.cast(exp).getTagType(), - scratchBuf[TAG_KEY_OFFSET], decode(KMIntegerArrayTag.cast(exp).getValues())); + return KMIntegerArrayTag.instance(KMIntegerArrayTag.getTagType(exp), + scratchBuf[TAG_KEY_OFFSET], decode(KMIntegerArrayTag.getValues(exp))); } private short decodeIntegerTag(short exp) { - readTagKey(KMIntegerTag.cast(exp).getTagType()); + readTagKey(KMIntegerTag.getTagType(exp)); // the value is an integer - return KMIntegerTag.instance(KMIntegerTag.cast(exp).getTagType(), - scratchBuf[TAG_KEY_OFFSET], decode(KMIntegerTag.cast(exp).getValue())); + return KMIntegerTag.instance(KMIntegerTag.getTagType(exp), + scratchBuf[TAG_KEY_OFFSET], decode(KMIntegerTag.getValue(exp))); } private short decodeBytesTag(short exp) { - readTagKey(KMByteTag.cast(exp).getTagType()); + readTagKey(KMByteTag.getTagType(exp)); // The value must be byte blob - return KMByteTag.instance(scratchBuf[TAG_KEY_OFFSET], decode(KMByteTag.cast(exp).getValue())); + return KMByteTag.instance(scratchBuf[TAG_KEY_OFFSET], decode(KMByteTag.getValue(exp))); } private short decodeBignumTag(short exp) { - readTagKey(KMBignumTag.cast(exp).getTagType()); + readTagKey(KMBignumTag.getTagType(exp)); // The value must be byte blob - return KMBignumTag.instance(scratchBuf[TAG_KEY_OFFSET], decode(KMBignumTag.cast(exp).getValue())); + return KMBignumTag.instance(scratchBuf[TAG_KEY_OFFSET], decode(KMBignumTag.getValue(exp))); } private short decodeMap(short exp) { @@ -419,11 +418,11 @@ private short decodeMap(short exp) { short keyobj; short valueobj; while (index < payloadLength) { - type = KMMap.cast(exp).getKey(index); + type = KMMap.getKey(exp, index); keyobj = decode(type); - type = KMMap.cast(exp).getKeyValue(index); + type = KMMap.getKeyValue(exp, index); valueobj = decode(type); - KMMap.cast(mapPtr).add(index, keyobj, valueobj); + KMMap.add(mapPtr, index, keyobj, valueobj); index++; } return mapPtr; @@ -436,23 +435,23 @@ private short decodeArray(short exp) { short type; short obj; // check whether array contains one type of objects or multiple types - if (KMArray.cast(exp).containedType() == 0) {// multiple types specified by expression. - if (KMArray.cast(exp).length() != KMArray.ANY_ARRAY_LENGTH) { - if (KMArray.cast(exp).length() != payloadLength) { + if (KMArray.containedType(exp) == 0) {// multiple types specified by expression. + if (KMArray.length(exp) != KMArray.ANY_ARRAY_LENGTH) { + if (KMArray.length(exp) != payloadLength) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } } while (index < payloadLength) { - type = KMArray.cast(exp).get(index); + type = KMArray.get(exp, index); obj = decode(type); - KMArray.cast(arrPtr).add(index, obj); + KMArray.add(arrPtr, index, obj); index++; } } else { // Array is a Vector containing objects of one type - type = KMArray.cast(exp).containedType(); + type = KMArray.containedType(exp); while (index < payloadLength) { obj = decode(type); - KMArray.cast(arrPtr).add(index, obj); + KMArray.add(arrPtr, index, obj); index++; } } @@ -460,7 +459,7 @@ private short decodeArray(short exp) { } private short decodeEnumTag(short exp) { - readTagKey(KMEnumTag.cast(exp).getTagType()); + readTagKey(KMEnumTag.getTagType(exp)); byte[] buffer = (byte[]) bufferRef[0]; short startOff = scratchBuf[START_OFFSET]; // Enum Tag value will always be integer with max 1 byte length. @@ -487,7 +486,7 @@ private short decodeEnumTag(short exp) { } private short decodeBoolTag(short exp) { - readTagKey(KMBoolTag.cast(exp).getTagType()); + readTagKey(KMBoolTag.getTagType(exp)); 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. @@ -524,11 +523,10 @@ private short decodeEnum(short exp) { enumVal = buffer[startOff]; incrementStartOff((short) 1); } - return KMEnum.instance(KMEnum.cast(exp).getEnumType(), enumVal); + return KMEnum.instance(KMEnum.getEnumType(exp), enumVal); } private short decodeSimpleValue(short exp) { - short inst; short startOff = scratchBuf[START_OFFSET]; byte[] buffer = (byte[]) bufferRef[0]; if ((buffer[startOff] & MAJOR_TYPE_MASK) != SIMPLE_VALUE_TYPE) { @@ -599,8 +597,8 @@ private short decodeNegIntegerValue(byte addInfo, byte[] buf, short startOffset) // Do (-1 - N), as per cbor negative integer decoding rule. // N is the integer value. scratchpad = KMByteBlob.instance((short) (len * 3)); - byte[] input = KMByteBlob.cast(scratchpad).getBuffer(); - short offset = KMByteBlob.cast(scratchpad).getStartOff(); + byte[] input = KMByteBlob.getBuffer(scratchpad); + short offset = KMByteBlob.getStartOff(scratchpad); Util.arrayFillNonAtomic(input, offset, len, (byte) -1); Util.arrayCopyNonAtomic(buf, startOffset, input, (short) (offset + len), len); KMUtils.subtract(input, offset, (short) (offset + len), (short) (offset + 2 * len), (byte) len); diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMDeviceUniqueKey.java b/Applet/src/com/android/javacard/kmdevice/KMDeviceUniqueKey.java similarity index 94% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMDeviceUniqueKey.java rename to Applet/src/com/android/javacard/kmdevice/KMDeviceUniqueKey.java index 08e60a3f..517a5b06 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMDeviceUniqueKey.java +++ b/Applet/src/com/android/javacard/kmdevice/KMDeviceUniqueKey.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.javacard.seprovider; +package com.android.javacard.kmdevice; public interface KMDeviceUniqueKey { diff --git a/Applet/src/com/android/javacard/keymaster/KMEncoder.java b/Applet/src/com/android/javacard/kmdevice/KMEncoder.java similarity index 86% rename from Applet/src/com/android/javacard/keymaster/KMEncoder.java rename to Applet/src/com/android/javacard/kmdevice/KMEncoder.java index bc5cbdd6..39f6fa7a 100644 --- a/Applet/src/com/android/javacard/keymaster/KMEncoder.java +++ b/Applet/src/com/android/javacard/kmdevice/KMEncoder.java @@ -14,9 +14,8 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; -import com.android.javacard.seprovider.KMException; import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.JCSystem; @@ -82,8 +81,8 @@ public short encode(short object, byte[] buffer, short startOff) { bufferRef[0] = buffer; scratchBuf[START_OFFSET] = startOff; short len = (short) (buffer.length - startOff); - if ((len < 0) || len > KMKeymasterApplet.MAX_LENGTH) { - scratchBuf[LEN_OFFSET] = KMKeymasterApplet.MAX_LENGTH; + if ((len < 0) || len > KMKeymasterDevice.MAX_LENGTH) { + scratchBuf[LEN_OFFSET] = KMKeymasterDevice.MAX_LENGTH; } else { scratchBuf[LEN_OFFSET] = (short) buffer.length; } @@ -145,7 +144,7 @@ public short encodeError(short errInt32Ptr, byte[] buffer, short startOff, short private void encode() { while (scratchBuf[STACK_PTR_OFFSET] > 0) { short exp = pop(); - byte type = KMType.getType(exp); + byte type = KMType.getKMType(exp); switch (type) { case KMType.BYTE_BLOB_TYPE: encodeByteBlob(exp); @@ -192,7 +191,7 @@ private void encode() { encodeHwAuthToken(exp); break; case KMType.TAG_TYPE: - short tagType = KMTag.getTagType(exp); + short tagType = KMTag.getKMTagType(exp); encodeTag(tagType, exp); break; case KMType.COSE_PAIR_TAG_TYPE: @@ -305,32 +304,32 @@ private void encodeCoseMap(short obj) { } private void encodeKeyParam(short obj) { - encodeAsMap(KMKeyParameters.cast(obj).getVals()); + encodeAsMap(KMKeyParameters.getVals(obj)); } private void encodeKeyChar(short obj) { - encode(KMKeyCharacteristics.cast(obj).getVals()); + encode(KMKeyCharacteristics.getVals(obj)); } private void encodeVeriToken(short obj) { - encode(KMVerificationToken.cast(obj).getVals()); + encode(KMVerificationToken.getVals(obj)); } private void encodeHwAuthToken(short obj) { - encode(KMHardwareAuthToken.cast(obj).getVals()); + encode(KMHardwareAuthToken.getVals(obj)); } private void encodeHmacSharingParam(short obj) { - encode(KMHmacSharingParameters.cast(obj).getVals()); + encode(KMHmacSharingParameters.getVals(obj)); } private void encodeArray(short obj) { - writeMajorTypeWithLength(ARRAY_TYPE, KMArray.cast(obj).length()); - short len = KMArray.cast(obj).length(); + writeMajorTypeWithLength(ARRAY_TYPE, KMArray.length(obj)); + short len = KMArray.length(obj); short index = (short) (len - 1); short subObj; while (index >= 0) { - subObj = KMArray.cast(obj).get(index); + subObj = KMArray.get(obj, index); if (subObj != KMType.INVALID_VALUE) encode(subObj); index--; @@ -345,60 +344,60 @@ public void encodeArrayOnlyLength(short arrLength, byte[] buffer, short offset, } private void encodeMap(short obj) { - writeMajorTypeWithLength(MAP_TYPE, KMMap.cast(obj).length()); - short len = KMMap.cast(obj).length(); + writeMajorTypeWithLength(MAP_TYPE, KMMap.length(obj)); + short len = KMMap.length(obj); short index = (short) (len - 1); while (index >= 0) { - encode(KMMap.cast(obj).getKeyValue(index)); - encode(KMMap.cast(obj).getKey(index)); + encode(KMMap.getKeyValue(obj, index)); + encode(KMMap.getKey(obj, index)); index--; } } private void encodeAsMap(short obj) { - writeMajorTypeWithLength(MAP_TYPE, KMArray.cast(obj).length()); - short len = KMArray.cast(obj).length(); + writeMajorTypeWithLength(MAP_TYPE, KMArray.length(obj)); + short len = KMArray.length(obj); short index = (short) (len - 1); short inst; while (index >= 0) { - inst = KMArray.cast(obj).get(index); + inst = KMArray.get(obj, index); encode(inst); index--; } } private void encodeIntegerArrayTag(short obj) { - writeTag(KMIntegerArrayTag.cast(obj).getTagType(), KMIntegerArrayTag.cast(obj).getKey()); - encode(KMIntegerArrayTag.cast(obj).getValues()); + writeTag(KMIntegerArrayTag.getTagType(obj), KMIntegerArrayTag.getKey(obj)); + encode(KMIntegerArrayTag.getValues(obj)); } private void encodeEnumArrayTag(short obj) { - writeTag(KMEnumArrayTag.cast(obj).getTagType(), KMEnumArrayTag.cast(obj).getKey()); - encode(KMEnumArrayTag.cast(obj).getValues()); + writeTag(KMEnumArrayTag.getTagType(obj), KMEnumArrayTag.getKey(obj)); + encode(KMEnumArrayTag.getValues(obj)); } private void encodeIntegerTag(short obj) { - writeTag(KMIntegerTag.cast(obj).getTagType(), KMIntegerTag.cast(obj).getKey()); - encode(KMIntegerTag.cast(obj).getValue()); + writeTag(KMIntegerTag.getTagType(obj), KMIntegerTag.getKey(obj)); + encode(KMIntegerTag.getValue(obj)); } private void encodeBytesTag(short obj) { - writeTag(KMByteTag.cast(obj).getTagType(), KMByteTag.cast(obj).getKey()); - encode(KMByteTag.cast(obj).getValue()); + writeTag(KMByteTag.getTagType(obj), KMByteTag.getKey(obj)); + encode(KMByteTag.getValue(obj)); } private void encodeBoolTag(short obj) { - writeTag(KMBoolTag.cast(obj).getTagType(), KMBoolTag.cast(obj).getKey()); - writeByteValue(KMBoolTag.cast(obj).getVal()); + writeTag(KMBoolTag.getTagType(obj), KMBoolTag.getKey(obj)); + writeByteValue(KMBoolTag.getVal(obj)); } private void encodeEnumTag(short obj) { - writeTag(KMEnumTag.cast(obj).getTagType(), KMEnumTag.cast(obj).getKey()); - writeByteValue(KMEnumTag.cast(obj).getValue()); + writeTag(KMEnumTag.getTagType(obj), KMEnumTag.getKey(obj)); + writeByteValue(KMEnumTag.getValue(obj)); } private void encodeEnum(short obj) { - writeByteValue(KMEnum.cast(obj).getVal()); + writeByteValue(KMEnum.getVal(obj)); } private void encodeInteger(byte[] val, short len, short startOff, short majorType) { @@ -488,30 +487,30 @@ public void removeNegIntegerEncodingRule(byte[] buf, short offset, short len, sh } private void encodeNegInteger(short obj) { - byte[] val = KMNInteger.cast(obj).getBuffer(); - short len = KMNInteger.cast(obj).length(); - short startOff = KMNInteger.cast(obj).getStartOff(); + byte[] val = KMNInteger.getBuffer(obj); + short len = KMNInteger.length(obj); + short startOff = KMNInteger.getStartOff(obj); short msbIndex = applyNegIntegerEncodingRule(val, startOff, len); encodeInteger(val, len, startOff, NEG_INT_TYPE); removeNegIntegerEncodingRule(val, startOff, len, msbIndex); } private void encodeUnsignedInteger(short obj) { - byte[] val = KMInteger.cast(obj).getBuffer(); - short len = KMInteger.cast(obj).length(); - short startOff = KMInteger.cast(obj).getStartOff(); + byte[] val = KMInteger.getBuffer(obj); + short len = KMInteger.length(obj); + short startOff = KMInteger.getStartOff(obj); encodeInteger(val, len, startOff, UINT_TYPE); } private void encodeSimpleValue(short obj) { - byte value = KMSimpleValue.cast(obj).getValue(); + byte value = KMSimpleValue.getValue(obj); writeByte((byte) (SIMPLE_VALUE_TYPE | value)); } private void encodeTextString(short obj) { - writeMajorTypeWithLength(TSTR_TYPE, KMTextString.cast(obj).length()); - writeBytes(KMTextString.cast(obj).getBuffer(), KMTextString.cast(obj).getStartOff(), - KMTextString.cast(obj).length()); + writeMajorTypeWithLength(TSTR_TYPE, KMTextString.length(obj)); + writeBytes(KMTextString.getBuffer(obj), KMTextString.getStartOff(obj), + KMTextString.length(obj)); } public short encodeByteBlobHeader(short bufLen, byte[] buffer, short startOff, short length) { @@ -523,14 +522,14 @@ public short encodeByteBlobHeader(short bufLen, byte[] buffer, short startOff, s } private void encodeByteBlob(short obj) { - writeMajorTypeWithLength(BYTES_TYPE, KMByteBlob.cast(obj).length()); - writeBytes(KMByteBlob.cast(obj).getBuffer(), KMByteBlob.cast(obj).getStartOff(), - KMByteBlob.cast(obj).length()); + writeMajorTypeWithLength(BYTES_TYPE, KMByteBlob.length(obj)); + writeBytes(KMByteBlob.getBuffer(obj), KMByteBlob.getStartOff(obj), + KMByteBlob.length(obj)); } public short getEncodedLength(short ptr) { short len = 0; - short type = KMType.getType(ptr); + short type = KMType.getKMType(ptr); switch (type) { case KMType.BYTE_BLOB_TYPE: len += getEncodedByteBlobLength(ptr); @@ -605,24 +604,24 @@ private short getEncodedCosePairTagLen(short tagType, short exp) { } private short getEncodedMapLen(short obj) { - short mapLen = KMMap.cast(obj).length(); + short mapLen = KMMap.length(obj); short len = getEncodedBytesLength(mapLen); short index = 0; while (index < mapLen) { - len += getEncodedLength(KMMap.cast(obj).getKey(index)); - len += getEncodedLength(KMMap.cast(obj).getKeyValue(index)); + len += getEncodedLength(KMMap.getKey(obj, index)); + len += getEncodedLength(KMMap.getKeyValue(obj, index)); index++; } return len; } private short getEncodedArrayLen(short obj) { - short arrLen = KMArray.cast(obj).length(); + short arrLen = KMArray.length(obj); short len = getEncodedBytesLength(arrLen); short index = 0; short subObj; while (index < arrLen) { - subObj = KMArray.cast(obj).get(index); + subObj = KMArray.get(obj, index); if (subObj != KMType.INVALID_VALUE) len += getEncodedLength(subObj); index++; @@ -645,21 +644,21 @@ private short getEncodedBytesLength(short len) { } private short getEncodedByteBlobLength(short obj) { - short len = KMByteBlob.cast(obj).length(); + short len = KMByteBlob.length(obj); len += getEncodedBytesLength(len); return len; } private short getEncodedTextStringLength(short obj) { - short len = KMTextString.cast(obj).length(); - len += getEncodedBytesLength(len); - return len; + //short len = KMTextString.byteBlobLength(obj); + //len += getEncodedBytesLength(len); + return 0;//len; } private short getEncodedNegIntegerLength(short obj) { - byte[] buf = KMNInteger.cast(obj).getBuffer(); - short len = KMNInteger.cast(obj).length(); - short offset = KMNInteger.cast(obj).getStartOff(); + byte[] buf = KMNInteger.getBuffer(obj); + short len = KMNInteger.length(obj); + short offset = KMNInteger.getStartOff(obj); short msbIndex = applyNegIntegerEncodingRule(buf, offset, len); short ret = getEncodedIntegerLength(buf, offset, len); removeNegIntegerEncodingRule(buf, offset, len, msbIndex); @@ -691,9 +690,9 @@ private short getEncodedIntegerLength(byte[] val, short startOff, short len) { } private short getEncodedIntegerLength(short obj) { - byte[] val = KMInteger.cast(obj).getBuffer(); - short len = KMInteger.cast(obj).length(); - short startOff = KMInteger.cast(obj).getStartOff(); + byte[] val = KMInteger.getBuffer(obj); + short len = KMInteger.length(obj); + short startOff = KMInteger.getStartOff(obj); return getEncodedIntegerLength(val, startOff, len); } diff --git a/Applet/src/com/android/javacard/keymaster/KMEnum.java b/Applet/src/com/android/javacard/kmdevice/KMEnum.java similarity index 85% rename from Applet/src/com/android/javacard/keymaster/KMEnum.java rename to Applet/src/com/android/javacard/kmdevice/KMEnum.java index 1cfe5803..d327dad8 100644 --- a/Applet/src/com/android/javacard/keymaster/KMEnum.java +++ b/Applet/src/com/android/javacard/kmdevice/KMEnum.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -30,23 +30,27 @@ public class KMEnum extends KMType { private static KMEnum prototype; // 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, - RULE - }; + private static short[] types; private static Object[] enums = null; private KMEnum() { } - + + public static void initStatics() { + types = new short[]{ + HARDWARE_TYPE, + KEY_FORMAT, + KEY_DERIVATION_FUNCTION, + VERIFIED_BOOT_STATE, + DEVICE_LOCKED, + USER_AUTH_TYPE, + PURPOSE, + ECCURVE, + RULE + }; + } + private static KMEnum proto(short ptr) { if (prototype == null) { prototype = new KMEnum(); @@ -64,14 +68,18 @@ public short length() { return Util.getShort(heap, (short) (KMType.instanceTable[KM_ENUM_OFFSET] + 1)); } - public static KMEnum cast(short ptr) { + private static KMEnum cast(short ptr) { + validate(ptr); + return proto(ptr); + } + + public static void validate(short ptr) { if (heap[ptr] != ENUM_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } if (Util.getShort(heap, (short) (ptr + 1)) == INVALID_VALUE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } - return proto(ptr); } public static short instance(short enumType) { @@ -164,4 +172,22 @@ private static boolean validateEnum(short key, byte value) { // return false if key does not exist return false; } + + public static void setVal(short bPtr, byte val) { + KMEnum.cast(bPtr).setVal(val); + } + + public static byte getVal(short bPtr) { + return KMEnum.cast(bPtr).getVal(); + } + + public static void setEnumType(short bPtr, short type) { + KMEnum.cast(bPtr).setEnumType(type); + } + + public static short getEnumType(short bPtr) { + return KMEnum.cast(bPtr).getEnumType(); + } + + } diff --git a/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java b/Applet/src/com/android/javacard/kmdevice/KMEnumArrayTag.java similarity index 85% rename from Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java rename to Applet/src/com/android/javacard/kmdevice/KMEnumArrayTag.java index 0f932a9d..e533b769 100644 --- a/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMEnumArrayTag.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -29,11 +29,15 @@ public class KMEnumArrayTag extends KMTag { private static KMEnumArrayTag prototype; // The allowed tag keys of enum array type. - private static short[] tags = {PURPOSE, BLOCK_MODE, DIGEST, PADDING, RSA_OAEP_MGF_DIGEST}; + private static short[] tags; // Tag Values. private static Object[] enums = null; + public static void initStatics() { + tags = new short[]{PURPOSE, BLOCK_MODE, DIGEST, PADDING, RSA_OAEP_MGF_DIGEST}; + } + private KMEnumArrayTag() { } @@ -69,15 +73,14 @@ public static short instance(short key, short byteBlob) { if (allowedVals == null) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } - KMByteBlob blob = KMByteBlob.cast(byteBlob); short byteIndex = 0; short enumIndex; boolean validValue; - while (byteIndex < blob.length()) { + while (byteIndex < KMByteBlob.length(byteBlob)) { enumIndex = 0; validValue = false; while (enumIndex < allowedVals.length) { - if (blob.get(byteIndex) == allowedVals[enumIndex]) { + if (KMByteBlob.get(byteBlob, byteIndex) == allowedVals[enumIndex]) { validValue = true; break; } @@ -95,7 +98,7 @@ public static short instance(short key, short byteBlob) { return ptr; } - public static KMEnumArrayTag cast(short ptr) { + private static KMEnumArrayTag cast(short ptr) { if (heap[ptr] != TAG_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -119,7 +122,7 @@ public short getValues() { public short length() { short blobPtr = Util.getShort(heap, (short) (KMType.instanceTable[KM_ENUM_ARRAY_TAG_OFFSET] + TLV_HEADER_SIZE + 4)); - return KMByteBlob.cast(blobPtr).length(); + return KMByteBlob.length(blobPtr); } public static void create() { @@ -151,20 +154,20 @@ private static byte[] getAllowedEnumValues(short key) { } public static short getValues(short tagId, short params, byte[] buf, short start) { - short tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, tagId, params); + short tag = KMKeyParameters.findTag(params, KMType.ENUM_ARRAY_TAG, tagId); if (tag == KMType.INVALID_VALUE) { return KMType.INVALID_VALUE; } tag = KMEnumArrayTag.cast(tag).getValues(); - return KMByteBlob.cast(tag).getValues(buf, start); + return KMByteBlob.getValues(tag, buf, start); } public short get(short index) { - return KMByteBlob.cast(getValues()).get(index); + return KMByteBlob.get(getValues(), index); } public static boolean contains(short tagId, short tagValue, short params) { - short tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, tagId, params); + short tag = KMKeyParameters.findTag(params, KMType.ENUM_ARRAY_TAG, tagId); if (tag != KMType.INVALID_VALUE) { short index = 0; while (index < KMEnumArrayTag.cast(tag).length()) { @@ -178,7 +181,7 @@ public static boolean contains(short tagId, short tagValue, short params) { } public static short length(short tagId, short params) { - short tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, tagId, params); + short tag = KMKeyParameters.findTag(params, KMType.ENUM_ARRAY_TAG, tagId); if (tag != KMType.INVALID_VALUE) { return KMEnumArrayTag.cast(tag).length(); } @@ -300,4 +303,30 @@ public boolean isValidBlockMode(byte alg) { return false; } } + + public static short get(short bPtr, short index) { + return KMEnumArrayTag.cast(bPtr).get(index); + } + + public static short length(short bPtr) { + return KMEnumArrayTag.cast(bPtr).length(); + } + + public static short getValues(short bPtr) { + return KMEnumArrayTag.cast(bPtr).getValues(); + } + + public static short getTagType(short bPtr) { + return KMType.ENUM_ARRAY_TAG; + } + + public static short getKey(short bPtr) { + return KMEnumArrayTag.cast(bPtr).getKey(); + } + + public static boolean contains(short bPtr, short tagValue) { + return KMEnumArrayTag.cast(bPtr).contains(tagValue); + } + + } diff --git a/Applet/src/com/android/javacard/keymaster/KMEnumTag.java b/Applet/src/com/android/javacard/kmdevice/KMEnumTag.java similarity index 87% rename from Applet/src/com/android/javacard/keymaster/KMEnumTag.java rename to Applet/src/com/android/javacard/kmdevice/KMEnumTag.java index 3f45c304..5866295d 100644 --- a/Applet/src/com/android/javacard/keymaster/KMEnumTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMEnumTag.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -30,12 +30,16 @@ public class KMEnumTag extends KMTag { private static KMEnumTag prototype; // The allowed tag keys of type enum tag. - private static short[] tags = { - ALGORITHM, ECCURVE, BLOB_USAGE_REQ, USER_AUTH_TYPE, ORIGIN, HARDWARE_TYPE - }; + private static short[] tags; private static Object[] enums = null; + public static void initStatics() { + tags = new short[]{ + ALGORITHM, ECCURVE, BLOB_USAGE_REQ, USER_AUTH_TYPE, ORIGIN, HARDWARE_TYPE + }; + } + private KMEnumTag() { } @@ -75,7 +79,7 @@ public static short instance(short key, byte val) { return ptr; } - public static KMEnumTag cast(short ptr) { + private static KMEnumTag cast(short ptr) { if (heap[ptr] != TAG_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -144,10 +148,23 @@ private static boolean validateEnum(short key, byte value) { } public static short getValue(short tagKey, short keyParameters) { - short tagPtr = KMKeyParameters.findTag(KMType.ENUM_TAG, tagKey, keyParameters); + short tagPtr = KMKeyParameters.findTag(keyParameters, KMType.ENUM_TAG, tagKey); if (tagPtr != KMType.INVALID_VALUE) { return heap[(short) (tagPtr + TLV_HEADER_SIZE + 4)]; } return KMType.INVALID_VALUE; } + + public static byte getValue(short bPtr) { + return KMEnumTag.cast(bPtr).getValue(); + } + + public static short getTagType(short bPtr) { + return KMEnumTag.cast(bPtr).getTagType(); + } + + public static short getKey(short bPtr) { + return KMEnumTag.cast(bPtr).getKey(); + } + } diff --git a/Applet/src/com/android/javacard/keymaster/KMError.java b/Applet/src/com/android/javacard/kmdevice/KMError.java similarity index 99% rename from Applet/src/com/android/javacard/keymaster/KMError.java rename to Applet/src/com/android/javacard/kmdevice/KMError.java index ddc9493f..6351c377 100644 --- a/Applet/src/com/android/javacard/keymaster/KMError.java +++ b/Applet/src/com/android/javacard/kmdevice/KMError.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; /** * KMError includes all the error codes from android keymaster hal specifications. The values are diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMException.java b/Applet/src/com/android/javacard/kmdevice/KMException.java similarity index 97% rename from Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMException.java rename to Applet/src/com/android/javacard/kmdevice/KMException.java index c0b2431f..9c466343 100644 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMException.java +++ b/Applet/src/com/android/javacard/kmdevice/KMException.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.seprovider; +package com.android.javacard.kmdevice; import javacard.framework.JCSystem; diff --git a/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java b/Applet/src/com/android/javacard/kmdevice/KMHardwareAuthToken.java similarity index 52% rename from Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java rename to Applet/src/com/android/javacard/kmdevice/KMHardwareAuthToken.java index deb53cf6..76311a66 100644 --- a/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java +++ b/Applet/src/com/android/javacard/kmdevice/KMHardwareAuthToken.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -43,13 +43,12 @@ private KMHardwareAuthToken() { public static short exp() { short arrPtr = KMArray.instance((short) 6); - KMArray arr = KMArray.cast(arrPtr); - arr.add(CHALLENGE, KMInteger.exp()); - arr.add(USER_ID, KMInteger.exp()); - arr.add(AUTHENTICATOR_ID, KMInteger.exp()); - arr.add(HW_AUTHENTICATOR_TYPE, KMEnum.instance(KMType.USER_AUTH_TYPE)); - arr.add(TIMESTAMP, KMInteger.exp()); - arr.add(MAC, KMByteBlob.exp()); + KMArray.add(arrPtr, CHALLENGE, KMInteger.exp()); + KMArray.add(arrPtr, USER_ID, KMInteger.exp()); + KMArray.add(arrPtr, AUTHENTICATOR_ID, KMInteger.exp()); + KMArray.add(arrPtr, HW_AUTHENTICATOR_TYPE, KMEnum.instance(KMType.USER_AUTH_TYPE)); + KMArray.add(arrPtr, TIMESTAMP, KMInteger.exp()); + KMArray.add(arrPtr, MAC, KMByteBlob.exp()); return instance(arrPtr); } @@ -63,19 +62,17 @@ private static KMHardwareAuthToken proto(short ptr) { public static short instance() { short arrPtr = KMArray.instance((short) 6); - KMArray arr = KMArray.cast(arrPtr); - arr.add(CHALLENGE, KMInteger.uint_16((short) 0)); - arr.add(USER_ID, KMInteger.uint_16((short) 0)); - arr.add(AUTHENTICATOR_ID, KMInteger.uint_16((short) 0)); - arr.add(HW_AUTHENTICATOR_TYPE, KMEnum.instance(KMType.USER_AUTH_TYPE, KMType.USER_AUTH_NONE)); - arr.add(TIMESTAMP, KMInteger.uint_16((short) 0)); - arr.add(MAC, KMByteBlob.instance((short) 0)); + KMArray.add(arrPtr, CHALLENGE, KMInteger.uint_16((short) 0)); + KMArray.add(arrPtr, USER_ID, KMInteger.uint_16((short) 0)); + KMArray.add(arrPtr, AUTHENTICATOR_ID, KMInteger.uint_16((short) 0)); + KMArray.add(arrPtr, HW_AUTHENTICATOR_TYPE, KMEnum.instance(KMType.USER_AUTH_TYPE, KMType.USER_AUTH_NONE)); + KMArray.add(arrPtr, TIMESTAMP, KMInteger.uint_16((short) 0)); + KMArray.add(arrPtr, MAC, KMByteBlob.instance((short) 0)); return instance(arrPtr); } public static short instance(short vals) { - KMArray arr = KMArray.cast(vals); - if (arr.length() != 6) { + if (KMArray.length(vals) != 6) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } short ptr = KMType.instance(HW_AUTH_TOKEN_TYPE, (short) 2); @@ -83,7 +80,7 @@ public static short instance(short vals) { return ptr; } - public static KMHardwareAuthToken cast(short ptr) { + private static KMHardwareAuthToken cast(short ptr) { if (heap[ptr] != HW_AUTH_TOKEN_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -100,72 +97,128 @@ public short getVals() { public short length() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).length(); + return KMArray.length(arrPtr); } public short getChallenge() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).get(CHALLENGE); + return KMArray.get(arrPtr, CHALLENGE); } public void setChallenge(short vals) { - KMInteger.cast(vals); + KMInteger.validate(vals); short arrPtr = getVals(); - KMArray.cast(arrPtr).add(CHALLENGE, vals); + KMArray.add(arrPtr, CHALLENGE, vals); } public short getUserId() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).get(USER_ID); + return KMArray.get(arrPtr, USER_ID); } public void setUserId(short vals) { - KMInteger.cast(vals); + KMInteger.validate(vals); short arrPtr = getVals(); - KMArray.cast(arrPtr).add(USER_ID, vals); + KMArray.add(arrPtr, USER_ID, vals); } public short getAuthenticatorId() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).get(AUTHENTICATOR_ID); + return KMArray.get(arrPtr, AUTHENTICATOR_ID); } public void setAuthenticatorId(short vals) { - KMInteger.cast(vals); + KMInteger.validate(vals); short arrPtr = getVals(); - KMArray.cast(arrPtr).add(AUTHENTICATOR_ID, vals); + KMArray.add(arrPtr, AUTHENTICATOR_ID, vals); } public short getHwAuthenticatorType() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).get(HW_AUTHENTICATOR_TYPE); + return KMArray.get(arrPtr, HW_AUTHENTICATOR_TYPE); } public void setHwAuthenticatorType(short vals) { - KMEnum.cast(vals); + KMEnum.validate(vals); short arrPtr = getVals(); - KMArray.cast(arrPtr).add(HW_AUTHENTICATOR_TYPE, vals); + KMArray.add(arrPtr, HW_AUTHENTICATOR_TYPE, vals); } public short getTimestamp() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).get(TIMESTAMP); + return KMArray.get(arrPtr, TIMESTAMP); } public void setTimestamp(short vals) { - KMInteger.cast(vals); + KMInteger.validate(vals); short arrPtr = getVals(); - KMArray.cast(arrPtr).add(TIMESTAMP, vals); + KMArray.add(arrPtr, TIMESTAMP, vals); } public short getMac() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).get(MAC); + return KMArray.get(arrPtr, MAC); } public void setMac(short vals) { - KMByteBlob.cast(vals); + KMByteBlob.validate(vals); short arrPtr = getVals(); - KMArray.cast(arrPtr).add(MAC, vals); + KMArray.add(arrPtr, MAC, vals); } + + public static short getVals(short bPtr) { + return KMHardwareAuthToken.cast(bPtr).getVals(); + } + + public static short length(short bPtr) { + return KMHardwareAuthToken.cast(bPtr).length(); + } + + public static short getChallenge(short bPtr) { + return KMHardwareAuthToken.cast(bPtr).getChallenge(); + } + + public static void setChallenge(short bPtr, short vals) { + KMHardwareAuthToken.cast(bPtr).setChallenge(vals); + } + + public static short getUserId(short bPtr) { + return KMHardwareAuthToken.cast(bPtr).getUserId(); + } + + public static void setUserId(short bPtr, short vals) { + KMHardwareAuthToken.cast(bPtr).setUserId(vals); + } + + public static short getAuthenticatorId(short bPtr) { + return KMHardwareAuthToken.cast(bPtr).getAuthenticatorId(); + } + + public static void setAuthenticatorId(short bPtr, short vals) { + KMHardwareAuthToken.cast(bPtr).setAuthenticatorId(vals); + } + + public static short getHwAuthenticatorType(short bPtr) { + return KMHardwareAuthToken.cast(bPtr).getHwAuthenticatorType(); + } + + public static void setHwAuthenticatorType(short bPtr, short vals) { + KMHardwareAuthToken.cast(bPtr).setHwAuthenticatorType(vals); + } + + public static short getTimestamp(short bPtr) { + return KMHardwareAuthToken.cast(bPtr).getTimestamp(); + } + + public static void setTimestamp(short bPtr, short vals) { + KMHardwareAuthToken.cast(bPtr).setTimestamp(vals); + } + + public static short getMac(short bPtr) { + return KMHardwareAuthToken.cast(bPtr).getMac(); + } + + public static void setMac(short bPtr, short vals) { + KMHardwareAuthToken.cast(bPtr).setMac(vals); + } } diff --git a/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java b/Applet/src/com/android/javacard/kmdevice/KMHmacSharingParameters.java similarity index 71% rename from Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java rename to Applet/src/com/android/javacard/kmdevice/KMHmacSharingParameters.java index 49a14ebe..b1d53d69 100644 --- a/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java +++ b/Applet/src/com/android/javacard/kmdevice/KMHmacSharingParameters.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -38,9 +38,8 @@ private KMHmacSharingParameters() { public static short exp() { short arrPtr = KMArray.instance((short) 2); - KMArray arr = KMArray.cast(arrPtr); - arr.add(SEED, KMByteBlob.exp()); - arr.add(NONCE, KMByteBlob.exp()); + KMArray.add(arrPtr, SEED, KMByteBlob.exp()); + KMArray.add(arrPtr, NONCE, KMByteBlob.exp()); return instance(arrPtr); } @@ -59,14 +58,14 @@ public static short instance() { public static short instance(short vals) { short ptr = KMType.instance(HMAC_SHARING_PARAM_TYPE, (short) 2); - if (KMArray.cast(vals).length() != 2) { + if (KMArray.length(vals) != 2) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), vals); return ptr; } - public static KMHmacSharingParameters cast(short ptr) { + private static KMHmacSharingParameters cast(short ptr) { if (heap[ptr] != HMAC_SHARING_PARAM_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -83,28 +82,52 @@ public short getVals() { public short length() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).length(); + return KMArray.length(arrPtr); } public void setSeed(short vals) { - KMByteBlob.cast(vals); + KMByteBlob.validate(vals); short arrPtr = getVals(); - KMArray.cast(arrPtr).add(SEED, vals); + KMArray.add(arrPtr, SEED, vals); } public void setNonce(short vals) { - KMByteBlob.cast(vals); + KMByteBlob.validate(vals); short arrPtr = getVals(); - KMArray.cast(arrPtr).add(NONCE, vals); + KMArray.add(arrPtr, NONCE, vals); } public short getNonce() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).get(NONCE); + return KMArray.get(arrPtr, NONCE); } public short getSeed() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).get(SEED); + return KMArray.get(arrPtr, SEED); + } + + public static short getVals(short bPtr) { + return KMHmacSharingParameters.cast(bPtr).getVals(); + } + + public static short length(short bPtr) { + return KMHmacSharingParameters.cast(bPtr).length(); + } + + public static void setSeed(short bPtr, short vals) { + KMHmacSharingParameters.cast(bPtr).setSeed(vals); + } + + public static void setNonce(short bPtr, short vals) { + KMHmacSharingParameters.cast(bPtr).setNonce(vals); + } + + public static short getNonce(short bPtr) { + return KMHmacSharingParameters.cast(bPtr).getNonce(); + } + + public static short getSeed(short bPtr) { + return KMHmacSharingParameters.cast(bPtr).getSeed(); } } diff --git a/Applet/src/com/android/javacard/keymaster/KMInteger.java b/Applet/src/com/android/javacard/kmdevice/KMInteger.java similarity index 71% rename from Applet/src/com/android/javacard/keymaster/KMInteger.java rename to Applet/src/com/android/javacard/kmdevice/KMInteger.java index c9ed7a3a..7825ef81 100644 --- a/Applet/src/com/android/javacard/keymaster/KMInteger.java +++ b/Applet/src/com/android/javacard/kmdevice/KMInteger.java @@ -14,9 +14,8 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; -import com.android.javacard.seprovider.KMException; import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.Util; @@ -74,7 +73,12 @@ public static short instance(byte[] num, short srcOff, short length) { } } - public static KMInteger cast(short ptr) { + private static KMInteger cast(short ptr) { + validate(ptr); + return proto(ptr); + } + + public static void validate(short ptr) { byte[] heap = repository.getHeap(); if (heap[ptr] != INTEGER_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); @@ -82,9 +86,8 @@ public static KMInteger cast(short ptr) { if (Util.getShort(heap, (short) (ptr + 1)) == INVALID_VALUE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } - return proto(ptr); } - + // create integer and copy byte value public static short uint_8(byte num) { short ptr = instance(UINT_32); @@ -114,21 +117,21 @@ public static short uint_64(byte[] num, short offset) { } // Get the length of the integer - public short length() { + private short length() { return Util.getShort(heap, (short) (getBaseOffset() + 1)); } // Get the buffer pointer in which blob is contained. - public byte[] getBuffer() { + private byte[] getBuffer() { return heap; } // Get the start of value - public short getStartOff() { + private short getStartOff() { return (short) (getBaseOffset() + TLV_HEADER_SIZE); } - public void getValue(byte[] dest, short destOff, short length) { + private void getValue(byte[] dest, short destOff, short length) { if (length < length()) { KMException.throwIt(KMError.UNKNOWN_ERROR); } @@ -139,15 +142,15 @@ public void getValue(byte[] dest, short destOff, short length) { Util.arrayCopyNonAtomic(heap, getStartOff(), dest, destOff, length); } - public void setValue(byte[] src, short srcOff) { + private void setValue(byte[] src, short srcOff) { Util.arrayCopyNonAtomic(src, srcOff, heap, getStartOff(), length()); } - public short value(byte[] dest, short destOff) { + private short value(byte[] dest, short destOff) { Util.arrayCopyNonAtomic(heap, getStartOff(), dest, destOff, length()); return length(); } - public short toLittleEndian(byte[] dest, short destOff) { + private short toLittleEndian(byte[] dest, short destOff) { short index = (short) (length() - 1); while (index >= 0) { dest[destOff++] = heap[(short) (instanceTable[KM_INTEGER_OFFSET] + TLV_HEADER_SIZE + index)]; @@ -156,19 +159,19 @@ public short toLittleEndian(byte[] dest, short destOff) { return length(); } - public short getShort() { + protected short getShort() { return Util.getShort(heap, (short) (getStartOff() + 2)); } - public short getSignificantShort() { + private short getSignificantShort() { return Util.getShort(heap, getStartOff()); } - public byte getByte() { + private byte getByte() { return heap[(short) (getStartOff() + 3)]; } - public boolean isZero() { + private boolean isZero() { if (getShort() == 0 && getSignificantShort() == 0) { return true; } @@ -180,10 +183,10 @@ public static short compare(short num1, short num2) { short num2Buf = repository.alloc((short) 8); Util.arrayFillNonAtomic(repository.getHeap(), num1Buf, (short) 8, (byte) 0); Util.arrayFillNonAtomic(repository.getHeap(), num2Buf, (short) 8, (byte) 0); - short len = KMInteger.cast(num1).length(); - KMInteger.cast(num1).getValue(repository.getHeap(), (short) (num1Buf + (short) (8 - len)), len); - len = KMInteger.cast(num2).length(); - KMInteger.cast(num2).getValue(repository.getHeap(), (short) (num2Buf + (short) (8 - len)), len); + short len = KMInteger.length(num1); + KMInteger.getValue(num1, repository.getHeap(), (short) (num1Buf + (short) (8 - len)), len); + len = KMInteger.length(num2); + KMInteger.getValue(num2, repository.getHeap(), (short) (num2Buf + (short) (8 - len)), len); return KMInteger.unsignedByteArrayCompare( repository.getHeap(), num1Buf, repository.getHeap(), num2Buf, @@ -213,4 +216,51 @@ public static byte unsignedByteArrayCompare(byte[] a1, short offset1, byte[] a2, protected short getBaseOffset() { return instanceTable[KM_INTEGER_OFFSET]; } + + // Get the length of the integer + public static short length(short bPtr) { + return KMInteger.cast(bPtr).length(); + } + + // Get the buffer pointer in which blob is contained. + public static byte[] getBuffer(short bPtr) { + return KMInteger.cast(bPtr).getBuffer(); + } + + // Get the start of value + public static short getStartOff(short bPtr) { + return KMInteger.cast(bPtr).getStartOff(); + } + + public static void getValue(short bPtr, byte[] dest, short destOff, short length) { + KMInteger.cast(bPtr).getValue(dest, destOff, length); + } + + public static void setValue(short bPtr, byte[] src, short srcOff) { + KMInteger.cast(bPtr).setValue(src, srcOff); + } + + public static short value(short bPtr, byte[] dest, short destOff) { + return KMInteger.cast(bPtr).value(dest, destOff); + } + + public static short toLittleEndian(short bPtr, byte[] dest, short destOff) { + return KMInteger.cast(bPtr).toLittleEndian(dest, destOff); + } + + public static short getShort(short bPtr) { + return KMInteger.cast(bPtr).getShort(); + } + + public static short getSignificantShort(short bPtr) { + return KMInteger.cast(bPtr).getSignificantShort(); + } + + public static byte getByte(short bPtr) { + return KMInteger.cast(bPtr).getByte(); + } + + public static boolean isZero(short bPtr) { + return KMInteger.cast(bPtr).isZero(); + } } diff --git a/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java b/Applet/src/com/android/javacard/kmdevice/KMIntegerArrayTag.java similarity index 79% rename from Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java rename to Applet/src/com/android/javacard/kmdevice/KMIntegerArrayTag.java index e62ce9fe..04c729bf 100644 --- a/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMIntegerArrayTag.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -29,7 +29,11 @@ public class KMIntegerArrayTag extends KMTag { private static KMIntegerArrayTag prototype; - private static final short[] tags = {USER_SECURE_ID}; + private static short[] tags; + + public static void initStatics() { + tags = new short[]{USER_SECURE_ID}; + } private KMIntegerArrayTag() { } @@ -82,7 +86,7 @@ public static short instance(short tagType, short key, short arrObj) { return ptr; } - public static KMIntegerArrayTag cast(short ptr) { + private static KMIntegerArrayTag cast(short ptr) { if (heap[ptr] != TAG_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -107,17 +111,15 @@ public short getValues() { public short length() { short ptr = getValues(); - return KMArray.cast(ptr).length(); + return KMArray.length(ptr); } public void add(short index, short val) { - KMArray arr = KMArray.cast(getValues()); - arr.add(index, val); + KMArray.add(getValues(), index, val); } public short get(short index) { - KMArray arr = KMArray.cast(getValues()); - return arr.get(index); + return KMArray.get(getValues(), index); } private static boolean validateKey(short key) { @@ -136,12 +138,12 @@ 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(params, KMType.UINT_ARRAY_TAG, tagId); if (tag != KMType.INVALID_VALUE) { short index = 0; tag = KMIntegerArrayTag.cast(tag).getValues(); - while (index < KMArray.cast(tag).length()) { - if (KMInteger.compare(tagValue, KMArray.cast(tag).get(index)) == 0) { + while (index < KMArray.length(tag)) { + if (KMInteger.compare(tagValue, KMArray.get(tag, index)) == 0) { return true; } index++; @@ -160,4 +162,30 @@ public boolean contains(short tagValue) { } return false; } + + public static boolean contains(short bPtr, short tagValue) { + return KMIntegerArrayTag.cast(bPtr).contains(tagValue); + } + + public static short getValues(short bPtr) { + return KMIntegerArrayTag.cast(bPtr).getValues(); + } + + public static short get(short bPtr, short index) { + return KMIntegerArrayTag.cast(bPtr).get(index); + } + + public static short getTagType(short bPtr) { + return KMIntegerArrayTag.cast(bPtr).getTagType(); + } + + public static short getKey(short bPtr) { + return KMIntegerArrayTag.cast(bPtr).getKey(); + } + + public static short length(short bPtr) { + return KMIntegerArrayTag.cast(bPtr).length(); + } + + } diff --git a/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java b/Applet/src/com/android/javacard/kmdevice/KMIntegerTag.java similarity index 76% rename from Applet/src/com/android/javacard/keymaster/KMIntegerTag.java rename to Applet/src/com/android/javacard/kmdevice/KMIntegerTag.java index 5311cbd8..2c14f3da 100644 --- a/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMIntegerTag.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -30,33 +30,37 @@ public class KMIntegerTag extends KMTag { private static KMIntegerTag prototype; // 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, - CERTIFICATE_NOT_BEFORE, - CERTIFICATE_NOT_AFTER, - USAGE_COUNT_LIMIT, - // custom tag - AUTH_TIMEOUT_MILLIS, - }; - + private static short[] tags; + + public static void initStatics() { + tags = new short[]{ + // 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, + CERTIFICATE_NOT_BEFORE, + CERTIFICATE_NOT_AFTER, + USAGE_COUNT_LIMIT, + // custom tag + AUTH_TIMEOUT_MILLIS, + }; + } + private KMIntegerTag() { } @@ -108,7 +112,7 @@ public static short instance(short tagType, short key, short intObj) { return ptr; } - public static KMIntegerTag cast(short ptr) { + private static KMIntegerTag cast(short ptr) { if (heap[ptr] != TAG_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -132,8 +136,7 @@ public short getValue() { } public short length() { - KMInteger obj = KMInteger.cast(getValue()); - return obj.length(); + return KMInteger.length(getValue()); } private static boolean validateKey(short key) { @@ -153,11 +156,11 @@ private static boolean validateTagType(short tagType) { public static short getShortValue(short tagType, short tagKey, short keyParameters) { short ptr; if (tagType == UINT_TAG) { - ptr = KMKeyParameters.findTag(KMType.UINT_TAG, tagKey, keyParameters); + ptr = KMKeyParameters.findTag(keyParameters, KMType.UINT_TAG, tagKey); if (ptr != KMType.INVALID_VALUE) { ptr = KMIntegerTag.cast(ptr).getValue(); - if (KMInteger.cast(ptr).getSignificantShort() == 0) { - return KMInteger.cast(ptr).getShort(); + if (KMInteger.getSignificantShort(ptr) == 0) { + return KMInteger.getShort(ptr); } } } @@ -168,10 +171,10 @@ public static short getValue( 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); + ptr = KMKeyParameters.findTag(keyParameters, tagType, tagKey); if (ptr != KMType.INVALID_VALUE) { ptr = KMIntegerTag.cast(ptr).getValue(); - return KMInteger.cast(ptr).value(buf, offset); + return KMInteger.value(ptr, buf, offset); } } return KMType.INVALID_VALUE; @@ -179,10 +182,10 @@ public static short getValue( public boolean isValidKeySize(byte alg) { short val = KMIntegerTag.cast(KMType.instanceTable[KM_INTEGER_TAG_OFFSET]).getValue(); - if (KMInteger.cast(val).getSignificantShort() != 0) { + if (KMInteger.getSignificantShort(val) != 0) { return false; } - val = KMInteger.cast(val).getShort(); + val = KMInteger.getShort(val); switch (alg) { case KMType.RSA: if (val == 2048) { @@ -214,4 +217,20 @@ public boolean isValidKeySize(byte alg) { } return false; } + + public static boolean isValidKeySize(short bPtr, byte alg) { + return KMIntegerTag.cast(bPtr).isValidKeySize(alg); + } + + public static short getTagType(short bPtr) { + return KMIntegerTag.cast(bPtr).getTagType(); + } + + public static short getValue(short bPtr) { + return KMIntegerTag.cast(bPtr).getValue(); + } + + public static short getKey(short bPtr) { + return KMIntegerTag.cast(bPtr).getKey(); + } } diff --git a/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java b/Applet/src/com/android/javacard/kmdevice/KMKeyCharacteristics.java similarity index 57% rename from Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java rename to Applet/src/com/android/javacard/kmdevice/KMKeyCharacteristics.java index ddf7abab..ea79b110 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java +++ b/Applet/src/com/android/javacard/kmdevice/KMKeyCharacteristics.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -36,16 +36,25 @@ public class KMKeyCharacteristics extends KMType { private KMKeyCharacteristics() { } - public static short exp() { + public static short keymasterExp() { + short sb = KMKeyParameters.exp(); + short keystore = KMKeyParameters.exp(); + short arrPtr = KMArray.instance((short) 2); + + KMArray.add(arrPtr, STRONGBOX_ENFORCED, sb); + KMArray.add(arrPtr, KEYSTORE_ENFORCED, keystore); + return instance(arrPtr); + } + + public static short keymintExp() { short sb = KMKeyParameters.exp(); short tee = KMKeyParameters.exp(); short keystore = KMKeyParameters.exp(); short arrPtr = KMArray.instance((short) 3); - KMArray arr = KMArray.cast(arrPtr); - arr.add(STRONGBOX_ENFORCED, sb); - arr.add(TEE_ENFORCED, tee); - arr.add(KEYSTORE_ENFORCED, keystore); + KMArray.add(arrPtr, STRONGBOX_ENFORCED, sb); + KMArray.add(arrPtr, TEE_ENFORCED, tee); + KMArray.add(arrPtr, KEYSTORE_ENFORCED, keystore); return instance(arrPtr); } @@ -57,21 +66,27 @@ private static KMKeyCharacteristics proto(short ptr) { return prototype; } + public static short instance2() { + short arrPtr = KMArray.instance((short) 2); + return instance(arrPtr); + } + public static short instance() { short arrPtr = KMArray.instance((short) 3); return instance(arrPtr); } public static short instance(short vals) { - short ptr = KMType.instance(KEY_CHAR_TYPE, (short) 3); - if (KMArray.cast(vals).length() != 3) { + short length = KMArray.length(vals); + short ptr = KMType.instance(KEY_CHAR_TYPE, length); + if (length != 3 && length != 2) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), vals); return ptr; } - public static KMKeyCharacteristics cast(short ptr) { + private static KMKeyCharacteristics cast(short ptr) { if (heap[ptr] != KEY_CHAR_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -88,39 +103,75 @@ public short getVals() { public short length() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).length(); + return KMArray.length(arrPtr); } public short getKeystoreEnforced() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).get(KEYSTORE_ENFORCED); + return KMArray.get(arrPtr, KEYSTORE_ENFORCED); } public short getTeeEnforced() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).get(TEE_ENFORCED); + if (length() <= TEE_ENFORCED) { + return KMType.INVALID_VALUE; + } + return KMArray.get(arrPtr, TEE_ENFORCED); } public short getStrongboxEnforced() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).get(STRONGBOX_ENFORCED); + return KMArray.get(arrPtr, STRONGBOX_ENFORCED); } public void setKeystoreEnforced(short ptr) { - KMKeyParameters.cast(ptr); + KMKeyParameters.validate(ptr); short arrPtr = getVals(); - KMArray.cast(arrPtr).add(KEYSTORE_ENFORCED, ptr); + KMArray.add(arrPtr, KEYSTORE_ENFORCED, ptr); } public void setTeeEnforced(short ptr) { - KMKeyParameters.cast(ptr); + KMKeyParameters.validate(ptr); short arrPtr = getVals(); - KMArray.cast(arrPtr).add(TEE_ENFORCED, ptr); + KMArray.add(arrPtr, TEE_ENFORCED, ptr); } public void setStrongboxEnforced(short ptr) { - KMKeyParameters.cast(ptr); + KMKeyParameters.validate(ptr); short arrPtr = getVals(); - KMArray.cast(arrPtr).add(STRONGBOX_ENFORCED, ptr); + KMArray.add(arrPtr, STRONGBOX_ENFORCED, ptr); + } + + public static short getVals(short bPtr) { + return KMKeyCharacteristics.cast(bPtr).getVals(); + } + + public static short length(short bPtr) { + return KMKeyCharacteristics.cast(bPtr).length(); + } + + public static short getKeystoreEnforced(short bPtr) { + return KMKeyCharacteristics.cast(bPtr).getKeystoreEnforced(); + } + + public static short getTeeEnforced(short bPtr) { + return KMKeyCharacteristics.cast(bPtr).getTeeEnforced(); + } + + public static short getStrongboxEnforced(short bPtr) { + return KMKeyCharacteristics.cast(bPtr).getStrongboxEnforced(); + } + + public static void setKeystoreEnforced(short bPtr, short ptr) { + KMKeyCharacteristics.cast(bPtr).setKeystoreEnforced(ptr); + } + + public static void setTeeEnforced(short bPtr, short ptr) { + KMKeyCharacteristics.cast(bPtr).setTeeEnforced(ptr); + } + + public static void setStrongboxEnforced(short bPtr, short ptr) { + KMKeyCharacteristics.cast(bPtr).setStrongboxEnforced(ptr); } + } diff --git a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java b/Applet/src/com/android/javacard/kmdevice/KMKeyParameters.java similarity index 56% rename from Applet/src/com/android/javacard/keymaster/KMKeyParameters.java rename to Applet/src/com/android/javacard/kmdevice/KMKeyParameters.java index d4cbc323..74980cbd 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java +++ b/Applet/src/com/android/javacard/kmdevice/KMKeyParameters.java @@ -14,9 +14,8 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; -import com.android.javacard.seprovider.KMException; import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.Util; @@ -30,13 +29,73 @@ public class KMKeyParameters extends KMType { private static KMKeyParameters prototype; - private static final short[] customTags = { - KMType.ULONG_TAG, KMType.AUTH_TIMEOUT_MILLIS, - }; - + private static short[] customTags; + private static short[] invalidTagsArr; + private static short[] unsupportedTagArr; + private static short[] hwEnforcedTagArr; + private static short[] swEnforcedTagsArr; + private static short[] teeEnforcedTagsArr; + private KMKeyParameters() { } + public static void initStatics() { + customTags = new short[] { + KMType.ULONG_TAG, KMType.AUTH_TIMEOUT_MILLIS, + }; + invalidTagsArr = new short[] { + KMType.BYTES_TAG, KMType.NONCE, + KMType.BYTES_TAG, KMType.ASSOCIATED_DATA, + KMType.BYTES_TAG, KMType.UNIQUE_ID, + KMType.UINT_TAG, KMType.MAC_LENGTH, + }; + unsupportedTagArr = new short[] { + // Unsupported tags. + KMType.BOOL_TAG, KMType.TRUSTED_USER_PRESENCE_REQUIRED, + KMType.UINT_TAG, KMType.MIN_SEC_BETWEEN_OPS + }; + hwEnforcedTagArr = new short[] { + // HW Enforced + KMType.ENUM_TAG, KMType.ORIGIN, + KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, + KMType.ENUM_TAG, KMType.ALGORITHM, + KMType.UINT_TAG, KMType.KEYSIZE, + KMType.ULONG_TAG, KMType.RSA_PUBLIC_EXPONENT, + KMType.ENUM_TAG, KMType.BLOB_USAGE_REQ, + KMType.ENUM_ARRAY_TAG, KMType.DIGEST, + KMType.ENUM_ARRAY_TAG, KMType.PADDING, + KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, + KMType.ENUM_ARRAY_TAG, KMType.RSA_OAEP_MGF_DIGEST, + KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, + KMType.BOOL_TAG, KMType.CALLER_NONCE, + KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, + KMType.ENUM_TAG, KMType.ECCURVE, + KMType.BOOL_TAG, KMType.INCLUDE_UNIQUE_ID, + KMType.BOOL_TAG, KMType.ROLLBACK_RESISTANCE, + KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED, + KMType.BOOL_TAG, KMType.RESET_SINCE_ID_ROTATION, + KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, + KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY, + KMType.UINT_TAG, KMType.MAX_USES_PER_BOOT, + KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED, + }; + swEnforcedTagsArr = new short[] { + KMType.DATE_TAG, KMType.ACTIVE_DATETIME, + KMType.DATE_TAG, KMType.ORIGINATION_EXPIRE_DATETIME, + KMType.DATE_TAG, KMType.USAGE_EXPIRE_DATETIME, + KMType.UINT_TAG, KMType.USERID, + KMType.DATE_TAG, KMType.CREATION_DATETIME, + KMType.UINT_TAG, KMType.USAGE_COUNT_LIMIT, + KMType.BOOL_TAG, KMType.ALLOW_WHILE_ON_BODY + }; + teeEnforcedTagsArr = new short[] { + KMType.ULONG_ARRAY_TAG, KMType.USER_SECURE_ID, + KMType.UINT_TAG, KMType.AUTH_TIMEOUT, + KMType.ENUM_TAG, KMType.USER_AUTH_TYPE, + }; + + } + private static KMKeyParameters proto(short ptr) { if (prototype == null) { prototype = new KMKeyParameters(); @@ -47,35 +106,33 @@ private static KMKeyParameters proto(short ptr) { public static short exp() { short arrPtr = KMArray.instance((short) 11); - KMArray arr = KMArray.cast(arrPtr); - arr.add((short) 0, KMEnum.instance(KMType.RULE, KMType.FAIL_ON_INVALID_TAGS)); - arr.add((short) 1, KMIntegerTag.exp(UINT_TAG)); - arr.add((short) 2, KMIntegerArrayTag.exp(UINT_ARRAY_TAG)); - arr.add((short) 3, KMIntegerTag.exp(ULONG_TAG)); - arr.add((short) 4, KMIntegerTag.exp(DATE_TAG)); - arr.add((short) 5, KMIntegerArrayTag.exp(ULONG_ARRAY_TAG)); - arr.add((short) 6, KMEnumTag.exp()); - arr.add((short) 7, KMEnumArrayTag.exp()); - arr.add((short) 8, KMByteTag.exp()); - arr.add((short) 9, KMBoolTag.exp()); - arr.add((short) 10, KMBignumTag.exp()); + KMArray.add(arrPtr, (short) 0, KMEnum.instance(KMType.RULE, KMType.FAIL_ON_INVALID_TAGS)); + KMArray.add(arrPtr, (short) 1, KMIntegerTag.exp(UINT_TAG)); + KMArray.add(arrPtr, (short) 2, KMIntegerArrayTag.exp(UINT_ARRAY_TAG)); + KMArray.add(arrPtr, (short) 3, KMIntegerTag.exp(ULONG_TAG)); + KMArray.add(arrPtr, (short) 4, KMIntegerTag.exp(DATE_TAG)); + KMArray.add(arrPtr, (short) 5, KMIntegerArrayTag.exp(ULONG_ARRAY_TAG)); + KMArray.add(arrPtr, (short) 6, KMEnumTag.exp()); + KMArray.add(arrPtr, (short) 7, KMEnumArrayTag.exp()); + KMArray.add(arrPtr, (short) 8, KMByteTag.exp()); + KMArray.add(arrPtr, (short) 9, KMBoolTag.exp()); + KMArray.add(arrPtr, (short) 10, KMBignumTag.exp()); return instance(arrPtr); } public static short expAny() { short arrPtr = KMArray.instance((short) 11); - KMArray arr = KMArray.cast(arrPtr); - arr.add((short) 0, KMEnum.instance(KMType.RULE, KMType.IGNORE_INVALID_TAGS)); - arr.add((short) 1, KMIntegerTag.exp(UINT_TAG)); - arr.add((short) 2, KMIntegerArrayTag.exp(UINT_ARRAY_TAG)); - arr.add((short) 3, KMIntegerTag.exp(ULONG_TAG)); - arr.add((short) 4, KMIntegerTag.exp(DATE_TAG)); - arr.add((short) 5, KMIntegerArrayTag.exp(ULONG_ARRAY_TAG)); - arr.add((short) 6, KMEnumTag.exp()); - arr.add((short) 7, KMEnumArrayTag.exp()); - arr.add((short) 8, KMByteTag.exp()); - arr.add((short) 9, KMBoolTag.exp()); - arr.add((short) 10, KMBignumTag.exp()); + KMArray.add(arrPtr, (short) 0, KMEnum.instance(KMType.RULE, KMType.IGNORE_INVALID_TAGS)); + KMArray.add(arrPtr, (short) 1, KMIntegerTag.exp(UINT_TAG)); + KMArray.add(arrPtr, (short) 2, KMIntegerArrayTag.exp(UINT_ARRAY_TAG)); + KMArray.add(arrPtr, (short) 3, KMIntegerTag.exp(ULONG_TAG)); + KMArray.add(arrPtr, (short) 4, KMIntegerTag.exp(DATE_TAG)); + KMArray.add(arrPtr, (short) 5, KMIntegerArrayTag.exp(ULONG_ARRAY_TAG)); + KMArray.add(arrPtr, (short) 6, KMEnumTag.exp()); + KMArray.add(arrPtr, (short) 7, KMEnumArrayTag.exp()); + KMArray.add(arrPtr, (short) 8, KMByteTag.exp()); + KMArray.add(arrPtr, (short) 9, KMBoolTag.exp()); + KMArray.add(arrPtr, (short) 10, KMBignumTag.exp()); return instance(arrPtr); } @@ -85,7 +142,12 @@ public static short instance(short vals) { return ptr; } - public static KMKeyParameters cast(short ptr) { + private static KMKeyParameters cast(short ptr) { + validate(ptr); + return proto(ptr); + } + + public static void validate(short ptr) { if (heap[ptr] != KEY_PARAM_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -93,7 +155,6 @@ public static KMKeyParameters cast(short ptr) { if (heap[arrPtr] != ARRAY_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } - return proto(ptr); } public short getVals() { @@ -102,26 +163,28 @@ public short getVals() { public short length() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).length(); + return KMArray.length(arrPtr); } - public static short findTag(short tagType, short tagKey, short keyParam) { - KMKeyParameters instParam = KMKeyParameters.cast(keyParam); - return instParam.findTag(tagType, tagKey); + public static short getVals(short bPtr) { + return KMKeyParameters.cast(bPtr).getVals(); } + public static short length(short bPtr) { + return KMKeyParameters.cast(bPtr).length(); + } + public short findTag(short tagType, short tagKey) { - KMArray vals = KMArray.cast(getVals()); short index = 0; - short length = vals.length(); + short length = KMArray.length(getVals()); short key; short type; short ret = KMType.INVALID_VALUE; short obj; while (index < length) { - obj = vals.get(index); - key = KMTag.getKey(obj); - type = KMTag.getTagType(obj); + obj = KMArray.get(getVals(), index); + key = KMTag.getKMTagKey(obj); + type = KMTag.getKMTagType(obj); if ((tagKey == key) && (tagType == type)) { ret = obj; break; @@ -131,27 +194,27 @@ public short findTag(short tagType, short tagKey) { return ret; } - public static boolean hasUnsupportedTags(short keyParamsPtr) { - final short[] tagArr = { - // Unsupported tags. - KMType.BOOL_TAG, KMType.TRUSTED_USER_PRESENCE_REQUIRED, - KMType.UINT_TAG, KMType.MIN_SEC_BETWEEN_OPS - }; + public static short findTag(short bPtr, short tagType, short tagKey) { + return KMKeyParameters.cast(bPtr).findTag(tagType, tagKey); + } + + public boolean hasUnsupportedTags(short keyParamsPtr) { + byte index = 0; short tagInd; short tagPtr; short tagKey; short tagType; - short arrPtr = KMKeyParameters.cast(keyParamsPtr).getVals(); - short len = KMArray.cast(arrPtr).length(); + short arrPtr = KMKeyParameters.getVals(keyParamsPtr); + short len = KMArray.length(arrPtr); while (index < len) { tagInd = 0; - tagPtr = KMArray.cast(arrPtr).get(index); - tagKey = KMTag.getKey(tagPtr); - tagType = KMTag.getTagType(tagPtr); - while (tagInd < (short) tagArr.length) { - if ((tagArr[tagInd] == tagType) - && (tagArr[(short) (tagInd + 1)] == tagKey)) { + tagPtr = KMArray.get(arrPtr, index); + tagKey = KMTag.getKMTagKey(tagPtr); + tagType = KMTag.getKMTagType(tagPtr); + while (tagInd < (short) unsupportedTagArr.length) { + if ((unsupportedTagArr[tagInd] == tagType) + && (unsupportedTagArr[(short) (tagInd + 1)] == tagKey)) { return true; } tagInd += 2; @@ -165,44 +228,20 @@ public static boolean hasUnsupportedTags(short keyParamsPtr) { public static short makeSbEnforced(short keyParamsPtr, byte origin, short osVersionObjPtr, short osPatchObjPtr, short vendorPatchObjPtr, short bootPatchObjPtr, byte[] scratchPad) { - final short[] hwEnforcedTagArr = { - // HW Enforced - KMType.ENUM_TAG, KMType.ORIGIN, - KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, - KMType.ENUM_TAG, KMType.ALGORITHM, - KMType.UINT_TAG, KMType.KEYSIZE, - KMType.ULONG_TAG, KMType.RSA_PUBLIC_EXPONENT, - KMType.ENUM_TAG, KMType.BLOB_USAGE_REQ, - KMType.ENUM_ARRAY_TAG, KMType.DIGEST, - KMType.ENUM_ARRAY_TAG, KMType.PADDING, - KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, - KMType.ENUM_ARRAY_TAG, KMType.RSA_OAEP_MGF_DIGEST, - KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, - KMType.BOOL_TAG, KMType.CALLER_NONCE, - KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, - KMType.ENUM_TAG, KMType.ECCURVE, - KMType.BOOL_TAG, KMType.INCLUDE_UNIQUE_ID, - KMType.BOOL_TAG, KMType.ROLLBACK_RESISTANCE, - KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED, - KMType.BOOL_TAG, KMType.RESET_SINCE_ID_ROTATION, - KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, - KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY, - KMType.UINT_TAG, KMType.MAX_USES_PER_BOOT, - KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED, - }; + byte index = 0; short tagInd; short arrInd = 0; short tagPtr; short tagKey; short tagType; - short arrPtr = KMKeyParameters.cast(keyParamsPtr).getVals(); - short len = KMArray.cast(arrPtr).length(); + short arrPtr = KMKeyParameters.getVals(keyParamsPtr); + short len = KMArray.length(arrPtr); while (index < len) { tagInd = 0; - tagPtr = KMArray.cast(arrPtr).get(index); - tagKey = KMTag.getKey(tagPtr); - tagType = KMTag.getTagType(tagPtr); + tagPtr = KMArray.get(arrPtr, index); + tagKey = KMTag.getKMTagKey(tagPtr); + tagType = KMTag.getKMTagType(tagPtr); if (!isValidTag(tagType, tagKey)) { KMException.throwIt(KMError.INVALID_KEY_BLOB); } @@ -238,47 +277,19 @@ public static short makeSbEnforced(short keyParamsPtr, byte origin, } public static short makeSbEnforced(short keyParamsPtr, byte[] scratchPad) { - final short[] hwEnforcedTagArr = { - // HW Enforced - KMType.ENUM_TAG, KMType.ORIGIN, - KMType.UINT_TAG, KMType.OS_VERSION, - KMType.UINT_TAG, KMType.OS_PATCH_LEVEL, - KMType.UINT_TAG, KMType.VENDOR_PATCH_LEVEL, - KMType.UINT_TAG, KMType.BOOT_PATCH_LEVEL, - KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, - KMType.ENUM_TAG, KMType.ALGORITHM, - KMType.UINT_TAG, KMType.KEYSIZE, - KMType.ULONG_TAG, KMType.RSA_PUBLIC_EXPONENT, - KMType.ENUM_TAG, KMType.BLOB_USAGE_REQ, - KMType.ENUM_ARRAY_TAG, KMType.DIGEST, - KMType.ENUM_ARRAY_TAG, KMType.PADDING, - KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, - KMType.ENUM_ARRAY_TAG, KMType.RSA_OAEP_MGF_DIGEST, - KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, - KMType.BOOL_TAG, KMType.CALLER_NONCE, - KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, - KMType.ENUM_TAG, KMType.ECCURVE, - KMType.BOOL_TAG, KMType.INCLUDE_UNIQUE_ID, - KMType.BOOL_TAG, KMType.ROLLBACK_RESISTANCE, - KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED, - KMType.BOOL_TAG, KMType.RESET_SINCE_ID_ROTATION, - KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, - KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY, - KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED, - }; byte index = 0; short tagInd; short arrInd = 0; short tagPtr; short tagKey; short tagType; - short arrPtr = KMKeyParameters.cast(keyParamsPtr).getVals(); - short len = KMArray.cast(arrPtr).length(); + short arrPtr = KMKeyParameters.getVals(keyParamsPtr); + short len = KMArray.length(arrPtr); while (index < len) { tagInd = 0; - tagPtr = KMArray.cast(arrPtr).get(index); - tagKey = KMTag.getKey(tagPtr); - tagType = KMTag.getTagType(tagPtr); + tagPtr = KMArray.get(arrPtr, index); + tagKey = KMTag.getKMTagKey(tagPtr); + tagType = KMTag.getKMTagType(tagPtr); if (!isValidTag(tagType, tagKey)) { KMException.throwIt(KMError.INVALID_KEY_BLOB); } @@ -297,26 +308,26 @@ public static short makeSbEnforced(short keyParamsPtr, byte[] scratchPad) { } public static short makeHwEnforced(short sb, short tee){ - short len = KMKeyParameters.cast(sb).length(); - len += KMKeyParameters.cast(tee).length(); + short len = KMKeyParameters.length(sb); + len += KMKeyParameters.length(tee); short hwEnf = KMArray.instance(len); - sb = KMKeyParameters.cast(sb).getVals(); - tee = KMKeyParameters.cast(tee).getVals(); - len = KMArray.cast(sb).length(); + sb = KMKeyParameters.getVals(sb); + tee = KMKeyParameters.getVals(tee); + len = KMArray.length(sb); short src = 0; short dest =0; short val = 0; while(src < len){ - val = KMArray.cast(sb).get(src); - KMArray.cast(hwEnf).add(dest, val); + val = KMArray.get(sb, src); + KMArray.add(hwEnf, dest, val); src++; dest++; } src = 0; - len = KMArray.cast(tee).length(); + len = KMArray.length(tee); while(src < len){ - val = KMArray.cast(tee).get(src); - KMArray.cast(hwEnf).add(dest, val); + val = KMArray.get(tee, src); + KMArray.add(hwEnf, dest, val); src++; dest++; } @@ -324,28 +335,19 @@ public static short makeHwEnforced(short sb, short tee){ } // ALL_USERS, EXPORTABLE missing from types.hal public static short makeKeystoreEnforced(short keyParamsPtr, byte[] scratchPad) { - final short[] swEnforcedTagsArr = { - KMType.DATE_TAG, KMType.ACTIVE_DATETIME, - KMType.DATE_TAG, KMType.ORIGINATION_EXPIRE_DATETIME, - KMType.DATE_TAG, KMType.USAGE_EXPIRE_DATETIME, - KMType.UINT_TAG, KMType.USERID, - KMType.DATE_TAG, KMType.CREATION_DATETIME, - KMType.UINT_TAG, KMType.USAGE_COUNT_LIMIT, - KMType.BOOL_TAG, KMType.ALLOW_WHILE_ON_BODY - }; byte index = 0; short tagInd; short arrInd = 0; short tagPtr; short tagKey; short tagType; - short arrPtr = KMKeyParameters.cast(keyParamsPtr).getVals(); - short len = KMArray.cast(arrPtr).length(); + short arrPtr = KMKeyParameters.getVals(keyParamsPtr); + short len = KMArray.length(arrPtr); while (index < len) { tagInd = 0; - tagPtr = KMArray.cast(arrPtr).get(index); - tagKey = KMTag.getKey(tagPtr); - tagType = KMTag.getTagType(tagPtr); + tagPtr = KMArray.get(arrPtr, index); + tagKey = KMTag.getKMTagKey(tagPtr); + tagType = KMTag.getKMTagType(tagPtr); if (!isValidTag(tagType, tagKey)) { KMException.throwIt(KMError.INVALID_KEY_BLOB); } @@ -364,24 +366,19 @@ public static short makeKeystoreEnforced(short keyParamsPtr, byte[] scratchPad) } public static short makeTeeEnforced(short keyParamsPtr, byte[] scratchPad) { - final short[] teeEnforcedTagsArr = { - KMType.ULONG_ARRAY_TAG, KMType.USER_SECURE_ID, - KMType.UINT_TAG, KMType.AUTH_TIMEOUT, - KMType.ENUM_TAG, KMType.USER_AUTH_TYPE, - }; byte index = 0; short tagInd; short arrInd = 0; short tagPtr; short tagKey; short tagType; - short arrPtr = KMKeyParameters.cast(keyParamsPtr).getVals(); - short len = KMArray.cast(arrPtr).length(); + short arrPtr = KMKeyParameters.getVals(keyParamsPtr); + short len = KMArray.length(arrPtr); while (index < len) { tagInd = 0; - tagPtr = KMArray.cast(arrPtr).get(index); - tagKey = KMTag.getKey(tagPtr); - tagType = KMTag.getTagType(tagPtr); + tagPtr = KMArray.get(arrPtr, index); + tagKey = KMTag.getKMTagKey(tagPtr); + tagType = KMTag.getKMTagType(tagPtr); if (!isValidTag(tagType, tagKey)) { KMException.throwIt(KMError.INVALID_KEY_BLOB); } @@ -403,14 +400,14 @@ public static short makeTeeEnforced(short keyParamsPtr, byte[] scratchPad) { } public static short makeHidden(short keyParamsPtr, short rootOfTrustBlob, byte[] scratchPad) { - short appId = KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_ID, keyParamsPtr); + short appId = KMKeyParameters.findTag(keyParamsPtr, KMType.BYTES_TAG, KMType.APPLICATION_ID); if (appId != KMTag.INVALID_VALUE) { - appId = KMByteTag.cast(appId).getValue(); + appId = KMByteTag.getValue(appId); } short appData = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_DATA, keyParamsPtr); + KMKeyParameters.findTag(keyParamsPtr, KMType.BYTES_TAG, KMType.APPLICATION_DATA); if (appData != KMTag.INVALID_VALUE) { - appData = KMByteTag.cast(appData).getValue(); + appData = KMByteTag.getValue(appData); } return makeHidden(appId, appData, rootOfTrustBlob, scratchPad); } @@ -419,11 +416,11 @@ public static short makeHidden(short appIdBlob, short appDataBlob, short rootOfT byte[] scratchPad) { // Order in which the hidden array is created should not change. short index = 0; - KMByteBlob.cast(rootOfTrustBlob); + KMByteBlob.validate(rootOfTrustBlob); Util.setShort(scratchPad, index, rootOfTrustBlob); index += 2; if (appIdBlob != KMTag.INVALID_VALUE) { - KMByteBlob.cast(appIdBlob); + KMByteBlob.validate(appIdBlob); Util.setShort(scratchPad, index, appIdBlob); index += 2; } @@ -436,12 +433,6 @@ public static short makeHidden(short appIdBlob, short appDataBlob, short rootOfT } public static boolean isValidTag(short tagType, short tagKey) { - short[] invalidTagsArr = { - KMType.BYTES_TAG, KMType.NONCE, - KMType.BYTES_TAG, KMType.ASSOCIATED_DATA, - KMType.BYTES_TAG, KMType.UNIQUE_ID, - KMType.UINT_TAG, KMType.MAC_LENGTH, - }; short index = 0; if (tagKey == KMType.INVALID_TAG) { return false; @@ -460,7 +451,7 @@ public static short createKeyParameters(byte[] ptrArr, short len) { short index = 0; short ptr = 0; while (index < len) { - KMArray.cast(arrPtr).add(index, Util.getShort(ptrArr, ptr)); + KMArray.add(arrPtr, index, Util.getShort(ptrArr, ptr)); index++; ptr += 2; } @@ -477,7 +468,7 @@ public static short addCustomTags(short keyParams, byte[] scratchPad, short offs switch(tagType) { case KMType.AUTH_TIMEOUT_MILLIS: short authTimeOutTag = - KMKeyParameters.cast(keyParams).findTag(KMType.UINT_TAG, KMType.AUTH_TIMEOUT); + KMKeyParameters.findTag(keyParams, KMType.UINT_TAG, KMType.AUTH_TIMEOUT); if (authTimeOutTag != KMType.INVALID_VALUE) { tagPtr = createAuthTimeOutMillisTag(authTimeOutTag, scratchPad, offset); Util.setShort(scratchPad, offset, tagPtr); @@ -499,21 +490,25 @@ public void deleteCustomTags() { while (index >= 0) { obj = findTag(customTags[(short) (index - 1)], customTags[index]); if (obj != KMType.INVALID_VALUE) { - KMArray.cast(arrPtr).deleteLastEntry(); + KMArray.deleteLastEntry(arrPtr); } index -= 2; } } + + public static void deleteCustomTags(short bPtr) { + KMKeyParameters.cast(bPtr).deleteCustomTags(); + } public static short createAuthTimeOutMillisTag(short authTimeOutTag, byte[] scratchPad, short offset) { - short authTime = KMIntegerTag.cast(authTimeOutTag).getValue(); + short authTime = KMIntegerTag.getValue(authTimeOutTag); Util.arrayFillNonAtomic(scratchPad, offset, (short) 40, (byte) 0); Util.arrayCopyNonAtomic( - KMInteger.cast(authTime).getBuffer(), - KMInteger.cast(authTime).getStartOff(), + KMInteger.getBuffer(authTime), + KMInteger.getStartOff(authTime), scratchPad, - (short) (offset + 8 - KMInteger.cast(authTime).length()), - KMInteger.cast(authTime).length()); + (short) (offset + 8 - KMInteger.length(authTime)), + KMInteger.length(authTime)); KMUtils.convertToMilliseconds(scratchPad, offset, (short) (offset + 8), (short) (offset + 16)); return KMIntegerTag.instance(KMType.ULONG_TAG, KMType.AUTH_TIMEOUT_MILLIS, KMInteger.uint_64(scratchPad, (short) (offset + 8))); diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/kmdevice/KMKeymasterDevice.java similarity index 63% rename from Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java rename to Applet/src/com/android/javacard/kmdevice/KMKeymasterDevice.java index addc5409..a6d4b00f 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/kmdevice/KMKeymasterDevice.java @@ -14,31 +14,24 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; -import com.android.javacard.seprovider.KMAttestationCert; -import com.android.javacard.seprovider.KMDeviceUniqueKey; -import com.android.javacard.seprovider.KMException; -import com.android.javacard.seprovider.KMSEProvider; 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.Util; import javacard.security.CryptoException; -import javacardx.apdu.ExtendedLength; /** * KMKeymasterApplet implements the javacard applet. It creates repository and other install time * objects. It also implements the keymaster state machine and handles javacard applet life cycle * events. */ -public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLength { +public class KMKeymasterDevice { // Constants. - public static final byte[] F4 = {0x01, 0x00, 0x01}; + public static byte[] F4; public static final byte AES_BLOCK_SIZE = 16; public static final byte DES_BLOCK_SIZE = 8; public static final short MAX_LENGTH = 15000; @@ -49,78 +42,56 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe public static final short VERIFIED_BOOT_HASH_SIZE = 32; public static final short BOOT_PATCH_LVL_SIZE = 4; - protected static final byte CLA_ISO7816_NO_SM_NO_CHAN = (byte) 0x80; - protected static final short KM_HAL_VERSION = (short) 0x5000; - protected static final short KEYMASTER_HAL_VERSION = (short) 0x4000; + public static final byte CLA_ISO7816_NO_SM_NO_CHAN = (byte) 0x80; + public static final short KEYMINT_HAL_VERSION = (short) 0x5000; + public static final short KEYMASTER_HAL_VERSION = (short) 0x4000; private static final short MAX_AUTH_DATA_SIZE = (short) 512; private static final short DERIVE_KEY_INPUT_SIZE = (short) 256; public static final byte TRUSTED_ENVIRONMENT = 1; // "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, - 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E - }; + public static byte[] sharingCheck; // "KeymasterSharedMac" - public static final byte[] ckdfLable = { - 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, - 0x4D, - 0x61, 0x63 - }; + public static byte[] ckdfLable; // "Auth Verification" - public static final byte[] authVerification = { - 0x41, 0x75, 0x74, 0x68, 0x20, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6F, - 0x6E - }; + public static byte[] authVerification; // "confirmation token" - public static final byte[] confirmationToken = { - 0x63, 0x6F, 0x6E, 0x66, 0x69, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x6F, - 0x6B, - 0x65, 0x6E - }; + public static byte[] confirmationToken; // Subject is a fixed field with only CN= Android Keystore Key - same for all the keys - private static final byte[] defaultSubject = { - 0x30, 0x1F, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x14, 0x41, 0x6e, - 0x64, - 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4B, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x4B, - 0x65, - 0x79 - }; + private static byte[] defaultSubject; public static final short MAX_COSE_BUF_SIZE = (short) 1024; // Top 32 commands are reserved for provisioning. private static final byte KEYMINT_CMD_APDU_START = 0x20; - public static final byte INS_GENERATE_KEY_CMD = KEYMINT_CMD_APDU_START + 1; //0x21 - public static final byte INS_IMPORT_KEY_CMD = KEYMINT_CMD_APDU_START + 2; //0x22 - public static final byte INS_IMPORT_WRAPPED_KEY_CMD = KEYMINT_CMD_APDU_START + 3; //0x23 - public static final byte INS_EXPORT_KEY_CMD = KEYMINT_CMD_APDU_START + 4; //0x24 - public static final byte INS_ATTEST_KEY_CMD = KEYMINT_CMD_APDU_START + 5; //0x25 - public static final byte INS_UPGRADE_KEY_CMD = KEYMINT_CMD_APDU_START + 6; //0x26 - public static final byte INS_DELETE_KEY_CMD = KEYMINT_CMD_APDU_START + 7; //0x27 - public static final byte INS_DELETE_ALL_KEYS_CMD = KEYMINT_CMD_APDU_START + 8; //0x28 - public static final byte INS_ADD_RNG_ENTROPY_CMD = KEYMINT_CMD_APDU_START + 9; //0x29 - public static final byte INS_COMPUTE_SHARED_HMAC_CMD = KEYMINT_CMD_APDU_START + 10; //0x2A - public static final byte INS_DESTROY_ATT_IDS_CMD = KEYMINT_CMD_APDU_START + 11; //0x2B - public static final byte INS_VERIFY_AUTHORIZATION_CMD = KEYMINT_CMD_APDU_START + 12; //0x2C - public static final byte INS_GET_HMAC_SHARING_PARAM_CMD = KEYMINT_CMD_APDU_START + 13; //0x2D - public static final byte INS_GET_KEY_CHARACTERISTICS_CMD = KEYMINT_CMD_APDU_START + 14; //0x2E - public static final byte INS_GET_HW_INFO_CMD = KEYMINT_CMD_APDU_START + 15; //0x2F - public static final byte INS_BEGIN_OPERATION_CMD = KEYMINT_CMD_APDU_START + 16; //0x30 - public static final byte INS_UPDATE_OPERATION_CMD = KEYMINT_CMD_APDU_START + 17; //0x31 - public static final byte INS_FINISH_OPERATION_CMD = KEYMINT_CMD_APDU_START + 18; //0x32 - public static final byte INS_ABORT_OPERATION_CMD = KEYMINT_CMD_APDU_START + 19; //0x33 - public static final byte INS_DEVICE_LOCKED_CMD = KEYMINT_CMD_APDU_START + 20;//0x34 - public static final byte INS_EARLY_BOOT_ENDED_CMD = KEYMINT_CMD_APDU_START + 21; //0x35 - public static final byte INS_GET_CERT_CHAIN_CMD = KEYMINT_CMD_APDU_START + 22; //0x36 - public static final byte INS_UPDATE_AAD_OPERATION_CMD = KEYMINT_CMD_APDU_START + 23; //0x37 - public static final byte INS_BEGIN_IMPORT_WRAPPED_KEY_CMD = KEYMINT_CMD_APDU_START + 24; //0x38 - public static final byte INS_FINISH_IMPORT_WRAPPED_KEY_CMD = KEYMINT_CMD_APDU_START + 25; //0x39 - public static final byte INS_INIT_STRONGBOX_CMD = KEYMINT_CMD_APDU_START + 26; //0x3A + private static final byte INS_GENERATE_KEY_CMD = KEYMINT_CMD_APDU_START + 1; //0x21 + private static final byte INS_IMPORT_KEY_CMD = KEYMINT_CMD_APDU_START + 2; //0x22 + private static final byte INS_IMPORT_WRAPPED_KEY_CMD = KEYMINT_CMD_APDU_START + 3; //0x23 + private static final byte INS_EXPORT_KEY_CMD = KEYMINT_CMD_APDU_START + 4; //0x24 + private static final byte INS_ATTEST_KEY_CMD = KEYMINT_CMD_APDU_START + 5; //0x25 + private static final byte INS_UPGRADE_KEY_CMD = KEYMINT_CMD_APDU_START + 6; //0x26 + private static final byte INS_DELETE_KEY_CMD = KEYMINT_CMD_APDU_START + 7; //0x27 + private static final byte INS_DELETE_ALL_KEYS_CMD = KEYMINT_CMD_APDU_START + 8; //0x28 + private static final byte INS_ADD_RNG_ENTROPY_CMD = KEYMINT_CMD_APDU_START + 9; //0x29 + private static final byte INS_COMPUTE_SHARED_HMAC_CMD = KEYMINT_CMD_APDU_START + 10; //0x2A + private static final byte INS_DESTROY_ATT_IDS_CMD = KEYMINT_CMD_APDU_START + 11; //0x2B + private static final byte INS_VERIFY_AUTHORIZATION_CMD = KEYMINT_CMD_APDU_START + 12; //0x2C + private static final byte INS_GET_HMAC_SHARING_PARAM_CMD = KEYMINT_CMD_APDU_START + 13; //0x2D + private static final byte INS_GET_KEY_CHARACTERISTICS_CMD = KEYMINT_CMD_APDU_START + 14; //0x2E + private static final byte INS_GET_HW_INFO_CMD = KEYMINT_CMD_APDU_START + 15; //0x2F + private static final byte INS_BEGIN_OPERATION_CMD = KEYMINT_CMD_APDU_START + 16; //0x30 + private static final byte INS_UPDATE_OPERATION_CMD = KEYMINT_CMD_APDU_START + 17; //0x31 + private static final byte INS_FINISH_OPERATION_CMD = KEYMINT_CMD_APDU_START + 18; //0x32 + private static final byte INS_ABORT_OPERATION_CMD = KEYMINT_CMD_APDU_START + 19; //0x33 + private static final byte INS_DEVICE_LOCKED_CMD = KEYMINT_CMD_APDU_START + 20;//0x34 + private static final byte INS_EARLY_BOOT_ENDED_CMD = KEYMINT_CMD_APDU_START + 21; //0x35 + protected static final byte INS_GET_CERT_CHAIN_CMD = KEYMINT_CMD_APDU_START + 22; //0x36 + private static final byte INS_UPDATE_AAD_OPERATION_CMD = KEYMINT_CMD_APDU_START + 23; //0x37 + private static final byte INS_BEGIN_IMPORT_WRAPPED_KEY_CMD = KEYMINT_CMD_APDU_START + 24; //0x38 + private static final byte INS_FINISH_IMPORT_WRAPPED_KEY_CMD = KEYMINT_CMD_APDU_START + 25; //0x39 + private static final byte INS_INIT_STRONGBOX_CMD = KEYMINT_CMD_APDU_START + 26; //0x3A // RKP public static final byte INS_GET_RKP_HARDWARE_INFO = KEYMINT_CMD_APDU_START + 27; //0x3B public static final byte INS_GENERATE_RKP_KEY_CMD = KEYMINT_CMD_APDU_START + 28; //0x3C @@ -175,8 +146,8 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe public static final byte TEE_PARAMETERS = 34; public static final byte SB_PARAMETERS = 35; public static final byte CONFIRMATION_TOKEN = 36; - public static final byte KEYMASTER_SPECIFICATION = 0x01; - public static final byte KEYMINT_SPECIFICATION = 0x02; + // public static final byte KEYMASTER_SPECIFICATION = 0x01; + // public static final byte KEYMINT_SPECIFICATION = 0x02; // Constant // AddRngEntropy @@ -194,35 +165,41 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe // ComputeHMAC constants private static final short HMAC_SHARED_PARAM_MAX_SIZE = 64; protected static final short MAX_CERT_SIZE = 2048; + + protected static final short POWER_RESET_MASK_FLAG = (short) 0x4000; + +//getHardwareInfo constants. + private static byte[] JAVACARD_KEYMASTER_DEVICE; + private static byte[] GOOGLE; + private static byte[] X509Subject; + +private static short[] ATTEST_ID_TAGS; + private static final byte SERIAL_NUM = (byte) 0x01; protected static RemotelyProvisionedComponentDevice rkp; - protected static KMEncoder encoder; protected static KMDecoder decoder; protected static KMRepository repository; + protected static KMEncoder encoder; protected static KMSEProvider seProvider; protected static KMOperationState[] opTable; - protected static KMSpecification specification; - protected static short[] tmpVariables; protected static short[] data; protected static byte[] wrappingKey; - + private KMCose kmCoseInst; + /** * Registers this applet. */ - protected KMKeymasterApplet(KMSEProvider seImpl, short specificationVer) { - seProvider = seImpl; - this.specification = - (specificationVer == KEYMASTER_SPECIFICATION) ? - new KMKeymasterSpecification() : - new KMKeymintSpecification(); + public KMKeymasterDevice(KMSEProvider seImpl, KMRepository repoInst, KMDecoder decoderInst) { + initKMDeviceStatics(); + seProvider = seImpl; boolean isUpgrading = seProvider.isUpgrading(); if (!isUpgrading) { seProvider.createMasterKey(MASTER_KEY_SIZE); } - repository = new KMRepository(isUpgrading); + repository = repoInst; encoder = new KMEncoder(); - decoder = new KMDecoder(); + decoder = decoderInst; data = JCSystem.makeTransientShortArray(DATA_ARRAY_SIZE, JCSystem.CLEAR_ON_DESELECT); tmpVariables = JCSystem.makeTransientShortArray(TMP_VARIABLE_ARRAY_SIZE, JCSystem.CLEAR_ON_DESELECT); @@ -239,9 +216,96 @@ protected KMKeymasterApplet(KMSEProvider seImpl, short specificationVer) { // initialize default values initHmacNonceAndSeed(); initSystemBootParams((short)0,(short)0,(short)0,(short)0); - rkp = new RemotelyProvisionedComponentDevice(encoder, decoder, repository, seProvider); + kmCoseInst = KMCose.getInstance(); + rkp = new RemotelyProvisionedComponentDevice(this, encoder, decoder, repository, seProvider); } - + + public static void initStatics(){ + F4 = new byte[] {0x01, 0x00, 0x01}; + // "Keymaster HMAC Verification" - used for HMAC key verification. + sharingCheck = new byte[] { + 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x48, 0x4D, 0x41, 0x43, 0x20, + 0x56, + 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E + }; + + // "KeymasterSharedMac" + ckdfLable = new byte[] { + 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, + 0x4D, + 0x61, 0x63 + }; + + // "Auth Verification" + authVerification = new byte[] { + 0x41, 0x75, 0x74, 0x68, 0x20, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6F, + 0x6E + }; + // "confirmation token" + confirmationToken = new byte[] { + 0x63, 0x6F, 0x6E, 0x66, 0x69, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x6F, + 0x6B, + 0x65, 0x6E + }; + // Subject is a fixed field with only CN= Android Keystore Key - same for all the keys + defaultSubject = new byte[] { + 0x30, 0x1F, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x14, 0x41, 0x6e, + 0x64, + 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4B, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x4B, + 0x65, + 0x79 + }; + //getHardwareInfo constants. + JAVACARD_KEYMASTER_DEVICE = new byte[] { + 0x4A, 0x61, 0x76, 0x61, 0x63, 0x61, 0x72, 0x64, 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, + 0x65, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + }; + GOOGLE = new byte[] {0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65}; + X509Subject = new byte[] { + 0x30, 0x1F, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x14, 0x41, 0x6e, + 0x64, + 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4B, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x4B, + 0x65, + 0x79 + }; + + ATTEST_ID_TAGS = 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 + }; + } + + private static void initKMDeviceStatics() { + initStatics(); + KMAttestationCertImpl.initStatics(); + KMRepository.initStatics(); + KMBignumTag.initStatics(); + KMCosePairCoseKeyTag.initStatics(); + KMEnumTag.initStatics(); + KMCosePairTextStringTag.initStatics(); + KMByteTag.initStatics(); + KMEnum.initStatics(); + KMIntegerTag.initStatics(); + KMCose.initStatics(); + KMKeyParameters.initStatics(); + KMUtils.initStatics(); + KMBoolTag.initStatics(); + KMPKCS8Decoder.initStatics(); + KMEnumArrayTag.initStatics(); + } + + + public void clean() { + repository.clean(); + } + protected void initHmacNonceAndSeed(){ short nonce = repository.alloc((short)32); seProvider.newRandomNumber(repository.getHeap(), nonce, KMRepository.HMAC_SEED_NONCE_SIZE); @@ -262,9 +326,9 @@ private KMOperationState reserveOperation(short algorithm, short opHandle){ if (opTable[index].getAlgorithm() == KMType.INVALID_VALUE) { opTable[index].reset(); opTable[index].setAlgorithm(algorithm); - opTable[index].setHandle(KMInteger.cast(opHandle).getBuffer(), - KMInteger.cast(opHandle).getStartOff(), - KMInteger.cast(opHandle).length()); + opTable[index].setHandle(KMInteger.getBuffer(opHandle), + KMInteger.getStartOff(opHandle), + KMInteger.length(opHandle)); return opTable[index]; } index++; @@ -273,9 +337,9 @@ private KMOperationState reserveOperation(short algorithm, short opHandle){ } private KMOperationState findOperation(short handle){ - return findOperation(KMInteger.cast(handle).getBuffer(), - KMInteger.cast(handle).getStartOff(), - KMInteger.cast(handle).length()); + return findOperation(KMInteger.getBuffer(handle), + KMInteger.getStartOff(handle), + KMInteger.length(handle)); } private KMOperationState findOperation(byte[] opHandle, short start, short len){ @@ -299,8 +363,7 @@ private void releaseOperation(KMOperationState op){ * * @return Returns true if the keymaster is in correct state */ - @Override - public boolean select() { + public boolean onSelect() { repository.onSelect(); return true; } @@ -308,20 +371,15 @@ public boolean select() { /** * De-selects this applet. */ - @Override - public void deselect() { + public void onDeselect() { repository.onDeselect(); } - /** - * Uninstalls the applet after cleaning the repository. - */ - @Override - public void uninstall() { + public void onUninstall() { repository.onUninstall(); } - private short mapISOErrorToKMError(short reason) { + public short mapISOErrorToKMError(short reason) { switch (reason) { case ISO7816.SW_CLA_NOT_SUPPORTED: return KMError.UNSUPPORTED_CLA; @@ -343,7 +401,7 @@ private short mapISOErrorToKMError(short reason) { } } - private short mapCryptoErrorToKMError(short reason) { + public short mapCryptoErrorToKMError(short reason) { switch (reason) { case CryptoException.ILLEGAL_USE: return KMError.CRYPTO_ILLEGAL_USE; @@ -360,33 +418,18 @@ private short mapCryptoErrorToKMError(short reason) { } } - protected short validateApduHeader(APDU apdu) { - // Read the apdu header and buffer. - byte[] apduBuffer = apdu.getBuffer(); - byte apduIns = apduBuffer[ISO7816.OFFSET_INS]; - // Validate whether INS can be supported - if (!(apduIns > KEYMINT_CMD_APDU_START && apduIns < KEYMINT_CMD_APDU_END)) { - ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); - } - return apduIns; - } - /** * Processes an incoming APDU and handles it using command objects. * @param apdu the incoming APDU */ - @Override public void process(APDU apdu) { try { + resetData(); repository.onProcess(); - // If this is select applet apdu which is selecting this applet then return - if (apdu.isISOInterindustryCLA()) { - if (selectingApplet()) { - return; - } - } // Validate APDU Header. - short apduIns = validateApduHeader(apdu); + byte[] apduBuffer = apdu.getBuffer(); + byte apduIns = apduBuffer[ISO7816.OFFSET_INS]; + switch (apduIns) { case INS_INIT_STRONGBOX_CMD: processInitStrongBoxCmd(apdu); @@ -485,7 +528,6 @@ public void process(APDU apdu) { resetWrappingKey(); sendError(apdu, KMException.reason()); } catch (ISOException exp) { - sendError(apdu, mapISOErrorToKMError(exp.getReason())); freeOperations(); resetWrappingKey(); sendError(apdu, mapISOErrorToKMError(exp.getReason())); @@ -497,8 +539,7 @@ public void process(APDU apdu) { freeOperations(); resetWrappingKey(); sendError(apdu, KMError.GENERIC_UNKNOWN_ERROR); - } finally { - resetData(); + } finally { repository.clean(); } } @@ -525,24 +566,24 @@ private void processEarlyBootEndedCmd(APDU apdu) { private short deviceLockedCmd(APDU apdu){ short cmd = KMArray.instance((short) 2); // passwordOnly - KMArray.cast(cmd).add((short) 0, KMInteger.exp()); + KMArray.add(cmd, (short) 0, KMInteger.exp()); // verification token - KMArray.cast(cmd).add((short) 1, specification.getKMVerificationTokenExp()); + KMArray.add(cmd, (short) 1, getKMVerificationTokenExp()); return receiveIncoming(apdu, cmd); } private void processDeviceLockedCmd(APDU apdu) { short cmd = deviceLockedCmd(apdu); byte[] scratchPad = apdu.getBuffer(); - short passwordOnly = KMArray.cast(cmd).get((short) 0); - short verToken = KMArray.cast(cmd).get((short) 1); - passwordOnly = KMInteger.cast(passwordOnly).getByte(); + short passwordOnly = KMArray.get(cmd, (short) 0); + short verToken = KMArray.get(cmd, (short) 1); + passwordOnly = KMInteger.getByte(passwordOnly); validateVerificationToken(verToken, scratchPad); - short verTime = KMVerificationToken.cast(verToken).getTimestamp(); + short verTime = KMVerificationToken.getTimestamp(verToken); 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); + KMInteger.getValue(verTime, scratchPad, (short) 0, (short) 8); repository.setDeviceLock(true); repository.setDeviceLockPasswordOnly(passwordOnly == 0x01); repository.setDeviceLockTimestamp(scratchPad, (short) 0, (short) 8); @@ -561,12 +602,12 @@ private boolean isValidWrappingKey(){ } private void setWrappingKey(short key){ - if(KMByteBlob.cast(key).length() != WRAPPING_KEY_SIZE){ + if(KMByteBlob.length(key) != WRAPPING_KEY_SIZE){ KMException.throwIt(KMError.UNKNOWN_ERROR); } wrappingKey[0] = 0; - Util.arrayCopyNonAtomic(KMByteBlob.cast(key).getBuffer(), - KMByteBlob.cast(key).getStartOff(),wrappingKey,(short)1,WRAPPING_KEY_SIZE); + Util.arrayCopyNonAtomic(KMByteBlob.getBuffer(key), + KMByteBlob.getStartOff(key),wrappingKey,(short)1,WRAPPING_KEY_SIZE); } private short getWrappingKey(){ @@ -608,29 +649,49 @@ public static void sendOutgoing(APDU apdu, short resp) { /** * Receives data, which can be extended data, as requested by the command instance. */ - public static short receiveIncoming(APDU apdu, short reqExp) { + public short receiveIncoming(APDU apdu, short reqExp) { + short recvLen = apdu.setIncomingAndReceive(); + short bufferLength = apdu.getIncomingLength(); + short bufferStartOffset = repository.allocReclaimableMemory(bufferLength); + short req = receiveIncoming(apdu, reqExp, repository.getHeap(), bufferLength, bufferStartOffset, recvLen); + repository.reclaimMemory(bufferLength); + return req; + } + + public short receiveIncoming(APDU apdu, short reqExp, byte[] reclamBuf, short bLen, short bStartOffset, short incomingReceivedLen) { byte[] srcBuffer = apdu.getBuffer(); - short recvLen = apdu.setIncomingAndReceive(); + short recvLen = incomingReceivedLen; short srcOffset = apdu.getOffsetCdata(); // TODO add logic to handle the extended length buffer. In this case the memory can be reused // from extended buffer. - short bufferLength = apdu.getIncomingLength(); - short bufferStartOffset = repository.allocReclaimableMemory(bufferLength); - short index = bufferStartOffset; - byte[] buffer = repository.getHeap(); - while (recvLen > 0 && ((short) (index - bufferStartOffset) < bufferLength)) { - Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, index, recvLen); + short index = bStartOffset; + while (recvLen > 0 && ((short) (index - bStartOffset) < bLen)) { + Util.arrayCopyNonAtomic(srcBuffer, srcOffset, reclamBuf, index, recvLen); index += recvLen; recvLen = apdu.receiveBytes(srcOffset); } - short req = decoder.decode(reqExp, buffer, bufferStartOffset, bufferLength); - repository.reclaimMemory(bufferLength); - return req; + return decoder.decode(reqExp, reclamBuf, bStartOffset, bLen); } - + + public void receiveIncomingCertData(APDU apdu, byte[] reclamBuf, short bLen, short bStartOffset, short incomingReceivedLen, byte[] outBuf, short outOff) { + byte[] srcBuffer = apdu.getBuffer(); + short recvLen = incomingReceivedLen; + short srcOffset = apdu.getOffsetCdata(); + short index = bStartOffset; + while (recvLen > 0 && ((short) (index - bStartOffset) < bLen)) { + Util.arrayCopyNonAtomic(srcBuffer, srcOffset, reclamBuf, index, recvLen); + index += recvLen; + recvLen = apdu.receiveBytes(srcOffset); + } + decoder.decodeCertificateData((short) 3, + reclamBuf, bStartOffset, bLen, + outBuf, outOff); + } + + private void processGetHwInfoCmd(APDU apdu) { // No arguments expected - short respPtr = specification.getHardwareInfo(); + short respPtr = getHardwareInfo(); // send buffer to master sendOutgoing(apdu, respPtr); } @@ -638,7 +699,7 @@ private void processGetHwInfoCmd(APDU apdu) { private short addRngEntropyCmd(APDU apdu){ short cmd = KMArray.instance((short) 1); // Rng entropy - KMArray.cast(cmd).add((short) 0, KMByteBlob.exp()); + KMArray.add(cmd, (short) 0, KMByteBlob.exp()); return receiveIncoming(apdu, cmd); } @@ -646,20 +707,20 @@ private void processAddRngEntropyCmd(APDU apdu) { // Receive the incoming request fully from the master. short cmd = addRngEntropyCmd(apdu); // Process - KMByteBlob blob = KMByteBlob.cast(KMArray.cast(cmd).get((short) 0)); + short blob = KMArray.get(cmd, (short) 0); // Maximum 2KiB of seed is allowed. - if (blob.length() > MAX_SEED_SIZE) { + if (KMByteBlob.length(blob) > MAX_SEED_SIZE) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); } - seProvider.addRngEntropy(blob.getBuffer(), blob.getStartOff(), blob.length()); + seProvider.addRngEntropy(KMByteBlob.getBuffer(blob), KMByteBlob.getStartOff(blob), KMByteBlob.length(blob)); sendError(apdu, KMError.OK); } private short getKeyCharacteristicsCmd(APDU apdu){ short cmd = KMArray.instance((short) 3); - KMArray.cast(cmd).add((short) 0, KMByteBlob.exp()); - KMArray.cast(cmd).add((short) 1, KMByteBlob.exp()); - KMArray.cast(cmd).add((short) 2, KMByteBlob.exp()); + KMArray.add(cmd, (short) 0, KMByteBlob.exp()); + KMArray.add(cmd, (short) 1, KMByteBlob.exp()); + KMArray.add(cmd, (short) 2, KMByteBlob.exp()); return receiveIncoming(apdu, cmd); } @@ -668,13 +729,13 @@ private void processGetKeyCharacteristicsCmd(APDU apdu) { short cmd = getKeyCharacteristicsCmd(apdu); // Re-purpose the apdu buffer as scratch pad. byte[] scratchPad = apdu.getBuffer(); - data[KEY_BLOB] = KMArray.cast(cmd).get((short) 0); - data[APP_ID] = KMArray.cast(cmd).get((short) 1); - data[APP_DATA] = KMArray.cast(cmd).get((short) 2); - if (!KMByteBlob.cast(data[APP_ID]).isValid()) { + data[KEY_BLOB] = KMArray.get(cmd, (short) 0); + data[APP_ID] = KMArray.get(cmd, (short) 1); + data[APP_DATA] = KMArray.get(cmd, (short) 2); + if (!KMByteBlob.isValid(data[APP_ID])) { data[APP_ID] = KMType.INVALID_VALUE; } - if (!KMByteBlob.cast(data[APP_DATA]).isValid()) { + if (!KMByteBlob.isValid(data[APP_DATA])) { data[APP_DATA] = KMType.INVALID_VALUE; } // Parse Key Blob @@ -682,14 +743,14 @@ private void processGetKeyCharacteristicsCmd(APDU apdu) { // Check Version and Patch Level checkVersionAndPatchLevel(scratchPad); // Remove custom tags from key characteristics - short teeParams = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced(); + short teeParams = KMKeyCharacteristics.getTeeEnforced(data[KEY_CHARACTERISTICS]); if (teeParams != KMType.INVALID_VALUE) { - KMKeyParameters.cast(teeParams).deleteCustomTags(); + KMKeyParameters.deleteCustomTags(teeParams); } // make response. short resp = KMArray.instance((short) 2); - KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(resp).add((short) 1, data[KEY_CHARACTERISTICS]); + KMArray.add(resp, (short) 0, buildErrorStatus(KMError.OK)); + KMArray.add(resp, (short) 1, data[KEY_CHARACTERISTICS]); sendOutgoing(apdu, resp); } @@ -699,12 +760,12 @@ private void processGetHmacSharingParamCmd(APDU apdu) { short params = KMHmacSharingParameters.instance(); short nonce = repository.getHmacNonce(); short seed = KMByteBlob.instance((short) 0); - KMHmacSharingParameters.cast(params).setNonce(nonce); - KMHmacSharingParameters.cast(params).setSeed(seed); + KMHmacSharingParameters.setNonce(params, nonce); + KMHmacSharingParameters.setSeed(params, seed); // prepare the response short resp = KMArray.instance((short) 2); - KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(resp).add((short) 1, params); + KMArray.add(resp, (short) 0, buildErrorStatus(KMError.OK)); + KMArray.add(resp, (short) 1, params); sendOutgoing(apdu, resp); } @@ -716,35 +777,35 @@ private void processDeleteAllKeysCmd(APDU apdu) { private short deleteKeyCmd(APDU apdu){ short cmd = KMArray.instance((short) 1); - KMArray.cast(cmd).add((short) 0, KMByteBlob.exp()); + KMArray.add(cmd, (short) 0, KMByteBlob.exp()); return receiveIncoming(apdu, cmd); } private short keyBlob(){ short keyBlob = KMArray.instance((short) 5); - KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_SECRET, KMByteBlob.exp()); - KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_AUTH_TAG, KMByteBlob.exp()); - KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_NONCE, KMByteBlob.exp()); - short keyChar = KMKeyCharacteristics.exp(); - KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_PARAMS, keyChar); - KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_PUB_KEY, KMByteBlob.exp()); + KMArray.add(keyBlob, KMKeymasterDevice.KEY_BLOB_SECRET, KMByteBlob.exp()); + KMArray.add(keyBlob, KMKeymasterDevice.KEY_BLOB_AUTH_TAG, KMByteBlob.exp()); + KMArray.add(keyBlob, KMKeymasterDevice.KEY_BLOB_NONCE, KMByteBlob.exp()); + short keyChar = getKeyCharacteristicsExp(); + KMArray.add(keyBlob, KMKeymasterDevice.KEY_BLOB_PARAMS, keyChar); + KMArray.add(keyBlob, KMKeymasterDevice.KEY_BLOB_PUB_KEY, KMByteBlob.exp()); return keyBlob; } private void processDeleteKeyCmd(APDU apdu) { short cmd = deleteKeyCmd(apdu); - data[KEY_BLOB] = KMArray.cast(cmd).get((short) 0); + data[KEY_BLOB] = KMArray.get(cmd, (short) 0); try { data[KEY_BLOB] = decoder.decodeArray(keyBlob(), - KMByteBlob.cast(data[KEY_BLOB]).getBuffer(), - KMByteBlob.cast(data[KEY_BLOB]).getStartOff(), - KMByteBlob.cast(data[KEY_BLOB]).length()); + KMByteBlob.getBuffer(data[KEY_BLOB]), + KMByteBlob.getStartOff(data[KEY_BLOB]), + KMByteBlob.length(data[KEY_BLOB])); } catch (ISOException e) { // As per VTS, deleteKey should return KMError.OK but in case if // input is empty then VTS accepts UNIMPLEMENTED errorCode as well. KMException.throwIt(KMError.UNIMPLEMENTED); } - if (KMArray.cast(data[KEY_BLOB]).length() < 4) { + if (KMArray.length(data[KEY_BLOB]) < 4) { KMException.throwIt(KMError.INVALID_KEY_BLOB); } // Send ok @@ -755,7 +816,7 @@ private short computeSharedHmacCmd(APDU apdu){ short params = KMHmacSharingParameters.exp(); short paramsVec = KMArray.exp(params); short cmd = KMArray.instance((short) 1); - KMArray.cast(cmd).add((short) 0, paramsVec); + KMArray.add(cmd, (short) 0, paramsVec); return receiveIncoming(apdu, cmd); } @@ -763,10 +824,10 @@ private void processComputeSharedHmacCmd(APDU apdu) { // Receive the incoming request fully from the master into buffer. short cmd = computeSharedHmacCmd(apdu); byte[] scratchPad = apdu.getBuffer(); - data[HMAC_SHARING_PARAMS] = KMArray.cast(cmd).get((short) 0); + data[HMAC_SHARING_PARAMS] = KMArray.get(cmd, (short) 0); // Concatenate HMAC Params //tmpVariables[0] - short paramsLen = KMArray.cast(data[HMAC_SHARING_PARAMS]).length(); // total number of params + short paramsLen = KMArray.length(data[HMAC_SHARING_PARAMS]); // total number of params //tmpVariables[1] short concateBuffer = repository.alloc((short) (paramsLen * HMAC_SHARED_PARAM_MAX_SIZE)); //tmpVariables[2] @@ -783,18 +844,18 @@ private void processComputeSharedHmacCmd(APDU apdu) { while (paramIndex < paramsLen) { // read HmacSharingParam //tmpVariables[4] - short param = KMArray.cast(data[HMAC_SHARING_PARAMS]).get(paramIndex); + short param = KMArray.get(data[HMAC_SHARING_PARAMS], paramIndex); // get seed - 32 bytes max //tmpVariables[5] - short seed = KMHmacSharingParameters.cast(param).getSeed(); + short seed = KMHmacSharingParameters.getSeed(param); //tmpVariables[6] - short seedLength = KMByteBlob.cast(seed).length(); + short seedLength = KMByteBlob.length(seed); // if seed is present if (seedLength != 0) { // then copy that to concatenation buffer Util.arrayCopyNonAtomic( - KMByteBlob.cast(seed).getBuffer(), - KMByteBlob.cast(seed).getStartOff(), + KMByteBlob.getBuffer(seed), + KMByteBlob.getStartOff(seed), repository.getHeap(), (short) (concateBuffer + bufferIndex), // concat index seedLength); @@ -804,16 +865,16 @@ private void processComputeSharedHmacCmd(APDU apdu) { } // if nonce is present get nonce - 32 bytes //tmpVariables[5] - short paramNonce = KMHmacSharingParameters.cast(param).getNonce(); - short nonceLen = KMByteBlob.cast(paramNonce).length(); + short paramNonce = KMHmacSharingParameters.getNonce(param); + short nonceLen = KMByteBlob.length(paramNonce); // if nonce is less then 32 - it is an error if (nonceLen < 32) { KMException.throwIt(KMError.INVALID_ARGUMENT); } // copy nonce to concatenation buffer Util.arrayCopyNonAtomic( - KMByteBlob.cast(paramNonce).getBuffer(), - KMByteBlob.cast(paramNonce).getStartOff(), + KMByteBlob.getBuffer(paramNonce), + KMByteBlob.getStartOff(paramNonce), repository.getHeap(), (short) (concateBuffer + bufferIndex), // index nonceLen); @@ -825,8 +886,8 @@ private void processComputeSharedHmacCmd(APDU apdu) { == Util.arrayCompare( repository.getHeap(), (short) (concateBuffer + bufferIndex), - KMByteBlob.cast(nonce).getBuffer(), - KMByteBlob.cast(nonce).getStartOff(), + KMByteBlob.getBuffer(nonce), + KMByteBlob.getStartOff(nonce), nonceLen)) { found = 2; // hmac nonce for this keymaster found. } else { @@ -872,23 +933,23 @@ private void processComputeSharedHmacCmd(APDU apdu) { short signature = KMByteBlob.instance(scratchPad, keyLen, signLen); // prepare the response short resp = KMArray.instance((short) 2); - KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(resp).add((short) 1, signature); + KMArray.add(resp, (short) 0, buildErrorStatus(KMError.OK)); + KMArray.add(resp, (short) 1, signature); sendOutgoing(apdu, resp); } private short upgradeKeyCmd(APDU apdu){ short cmd = KMArray.instance((short) 2); short keyParams = KMKeyParameters.exp(); - KMArray.cast(cmd).add((short) 0, KMByteBlob.exp()); // Key Blob - KMArray.cast(cmd).add((short) 1, keyParams); // Key Params + KMArray.add(cmd, (short) 0, KMByteBlob.exp()); // Key Blob + KMArray.add(cmd, (short) 1, keyParams); // Key Params return receiveIncoming(apdu, cmd); } private boolean isKeyUpgradeRequired(short tag, short systemParam) { // validate the tag and check if key needs upgrade. - short tagValue = KMKeyParameters.findTag(KMType.UINT_TAG, tag, data[HW_PARAMETERS]); - tagValue = KMIntegerTag.cast(tagValue).getValue(); + short tagValue = KMKeyParameters.findTag(data[HW_PARAMETERS], KMType.UINT_TAG, tag); + tagValue = KMIntegerTag.getValue(tagValue); short zero = KMInteger.uint_8((byte) 0); if (tagValue != KMType.INVALID_VALUE) { // OS version in key characteristics must be less the OS version stored in Javacard or the @@ -915,18 +976,18 @@ private void processUpgradeKeyCmd(APDU apdu) { short cmd = upgradeKeyCmd(apdu); byte[] scratchPad = apdu.getBuffer(); - data[KEY_BLOB] = KMArray.cast(cmd).get((short) 0); - data[KEY_PARAMETERS] = KMArray.cast(cmd).get((short) 1); + data[KEY_BLOB] = KMArray.get(cmd, (short) 0); + data[KEY_PARAMETERS] = KMArray.get(cmd ,(short) 1); //tmpVariables[0] short appId = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_ID, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.BYTES_TAG, KMType.APPLICATION_ID); if (appId != KMTag.INVALID_VALUE) { - data[APP_ID] = KMByteTag.cast(appId).getValue(); + data[APP_ID] = KMByteTag.getValue(appId); } short appData = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_DATA, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.BYTES_TAG, KMType.APPLICATION_DATA); if (appData != KMTag.INVALID_VALUE) { - data[APP_DATA] = KMByteTag.cast(appData).getValue(); + data[APP_DATA] = KMByteTag.getValue(appData); } // parse existing key blob parseEncryptedKeyBlob(data[KEY_BLOB], data[APP_ID], data[APP_DATA], scratchPad); @@ -952,8 +1013,8 @@ private void processUpgradeKeyCmd(APDU apdu) { } // prepare the response short resp = KMArray.instance((short) 2); - KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(resp).add((short) 1, data[KEY_BLOB]); + KMArray.add(resp, (short) 0, buildErrorStatus(KMError.OK)); + KMArray.add(resp, (short) 1, data[KEY_BLOB]); sendOutgoing(apdu, resp); } @@ -963,14 +1024,14 @@ private void processExportKeyCmd(APDU apdu) { private void processWrappingKeyBlob(short keyBlob, short wrapParams, byte[] scratchPad) { // Read App Id and App Data if any from un wrapping key params short appId = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_ID, wrapParams); + KMKeyParameters.findTag(wrapParams, KMType.BYTES_TAG, KMType.APPLICATION_ID); short appData = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_DATA, wrapParams); + KMKeyParameters.findTag(wrapParams, KMType.BYTES_TAG, KMType.APPLICATION_DATA); if (appId != KMTag.INVALID_VALUE) { - appId = KMByteTag.cast(appId).getValue(); + appId = KMByteTag.getValue(appId); } if (appData != KMTag.INVALID_VALUE) { - appData = KMByteTag.cast(appData).getValue(); + appData = KMByteTag.getValue(appData); } data[APP_ID] = appId; data[APP_DATA] = appData; @@ -1002,15 +1063,15 @@ private void validateWrappingKeyBlob(){ private short decryptTransportKey(short privExp, short modulus, short transportKey, byte[] scratchPad){ short length = seProvider.rsaDecipherOAEP256( - KMByteBlob.cast(privExp).getBuffer(), - KMByteBlob.cast(privExp).getStartOff(), - KMByteBlob.cast(privExp).length(), - KMByteBlob.cast(modulus).getBuffer(), - KMByteBlob.cast(modulus).getStartOff(), - KMByteBlob.cast(modulus).length(), - KMByteBlob.cast(transportKey).getBuffer(), - KMByteBlob.cast(transportKey).getStartOff(), - KMByteBlob.cast(transportKey).length(), + KMByteBlob.getBuffer(privExp), + KMByteBlob.getStartOff(privExp), + KMByteBlob.length(privExp), + KMByteBlob.getBuffer(modulus), + KMByteBlob.getStartOff(modulus), + KMByteBlob.length(modulus), + KMByteBlob.getBuffer(transportKey), + KMByteBlob.getStartOff(transportKey), + KMByteBlob.length(transportKey), scratchPad, (short) 0); return KMByteBlob.instance(scratchPad, (short) 0, length); @@ -1018,8 +1079,8 @@ private short decryptTransportKey(short privExp, short modulus, short transportK } private void unmask(short data, short maskingKey){ - short dataLength = KMByteBlob.cast(data).length(); - short maskLength = KMByteBlob.cast(maskingKey).length(); + short dataLength = KMByteBlob.length(data); + short maskLength = KMByteBlob.length(maskingKey); // Length of masking key and transport key must be same. if (maskLength != dataLength) { KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH); @@ -1028,21 +1089,22 @@ private void unmask(short data, short maskingKey){ // Xor every byte of masking and key and store the result in data[SECRET] while (index < maskLength) { short var1 = - (short) (((short) KMByteBlob.cast(maskingKey).get(index)) & 0x00FF); + (short) (((short) KMByteBlob.get(maskingKey, index)) & 0x00FF); short var2 = - (short) (((short) KMByteBlob.cast(data).get(index)) & 0x00FF); - KMByteBlob.cast(data).add(index, (byte) (var1 ^ var2)); + (short) (((short) KMByteBlob.get(data, index)) & 0x00FF); + KMByteBlob.add(data, index, (byte) (var1 ^ var2)); index++; } } + private short beginImportWrappedKeyCmd(APDU apdu){ short cmd = KMArray.instance((short) 4); short params = KMKeyParameters.expAny(); - KMArray.cast(cmd).add((short) 0, KMByteBlob.exp()); // Encrypted Transport Key - KMArray.cast(cmd).add((short) 1, KMByteBlob.exp()); // Wrapping Key KeyBlob - KMArray.cast(cmd).add((short) 2, KMByteBlob.exp()); // Masking Key + KMArray.add(cmd, (short) 0, KMByteBlob.exp()); // Encrypted Transport Key + KMArray.add(cmd, (short) 1, KMByteBlob.exp()); // Wrapping Key KeyBlob + KMArray.add(cmd, (short) 2, KMByteBlob.exp()); // Masking Key params = KMKeyParameters.exp(); - KMArray.cast(cmd).add((short) 3, params); // Wrapping key blob Params + KMArray.add(cmd, (short) 3, params); // Wrapping key blob Params return receiveIncoming(apdu, cmd); } @@ -1052,97 +1114,74 @@ private void processBeginImportWrappedKeyCmd(APDU apdu) { byte[] scratchPad = apdu.getBuffer(); // Step -1 parse the wrapping key blob // read wrapping key blob - short keyBlob = KMArray.cast(cmd).get((short) 1); + short keyBlob = KMArray.get(cmd, (short) 1); // read un wrapping key params - short wrappingKeyParameters = KMArray.cast(cmd).get((short) 3); + short wrappingKeyParameters = KMArray.get(cmd, (short) 3); processWrappingKeyBlob(keyBlob, wrappingKeyParameters, scratchPad); // Step 2 - decrypt the encrypted transport key - 32 bytes AES-GCM key short transportKey = decryptTransportKey(data[SECRET], data[PUB_KEY], - KMArray.cast(cmd).get((short) 0), scratchPad); + KMArray.get(cmd, (short) 0), scratchPad); // Step 3 - XOR the decrypted AES-GCM key with with masking key - unmask(transportKey, KMArray.cast(cmd).get((short) 2)); + unmask(transportKey, KMArray.get(cmd, (short) 2)); if(isValidWrappingKey()){ KMException.throwIt(KMError.UNKNOWN_ERROR); } setWrappingKey(transportKey); sendError(apdu, KMError.OK); } - private short aesGCMEncrypt(short aesSecret, short input, short nonce, short authData, short authTag,byte[] scratchPad){ - Util.arrayFillNonAtomic(scratchPad, (short) 0, KMByteBlob.cast(input).length(), (byte) 0); - short len = seProvider.aesGCMEncrypt( - KMByteBlob.cast(aesSecret).getBuffer(), - KMByteBlob.cast(aesSecret).getStartOff(), - KMByteBlob.cast(aesSecret).length(), - KMByteBlob.cast(input).getBuffer(), - KMByteBlob.cast(input).getStartOff(), - KMByteBlob.cast(input).length(), - scratchPad, - (short) 0, - KMByteBlob.cast(nonce).getBuffer(), - KMByteBlob.cast(nonce).getStartOff(), - KMByteBlob.cast(nonce).length(), - KMByteBlob.cast(authData).getBuffer(), - KMByteBlob.cast(authData).getStartOff(), - KMByteBlob.cast(authData).length(), - KMByteBlob.cast(authTag).getBuffer(), - KMByteBlob.cast(authTag).getStartOff(), - KMByteBlob.cast(authTag).length()); - return KMByteBlob.instance(scratchPad, (short) 0, len); - } private short aesGCMDecrypt(short aesSecret, short input, short nonce, short authData, short authTag,byte[] scratchPad){ - Util.arrayFillNonAtomic(scratchPad, (short) 0, KMByteBlob.cast(input).length(), (byte) 0); + Util.arrayFillNonAtomic(scratchPad, (short) 0, KMByteBlob.length(input), (byte) 0); if (!seProvider.aesGCMDecrypt( - KMByteBlob.cast(aesSecret).getBuffer(), - KMByteBlob.cast(aesSecret).getStartOff(), - KMByteBlob.cast(aesSecret).length(), - KMByteBlob.cast(input).getBuffer(), - KMByteBlob.cast(input).getStartOff(), - KMByteBlob.cast(input).length(), + KMByteBlob.getBuffer(aesSecret), + KMByteBlob.getStartOff(aesSecret), + KMByteBlob.length(aesSecret), + KMByteBlob.getBuffer(input), + KMByteBlob.getStartOff(input), + KMByteBlob.length(input), scratchPad, (short) 0, - KMByteBlob.cast(nonce).getBuffer(), - KMByteBlob.cast(nonce).getStartOff(), - KMByteBlob.cast(nonce).length(), - KMByteBlob.cast(authData).getBuffer(), - KMByteBlob.cast(authData).getStartOff(), - KMByteBlob.cast(authData).length(), - KMByteBlob.cast(authTag).getBuffer(), - KMByteBlob.cast(authTag).getStartOff(), - KMByteBlob.cast(authTag).length())) { + KMByteBlob.getBuffer(nonce), + KMByteBlob.getStartOff(nonce), + KMByteBlob.length(nonce), + KMByteBlob.getBuffer(authData), + KMByteBlob.getStartOff(authData), + KMByteBlob.length(authData), + KMByteBlob.getBuffer(authTag), + KMByteBlob.getStartOff(authTag), + KMByteBlob.length(authTag))) { KMException.throwIt(KMError.VERIFICATION_FAILED); } - return KMByteBlob.instance(scratchPad, (short) 0, KMByteBlob.cast(input).length()); + return KMByteBlob.instance(scratchPad, (short) 0, KMByteBlob.length(input)); } private short finishImportWrappedKeyCmd(APDU apdu){ short cmd = KMArray.instance((short) 8); short params = KMKeyParameters.expAny(); - KMArray.cast(cmd).add((short) 0, params); // Key Params of wrapped key - KMArray.cast(cmd).add((short) 1, KMEnum.instance(KMType.KEY_FORMAT)); // Key Format - KMArray.cast(cmd).add((short) 2, KMByteBlob.exp()); // Wrapped Import Key Blob - KMArray.cast(cmd).add((short) 3, KMByteBlob.exp()); // Auth Tag - KMArray.cast(cmd).add((short) 4, KMByteBlob.exp()); // IV - Nonce - KMArray.cast(cmd) - .add((short) 5, KMByteBlob.exp()); // Wrapped Key ASSOCIATED AUTH DATA - KMArray.cast(cmd).add((short) 6, KMInteger.exp()); // Password Sid - KMArray.cast(cmd).add((short) 7, KMInteger.exp()); // Biometric Sid + KMArray.add(cmd, (short) 0, params); // Key Params of wrapped key + KMArray.add(cmd, (short) 1, KMEnum.instance(KMType.KEY_FORMAT)); // Key Format + KMArray.add(cmd, (short) 2, KMByteBlob.exp()); // Wrapped Import Key Blob + KMArray.add(cmd, (short) 3, KMByteBlob.exp()); // Auth Tag + KMArray.add(cmd, (short) 4, KMByteBlob.exp()); // IV - Nonce + KMArray.add(cmd, (short) 5, KMByteBlob.exp()); // Wrapped Key ASSOCIATED AUTH DATA + KMArray.add(cmd, (short) 6, KMInteger.exp()); // Password Sid + KMArray.add(cmd, (short) 7, KMInteger.exp()); // Biometric Sid return receiveIncoming(apdu, cmd); } //TODO remove cmd later on private void processFinishImportWrappedKeyCmd(APDU apdu){ short cmd = finishImportWrappedKeyCmd(apdu); - short keyParameters = KMArray.cast(cmd).get((short) 0); - short keyFmt = KMArray.cast(cmd).get((short) 1); - keyFmt = KMEnum.cast(keyFmt).getVal(); + short keyParameters = KMArray.get(cmd, (short) 0); + short keyFmt = KMArray.get(cmd, (short) 1); + keyFmt = KMEnum.getVal(keyFmt); validateImportKey(keyParameters, keyFmt); byte[] scratchPad = apdu.getBuffer(); // Step 4 - AES-GCM decrypt the wrapped key - data[INPUT_DATA] = KMArray.cast(cmd).get((short) 2); - data[AUTH_TAG] = KMArray.cast(cmd).get((short) 3); - data[NONCE] = KMArray.cast(cmd).get((short) 4); - data[AUTH_DATA] = KMArray.cast(cmd).get((short) 5); + data[INPUT_DATA] = KMArray.get(cmd, (short) 2); + data[AUTH_TAG] = KMArray.get(cmd, (short) 3); + data[NONCE] = KMArray.get(cmd, (short) 4); + data[AUTH_DATA] = KMArray.get(cmd, (short) 5); if(!isValidWrappingKey()){ KMException.throwIt(KMError.UNKNOWN_ERROR); @@ -1160,16 +1199,16 @@ private void processFinishImportWrappedKeyCmd(APDU apdu){ private KMAttestationCert makeAttestationCert(short attKeyBlob, short attKeyParam, short attChallenge, short issuer, short hwParameters, short swParameters, short keyParams, byte[] scratchPad) { - KMAttestationCert cert = specification.makeCommonCert(swParameters, hwParameters, + KMAttestationCert cert = makeCommonCert(swParameters, hwParameters, keyParams, scratchPad, seProvider); - short subject = KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.CERTIFICATE_SUBJECT_NAME, keyParams); + short subject = KMKeyParameters.findTag(keyParams, KMType.BYTES_TAG, KMType.CERTIFICATE_SUBJECT_NAME); // If no subject name is specified then use the default subject name. - if(subject == KMType.INVALID_VALUE || KMByteTag.cast(subject).length() == 0){ + if(subject == KMType.INVALID_VALUE || KMByteTag.length(subject) == 0){ subject = KMByteBlob.instance(defaultSubject, (short) 0, (short) defaultSubject.length); }else{ - subject = KMByteTag.cast(subject).getValue(); + subject = KMByteTag.getValue(subject); } cert.subjectName(subject); @@ -1178,37 +1217,37 @@ private KMAttestationCert makeAttestationCert(short attKeyBlob, short attKeyPara short appData = KMType.INVALID_VALUE; if(attKeyParam != KMType.INVALID_VALUE) { appId = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_ID, attKeyParam); + KMKeyParameters.findTag(attKeyParam, KMType.BYTES_TAG, KMType.APPLICATION_ID); if (appId != KMTag.INVALID_VALUE) { - appId = KMByteTag.cast(appId).getValue(); + appId = KMByteTag.getValue(appId); } appData = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_DATA, attKeyParam); + KMKeyParameters.findTag(attKeyParam, KMType.BYTES_TAG, KMType.APPLICATION_DATA); if (appData != KMTag.INVALID_VALUE) { - appData = KMByteTag.cast(appData).getValue(); + appData = KMByteTag.getValue(appData); } } //TODO remove following line short origBlob = data[KEY_BLOB]; short pubKey = data[PUB_KEY]; short keyBlob = parseEncryptedKeyBlob(attKeyBlob, appId, appData, scratchPad); - short attestationKeySecret = KMArray.cast(keyBlob).get(KEY_BLOB_SECRET); - short attestParam = KMArray.cast(keyBlob).get(KEY_BLOB_PARAMS); - attestParam = KMKeyCharacteristics.cast(attestParam).getStrongboxEnforced(); + short attestationKeySecret = KMArray.get(keyBlob, KEY_BLOB_SECRET); + short attestParam = KMArray.get(keyBlob, KEY_BLOB_PARAMS); + attestParam = KMKeyCharacteristics.getStrongboxEnforced(attestParam); short attKeyPurpose = - KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, attestParam); + KMKeyParameters.findTag(attestParam, KMType.ENUM_ARRAY_TAG, KMType.PURPOSE); // If the attest key's purpose is not "attest key" then error. - if (!KMEnumArrayTag.cast(attKeyPurpose).contains(KMType.ATTEST_KEY)) { + if (!KMEnumArrayTag.contains(attKeyPurpose, KMType.ATTEST_KEY)) { KMException.throwIt(KMError.INCOMPATIBLE_PURPOSE); } // If issuer is not present then it is an error - if (KMByteBlob.cast(issuer).length() <= 0) { + if (KMByteBlob.length(issuer) <= 0) { KMException.throwIt(KMError.MISSING_ISSUER_SUBJECT_NAME); } - short alg = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, attestParam); + short alg = KMKeyParameters.findTag(attestParam, KMType.ENUM_TAG, KMType.ALGORITHM); - if(KMEnumTag.cast(alg).getValue() == KMType.RSA) { - short attestationKeyPublic = KMArray.cast(keyBlob).get(KEY_BLOB_PUB_KEY); + if(KMEnumTag.getValue(alg) == KMType.RSA) { + short attestationKeyPublic = KMArray.get(keyBlob, KEY_BLOB_PUB_KEY); cert.rsaAttestKey(attestationKeySecret, attestationKeyPublic, KMType.ATTESTATION_CERT); }else{ cert.ecAttestKey(attestationKeySecret, KMType.ATTESTATION_CERT); @@ -1221,7 +1260,7 @@ private KMAttestationCert makeAttestationCert(short attKeyBlob, short attKeyPara // Save attestation application id - must be present. short attAppId = - KMKeyParameters.findTag( KMType.BYTES_TAG, KMType.ATTESTATION_APPLICATION_ID, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.BYTES_TAG, KMType.ATTESTATION_APPLICATION_ID); if (attAppId == KMType.INVALID_VALUE) { KMException.throwIt(KMError.ATTESTATION_APPLICATION_ID_MISSING); } @@ -1248,7 +1287,7 @@ private KMAttestationCert makeAttestationCert(short attKeyBlob, short attKeyPara } private KMAttestationCert makeCertWithFactoryProvisionedKey(short attChallenge, byte[] scratchPad) { - KMAttestationCert cert = specification.makeCommonCert(data[SW_PARAMETERS], data[HW_PARAMETERS], + KMAttestationCert cert = makeCommonCert(data[SW_PARAMETERS], data[HW_PARAMETERS], data[KEY_PARAMETERS], scratchPad, seProvider); cert.attestationChallenge(attChallenge); cert.publicKey(data[PUB_KEY]); @@ -1256,7 +1295,7 @@ private KMAttestationCert makeCertWithFactoryProvisionedKey(short attChallenge, // Save attestation application id - must be present. short attAppId = - KMKeyParameters.findTag( KMType.BYTES_TAG, KMType.ATTESTATION_APPLICATION_ID, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.BYTES_TAG, KMType.ATTESTATION_APPLICATION_ID); if (attAppId == KMType.INVALID_VALUE) { KMException.throwIt(KMError.ATTESTATION_APPLICATION_ID_MISSING); } @@ -1285,237 +1324,32 @@ private KMAttestationCert makeCertWithFactoryProvisionedKey(short attChallenge, private KMAttestationCert makeSelfSignedCert(short attPrivKey, short attPubKey, byte[] scratchPad) { //KMAttestationCert cert = makeCommonCert(scratchPad); KMAttestationCert cert = - specification.makeCommonCert(data[SW_PARAMETERS], data[HW_PARAMETERS], + makeCommonCert(data[SW_PARAMETERS], data[HW_PARAMETERS], data[KEY_PARAMETERS], scratchPad, seProvider); - short alg = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, data[KEY_PARAMETERS]); + short alg = KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.ENUM_TAG, KMType.ALGORITHM); byte mode = KMType.FAKE_CERT; if(attPrivKey != KMType.INVALID_VALUE){ mode = KMType.SELF_SIGNED_CERT; } - short subject = KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.CERTIFICATE_SUBJECT_NAME, data[KEY_PARAMETERS]); + short subject = KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.BYTES_TAG, KMType.CERTIFICATE_SUBJECT_NAME); // If no subject name is specified then use the default subject name. - if(subject == KMType.INVALID_VALUE || KMByteTag.cast(subject).length() == 0){ + if(subject == KMType.INVALID_VALUE || KMByteTag.length(subject) == 0){ subject = KMByteBlob.instance(defaultSubject, (short) 0, (short) defaultSubject.length); }else{ - subject = KMByteTag.cast(subject).getValue(); + subject = KMByteTag.getValue(subject); } - if(KMEnumTag.cast(alg).getValue() == KMType.RSA) { + if(KMEnumTag.getValue(alg) == KMType.RSA) { cert.rsaAttestKey(attPrivKey, attPubKey, mode); }else{ cert.ecAttestKey(attPrivKey, mode); } -// cert.attestKey(attPrivKey, rsaAttest, KMType.SELF_SIGNED_CERT); -// cert.attestKey(KMType.INVALID_VALUE, rsaAttest, KMType.FAKE_CERT); cert.issuer(subject); cert.subjectName(subject); cert.publicKey(attPubKey); return cert; } - // private KMAttestationCert makeFakeCert(byte[] scratchPad) { - // KMAttestationCert cert = makeCommonCert(scratchPad); - // short alg = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, data[KEY_PARAMETERS]); - // boolean rsaAttest = KMEnumTag.cast(alg).getValue() == KMType.RSA; - // - // // If the generated/imported key can sign then mode is self signed - // short subject = KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.CERTIFICATE_SUBJECT_NAME, data[KEY_PARAMETERS]); - // // If no subject name is specified then use the default subject name. - // if(subject == KMType.INVALID_VALUE || KMByteTag.cast(subject).length() == 0){ - // subject = KMByteBlob.instance(defaultSubject, (short) 0, (short) defaultSubject.length); - // }else{ - // subject = KMByteTag.cast(subject).getValue(); - // } - // cert.attestKey(KMType.INVALID_VALUE, rsaAttest,KMType.FAKE_CERT); - // cert.issuer(subject); - // cert.subjectName(subject); - // cert.publicKey(data[PUB_KEY]); - // return cert; - // } - - /** - * 1) If attestation key is present and attestation challenge is absent then it is an error. - * 2) If attestation key is absent and attestation challenge is present then it is an error as - * factory provisioned attestation key is not supported. - * 3) If both are present and issuer is absent or attest key purpose is not ATTEST_KEY then it is an error. - * 4) If the generated/imported keys are RSA or EC then validity period must be specified. - * Device Unique Attestation is not supported. - */ - // private KMAttestationCert makeCert(short attKeyBlob, short attKeyParam, byte[] scratchPad) { - // short appId = KMType.INVALID_VALUE; - // short appData = KMType.INVALID_VALUE; - // if(attKeyParam != KMType.INVALID_VALUE) { - // appId = - // KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_ID, attKeyParam); - // if (appId != KMTag.INVALID_VALUE) { - // appId = KMByteTag.cast(appId).getValue(); - // } - // appData = - // KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_DATA, attKeyParam); - // if (appData != KMTag.INVALID_VALUE) { - // appData = KMByteTag.cast(appData).getValue(); - // } - // } - // byte mode = KMType.FAKE_CERT; - // boolean rsaCert = true; - // short attestationKey = KMType.INVALID_VALUE; - // short attestParam = KMType.INVALID_VALUE; - // boolean rsaAttest = true; - // // No attestation required for symmetric keys - // short alg = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, data[KEY_PARAMETERS]); - // if(KMEnumTag.cast(alg).getValue() != KMType.RSA && - // KMEnumTag.cast(alg).getValue() != KMType.EC){ - // return null; - // } - // // Device unique attestation not supported - // short deviceUniqueAttest = KMKeyParameters.findTag(KMType.BOOL_TAG, - // KMType.DEVICE_UNIQUE_ATTESTATION, data[KEY_PARAMETERS]); - // if(deviceUniqueAttest != KMType.INVALID_VALUE){ - // KMException.throwIt(KMError.CANNOT_ATTEST_IDS); - // } - // if(KMEnumTag.cast(alg).getValue() == KMType.EC) { - // rsaCert = false; - // rsaAttest = false; - // } - // KMAttestationCert cert = seProvider.getAttestationCert(rsaCert); - // // Read attestation challenge if present - // short attChallenge = - // KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.ATTESTATION_CHALLENGE, data[KEY_PARAMETERS]); - // if(attChallenge != KMType.INVALID_VALUE){ - // attChallenge = KMByteTag.cast(attChallenge).getValue(); - // } - // short subject = KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.CERTIFICATE_SUBJECT_NAME, data[KEY_PARAMETERS]); - // // If no subject name is specified then use the default subject name. - // if(subject == KMType.INVALID_VALUE || KMByteTag.cast(subject).length() == 0){ - // subject = KMByteBlob.instance(defaultSubject, (short) 0, (short) defaultSubject.length); - // }else{ - // subject = KMByteTag.cast(subject).getValue(); - // } - // // If attestation key is given by the caller - // if(attKeyBlob != KMType.INVALID_VALUE && KMByteBlob.cast(attKeyBlob).length() > 0) { - // short keyBlob = KMType.INVALID_VALUE; - // keyBlob = parseEncryptedKeyBlob(attKeyBlob, appId, appData, scratchPad); - // - // // If no attestation challenge present then it is an error - // if (attChallenge == KMType.INVALID_VALUE || KMByteBlob.cast(attChallenge).length() <= 0) { - // KMException.throwIt(KMError.INVALID_ARGUMENT); - // } - // mode = KMType.ATTESTATION_CERT; - // attestationKey = KMArray.cast(keyBlob).get(KEY_BLOB_SECRET); - // attestParam = KMArray.cast(keyBlob).get(KEY_BLOB_PARAMS); - // attestParam = KMKeyCharacteristics.cast(attestParam).getStrongboxEnforced(); - // alg = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, attestParam); - // if(KMEnumTag.cast(alg).getValue() == KMType.EC){ - // rsaAttest = false; - // } - // // If issuer is not present then it is an error - // if (KMByteBlob.cast(data[ATTEST_KEY_ISSUER]).length() <= 0) { - // KMException.throwIt(KMError.MISSING_ISSUER_SUBJECT_NAME); - // } - // // TODO KeyMint should parse issuer subject name to validate that it is valid der encoded - // // string. - // // Currently not done as X509 parsing not yet supported. - // - // short attKeyPurpose = - // KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, attestParam); - // // If the attest key's purpose is not "attest key" then error. - // if (!KMEnumArrayTag.cast(attKeyPurpose).contains(KMType.ATTEST_KEY)) { - // KMException.throwIt(KMError.INCOMPATIBLE_PURPOSE); - // } - // }else if (attChallenge != KMType.INVALID_VALUE && KMByteBlob.cast(attChallenge).length() > 0) { - // // If the challenge is present and attest key is absent then it is an error. - // // Note: The keymint applet does not support factory provisioned attestation keys. - // KMException.throwIt(KMError.ATTESTATION_KEYS_NOT_PROVISIONED); - // }else { - // // Both attestation key and challenge are are absent. - // short purpose = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, data[KEY_PARAMETERS]); - // if(purpose != KMType.INVALID_VALUE && KMEnumArrayTag.cast(purpose).contains(KMType.SIGN)) { - // // If the generated/imported key can sign then mode is self signed - // mode = KMType.SELF_SIGNED_CERT; - // attestationKey = data[SECRET]; - // attestParam = data[KEY_PARAMETERS]; - // data[ATTEST_KEY_ISSUER] = subject; - // }else{ - // // else a fake cert i.e. certificated without signature must be generated - // mode = KMType.FAKE_CERT; - // attestationKey = KMType.INVALID_VALUE; - // data[ATTEST_KEY_ISSUER] = subject; - // } - // } - // cert.attestKey(attestationKey, rsaAttest,mode); - // cert.attestationChallenge(attChallenge); - // cert.issuer(data[ATTEST_KEY_ISSUER]); - // cert.subjectName(subject); - // - // // Validity period must be specified - // short notBefore = KMKeyParameters.findTag(KMType.DATE_TAG, KMType.CERTIFICATE_NOT_BEFORE, data[KEY_PARAMETERS]); - // if(notBefore == KMType.INVALID_VALUE){ - // KMException.throwIt(KMError.MISSING_NOT_BEFORE); - // } - // notBefore = KMIntegerTag.cast(notBefore).getValue(); - // short notAfter = KMKeyParameters.findTag(KMType.DATE_TAG, KMType.CERTIFICATE_NOT_AFTER, data[KEY_PARAMETERS]); - // if(notAfter == KMType.INVALID_VALUE ){ - // KMException.throwIt(KMError.MISSING_NOT_AFTER); - // } - // - // notAfter = KMIntegerTag.cast(notAfter).getValue(); - // // VTS sends notBefore == Epoch. - // Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 8, (byte) 0); - // short epoch = KMInteger.instance(scratchPad, (short)0, (short)8); - // short end = KMInteger.instance(dec319999Ms, (short)0, (short)dec319999Ms.length); - // if(KMInteger.compare(notBefore, epoch) == 0){ - // cert.notBefore(KMByteBlob.instance(jan01970, (short)0, (short)jan01970.length), - // true, scratchPad); - // }else { - // cert.notBefore(notBefore, false, scratchPad); - // } - // // VTS sends notAfter == Dec 31st 9999 - // if(KMInteger.compare(notAfter, end) == 0){ - // cert.notAfter(KMByteBlob.instance(dec319999, (short)0, (short)dec319999.length), - // true, scratchPad); - // }else { - // cert.notAfter(notAfter, false, scratchPad); - // } - // // Serial number - // short serialNum = - // KMKeyParameters.findTag(KMType.BIGNUM_TAG, KMType.CERTIFICATE_SERIAL_NUM, data[KEY_PARAMETERS]); - // if (serialNum != KMType.INVALID_VALUE) { - // serialNum = KMBignumTag.cast(serialNum).getValue(); - // }else{ - // serialNum= KMByteBlob.instance((short)1); - // KMByteBlob.cast(serialNum).add((short)0, (byte)1); - // } - // cert.serialNumber(serialNum); - // - // //Extension - // if(mode == KMType.ATTESTATION_CERT){ - // // Save attestation application id - must be present. - // short attAppId = - // KMKeyParameters.findTag( KMType.BYTES_TAG, KMType.ATTESTATION_APPLICATION_ID, data[KEY_PARAMETERS]); - // if (attAppId == KMType.INVALID_VALUE) { - // KMException.throwIt(KMError.ATTESTATION_APPLICATION_ID_MISSING); - // } - // cert.extensionTag(attAppId, false); - // // unique id byte blob - uses application id and temporal month count of creation time. - // setUniqueId(cert, scratchPad); - // // Add Attestation Ids if present - // addAttestationIds(cert, scratchPad); - // // Add Tags - // addTags(data[HW_PARAMETERS], true, cert); - // addTags(data[SW_PARAMETERS], false, cert); - // // Add Device Boot locked status - // cert.deviceLocked(seProvider.isDeviceBootLocked()); - // // VB data - // cert.verifiedBootHash(getVerifiedBootHash(scratchPad)); - // cert.verifiedBootKey(getBootKey(scratchPad)); - // cert.verifiedBootState((byte)seProvider.getBootState()); - // } - // - // // Public key - // cert.publicKey(data[PUB_KEY]); - // return cert; - // } - protected short getBootKey(byte[] scratchPad){ Util.arrayFillNonAtomic(scratchPad, (short)0, VERIFIED_BOOT_KEY_SIZE, (byte)0); short len = seProvider.getBootKey(scratchPad, (short) 0); @@ -1540,75 +1374,64 @@ protected short getVerifiedBootHash(byte[] scratchPad){ // id values of both the requested parameters and the provisioned parameters // then throw INVALID_TAG error. private void addAttestationIds(KMAttestationCert cert, byte[] scratchPad) { - 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; short attIdTagValue; short storedAttIdLen; - while (index < (short) attTags.length) { - attIdTag = KMKeyParameters.findTag(KMType.BYTES_TAG, attTags[index], data[KEY_PARAMETERS]); + while (index < (short) ATTEST_ID_TAGS.length) { + attIdTag = KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.BYTES_TAG, ATTEST_ID_TAGS[index]); if (attIdTag != KMType.INVALID_VALUE) { - attIdTagValue = KMByteTag.cast(attIdTag).getValue(); - storedAttIdLen = seProvider.getAttestationId(attTags[index],scratchPad, (short)0); + attIdTagValue = KMByteTag.getValue(attIdTag); + storedAttIdLen = seProvider.getAttestationId(ATTEST_ID_TAGS[index],scratchPad, (short)0); // Return CANNOT_ATTEST_IDS if Attestation IDs are not provisioned or // Attestation IDs are deleted. if (storedAttIdLen == 0) { KMException.throwIt(KMError.CANNOT_ATTEST_IDS); } // Return INVALID_TAG if Attestation IDs does not match. - if ((storedAttIdLen != KMByteBlob.cast(attIdTagValue).length()) || + if ((storedAttIdLen != KMByteBlob.length(attIdTagValue)) || (0 != Util.arrayCompare(scratchPad, (short) 0, - KMByteBlob.cast(attIdTagValue).getBuffer(), - KMByteBlob.cast(attIdTagValue).getStartOff(), + KMByteBlob.getBuffer(attIdTagValue), + KMByteBlob.getStartOff(attIdTagValue), storedAttIdLen))) { KMException.throwIt(KMError.INVALID_TAG); } short blob = KMByteBlob.instance(scratchPad, (short)0, storedAttIdLen); - cert.extensionTag(KMByteTag.instance(attTags[index], blob), true); + cert.extensionTag(KMByteTag.instance(ATTEST_ID_TAGS[index], blob), true); } index++; } } - private static void addTags(short params, boolean hwEnforced, KMAttestationCert cert) { + private void addTags(short params, boolean hwEnforced, KMAttestationCert cert) { short index = 0; - short arr = KMKeyParameters.cast(params).getVals(); - short len = KMArray.cast(arr).length(); + short arr = KMKeyParameters.getVals(params); + short len = KMArray.length(arr); short tag; while (index < len) { - tag = KMArray.cast(arr).get(index); + tag = KMArray.get(arr, index); cert.extensionTag(tag, hwEnforced); index++; } } - private static void setUniqueId(KMAttestationCert cert, byte[] scratchPad) { + private void setUniqueId(KMAttestationCert cert, byte[] scratchPad) { if(!KMTag.isPresent(data[HW_PARAMETERS],KMType.BOOL_TAG, KMType.INCLUDE_UNIQUE_ID)){ return; } // temporal count T - short time = KMKeyParameters.findTag(KMType.DATE_TAG, KMType.CREATION_DATETIME, data[SW_PARAMETERS]); + short time = KMKeyParameters.findTag(data[SW_PARAMETERS], KMType.DATE_TAG, KMType.CREATION_DATETIME); if(time == KMType.INVALID_VALUE){ KMException.throwIt(KMError.INVALID_TAG); } - time = KMIntegerTag.cast(time).getValue(); + time = KMIntegerTag.getValue(time); // Application Id C - short appId = KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.ATTESTATION_APPLICATION_ID, data[KEY_PARAMETERS]); + short appId = KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.BYTES_TAG, KMType.ATTESTATION_APPLICATION_ID); if (appId == KMType.INVALID_VALUE) { KMException.throwIt(KMError.ATTESTATION_APPLICATION_ID_MISSING); } - appId = KMByteTag.cast(appId).getValue(); + appId = KMByteTag.getValue(appId); // Reset After Rotation R - it will be part of HW Enforced key // characteristics @@ -1617,9 +1440,9 @@ private static void setUniqueId(KMAttestationCert cert, byte[] scratchPad) { resetAfterRotation = 0x01; } - cert.makeUniqueId(scratchPad, (short) 0, KMInteger.cast(time).getBuffer(), - KMInteger.cast(time).getStartOff(), KMInteger.cast(time).length(), - KMByteBlob.cast(appId).getBuffer(), KMByteBlob.cast(appId).getStartOff(), KMByteBlob.cast(appId).length(), resetAfterRotation, + cert.makeUniqueId(scratchPad, (short) 0, KMInteger.getBuffer(time), + KMInteger.getStartOff(time), KMInteger.length(time), + KMByteBlob.getBuffer(appId), KMByteBlob.getStartOff(appId), KMByteBlob.length(appId), resetAfterRotation, seProvider.getMasterKey()); } @@ -1634,13 +1457,13 @@ private void processVerifyAuthorizationCmd(APDU apdu) { private short abortOperationCmd(APDU apdu){ short cmd = KMArray.instance((short) 1); - KMArray.cast(cmd).add((short) 0, KMInteger.exp()); + KMArray.add(cmd, (short) 0, KMInteger.exp()); return receiveIncoming(apdu, cmd); } private void processAbortOperationCmd(APDU apdu) { short cmd = abortOperationCmd(apdu); - data[OP_HANDLE] = KMArray.cast(cmd).get((short) 0); + data[OP_HANDLE] = KMArray.get(cmd, (short) 0); KMOperationState op = findOperation(data[OP_HANDLE]); if (op == null) { sendError(apdu,KMError.INVALID_OPERATION_HANDLE); @@ -1651,14 +1474,15 @@ private void processAbortOperationCmd(APDU apdu) { } private short finishOperationCmd(APDU apdu){ - return receiveIncoming(apdu, specification.prepareFinishExp()); + return receiveIncoming(apdu, prepareFinishExp()); } private void processFinishOperationCmd(APDU apdu) { short cmd = finishOperationCmd(apdu); - byte[] scratchPad = apdu.getBuffer(); - specification.getFinishInputParameters(cmd, data, OP_HANDLE, KEY_PARAMETERS, INPUT_DATA, - SIGNATURE, HW_TOKEN, VERIFICATION_TOKEN, CONFIRMATION_TOKEN); + byte[] scratchPad = apdu.getBuffer(); + getFinishInputParameters(cmd, data, OP_HANDLE, KEY_PARAMETERS, INPUT_DATA, + SIGNATURE, HW_TOKEN, VERIFICATION_TOKEN, CONFIRMATION_TOKEN); + // Check Operation Handle KMOperationState op = findOperation(data[OP_HANDLE]); if (op == null) { @@ -1679,11 +1503,7 @@ private void processFinishOperationCmd(APDU apdu) { finishDecryptOperation(op, scratchPad); break; case KMType.AGREE_KEY: - if(specification.isKeyAgreementSupported()) { - finishKeyAgreementOperation(op, scratchPad); - } else { - KMException.throwIt(KMError.UNIMPLEMENTED); - } + finishKeyAgreementOperation(op, scratchPad); break; } if (data[OUTPUT_DATA] == KMType.INVALID_VALUE) { @@ -1693,7 +1513,7 @@ private void processFinishOperationCmd(APDU apdu) { releaseOperation(op); // make response - sendOutgoing(apdu, specification.prepareFinishResp(data[OUTPUT_DATA])); + sendOutgoing(apdu, prepareFinishResp(data[OUTPUT_DATA])); } private void finishEncryptOperation(KMOperationState op, byte[] scratchPad) { @@ -1704,7 +1524,7 @@ private void finishEncryptOperation(KMOperationState op, byte[] scratchPad) { } private void finishDecryptOperation(KMOperationState op, byte[] scratchPad) { - short len = KMByteBlob.cast(data[INPUT_DATA]).length(); + short len = KMByteBlob.length(data[INPUT_DATA]); switch (op.getAlgorithm()) { case KMType.RSA: // Fill the scratch pad with zero @@ -1714,7 +1534,7 @@ private void finishDecryptOperation(KMOperationState op, byte[] scratchPad) { } len = op.getOperation().finish( - KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), + KMByteBlob.getBuffer(data[INPUT_DATA]), KMByteBlob.getStartOff(data[INPUT_DATA]), len, scratchPad, (short) 0); data[OUTPUT_DATA] = KMByteBlob.instance(scratchPad, (short) 0, len); @@ -1727,7 +1547,7 @@ private void finishDecryptOperation(KMOperationState op, byte[] scratchPad) { } private void finishAesDesOperation(KMOperationState op){ - short len = KMByteBlob.cast(data[INPUT_DATA]).length(); + short len = KMByteBlob.length(data[INPUT_DATA]); short blockSize = AES_BLOCK_SIZE; if (op.getAlgorithm() == KMType.DES) { blockSize= DES_BLOCK_SIZE; @@ -1757,40 +1577,21 @@ private void finishAesDesOperation(KMOperationState op){ data[OUTPUT_DATA] = KMByteBlob.instance((short) (len + 2 * blockSize)); try { len = op.getOperation().finish( - KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), - KMByteBlob.cast(data[INPUT_DATA]).length(), - KMByteBlob.cast(data[OUTPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[OUTPUT_DATA]).getStartOff()); + KMByteBlob.getBuffer(data[INPUT_DATA]), + KMByteBlob.getStartOff(data[INPUT_DATA]), + KMByteBlob.length(data[INPUT_DATA]), + KMByteBlob.getBuffer(data[OUTPUT_DATA]), + KMByteBlob.getStartOff(data[OUTPUT_DATA])); } catch (CryptoException e) { if (e.getReason() == CryptoException.ILLEGAL_USE) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); } } - KMByteBlob.cast(data[OUTPUT_DATA]).setLength(len); + KMByteBlob.setLength(data[OUTPUT_DATA], len); } - private void finishKeyAgreementOperation(KMOperationState op, byte[] scratchPad) { - try { - KMPKCS8Decoder pkcs8 = KMPKCS8Decoder.instance(); - short blob = pkcs8.decodeEcSubjectPublicKeyInfo(data[INPUT_DATA]); - short len = op.getOperation().finish( - KMByteBlob.cast(blob).getBuffer(), - KMByteBlob.cast(blob).getStartOff(), - KMByteBlob.cast(blob).length(), - scratchPad, - (short) 0 - ); - data[OUTPUT_DATA] = KMByteBlob.instance((short) 32); - Util.arrayCopyNonAtomic( - scratchPad, - (short) 0, - KMByteBlob.cast(data[OUTPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[OUTPUT_DATA]).getStartOff(), - len); - } catch (CryptoException e) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } + public void finishKeyAgreementOperation(KMOperationState op, byte[] scratchPad) { + KMException.throwIt(KMError.UNIMPLEMENTED); } private void finishSigningVerifyingOperation(KMOperationState op, byte[] scratchPad) { @@ -1802,17 +1603,17 @@ private void finishSigningVerifyingOperation(KMOperationState op, byte[] scratch if (op.getPurpose() == KMType.SIGN) { // len of signature will be 256 bytes - but it can be less then 256 bytes short len = op.getOperation().sign( - KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), - KMByteBlob.cast(data[INPUT_DATA]).length(), scratchPad, + KMByteBlob.getBuffer(data[INPUT_DATA]), + KMByteBlob.getStartOff(data[INPUT_DATA]), + KMByteBlob.length(data[INPUT_DATA]), scratchPad, (short) 0); // Maximum output size of signature is 256 bytes. - the signature will always be positive data[OUTPUT_DATA] = KMByteBlob.instance((short) 256); Util.arrayCopyNonAtomic( scratchPad, (short) 0, - KMByteBlob.cast(data[OUTPUT_DATA]).getBuffer(), - (short) (KMByteBlob.cast(data[OUTPUT_DATA]).getStartOff() + 256 - len), + KMByteBlob.getBuffer(data[OUTPUT_DATA]), + (short) (KMByteBlob.getStartOff(data[OUTPUT_DATA]) + 256 - len), len); } else { KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); @@ -1822,7 +1623,7 @@ private void finishSigningVerifyingOperation(KMOperationState op, byte[] scratch } break; case KMType.EC: - short len = KMByteBlob.cast(data[INPUT_DATA]).length(); + short len = KMByteBlob.length(data[INPUT_DATA]); // If DIGEST NONE then truncate the input data to 32 bytes. if (op.getDigest() == KMType.DIGEST_NONE && len > 32) { len = 32; @@ -1832,8 +1633,8 @@ private void finishSigningVerifyingOperation(KMOperationState op, byte[] scratch len = op.getOperation() .sign( - KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), + KMByteBlob.getBuffer(data[INPUT_DATA]), + KMByteBlob.getStartOff(data[INPUT_DATA]), len, scratchPad, (short) 0); @@ -1856,9 +1657,9 @@ private void finishSigningVerifyingOperation(KMOperationState op, byte[] scratch // instead of using op.getPurpose(). op.getOperation() .sign( - KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), - KMByteBlob.cast(data[INPUT_DATA]).length(), + KMByteBlob.getBuffer(data[INPUT_DATA]), + KMByteBlob.getStartOff(data[INPUT_DATA]), + KMByteBlob.length(data[INPUT_DATA]), scratchPad, (short) 0); if(op.getPurpose() == KMType.SIGN) { @@ -1869,9 +1670,9 @@ private void finishSigningVerifyingOperation(KMOperationState op, byte[] scratch if (0 != Util.arrayCompare( scratchPad, (short)0, - KMByteBlob.cast(data[SIGNATURE]).getBuffer(), - KMByteBlob.cast(data[SIGNATURE]).getStartOff(), - KMByteBlob.cast(data[SIGNATURE]).length())) { + KMByteBlob.getBuffer(data[SIGNATURE]), + KMByteBlob.getStartOff(data[SIGNATURE]), + KMByteBlob.length(data[SIGNATURE]))) { KMException.throwIt(KMError.VERIFICATION_FAILED); } data[OUTPUT_DATA] = KMByteBlob.instance((short) 0); @@ -1889,12 +1690,12 @@ private void authorizeUpdateFinishOperation(KMOperationState op, byte[] scratchP // Validate Verification Token. validateVerificationToken(data[VERIFICATION_TOKEN], scratchPad); // validate operation handle. - short ptr = KMVerificationToken.cast(data[VERIFICATION_TOKEN]).getChallenge(); + short ptr = KMVerificationToken.getChallenge(data[VERIFICATION_TOKEN]); if (KMInteger.compare(ptr, op.getHandle()) != 0) { KMException.throwIt(KMError.VERIFICATION_FAILED); } tmpVariables[0] = op.getAuthTime(); - tmpVariables[2] = KMVerificationToken.cast(data[VERIFICATION_TOKEN]).getTimestamp(); + tmpVariables[2] = KMVerificationToken.getTimestamp(data[VERIFICATION_TOKEN]); if (tmpVariables[2] == KMType.INVALID_VALUE) { KMException.throwIt(KMError.VERIFICATION_FAILED); } @@ -1903,7 +1704,7 @@ private void authorizeUpdateFinishOperation(KMOperationState op, byte[] scratchP } op.setAuthTimeoutValidated(true); } else if (op.isAuthPerOperationReqd()) { // If Auth per operation is required - tmpVariables[0] = KMHardwareAuthToken.cast(data[HW_TOKEN]).getChallenge(); + tmpVariables[0] = KMHardwareAuthToken.getChallenge(data[HW_TOKEN]); if (KMInteger.compare(data[OP_HANDLE], tmpVariables[0]) != 0) { KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED); } @@ -1960,14 +1761,13 @@ private void authorizeDeviceUnlock(byte[] scratchPad) { // If device is locked and key characteristics requires unlocked device then check whether // HW auth token has correct timestamp. short ptr = - KMKeyParameters.findTag( - KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED, data[HW_PARAMETERS]); + KMKeyParameters.findTag(data[HW_PARAMETERS], KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED); if (ptr != KMType.INVALID_VALUE && repository.getDeviceLock()) { if (!validateHwToken(data[HW_TOKEN], scratchPad)) { KMException.throwIt(KMError.DEVICE_LOCKED); } - ptr = KMHardwareAuthToken.cast(data[HW_TOKEN]).getTimestamp(); + ptr = KMHardwareAuthToken.getTimestamp(data[HW_TOKEN]); // Check if the current auth time stamp is greater than device locked time stamp short ts = repository.getDeviceTimeStamp(); if (KMInteger.compare(ptr, ts) <= 0) { @@ -1976,8 +1776,8 @@ private void authorizeDeviceUnlock(byte[] scratchPad) { // Now check if the device unlock requires password only authentication and whether // auth token is generated through password authentication or not. if (repository.getDeviceLockPasswordOnly()) { - ptr = KMHardwareAuthToken.cast(data[HW_TOKEN]).getHwAuthenticatorType(); - ptr = KMEnum.cast(ptr).getVal(); + ptr = KMHardwareAuthToken.getHwAuthenticatorType(data[HW_TOKEN]); + ptr = KMEnum.getVal(ptr); if (((byte) ptr & KMType.PASSWORD) == 0) { KMException.throwIt(KMError.DEVICE_LOCKED); } @@ -1998,35 +1798,33 @@ private boolean verifyVerificationTokenMacInBigEndian(short verToken, byte[] scr (short) authVerification.length); short len = (short) authVerification.length; // concatenate challenge - 8 bytes - short ptr = KMVerificationToken.cast(verToken).getChallenge(); - KMInteger.cast(ptr) - .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); + short ptr = KMVerificationToken.getChallenge(verToken); + KMInteger.value(ptr, scratchPad, (short) (len + (short) (8 - KMInteger.length(ptr)))); len += 8; // concatenate timestamp -8 bytes - ptr = KMVerificationToken.cast(verToken).getTimestamp(); - KMInteger.cast(ptr) - .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); + ptr = KMVerificationToken.getTimestamp(verToken); + KMInteger.value(ptr, scratchPad, (short) (len + (short) (8 - KMInteger.length(ptr)))); len += 8; // concatenate security level - 4 bytes scratchPad[(short) (len + 3)] = TRUSTED_ENVIRONMENT; len += 4; // hmac the data - ptr = specification.getMacFromVerificationToken(verToken); + ptr = getMacFromVerificationToken(verToken); return seProvider.hmacVerify( seProvider.getComputedHmacKey(), scratchPad, (short) 0, len, - KMByteBlob.cast(ptr).getBuffer(), - KMByteBlob.cast(ptr).getStartOff(), - KMByteBlob.cast(ptr).length()); + KMByteBlob.getBuffer(ptr), + KMByteBlob.getStartOff(ptr), + KMByteBlob.length(ptr)); } private void validateVerificationToken(short verToken, byte[] scratchPad) { - short ptr = specification.getMacFromVerificationToken(verToken); + short ptr = getMacFromVerificationToken(verToken); // If mac length is zero then token is empty. - if (KMByteBlob.cast(ptr).length() == 0) { + if (KMByteBlob.length(ptr) == 0) { KMException.throwIt(KMError.INVALID_MAC_LENGTH); } if (!verifyVerificationTokenMacInBigEndian(verToken, scratchPad)) { @@ -2036,14 +1834,14 @@ private void validateVerificationToken(short verToken, byte[] scratchPad) { } private short updateOperationCmd(APDU apdu){ - return receiveIncoming(apdu, specification.prepareUpdateExp()); + return receiveIncoming(apdu, prepareUpdateExp()); } private void processUpdateOperationCmd(APDU apdu) { short cmd = updateOperationCmd(apdu); byte[] scratchPad = apdu.getBuffer(); - specification.getUpdateInputParameters(cmd, data, OP_HANDLE, KEY_PARAMETERS, - INPUT_DATA, HW_TOKEN, VERIFICATION_TOKEN); + getUpdateInputParameters(cmd, data, OP_HANDLE, KEY_PARAMETERS, + INPUT_DATA, HW_TOKEN, VERIFICATION_TOKEN); // Input data must be present even if it is zero length. if (data[INPUT_DATA] == KMType.INVALID_VALUE) { @@ -2063,9 +1861,9 @@ private void processUpdateOperationCmd(APDU apdu) { // update the data. op.getOperation() .update( - KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), - KMByteBlob.cast(data[INPUT_DATA]).length()); + KMByteBlob.getBuffer(data[INPUT_DATA]), + KMByteBlob.getStartOff(data[INPUT_DATA]), + KMByteBlob.length(data[INPUT_DATA])); // update trusted confirmation operation updateTrustedConfirmationOperation(op); @@ -2076,7 +1874,7 @@ private void processUpdateOperationCmd(APDU apdu) { if (op.getAlgorithm() == KMType.RSA) { KMException.throwIt(KMError.OPERATION_CANCELLED); } - short len = KMByteBlob.cast(data[INPUT_DATA]).length(); + short len = KMByteBlob.length(data[INPUT_DATA]); short blockSize = DES_BLOCK_SIZE; if (op.getAlgorithm() == KMType.AES) { blockSize = AES_BLOCK_SIZE; @@ -2104,18 +1902,18 @@ private void processUpdateOperationCmd(APDU apdu) { len = op.getOperation() .update( - KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), - KMByteBlob.cast(data[INPUT_DATA]).length(), - KMByteBlob.cast(data[OUTPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[OUTPUT_DATA]).getStartOff()); + KMByteBlob.getBuffer(data[INPUT_DATA]), + KMByteBlob.getStartOff(data[INPUT_DATA]), + KMByteBlob.length(data[INPUT_DATA]), + KMByteBlob.getBuffer(data[OUTPUT_DATA]), + KMByteBlob.getStartOff(data[OUTPUT_DATA])); } catch (CryptoException e) { KMException.throwIt(KMError.INVALID_TAG); } // Adjust the Output data if it is not equal to input data. // This happens in case of JCardSim provider. - KMByteBlob.cast(data[OUTPUT_DATA]).setLength(len); + KMByteBlob.setLength(data[OUTPUT_DATA], len); } if (data[OUTPUT_DATA] == KMType.INVALID_VALUE) { @@ -2123,35 +1921,32 @@ private void processUpdateOperationCmd(APDU apdu) { } // Persist if there are any updates. // make response - sendOutgoing(apdu, specification.prepareUpdateResp(data[OUTPUT_DATA], KMInteger.uint_16(inputConsumed))); + sendOutgoing(apdu, prepareUpdateResp(data[OUTPUT_DATA], KMInteger.uint_16(inputConsumed))); } private short updateAadOperationCmd(APDU apdu){ short cmd = KMArray.instance((short) 4); - KMArray.cast(cmd).add((short) 0, KMInteger.exp()); - KMArray.cast(cmd).add((short) 1, KMByteBlob.exp()); + KMArray.add(cmd, (short) 0, KMInteger.exp()); + KMArray.add(cmd, (short) 1, KMByteBlob.exp()); short authToken = KMHardwareAuthToken.exp(); - KMArray.cast(cmd).add((short) 2, authToken); - short verToken = specification.getKMVerificationTokenExp(); - KMArray.cast(cmd).add((short) 3, verToken); + KMArray.add(cmd, (short) 2, authToken); + short verToken = getKMVerificationTokenExp(); + KMArray.add(cmd, (short) 3, verToken); return receiveIncoming(apdu, cmd); } //update operation should send 0x00 for finish variable, where as finish operation // should send 0x01 for finish variable. - private void updateAAD(KMOperationState op, byte finish) { - if (!specification.isAssociatedDataTagSupported()) { - return; - } + public void updateAAD(KMOperationState op, byte finish) { // Is input data absent if (data[INPUT_DATA] == KMType.INVALID_VALUE) { KMException.throwIt(KMError.INVALID_ARGUMENT); } // Update can be called either to update auth data, update input data or both. // But if it is called for neither then return error. - short len = KMByteBlob.cast(data[INPUT_DATA]).length(); + short len = KMByteBlob.length(data[INPUT_DATA]); short tag = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.ASSOCIATED_DATA, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.BYTES_TAG, KMType.ASSOCIATED_DATA); // For Finish operation the input data can be zero length and associated data can be // INVALID_VALUE // For update operation either input data or associated data should be present. @@ -2165,23 +1960,23 @@ private void updateAAD(KMOperationState op, byte finish) { KMException.throwIt(KMError.INVALID_TAG); } // If allowed the update the aad - short aData = KMByteTag.cast(tag).getValue(); + short aData = KMByteTag.getValue(tag); op.getOperation() .updateAAD( - KMByteBlob.cast(aData).getBuffer(), - KMByteBlob.cast(aData).getStartOff(), - KMByteBlob.cast(aData).length()); + KMByteBlob.getBuffer(aData), + KMByteBlob.getStartOff(aData), + KMByteBlob.length(aData)); } } private void processUpdateAadOperationCmd(APDU apdu) { short cmd = updateAadOperationCmd(apdu); byte[] scratchPad = apdu.getBuffer(); - data[OP_HANDLE] = KMArray.cast(cmd).get((short) 0); - data[INPUT_DATA] = KMArray.cast(cmd).get((short) 1); - data[HW_TOKEN] = KMArray.cast(cmd).get((short) 2); - data[VERIFICATION_TOKEN] = KMArray.cast(cmd).get((short) 3); + data[OP_HANDLE] = KMArray.get(cmd, (short) 0); + data[INPUT_DATA] = KMArray.get(cmd, (short) 1); + data[HW_TOKEN] = KMArray.get(cmd, (short) 2); + data[VERIFICATION_TOKEN] = KMArray.get(cmd, (short) 3); // Input data must be present even if it is zero length. if (data[INPUT_DATA] == KMType.INVALID_VALUE) { @@ -2208,18 +2003,18 @@ private void processUpdateAadOperationCmd(APDU apdu) { // authorize the update operation authorizeUpdateFinishOperation(op, scratchPad); try { - op.getOperation() - .updateAAD( - KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), - KMByteBlob.cast(data[INPUT_DATA]).length()); + op.getOperation() + .updateAAD( + KMByteBlob.getBuffer(data[INPUT_DATA]), + KMByteBlob.getStartOff(data[INPUT_DATA]), + KMByteBlob.length(data[INPUT_DATA])); } catch(CryptoException exp){ KMException.throwIt(KMError.UNKNOWN_ERROR); } // make response short resp = KMArray.instance((short) 1); - KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); + KMArray.add(resp, (short) 0, buildErrorStatus(KMError.OK)); sendOutgoing(apdu, resp); } @@ -2227,56 +2022,39 @@ private short beginOperationCmd(APDU apdu){ short cmd = KMArray.instance((short) 4); // Arguments short params = KMKeyParameters.expAny(); - KMArray.cast(cmd).add((short) 0, KMEnum.instance(KMType.PURPOSE)); - KMArray.cast(cmd).add((short) 1, KMByteBlob.exp()); - KMArray.cast(cmd).add((short) 2, params); + KMArray.add(cmd, (short) 0, KMEnum.instance(KMType.PURPOSE)); + KMArray.add(cmd, (short) 1, KMByteBlob.exp()); + KMArray.add(cmd, (short) 2, params); short authToken = KMHardwareAuthToken.exp(); - KMArray.cast(cmd).add((short) 3, authToken); + KMArray.add(cmd, (short) 3, authToken); return receiveIncoming(apdu, cmd); } - - void assertPrivateOperation(short purpose, short algorithm) { - switch(algorithm) { - case KMType.RSA: - if (purpose == KMType.ENCRYPT || purpose == KMType.VERIFY) { - KMException.throwIt(KMError.PUBLIC_KEY_OPERATION); - } - break; - case KMType.EC: - if (purpose == KMType.VERIFY) { - KMException.throwIt(KMError.PUBLIC_KEY_OPERATION); - } - break; - default: - break; - } - } private void processBeginOperationCmd(APDU apdu) { // Receive the incoming request fully from the master into buffer. short cmd = beginOperationCmd(apdu); byte[] scratchPad = apdu.getBuffer(); - short purpose = KMArray.cast(cmd).get((short) 0); - data[KEY_BLOB] = KMArray.cast(cmd).get((short) 1); - data[KEY_PARAMETERS] = KMArray.cast(cmd).get((short) 2); - data[HW_TOKEN] = KMArray.cast(cmd).get((short) 3); - purpose = KMEnum.cast(purpose).getVal(); + short purpose = KMArray.get(cmd, (short) 0); + data[KEY_BLOB] = KMArray.get(cmd, (short) 1); + data[KEY_PARAMETERS] = KMArray.get(cmd, (short) 2); + data[HW_TOKEN] = KMArray.get(cmd, (short) 3); + purpose = KMEnum.getVal(purpose); // Check for app id and app data. data[APP_ID] = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_ID, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.BYTES_TAG, KMType.APPLICATION_ID); data[APP_DATA] = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_DATA, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.BYTES_TAG, KMType.APPLICATION_DATA); if (data[APP_ID] != KMTag.INVALID_VALUE) { - data[APP_ID] = KMByteTag.cast(data[APP_ID]).getValue(); + data[APP_ID] = KMByteTag.getValue(data[APP_ID]); } if (data[APP_DATA] != KMTag.INVALID_VALUE) { - data[APP_DATA] = KMByteTag.cast(data[APP_DATA]).getValue(); + data[APP_DATA] = KMByteTag.getValue(data[APP_DATA]); } // Parse the encrypted blob and decrypt it. parseEncryptedKeyBlob(data[KEY_BLOB], data[APP_ID], data[APP_DATA], scratchPad); KMTag.assertPresence(data[SB_PARAMETERS],KMType.ENUM_TAG,KMType.ALGORITHM,KMError.UNSUPPORTED_ALGORITHM); short algorithm = KMEnumTag.getValue(KMType.ALGORITHM,data[SB_PARAMETERS]); - + //TODO should be removed for keymint // If Blob usage tag is present in key characteristics then it should be standalone. if(KMTag.isPresent(data[SB_PARAMETERS],KMType.ENUM_TAG, KMType.BLOB_USAGE_REQ)){ @@ -2288,21 +2066,21 @@ private void processBeginOperationCmd(APDU apdu) { // Generate a random number for operation handle short buf = KMByteBlob.instance(KMOperationState.OPERATION_HANDLE_SIZE); generateUniqueOperationHandle( - KMByteBlob.cast(buf).getBuffer(), - KMByteBlob.cast(buf).getStartOff(), - KMByteBlob.cast(buf).length()); + KMByteBlob.getBuffer(buf), + KMByteBlob.getStartOff(buf), + KMByteBlob.length(buf)); /* opHandle is a KMInteger and is encoded as KMInteger when it is returned back. */ short opHandle = KMInteger.instance( - KMByteBlob.cast(buf).getBuffer(), - KMByteBlob.cast(buf).getStartOff(), - KMByteBlob.cast(buf).length()); + KMByteBlob.getBuffer(buf), + KMByteBlob.getStartOff(buf), + KMByteBlob.length(buf)); KMOperationState op = reserveOperation(algorithm,opHandle); if (op == null) { KMException.throwIt(KMError.TOO_MANY_OPERATIONS); } data[OP_HANDLE] = op.getHandle(); op.setPurpose((byte) purpose); - op.setKeySize(KMByteBlob.cast(data[SECRET]).length()); + op.setKeySize(KMByteBlob.length(data[SECRET])); authorizeAndBeginOperation(op, scratchPad); switch (op.getPurpose()) { case KMType.SIGN: @@ -2315,11 +2093,7 @@ private void processBeginOperationCmd(APDU apdu) { beginCipherOperation(op); break; case KMType.AGREE_KEY: - if(specification.isKeyAgreementSupported()) { - beginKeyAgreementOperation(op); - } else { - KMException.throwIt(KMError.UNIMPLEMENTED); - } + beginKeyAgreementOperation(op); break; default: KMException.throwIt(KMError.UNIMPLEMENTED); @@ -2338,33 +2112,24 @@ private void processBeginOperationCmd(APDU apdu) { // 8 bytes back. short ivBlob = KMByteBlob.instance((short) 8); Util.arrayCopy( - KMByteBlob.cast(data[IV]).getBuffer(), - KMByteBlob.cast(data[IV]).getStartOff(), - KMByteBlob.cast(ivBlob).getBuffer(), - KMByteBlob.cast(ivBlob).getStartOff(), + KMByteBlob.getBuffer(data[IV]), + KMByteBlob.getStartOff(data[IV]), + KMByteBlob.getBuffer(ivBlob), + KMByteBlob.getStartOff(ivBlob), (short) 8); data[IV] = ivBlob; } - KMArray.cast(iv).add((short) 0, KMByteTag.instance(KMType.NONCE, data[IV])); + KMArray.add(iv, (short) 0, KMByteTag.instance(KMType.NONCE, data[IV])); } else { iv = KMArray.instance((short) 0); } short params = KMKeyParameters.instance(iv); - short resp = - specification.prepareBeginResp(params, data[OP_HANDLE], KMInteger.uint_8(op.getBufferingMode()), - KMInteger.uint_16((short) (op.getMacLength() / 8))); + short resp = prepareBeginResp(params, data[OP_HANDLE], KMInteger.uint_8(op.getBufferingMode()), + KMInteger.uint_16((short) (op.getMacLength() / 8))); sendOutgoing(apdu, resp); } - private void authorizeAlgorithm(KMOperationState op) { - short alg = KMEnumTag.getValue(KMType.ALGORITHM, data[HW_PARAMETERS]); - if (alg == KMType.INVALID_VALUE) { - KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); - } - op.setAlgorithm((byte) alg); - } - private void authorizePurpose(KMOperationState op) { switch (op.getAlgorithm()) { case KMType.AES: @@ -2399,16 +2164,16 @@ private void authorizePurpose(KMOperationState op) { private void authorizeDigest(KMOperationState op) { short digests = - KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, data[HW_PARAMETERS]); + KMKeyParameters.findTag(data[HW_PARAMETERS], KMType.ENUM_ARRAY_TAG, KMType.DIGEST); op.setDigest(KMType.DIGEST_NONE); short param = - KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.ENUM_ARRAY_TAG, KMType.DIGEST); if (param != KMType.INVALID_VALUE) { - if (KMEnumArrayTag.cast(param).length() != 1) { + if (KMEnumArrayTag.length(param) != 1) { KMException.throwIt(KMError.UNSUPPORTED_DIGEST); } - param = KMEnumArrayTag.cast(param).get((short) 0); - if (!KMEnumArrayTag.cast(digests).contains(param)) { + param = KMEnumArrayTag.get(param, (short) 0); + if (!KMEnumArrayTag.contains(digests, param)) { KMException.throwIt(KMError.INCOMPATIBLE_DIGEST); } op.setDigest((byte) param); @@ -2416,13 +2181,13 @@ private void authorizeDigest(KMOperationState op) { KMException.throwIt(KMError.UNSUPPORTED_DIGEST); } short paramPadding = - KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.ENUM_ARRAY_TAG, KMType.PADDING); if (paramPadding != KMType.INVALID_VALUE) { - if (KMEnumArrayTag.cast(paramPadding).length() != 1) { + if (KMEnumArrayTag.length(paramPadding) != 1) { //TODO vts fails because it expects UNSUPPORTED_PADDING_MODE KMException.throwIt(KMError.UNSUPPORTED_PADDING_MODE); } - paramPadding = KMEnumArrayTag.cast(paramPadding).get((short) 0); + paramPadding = KMEnumArrayTag.get(paramPadding, (short) 0); } switch (op.getAlgorithm()) { case KMType.RSA: @@ -2444,16 +2209,16 @@ private void authorizeDigest(KMOperationState op) { private void authorizePadding(KMOperationState op) { short paddings = - KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, data[HW_PARAMETERS]); + KMKeyParameters.findTag(data[HW_PARAMETERS], KMType.ENUM_ARRAY_TAG, KMType.PADDING); op.setPadding(KMType.PADDING_NONE); short param = - KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.ENUM_ARRAY_TAG, KMType.PADDING); if (param != KMType.INVALID_VALUE) { - if (KMEnumArrayTag.cast(param).length() != 1) { + if (KMEnumArrayTag.length(param) != 1) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - param = KMEnumArrayTag.cast(param).get((short) 0); - if (!KMEnumArrayTag.cast(paddings).contains(param)) { + param = KMEnumArrayTag.get(param, (short) 0); + if (!KMEnumArrayTag.contains(paddings, param)) { KMException.throwIt(KMError.INCOMPATIBLE_PADDING_MODE); } } @@ -2484,7 +2249,7 @@ private void authorizePadding(KMOperationState op) { } if(param == KMType.RSA_OAEP) { op.setMgfDigest( - (byte) specification.getMgf1Digest(data[KEY_PARAMETERS], data[HW_PARAMETERS])); + (byte) getMgf1Digest(data[KEY_PARAMETERS], data[HW_PARAMETERS])); } op.setPadding((byte) param); break; @@ -2502,12 +2267,12 @@ private void authorizePadding(KMOperationState op) { private void authorizeBlockModeAndMacLength(KMOperationState op) { short param = - KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE); if (param != KMType.INVALID_VALUE) { - if (KMEnumArrayTag.cast(param).length() != 1) { + if (KMEnumArrayTag.length(param) != 1) { KMException.throwIt(KMError.UNSUPPORTED_BLOCK_MODE); } - param = KMEnumArrayTag.cast(param).get((short) 0); + param = KMEnumArrayTag.get(param, (short) 0); } if (KMType.AES == op.getAlgorithm() || KMType.DES == op.getAlgorithm()) { if (!KMEnumArrayTag.contains(KMType.BLOCK_MODE, param, data[HW_PARAMETERS])) { @@ -2626,26 +2391,26 @@ private void authorizeAndBeginOperation(KMOperationState op, byte[] scratchPad) KMException.throwIt(KMError.CALLER_NONCE_PROHIBITED); } - short nonce = KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.NONCE, data[KEY_PARAMETERS]); + short nonce = KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.BYTES_TAG, KMType.NONCE); // If Nonce is present then check whether the size of nonce is correct. if (nonce != KMType.INVALID_VALUE) { - data[IV] = KMByteTag.cast(nonce).getValue(); + data[IV] = KMByteTag.getValue(nonce); // For CBC mode - iv must be 8 bytes if (op.getBlockMode() == KMType.CBC && op.getAlgorithm() == KMType.DES - && KMByteBlob.cast(data[IV]).length() != 8) { + && KMByteBlob.length(data[IV]) != 8) { KMException.throwIt(KMError.INVALID_NONCE); } // For GCM mode - IV must be 12 bytes - if (KMByteBlob.cast(data[IV]).length() != 12 && op.getBlockMode() == KMType.GCM) { + if (KMByteBlob.length(data[IV]) != 12 && op.getBlockMode() == KMType.GCM) { KMException.throwIt(KMError.INVALID_NONCE); } // For AES CBC and CTR modes IV must be 16 bytes if ((op.getBlockMode() == KMType.CBC || op.getBlockMode() == KMType.CTR) && op.getAlgorithm() == KMType.AES - && KMByteBlob.cast(data[IV]).length() != 16) { + && KMByteBlob.length(data[IV]) != 16) { KMException.throwIt(KMError.INVALID_NONCE); } } else if (op.getAlgorithm() == KMType.AES || op.getAlgorithm() == KMType.DES) { @@ -2670,30 +2435,15 @@ private void authorizeAndBeginOperation(KMOperationState op, byte[] scratchPad) } data[IV] = KMByteBlob.instance(ivLen); seProvider.newRandomNumber( - KMByteBlob.cast(data[IV]).getBuffer(), - KMByteBlob.cast(data[IV]).getStartOff(), - KMByteBlob.cast(data[IV]).length()); + KMByteBlob.getBuffer(data[IV]), + KMByteBlob.getStartOff(data[IV]), + KMByteBlob.length(data[IV])); } } } - private void beginKeyAgreementOperation(KMOperationState op) { - if (op.getAlgorithm() != KMType.EC) - KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); - - op.setOperation( - seProvider.initAsymmetricOperation( - (byte) op.getPurpose(), - (byte)op.getAlgorithm(), - (byte)op.getPadding(), - (byte)op.getDigest(), - KMType.DIGEST_NONE, /* No MGF1 Digest */ - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length(), - null, - (short) 0, - (short) 0)); + public void beginKeyAgreementOperation(KMOperationState op) { + KMException.throwIt(KMError.UNIMPLEMENTED); } private void beginCipherOperation(KMOperationState op) { @@ -2708,12 +2458,12 @@ private void beginCipherOperation(KMOperationState op) { (byte)op.getPadding(), (byte)op.getDigest(), (byte) op.getMgfDigest(), - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length(), - KMByteBlob.cast(data[PUB_KEY]).getBuffer(), - KMByteBlob.cast(data[PUB_KEY]).getStartOff(), - KMByteBlob.cast(data[PUB_KEY]).length())); + KMByteBlob.getBuffer(data[SECRET]), + KMByteBlob.getStartOff(data[SECRET]), + KMByteBlob.length(data[SECRET]), + KMByteBlob.getBuffer(data[PUB_KEY]), + KMByteBlob.getStartOff(data[PUB_KEY]), + KMByteBlob.length(data[PUB_KEY]))); } else { KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); } @@ -2734,12 +2484,12 @@ private void beginCipherOperation(KMOperationState op) { (byte)op.getDigest(), (byte)op.getPadding(), (byte)op.getBlockMode(), - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length(), - KMByteBlob.cast(data[IV]).getBuffer(), - KMByteBlob.cast(data[IV]).getStartOff(), - KMByteBlob.cast(data[IV]).length(), + KMByteBlob.getBuffer(data[SECRET]), + KMByteBlob.getStartOff(data[SECRET]), + KMByteBlob.length(data[SECRET]), + KMByteBlob.getBuffer(data[IV]), + KMByteBlob.getStartOff(data[IV]), + KMByteBlob.length(data[IV]), op.getMacLength())); } catch (CryptoException exception) { if (exception.getReason() == CryptoException.ILLEGAL_VALUE) { @@ -2753,8 +2503,7 @@ private void beginCipherOperation(KMOperationState op) { private void beginTrustedConfirmationOperation(KMOperationState op) { // Check for trusted confirmation - if required then set the signer in op state. - if (KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED, - data[HW_PARAMETERS]) != KMType.INVALID_VALUE) { + if (KMKeyParameters.findTag(data[HW_PARAMETERS], KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED) != KMType.INVALID_VALUE) { op.setTrustedConfirmationSigner( seProvider.initTrustedConfirmationSymmetricOperation(seProvider.getComputedHmacKey())); @@ -2779,12 +2528,12 @@ private void beginSignVerifyOperation(KMOperationState op) { (byte)op.getPadding(), (byte)op.getDigest(), KMType.DIGEST_NONE, /* No MGF Digest */ - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length(), - KMByteBlob.cast(data[PUB_KEY]).getBuffer(), - KMByteBlob.cast(data[PUB_KEY]).getStartOff(), - KMByteBlob.cast(data[PUB_KEY]).length())); + KMByteBlob.getBuffer(data[SECRET]), + KMByteBlob.getStartOff(data[SECRET]), + KMByteBlob.length(data[SECRET]), + KMByteBlob.getBuffer(data[PUB_KEY]), + KMByteBlob.getStartOff(data[PUB_KEY]), + KMByteBlob.length(data[PUB_KEY]))); } else { KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); } @@ -2802,9 +2551,9 @@ private void beginSignVerifyOperation(KMOperationState op) { (byte)op.getPadding(), (byte)op.getDigest(), KMType.DIGEST_NONE, /* No MGF Digest */ - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length(), + KMByteBlob.getBuffer(data[SECRET]), + KMByteBlob.getStartOff(data[SECRET]), + KMByteBlob.length(data[SECRET]), null, (short) 0, (short) 0)); @@ -2836,9 +2585,9 @@ private void beginSignVerifyOperation(KMOperationState op) { (byte)op.getDigest(), (byte)op.getPadding(), (byte)op.getBlockMode(), - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length(), + KMByteBlob.getBuffer(data[SECRET]), + KMByteBlob.getStartOff(data[SECRET]), + KMByteBlob.length(data[SECRET]), null, (short) 0, (short) 0, @@ -2855,15 +2604,15 @@ private void beginSignVerifyOperation(KMOperationState op) { private boolean isHwAuthTokenContainsMatchingSecureId(short hwAuthToken, short secureUserIdsObj) { - short secureUserId = KMHardwareAuthToken.cast(hwAuthToken).getUserId(); - if (!KMInteger.cast(secureUserId).isZero()) { - if (KMIntegerArrayTag.cast(secureUserIdsObj).contains(secureUserId)) + short secureUserId = KMHardwareAuthToken.getUserId(hwAuthToken); + if (!KMInteger.isZero(secureUserId)) { + if (KMIntegerArrayTag.contains(secureUserIdsObj, secureUserId)) return true; } - short authenticatorId = KMHardwareAuthToken.cast(hwAuthToken).getAuthenticatorId(); - if (!KMInteger.cast(authenticatorId).isZero()) { - if (KMIntegerArrayTag.cast(secureUserIdsObj).contains(authenticatorId)) + short authenticatorId = KMHardwareAuthToken.getAuthenticatorId(hwAuthToken); + if (!KMInteger.isZero(authenticatorId)) { + if (KMIntegerArrayTag.contains(secureUserIdsObj, authenticatorId)) return true; } return false; @@ -2878,8 +2627,8 @@ private boolean authTokenMatches(short userSecureIdsPtr, short authType, return false; } // check auth type - tmpVariables[2] = KMHardwareAuthToken.cast(data[HW_TOKEN]).getHwAuthenticatorType(); - tmpVariables[2] = KMEnum.cast(tmpVariables[2]).getVal(); + tmpVariables[2] = KMHardwareAuthToken.getHwAuthenticatorType(data[HW_TOKEN]); + tmpVariables[2] = KMEnum.getVal(tmpVariables[2]); if (((byte) tmpVariables[2] & (byte) authType) == 0) { return false; } @@ -2891,11 +2640,11 @@ private void authorizeUserSecureIdAuthTimeout(KMOperationState op, byte[] scratc short authType; // Authorize User Secure Id and Auth timeout short userSecureIdPtr = - KMKeyParameters.findTag(KMType.ULONG_ARRAY_TAG, KMType.USER_SECURE_ID, data[HW_PARAMETERS]); + KMKeyParameters.findTag(data[HW_PARAMETERS], KMType.ULONG_ARRAY_TAG, KMType.USER_SECURE_ID); if (userSecureIdPtr != KMType.INVALID_VALUE) { // Authentication required. if (KMType.INVALID_VALUE != - KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, data[HW_PARAMETERS])) { + KMKeyParameters.findTag(data[HW_PARAMETERS], KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED)) { // Key has both USER_SECURE_ID and NO_AUTH_REQUIRED KMException.throwIt(KMError.INVALID_KEY_BLOB); } @@ -2907,7 +2656,7 @@ private void authorizeUserSecureIdAuthTimeout(KMOperationState op, byte[] scratc } short authTimeoutTagPtr = - KMKeyParameters.findTag(KMType.UINT_TAG, KMType.AUTH_TIMEOUT, data[HW_PARAMETERS]); + KMKeyParameters.findTag(data[HW_PARAMETERS], KMType.UINT_TAG, KMType.AUTH_TIMEOUT); if (authTimeoutTagPtr != KMType.INVALID_VALUE) { // authenticate user if (!authTokenMatches(userSecureIdPtr, authType, scratchPad)) { @@ -2915,19 +2664,19 @@ private void authorizeUserSecureIdAuthTimeout(KMOperationState op, byte[] scratc } authTimeoutTagPtr = - KMKeyParameters.findTag(KMType.ULONG_TAG, KMType.AUTH_TIMEOUT_MILLIS, data[HW_PARAMETERS]); + KMKeyParameters.findTag(data[HW_PARAMETERS], KMType.ULONG_TAG, KMType.AUTH_TIMEOUT_MILLIS); if (authTimeoutTagPtr == KMType.INVALID_VALUE) { KMException.throwIt(KMError.INVALID_KEY_BLOB); } - authTime = KMIntegerTag.cast(authTimeoutTagPtr).getValue(); + authTime = KMIntegerTag.getValue(authTimeoutTagPtr); // set the one time auth op.setOneTimeAuthReqd(true); // set the authentication time stamp in operation state authTime = addIntegers(authTime, - KMHardwareAuthToken.cast(data[HW_TOKEN]).getTimestamp(), scratchPad); + KMHardwareAuthToken.getTimestamp(data[HW_TOKEN]), scratchPad); op.setAuthTime( - KMInteger.cast(authTime).getBuffer(), KMInteger.cast(authTime).getStartOff()); + KMInteger.getBuffer(authTime), KMInteger.getStartOff(authTime)); // auth time validation will happen in update or finish op.setAuthTimeoutValidated(false); } else { @@ -2950,40 +2699,36 @@ private boolean verifyHwTokenMacInBigEndian(short hwToken, byte[] scratchPad) { Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); len = 1; // concatenate challenge - 8 bytes - short ptr = KMHardwareAuthToken.cast(hwToken).getChallenge(); - KMInteger.cast(ptr) - .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); + short ptr = KMHardwareAuthToken.getChallenge(hwToken); + KMInteger.value(ptr, scratchPad, (short) (len + (short) (8 - KMInteger.length(ptr)))); len += 8; // concatenate user id - 8 bytes - ptr = KMHardwareAuthToken.cast(hwToken).getUserId(); - KMInteger.cast(ptr) - .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); + ptr = KMHardwareAuthToken.getUserId(hwToken); + KMInteger.value(ptr, scratchPad, (short) (len + (short) (8 - KMInteger.length(ptr)))); len += 8; // concatenate authenticator id - 8 bytes - ptr = KMHardwareAuthToken.cast(hwToken).getAuthenticatorId(); - KMInteger.cast(ptr) - .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); + ptr = KMHardwareAuthToken.getAuthenticatorId(hwToken); + KMInteger.value(ptr, scratchPad, (short) (len + (short) (8 - KMInteger.length(ptr)))); len += 8; // concatenate authenticator type - 4 bytes - ptr = KMHardwareAuthToken.cast(hwToken).getHwAuthenticatorType(); - scratchPad[(short) (len + 3)] = KMEnum.cast(ptr).getVal(); + ptr = KMHardwareAuthToken.getHwAuthenticatorType(hwToken); + scratchPad[(short) (len + 3)] = KMEnum.getVal(ptr); len += 4; // concatenate timestamp -8 bytes - ptr = KMHardwareAuthToken.cast(hwToken).getTimestamp(); - KMInteger.cast(ptr) - .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); + ptr = KMHardwareAuthToken.getTimestamp(hwToken); + KMInteger.value(ptr, scratchPad, (short) (len + (short) (8 - KMInteger.length(ptr)))); len += 8; - ptr = KMHardwareAuthToken.cast(hwToken).getMac(); + ptr = KMHardwareAuthToken.getMac(hwToken); return seProvider.hmacVerify( seProvider.getComputedHmacKey(), scratchPad, (short) 0, len, - KMByteBlob.cast(ptr).getBuffer(), - KMByteBlob.cast(ptr).getStartOff(), - KMByteBlob.cast(ptr).length()); + KMByteBlob.getBuffer(ptr), + KMByteBlob.getStartOff(ptr), + KMByteBlob.length(ptr)); } private boolean verifyHwTokenMacInLittleEndian(short hwToken, byte[] scratchPad) { @@ -2994,44 +2739,43 @@ private boolean verifyHwTokenMacInLittleEndian(short hwToken, byte[] scratchPad) Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); len = 1; // concatenate challenge - 8 bytes - short ptr = KMHardwareAuthToken.cast(hwToken).getChallenge(); - KMInteger.cast(ptr).toLittleEndian(scratchPad, len); + short ptr = KMHardwareAuthToken.getChallenge(hwToken); + KMInteger.toLittleEndian(ptr, scratchPad, len); len += 8; // concatenate user id - 8 bytes - ptr = KMHardwareAuthToken.cast(hwToken).getUserId(); - KMInteger.cast(ptr).toLittleEndian(scratchPad, len); + ptr = KMHardwareAuthToken.getUserId(hwToken); + KMInteger.toLittleEndian(ptr, scratchPad, len); len += 8; // concatenate authenticator id - 8 bytes - ptr = KMHardwareAuthToken.cast(hwToken).getAuthenticatorId(); - KMInteger.cast(ptr).toLittleEndian(scratchPad, len); + ptr = KMHardwareAuthToken.getAuthenticatorId(hwToken); + KMInteger.toLittleEndian(ptr, scratchPad, len); len += 8; // concatenate authenticator type - 4 bytes - ptr = KMHardwareAuthToken.cast(hwToken).getHwAuthenticatorType(); - scratchPad[(short) (len + 3)] = KMEnum.cast(ptr).getVal(); + ptr = KMHardwareAuthToken.getHwAuthenticatorType(hwToken); + scratchPad[(short) (len + 3)] = KMEnum.getVal(ptr); len += 4; // concatenate timestamp - 8 bytes - ptr = KMHardwareAuthToken.cast(hwToken).getTimestamp(); - KMInteger.cast(ptr) - .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); + ptr = KMHardwareAuthToken.getTimestamp(hwToken); + KMInteger.value(ptr, scratchPad, (short) (len + (short) (8 - KMInteger.length(ptr)))); len += 8; - ptr = KMHardwareAuthToken.cast(hwToken).getMac(); + ptr = KMHardwareAuthToken.getMac(hwToken); return seProvider.hmacVerify( seProvider.getComputedHmacKey(), scratchPad, (short) 0, len, - KMByteBlob.cast(ptr).getBuffer(), - KMByteBlob.cast(ptr).getStartOff(), - KMByteBlob.cast(ptr).length()); + KMByteBlob.getBuffer(ptr), + KMByteBlob.getStartOff(ptr), + KMByteBlob.length(ptr)); } private boolean validateHwToken(short hwToken, byte[] scratchPad) { // CBOR Encoding is always big endian - short ptr = KMHardwareAuthToken.cast(hwToken).getMac(); + short ptr = KMHardwareAuthToken.getMac(hwToken); // If mac length is zero then token is empty. - if (KMByteBlob.cast(ptr).length() == 0) { + if (KMByteBlob.length(ptr) == 0) { return false; } if (KMConfigurations.TEE_MACHINE_TYPE == KMConfigurations.LITTLE_ENDIAN) { @@ -3042,12 +2786,12 @@ private boolean validateHwToken(short hwToken, byte[] scratchPad) { } private short importKeyCmd(APDU apdu){ - short cmd = KMArray.instance((short) 3); + short cmd = KMArray.instance((short) 3); // Arguments short params = KMKeyParameters.expAny(); - KMArray.cast(cmd).add((short) 0, params); - KMArray.cast(cmd).add((short) 1, KMEnum.instance(KMType.KEY_FORMAT)); - KMArray.cast(cmd).add((short) 2, KMByteBlob.exp()); + KMArray.add(cmd, (short) 0, params); + KMArray.add(cmd, (short) 1, KMEnum.instance(KMType.KEY_FORMAT)); + KMArray.add(cmd, (short) 2, KMByteBlob.exp()); return receiveIncoming(apdu, cmd); } @@ -3055,10 +2799,10 @@ private void processImportKeyCmd(APDU apdu) { // Receive the incoming request fully from the master into buffer. short cmd = importKeyCmd(apdu); byte[] scratchPad = apdu.getBuffer(); - data[KEY_PARAMETERS] = KMArray.cast(cmd).get((short) 0); - short keyFmt = KMArray.cast(cmd).get((short) 1); - data[IMPORTED_KEY_BLOB] = KMArray.cast(cmd).get((short) 2); - keyFmt = KMEnum.cast(keyFmt).getVal(); + data[KEY_PARAMETERS] = KMArray.get(cmd, (short) 0); + short keyFmt = KMArray.get(cmd, (short) 1); + data[IMPORTED_KEY_BLOB] = KMArray.get(cmd, (short) 2); + keyFmt = KMEnum.getVal(keyFmt); data[CERTIFICATE] = KMArray.instance((short)0); //by default the cert is empty. data[ORIGIN] = KMType.IMPORTED; @@ -3070,19 +2814,18 @@ private short importWrappedKeyCmd(APDU apdu){ // Arguments short params = KMKeyParameters.exp(); short bBlob = KMByteBlob.exp(); - KMArray.cast(cmd).add((short) 0, params); // Key Params of wrapped key - KMArray.cast(cmd).add((short) 1, KMEnum.instance(KMType.KEY_FORMAT)); // Key Format - KMArray.cast(cmd).add((short) 2, bBlob); // Wrapped Import Key Blob - KMArray.cast(cmd).add((short) 3, bBlob); // Auth Tag - KMArray.cast(cmd).add((short) 4, bBlob); // IV - Nonce - KMArray.cast(cmd).add((short) 5, bBlob); // Encrypted Transport Key - KMArray.cast(cmd).add((short) 6, bBlob); // Wrapping Key KeyBlob - KMArray.cast(cmd).add((short) 7, bBlob); // Masking Key - KMArray.cast(cmd).add((short) 8, params); // Un-wrapping Params - KMArray.cast(cmd) - .add((short) 9, bBlob); // Wrapped Key ASSOCIATED AUTH DATA - KMArray.cast(cmd).add((short) 10, KMInteger.exp()); // Password Sid - KMArray.cast(cmd).add((short) 11, KMInteger.exp()); // Biometric Sid + KMArray.add(cmd, (short) 0, params); // Key Params of wrapped key + KMArray.add(cmd, (short) 1, KMEnum.instance(KMType.KEY_FORMAT)); // Key Format + KMArray.add(cmd, (short) 2, bBlob); // Wrapped Import Key Blob + KMArray.add(cmd, (short) 3, bBlob); // Auth Tag + KMArray.add(cmd, (short) 4, bBlob); // IV - Nonce + KMArray.add(cmd, (short) 5, bBlob); // Encrypted Transport Key + KMArray.add(cmd, (short) 6, bBlob); // Wrapping Key KeyBlob + KMArray.add(cmd, (short) 7, bBlob); // Masking Key + KMArray.add(cmd, (short) 8, params); // Un-wrapping Params + KMArray.add(cmd, (short) 9, bBlob); // Wrapped Key ASSOCIATED AUTH DATA + KMArray.add(cmd, (short) 10, KMInteger.exp()); // Password Sid + KMArray.add(cmd, (short) 11, KMInteger.exp()); // Biometric Sid return receiveIncoming(apdu, cmd); } @@ -3093,11 +2836,11 @@ private void processImportWrappedKeyCmd(APDU apdu) { // Step -0 - check whether the key format and algorithm supported // read algorithm - tmpVariables[0] = KMArray.cast(cmd).get((short) 0); + tmpVariables[0] = KMArray.get(cmd, (short) 0); tmpVariables[1] = KMEnumTag.getValue(KMType.ALGORITHM, tmpVariables[0]); // read key format - tmpVariables[2] = KMArray.cast(cmd).get((short) 1); - byte keyFormat = KMEnum.cast(tmpVariables[2]).getVal(); + tmpVariables[2] = KMArray.get(cmd, (short) 1); + byte keyFormat = KMEnum.getVal(tmpVariables[2]); if ((tmpVariables[1] == KMType.RSA || tmpVariables[1] == KMType.EC) && (keyFormat != KMType.PKCS8)) { KMException.throwIt(KMError.UNIMPLEMENTED); @@ -3105,19 +2848,19 @@ private void processImportWrappedKeyCmd(APDU apdu) { // Step -1 parse the wrapping key blob // read wrapping key blob - data[KEY_BLOB] = KMArray.cast(cmd).get((short) 6); + data[KEY_BLOB] = KMArray.get(cmd, (short) 6); // read un wrapping key params - data[KEY_PARAMETERS] = KMArray.cast(cmd).get((short) 8); + data[KEY_PARAMETERS] = KMArray.get(cmd, (short) 8); // Read App Id and App Data if any from un wrapping key params data[APP_ID] = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_ID, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.BYTES_TAG, KMType.APPLICATION_ID); data[APP_DATA] = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_DATA, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.BYTES_TAG, KMType.APPLICATION_DATA); if (data[APP_ID] != KMTag.INVALID_VALUE) { - data[APP_ID] = KMByteTag.cast(data[APP_ID]).getValue(); + data[APP_ID] = KMByteTag.getValue(data[APP_ID]); } if (data[APP_DATA] != KMTag.INVALID_VALUE) { - data[APP_DATA] = KMByteTag.cast(data[APP_DATA]).getValue(); + data[APP_DATA] = KMByteTag.getValue(data[APP_DATA]); } // parse the wrapping key blob parseEncryptedKeyBlob(data[KEY_BLOB], data[APP_ID], data[APP_DATA], scratchPad); @@ -3139,81 +2882,81 @@ private void processImportWrappedKeyCmd(APDU apdu) { // Step 2 - decrypt the encrypted transport key - 32 bytes AES-GCM key // create rsa decipher // read encrypted transport key from args - tmpVariables[0] = KMArray.cast(cmd).get((short) 5); + tmpVariables[0] = KMArray.get(cmd, (short) 5); // Decrypt the transport key tmpVariables[1] = seProvider.rsaDecipherOAEP256( - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length(), - KMByteBlob.cast(data[PUB_KEY]).getBuffer(), - KMByteBlob.cast(data[PUB_KEY]).getStartOff(), - KMByteBlob.cast(data[PUB_KEY]).length(), - KMByteBlob.cast(tmpVariables[0]).getBuffer(), - KMByteBlob.cast(tmpVariables[0]).getStartOff(), - KMByteBlob.cast(tmpVariables[0]).length(), + KMByteBlob.getBuffer(data[SECRET]), + KMByteBlob.getStartOff(data[SECRET]), + KMByteBlob.length(data[SECRET]), + KMByteBlob.getBuffer(data[PUB_KEY]), + KMByteBlob.getStartOff(data[PUB_KEY]), + KMByteBlob.length(data[PUB_KEY]), + KMByteBlob.getBuffer(tmpVariables[0]), + KMByteBlob.getStartOff(tmpVariables[0]), + KMByteBlob.length(tmpVariables[0]), scratchPad, (short) 0); data[SECRET] = KMByteBlob.instance(scratchPad, (short) 0, tmpVariables[1]); // Step 3 - XOR the decrypted AES-GCM key with with masking key // read masking key - tmpVariables[0] = KMArray.cast(cmd).get((short) 7); - tmpVariables[1] = KMByteBlob.cast(tmpVariables[0]).length(); + tmpVariables[0] = KMArray.get(cmd, (short) 7); + tmpVariables[1] = KMByteBlob.length(tmpVariables[0]); // Length of masking key and transport key must be same. - if (tmpVariables[1] != KMByteBlob.cast(data[SECRET]).length()) { + if (tmpVariables[1] != KMByteBlob.length(data[SECRET])) { KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH); } tmpVariables[2] = 0; // index // Xor every byte of masking and key and store the result in data[SECRET] while (tmpVariables[2] < tmpVariables[1]) { tmpVariables[3] = - (short) (((short) KMByteBlob.cast(tmpVariables[0]).get(tmpVariables[2])) & 0x00FF); + (short) (((short) KMByteBlob.get(tmpVariables[0], tmpVariables[2])) & 0x00FF); tmpVariables[4] = - (short) (((short) KMByteBlob.cast(data[SECRET]).get(tmpVariables[2])) & 0x00FF); - KMByteBlob.cast(data[SECRET]) - .add(tmpVariables[2], (byte) (tmpVariables[3] ^ tmpVariables[4])); + (short) (((short) KMByteBlob.get(data[SECRET], tmpVariables[2])) & 0x00FF); + KMByteBlob.add(data[SECRET], tmpVariables[2], (byte) (tmpVariables[3] ^ tmpVariables[4])); tmpVariables[2]++; } // Step 4 - AES-GCM decrypt the wrapped key - data[INPUT_DATA] = KMArray.cast(cmd).get((short) 2); - data[AUTH_DATA] = KMArray.cast(cmd).get((short) 9); - data[AUTH_TAG] = KMArray.cast(cmd).get((short) 3); - data[NONCE] = KMArray.cast(cmd).get((short) 4); + data[INPUT_DATA] = KMArray.get(cmd, (short) 2); + data[AUTH_DATA] = KMArray.get(cmd, (short) 9); + data[AUTH_TAG] = KMArray.get(cmd, (short) 3); + data[NONCE] = KMArray.get(cmd, (short) 4); Util.arrayFillNonAtomic( - scratchPad, (short) 0, KMByteBlob.cast(data[INPUT_DATA]).length(), (byte) 0); + scratchPad, (short) 0, KMByteBlob.length(data[INPUT_DATA]), (byte) 0); if (!seProvider.aesGCMDecrypt( - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length(), - KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), - KMByteBlob.cast(data[INPUT_DATA]).length(), + KMByteBlob.getBuffer(data[SECRET]), + KMByteBlob.getStartOff(data[SECRET]), + KMByteBlob.length(data[SECRET]), + KMByteBlob.getBuffer(data[INPUT_DATA]), + KMByteBlob.getStartOff(data[INPUT_DATA]), + KMByteBlob.length(data[INPUT_DATA]), scratchPad, (short) 0, - KMByteBlob.cast(data[NONCE]).getBuffer(), - KMByteBlob.cast(data[NONCE]).getStartOff(), - KMByteBlob.cast(data[NONCE]).length(), - KMByteBlob.cast(data[AUTH_DATA]).getBuffer(), - KMByteBlob.cast(data[AUTH_DATA]).getStartOff(), - KMByteBlob.cast(data[AUTH_DATA]).length(), - KMByteBlob.cast(data[AUTH_TAG]).getBuffer(), - KMByteBlob.cast(data[AUTH_TAG]).getStartOff(), - KMByteBlob.cast(data[AUTH_TAG]).length())) { + KMByteBlob.getBuffer(data[NONCE]), + KMByteBlob.getStartOff(data[NONCE]), + KMByteBlob.length(data[NONCE]), + KMByteBlob.getBuffer(data[AUTH_DATA]), + KMByteBlob.getStartOff(data[AUTH_DATA]), + KMByteBlob.length(data[AUTH_DATA]), + KMByteBlob.getBuffer(data[AUTH_TAG]), + KMByteBlob.getStartOff(data[AUTH_TAG]), + KMByteBlob.length(data[AUTH_TAG]))) { KMException.throwIt(KMError.VERIFICATION_FAILED); } // Step 5 - Import decrypted key data[ORIGIN] = KMType.SECURELY_IMPORTED; - data[KEY_PARAMETERS] = KMArray.cast(cmd).get((short) 0); + data[KEY_PARAMETERS] = KMArray.get(cmd, (short) 0); // create key blob array - data[IMPORTED_KEY_BLOB] = KMByteBlob.instance(scratchPad, (short) 0, KMByteBlob.cast(data[INPUT_DATA]).length()); + data[IMPORTED_KEY_BLOB] = KMByteBlob.instance(scratchPad, (short) 0, KMByteBlob.length(data[INPUT_DATA])); importKey(apdu, keyFormat, scratchPad); } private void validateImportKey(short params, short keyFmt){ + validatePurpose(params); // Rollback protection not supported KMTag.assertAbsence(params, KMType.BOOL_TAG, KMType.ROLLBACK_RESISTANCE, KMError.ROLLBACK_RESISTANCE_UNAVAILABLE); // As per specification, Early boot keys may not be imported at all, if Tag::EARLY_BOOT_ONLY is @@ -3232,6 +2975,10 @@ private void validateImportKey(short params, short keyFmt){ } } + public void validatePurpose(short params) { + return; + } + private void importKey(APDU apdu, short keyFmt, byte[] scratchPad) { validateImportKey(data[KEY_PARAMETERS], keyFmt); // Check algorithm and dispatch to appropriate handler. @@ -3260,51 +3007,51 @@ private void importKey(APDU apdu, short keyFmt, byte[] scratchPad) { createEncryptedKeyBlob(scratchPad); // prepare the response short resp = KMArray.instance((short) 3); - KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(resp).add((short) 1, data[KEY_BLOB]); - KMArray.cast(resp).add((short) 2, data[KEY_CHARACTERISTICS]); + KMArray.add(resp, (short) 0, buildErrorStatus(KMError.OK)); + KMArray.add(resp, (short) 1, data[KEY_BLOB]); + KMArray.add(resp, (short) 2, data[KEY_CHARACTERISTICS]); sendOutgoing(apdu, resp); } - protected short decodeRawECKey(short rawBlob) { + public short decodeRawECKey(short rawBlob) { // Decode key material short arrPtr = KMArray.instance((short) 2); - KMArray.cast(arrPtr).add((short) 0, KMByteBlob.exp()); // secret - KMArray.cast(arrPtr).add((short) 1, KMByteBlob.exp()); // public key + KMArray.add(arrPtr, (short) 0, KMByteBlob.exp()); // secret + KMArray.add(arrPtr, (short) 1, KMByteBlob.exp()); // public key arrPtr = decoder.decode( arrPtr, - KMByteBlob.cast(rawBlob).getBuffer(), - KMByteBlob.cast(rawBlob).getStartOff(), - KMByteBlob.cast(rawBlob).length()); + KMByteBlob.getBuffer(rawBlob), + KMByteBlob.getStartOff(rawBlob), + KMByteBlob.length(rawBlob)); return arrPtr; - //data[SECRET] = KMArray.cast(arrPtr).get((short) 0); - //data[PUB_KEY] = KMArray.cast(arrPtr).get((short) 1); } private void importECKeys(byte[] scratchPad) { // Decode key material KMPKCS8Decoder pkcs8 = KMPKCS8Decoder.instance(); short keyBlob = pkcs8.decodeEc(data[IMPORTED_KEY_BLOB]); - data[PUB_KEY] = KMArray.cast(keyBlob).get((short) 0); - data[SECRET] = KMArray.cast(keyBlob).get((short) 1); + data[PUB_KEY] = KMArray.get(keyBlob, (short) 0); + data[SECRET] = KMArray.get(keyBlob, (short) 1); // initialize 256 bit p256 key for given private key and public key. short index = 0; // check whether the key size tag is present in key parameters. short keySize = KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.KEYSIZE, data[KEY_PARAMETERS]); + short SecretLen = (short) (KMByteBlob.length(data[SECRET]) * 8); if (keySize != KMType.INVALID_VALUE) { // As per NIST.SP.800-186 page 9, secret for 256 curve should be between // 256-383 - if (((256 <= (short) (KMByteBlob.cast(data[SECRET]).length() * 8)) - && (383 >= (short) (KMByteBlob.cast(data[SECRET]).length() * 8))) - ^ keySize == 256) { + if (((256 <= SecretLen) && (383 >= SecretLen)) ^ keySize == 256) { KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH); } if (keySize != 256) { KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE); } } else { + if ((256 > SecretLen) || (383 < SecretLen)){ + KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE); + } // add the key size to scratchPad keySize = KMInteger.uint_16((short) 256); keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, keySize); @@ -3316,15 +3063,16 @@ private void importECKeys(byte[] scratchPad) { if (curve != KMType.INVALID_VALUE) { // As per NIST.SP.800-186 page 9, secret length for 256 curve should be between // 256-383 - if (((256 <= (short) (KMByteBlob.cast(data[SECRET]).length() * 8)) - && (383 >= (short) (KMByteBlob.cast(data[SECRET]).length() * 8))) - ^ curve == KMType.P_256) { + if (((256 <= SecretLen) && (383 >= SecretLen)) ^ curve == KMType.P_256) { KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH); } if (curve != KMType.P_256) { KMException.throwIt(KMError.UNSUPPORTED_EC_CURVE); } } else { + if ((256 > SecretLen) || (383 < SecretLen)){ + KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE); + } // add the curve to scratchPad curve = KMEnumTag.instance(KMType.ECCURVE, KMType.P_256); Util.setShort(scratchPad, index, curve); @@ -3334,19 +3082,17 @@ private void importECKeys(byte[] scratchPad) { // Check whether key can be created seProvider.importAsymmetricKey( KMType.EC, - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length(), - KMByteBlob.cast(data[PUB_KEY]).getBuffer(), - KMByteBlob.cast(data[PUB_KEY]).getStartOff(), - KMByteBlob.cast(data[PUB_KEY]).length()); + KMByteBlob.getBuffer(data[SECRET]), + KMByteBlob.getStartOff(data[SECRET]), + KMByteBlob.length(data[SECRET]), + KMByteBlob.getBuffer(data[PUB_KEY]), + KMByteBlob.getStartOff(data[PUB_KEY]), + KMByteBlob.length(data[PUB_KEY])); // add scratch pad to key parameters updateKeyParameters(scratchPad, index); - // validate updated key parameters. - validateECKeys(); data[KEY_BLOB] = KMArray.instance((short) 5); - KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_PUB_KEY, data[PUB_KEY]); + KMArray.add(data[KEY_BLOB], KEY_BLOB_PUB_KEY, data[PUB_KEY]); } private void importHmacKey(byte[] scratchPad) { @@ -3363,7 +3109,7 @@ private void importHmacKey(byte[] scratchPad) { } } else { // add the key size to scratchPad - keysize = KMInteger.uint_16((short) (KMByteBlob.cast(data[SECRET]).length() * 8)); + keysize = KMInteger.uint_16((short) (KMByteBlob.length(data[SECRET]) * 8)); short keySizeTag = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, keysize); Util.setShort(scratchPad, index, keySizeTag); index += 2; @@ -3372,9 +3118,9 @@ private void importHmacKey(byte[] scratchPad) { seProvider.importSymmetricKey( KMType.HMAC, keysize, - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length()); + KMByteBlob.getBuffer(data[SECRET]), + KMByteBlob.getStartOff(data[SECRET]), + KMByteBlob.length(data[SECRET])); // update the key parameters list updateKeyParameters(scratchPad, index); @@ -3405,9 +3151,9 @@ private void importTDESKey(byte[] scratchPad) { seProvider.importSymmetricKey( KMType.DES, keysize, - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length()); + KMByteBlob.getBuffer(data[SECRET]), + KMByteBlob.getStartOff(data[SECRET]), + KMByteBlob.length(data[SECRET])); // update the key parameters list updateKeyParameters(scratchPad, index); // validate TDES Key parameters @@ -3433,7 +3179,7 @@ private void importAESKey(byte[] scratchPad) { validateAesKeySize(keysize); } else { // add the key size to scratchPad - keysize = (short) ( 8 * KMByteBlob.cast(data[SECRET]).length()); + keysize = (short) ( 8 * KMByteBlob.length(data[SECRET])); validateAesKeySize(keysize); keysize = KMInteger.uint_16(keysize); short keysizeTag = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, keysize); @@ -3444,9 +3190,9 @@ private void importAESKey(byte[] scratchPad) { seProvider.importSymmetricKey( KMType.AES, keysize, - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length()); + KMByteBlob.getBuffer(data[SECRET]), + KMByteBlob.getStartOff(data[SECRET]), + KMByteBlob.length(data[SECRET])); // update the key parameters list updateKeyParameters(scratchPad, index); @@ -3459,14 +3205,14 @@ private void importRSAKey(byte[] scratchPad) { // Decode key material KMPKCS8Decoder pkcs8 = KMPKCS8Decoder.instance(); short keyblob = pkcs8.decodeRsa(data[IMPORTED_KEY_BLOB]); - data[PUB_KEY] = KMArray.cast(keyblob).get((short) 0); - short pubKeyExp = KMArray.cast(keyblob).get((short)1); - data[SECRET] = KMArray.cast(keyblob).get((short) 2); - if(F4.length != KMByteBlob.cast(pubKeyExp).length()){ + data[PUB_KEY] = KMArray.get(keyblob, (short) 0); + short pubKeyExp = KMArray.get(keyblob, (short)1); + data[SECRET] = KMArray.get(keyblob, (short) 2); + if(F4.length != KMByteBlob.length(pubKeyExp)){ KMException.throwIt(KMError.INVALID_KEY_BLOB); } - if(Util.arrayCompare(F4, (short)0, KMByteBlob.cast(pubKeyExp).getBuffer(), - KMByteBlob.cast(pubKeyExp).getStartOff(), (short)F4.length) != 0){ + if(Util.arrayCompare(F4, (short)0, KMByteBlob.getBuffer(pubKeyExp), + KMByteBlob.getStartOff(pubKeyExp), (short)F4.length) != 0){ KMException.throwIt(KMError.INVALID_ARGUMENT); } short index = 0; // index in scratchPad for update parameters. @@ -3500,7 +3246,7 @@ private void importRSAKey(byte[] scratchPad) { KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.KEYSIZE, data[KEY_PARAMETERS]); if (keysize != KMType.INVALID_VALUE) { if (keysize != 2048 - || keysize != (short) (KMByteBlob.cast(data[SECRET]).length() * 8)) { + || keysize != (short) (KMByteBlob.length(data[SECRET]) * 8)) { KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH); } } else { @@ -3514,19 +3260,19 @@ private void importRSAKey(byte[] scratchPad) { // Check whether key can be created seProvider.importAsymmetricKey( KMType.RSA, - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length(), - KMByteBlob.cast(data[PUB_KEY]).getBuffer(), - KMByteBlob.cast(data[PUB_KEY]).getStartOff(), - KMByteBlob.cast(data[PUB_KEY]).length()); + KMByteBlob.getBuffer(data[SECRET]), + KMByteBlob.getStartOff(data[SECRET]), + KMByteBlob.length(data[SECRET]), + KMByteBlob.getBuffer(data[PUB_KEY]), + KMByteBlob.getStartOff(data[PUB_KEY]), + KMByteBlob.length(data[PUB_KEY])); // update the key parameters list updateKeyParameters(scratchPad, index); // validate RSA Key parameters validateRSAKey(scratchPad); data[KEY_BLOB] = KMArray.instance((short) 5); - KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_PUB_KEY, data[PUB_KEY]); + KMArray.add(data[KEY_BLOB], KEY_BLOB_PUB_KEY, data[PUB_KEY]); } private void updateKeyParameters(byte[] newParams, short len) { @@ -3534,26 +3280,26 @@ private void updateKeyParameters(byte[] newParams, short len) { return; // nothing to update } // Create Update Param array and copy current params - short params = KMKeyParameters.cast(data[KEY_PARAMETERS]).getVals(); - len = (short) (KMArray.cast(params).length() + (short) (len / 2)); + short params = KMKeyParameters.getVals(data[KEY_PARAMETERS]); + len = (short) (KMArray.length(params) + (short) (len / 2)); short updatedParams = KMArray.instance(len); // update params - len = KMArray.cast(params).length(); + len = KMArray.length(params); short index = 0; // copy the existing key parameters to updated array while (index < len) { - short tag = KMArray.cast(params).get(index); - KMArray.cast(updatedParams).add(index, tag); + short tag = KMArray.get(params, index); + KMArray.add(updatedParams, index, tag); index++; } // copy new parameters to updated array - len = KMArray.cast(updatedParams).length(); + len = KMArray.length(updatedParams); short newParamIndex = 0; // index in ptrArr while (index < len) { short tag = Util.getShort(newParams, newParamIndex); - KMArray.cast(updatedParams).add(index, tag); + KMArray.add(updatedParams, index, tag); index++; newParamIndex += 2; } @@ -3563,9 +3309,9 @@ private void updateKeyParameters(byte[] newParams, short len) { private short initStrongBoxCmd(APDU apdu){ short cmd = KMArray.instance((short) 3); - KMArray.cast(cmd).add((short) 0, KMInteger.exp()); //OS version - KMArray.cast(cmd).add((short) 1, KMInteger.exp()); //OS patch level - KMArray.cast(cmd).add((short) 2, KMInteger.exp()); //Vendor patch level + KMArray.add(cmd, (short) 0, KMInteger.exp()); //OS version + KMArray.add(cmd, (short) 1, KMInteger.exp()); //OS patch level + KMArray.add(cmd, (short) 2, KMInteger.exp()); //Vendor patch level return receiveIncoming(apdu, cmd); } @@ -3576,11 +3322,10 @@ private short initStrongBoxCmd(APDU apdu){ // is moved to a place where it is called on every boot. private void processInitStrongBoxCmd(APDU apdu) { short cmd = initStrongBoxCmd(apdu); - byte[] scratchPad = apdu.getBuffer(); - short osVersion = KMArray.cast(cmd).get((short) 0); - short osPatchLevel = KMArray.cast(cmd).get((short) 1); - short vendorPatchLevel = KMArray.cast(cmd).get((short) 2); + short osVersion = KMArray.get(cmd, (short) 0); + short osPatchLevel = KMArray.get(cmd, (short) 1); + short vendorPatchLevel = KMArray.get(cmd, (short) 2); setOsVersion(osVersion); setOsPatchLevel(osPatchLevel); setVendorPatchLevel(vendorPatchLevel); @@ -3612,31 +3357,30 @@ protected void initSystemBootParams(short osVersion, protected void setOsVersion(short version){ repository.setOsVersion( - KMInteger.cast(version).getBuffer(), - KMInteger.cast(version).getStartOff(), - KMInteger.cast(version).length()); + KMInteger.getBuffer(version), + KMInteger.getStartOff(version), + KMInteger.length(version)); } protected void setOsPatchLevel(short patch){ repository.setOsPatch( - KMInteger.cast(patch).getBuffer(), - KMInteger.cast(patch).getStartOff(), - KMInteger.cast(patch).length()); + KMInteger.getBuffer(patch), + KMInteger.getStartOff(patch), + KMInteger.length(patch)); } protected void setVendorPatchLevel(short patch){ repository.setVendorPatchLevel( - KMInteger.cast(patch).getBuffer(), - KMInteger.cast(patch).getStartOff(), - KMInteger.cast(patch).length()); + KMInteger.getBuffer(patch), + KMInteger.getStartOff(patch), + KMInteger.length(patch)); } private short generateKeyCmd(APDU apdu){ short params = KMKeyParameters.expAny(); - short blob = KMByteBlob.exp(); // Array of expected arguments short cmd = KMArray.instance((short) 1); - KMArray.cast(cmd).add((short) 0, params); //key params + KMArray.add(cmd, (short) 0, params); //key params return receiveIncoming(apdu, cmd); } @@ -3645,19 +3389,16 @@ private void processGenerateKey(APDU apdu) { short cmd = generateKeyCmd(apdu); // Re-purpose the apdu buffer as scratch pad. byte[] scratchPad = apdu.getBuffer(); - data[KEY_PARAMETERS] = KMArray.cast(cmd).get((short) 0); + data[KEY_PARAMETERS] = KMArray.get(cmd, (short) 0); data[CERTIFICATE] = KMArray.instance((short)0); //by default the cert is empty. // ROLLBACK_RESISTANCE not supported. KMTag.assertAbsence(data[KEY_PARAMETERS], KMType.BOOL_TAG,KMType.ROLLBACK_RESISTANCE, KMError.ROLLBACK_RESISTANCE_UNAVAILABLE); // BOOTLOADER_ONLY keys not supported. KMTag.assertAbsence(data[KEY_PARAMETERS], KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY, KMError.INVALID_KEY_BLOB); // As per specification Early boot keys may be created after early boot ended. - if (!specification.canCreateEarlyBootKeys() && repository.getEarlyBootEndedStatus()) { - //Validate early boot - KMTag.assertAbsence(data[KEY_PARAMETERS], KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, - KMError.INVALID_KEY_BLOB); - } + validateEarlyBoot(); // Algorithm must be present + validatePurpose(data[KEY_PARAMETERS]); KMTag.assertPresence(data[KEY_PARAMETERS], KMType.ENUM_TAG, KMType.ALGORITHM, KMError.INVALID_ARGUMENT); short alg = KMEnumTag.getValue(KMType.ALGORITHM, data[KEY_PARAMETERS]); // Check algorithm and dispatch to appropriate handler. @@ -3688,13 +3429,13 @@ private void processGenerateKey(APDU apdu) { createEncryptedKeyBlob(scratchPad); // prepare the response short resp = KMArray.instance((short) 3); - KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(resp).add((short) 1, data[KEY_BLOB]); - KMArray.cast(resp).add((short) 2, data[KEY_CHARACTERISTICS]); + KMArray.add(resp, (short) 0, buildErrorStatus(KMError.OK)); + KMArray.add(resp, (short) 1, data[KEY_BLOB]); + KMArray.add(resp, (short) 2, data[KEY_CHARACTERISTICS]); sendOutgoing(apdu, resp); } - protected void processAttestationCertDataCmd(APDU apdu) { + public void processAttestationCertDataCmd(APDU apdu) { // TODO optimize this function. byte[] srcBuffer = apdu.getBuffer(); short recvLen = apdu.setIncomingAndReceive(); @@ -3712,28 +3453,28 @@ protected void processAttestationCertDataCmd(APDU apdu) { // in the bufferRef[0] buffer. short var = KMByteBlob.instance((short) 12); // These variables point to the appropriate positions in the var buffer. - short certChainPos = KMByteBlob.cast(var).getStartOff(); - short certIssuerPos = (short) (KMByteBlob.cast(var).getStartOff() + 4); - short certExpiryPos = (short) (KMByteBlob.cast(var).getStartOff() + 8); + short certChainPos = KMByteBlob.getStartOff(var); + short certIssuerPos = (short) (KMByteBlob.getStartOff(var) + 4); + short certExpiryPos = (short) (KMByteBlob.getStartOff(var) + 8); decoder.decodeCertificateData((short) 3, buffer, bufferStartOffset, bufferLength, - KMByteBlob.cast(var).getBuffer(), KMByteBlob.cast(var).getStartOff()); + KMByteBlob.getBuffer(var), KMByteBlob.getStartOff(var)); // persist data seProvider.persistProvisionData( (byte[]) buffer, - Util.getShort(KMByteBlob.cast(var).getBuffer(), certChainPos), // offset - Util.getShort(KMByteBlob.cast(var).getBuffer(), (short) (certChainPos + 2)), // length - Util.getShort(KMByteBlob.cast(var).getBuffer(), certIssuerPos), // offset - Util.getShort(KMByteBlob.cast(var).getBuffer(), (short) (certIssuerPos + 2)), // length - Util.getShort(KMByteBlob.cast(var).getBuffer(), certExpiryPos), // offset - Util.getShort(KMByteBlob.cast(var).getBuffer(), (short) (certExpiryPos + 2))); // length + Util.getShort(KMByteBlob.getBuffer(var), certChainPos), // offset + Util.getShort(KMByteBlob.getBuffer(var), (short) (certChainPos + 2)), // length + Util.getShort(KMByteBlob.getBuffer(var), certIssuerPos), // offset + Util.getShort(KMByteBlob.getBuffer(var), (short) (certIssuerPos + 2)), // length + Util.getShort(KMByteBlob.getBuffer(var), certExpiryPos), // offset + Util.getShort(KMByteBlob.getBuffer(var), (short) (certExpiryPos + 2))); // length // reclaim memory repository.reclaimMemory(bufferLength); } private short generateAttestKeyCmd(APDU apdu) { - return receiveIncoming(apdu, specification.generateAttestKeyExp()); + return receiveIncoming(apdu, generateAttestKeyExp()); } private void processGetCertChainCmd(APDU apdu) { @@ -3747,27 +3488,27 @@ private void processGetCertChainCmd(APDU apdu) { encoder.getEncodedLength(int32Ptr); short totalLen = (short) (arrayHeaderLen + encoder.getEncodedLength(int32Ptr) + maxByteHeaderLen + certChainLen); short certChain = KMByteBlob.instance(totalLen); - //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(); + //bufferRef[0] = (tmpVariables[1]).getBuffer(); + //bufferProp[BUF_START_OFFSET] = (tmpVariables[1]).getStartOff(); + //bufferProp[BUF_LEN_OFFSET] = (tmpVariables[1]).length(); // copy the certificate chain to the end of the buffer. seProvider.readProvisionedData( KMSEProvider.CERTIFICATE_CHAIN, - KMByteBlob.cast(certChain).getBuffer(), - (short) (KMByteBlob.cast(certChain).getStartOff() + totalLen - certChainLen)); + KMByteBlob.getBuffer(certChain), + (short) (KMByteBlob.getStartOff(certChain) + totalLen - certChainLen)); // Encode cert chain. encoder.encodeCertChain( - KMByteBlob.cast(certChain).getBuffer(), - KMByteBlob.cast(certChain).getStartOff(), - KMByteBlob.cast(certChain).length(), + KMByteBlob.getBuffer(certChain), + KMByteBlob.getStartOff(certChain), + KMByteBlob.length(certChain), int32Ptr, // uint32 ptr - (short) (KMByteBlob.cast(certChain).getStartOff() + totalLen - certChainLen), // start pos of cert chain. + (short) (KMByteBlob.getStartOff(certChain) + totalLen - certChainLen), // start pos of cert chain. certChainLen); apdu.setOutgoing(); - apdu.setOutgoingLength(KMByteBlob.cast(certChain).length()); - apdu.sendBytesLong(KMByteBlob.cast(certChain).getBuffer(), - KMByteBlob.cast(certChain).getStartOff(), - KMByteBlob.cast(certChain).length()); + apdu.setOutgoingLength(KMByteBlob.length(certChain)); + apdu.sendBytesLong(KMByteBlob.getBuffer(certChain), + KMByteBlob.getStartOff(certChain), + KMByteBlob.length(certChain)); } private void processAttestKeyCmd(APDU apdu) { @@ -3775,20 +3516,20 @@ private void processAttestKeyCmd(APDU apdu) { short cmd = generateAttestKeyCmd(apdu); // Re-purpose the apdu buffer as scratch pad. byte[] scratchPad = apdu.getBuffer(); - specification.getAttestKeyInputParameters(cmd, data, KEY_BLOB, KEY_PARAMETERS, ATTEST_KEY_BLOB, - ATTEST_KEY_PARAMS, ATTEST_KEY_ISSUER); + getAttestKeyInputParameters(cmd, data, KEY_BLOB, KEY_PARAMETERS, ATTEST_KEY_BLOB, + ATTEST_KEY_PARAMS, ATTEST_KEY_ISSUER); data[CERTIFICATE] = KMArray.instance((short)0); //by default the cert is empty. // Check for app id and app data. data[APP_ID] = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_ID, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.BYTES_TAG, KMType.APPLICATION_ID); data[APP_DATA] = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_DATA, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.BYTES_TAG, KMType.APPLICATION_DATA); if (data[APP_ID] != KMTag.INVALID_VALUE) { - data[APP_ID] = KMByteTag.cast(data[APP_ID]).getValue(); + data[APP_ID] = KMByteTag.getValue(data[APP_ID]); } if (data[APP_DATA] != KMTag.INVALID_VALUE) { - data[APP_DATA] = KMByteTag.cast(data[APP_DATA]).getValue(); + data[APP_DATA] = KMByteTag.getValue(data[APP_DATA]); } // parse key blob parseEncryptedKeyBlob(data[KEY_BLOB], data[APP_ID], data[APP_DATA], scratchPad); @@ -3801,40 +3542,29 @@ private void processAttestKeyCmd(APDU apdu) { generateAttestation(data[ATTEST_KEY_BLOB], data[ATTEST_KEY_PARAMS], scratchPad); short resp = KMArray.instance((short) 2); - KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(resp).add((short) 1, data[CERTIFICATE]); + KMArray.add(resp, (short) 0, buildErrorStatus(KMError.OK)); + KMArray.add(resp, (short) 1, data[CERTIFICATE]); sendOutgoing(apdu, resp); } - private short getAttestationMode(short attKeyBlob, short attChallenge){ - short alg = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, data[HW_PARAMETERS]); + short alg = KMKeyParameters.findTag(data[HW_PARAMETERS], KMType.ENUM_TAG, KMType.ALGORITHM); short mode = KMType.NO_CERT; // TODO Keymaster specification: Symmetric keys with challenge should return error. - if(KMEnumTag.cast(alg).getValue() != KMType.RSA && - KMEnumTag.cast(alg).getValue() != KMType.EC){ + if(KMEnumTag.getValue(alg) != KMType.RSA && + KMEnumTag.getValue(alg) != KMType.EC){ return mode; } - // If attestation keyblob preset - if (attKeyBlob != KMType.INVALID_VALUE && KMByteBlob.cast(attKeyBlob).length() > 0) { + // If attestation keyblob present + if (attKeyBlob != KMType.INVALID_VALUE && KMByteBlob.length(attKeyBlob) > 0) { // No attestation challenge present then it is an error - if (attChallenge == KMType.INVALID_VALUE || KMByteBlob.cast(attChallenge).length() <= 0) { + if (attChallenge == KMType.INVALID_VALUE || KMByteBlob.length(attChallenge) <= 0) { KMException.throwIt(KMError.ATTESTATION_CHALLENGE_MISSING); } else { mode = KMType.ATTESTATION_CERT; } - } else if (specification.isFactoryAttestationSupported()) { - mode = KMType.FACTORY_PROVISIONED_ATTEST_CERT; - } else { // no attestation key blob - // Attestation challenge present then it is an error because no factory provisioned attest key - if (attChallenge != KMType.INVALID_VALUE && KMByteBlob.cast(attChallenge).length() > 0) { - KMException.throwIt(KMError.ATTESTATION_KEYS_NOT_PROVISIONED); - } else if(KMEnumArrayTag.contains(KMType.PURPOSE, KMType.ATTEST_KEY, data[HW_PARAMETERS]) || - KMEnumArrayTag.contains(KMType.PURPOSE, KMType.SIGN, data[HW_PARAMETERS])) { - mode = KMType.SELF_SIGNED_CERT; - }else{ - mode = KMType.FAKE_CERT; - } + } else { + mode = getSupportedAttestationMode(attChallenge); } return mode; } @@ -3844,9 +3574,9 @@ private void generateAttestation(short attKeyBlob, short attKeyParam, byte[] sc KMTag.assertAbsence(data[KEY_PARAMETERS],KMType.BOOL_TAG,KMType.DEVICE_UNIQUE_ATTESTATION,KMError.CANNOT_ATTEST_IDS); // Read attestation challenge if present short attChallenge = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.ATTESTATION_CHALLENGE, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.BYTES_TAG, KMType.ATTESTATION_CHALLENGE); if(attChallenge != KMType.INVALID_VALUE){ - attChallenge = KMByteTag.cast(attChallenge).getValue(); + attChallenge = KMByteTag.getValue(attChallenge); } // No attestation required for symmetric keys short mode = getAttestationMode(attKeyBlob, attChallenge); @@ -3875,57 +3605,18 @@ private void generateAttestation(short attKeyBlob, short attKeyParam, byte[] sc // Allocate memory short certData = KMByteBlob.instance(MAX_CERT_SIZE); - cert.buffer(KMByteBlob.cast(certData).getBuffer(), - KMByteBlob.cast(certData).getStartOff(), - KMByteBlob.cast(certData).length()); + cert.buffer(KMByteBlob.getBuffer(certData), + KMByteBlob.getStartOff(certData), + KMByteBlob.length(certData)); // Build the certificate - this will sign the cert cert.build(); // Adjust the start and length of the certificate in the blob - KMByteBlob.cast(certData).setStartOff(cert.getCertStart()); - KMByteBlob.cast(certData).setLength(cert.getCertLength()); + KMByteBlob.setStartOff(certData, cert.getCertStart()); + KMByteBlob.setLength(certData, cert.getCertLength()); // Initialize the certificate as array of blob data[CERTIFICATE] = KMArray.instance((short)1); - KMArray.cast(data[CERTIFICATE]).add((short)0, certData); - -/* - boolean rsaCert = KMEnumTag.cast(alg).getValue() == KMType.EC; - short appId = KMType.INVALID_VALUE; - short appData = KMType.INVALID_VALUE; - if(attKeyParam != KMType.INVALID_VALUE) { - appId = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_ID, attKeyParam); - if (appId != KMTag.INVALID_VALUE) { - appId = KMByteTag.cast(appId).getValue(); - } - appData = - KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_DATA, attKeyParam); - if (appData != KMTag.INVALID_VALUE) { - appData = KMByteTag.cast(appData).getValue(); - } - } - - KMAttestationCert cert = makeCert(attKeyBlob, appId, appData, scratchPad); - if(cert == null) {// No certificate - data[CERTIFICATE] = KMArray.instance((short)0); - return; - } - - // Allocate memory - short certData = KMByteBlob.instance(MAX_CERT_SIZE); - cert.buffer(KMByteBlob.cast(certData).getBuffer(), - KMByteBlob.cast(certData).getStartOff(), - KMByteBlob.cast(certData).length()); - // Build the certificate - this will sign the cert - cert.build(); - // Adjust the start and length of the certificate in the blob - KMByteBlob.cast(certData).setStartOff(cert.getCertStart()); - KMByteBlob.cast(certData).setLength(cert.getCertLength()); - - // Initialize the certificate as array of blob - data[CERTIFICATE] = KMArray.instance((short)1); - KMArray.cast(data[CERTIFICATE]).add((short)0, certData); - */ + KMArray.add(data[CERTIFICATE], (short)0, certData); } /** @@ -3948,7 +3639,7 @@ private static void validateRSAKey(byte[] scratchPad) { } // Generate key handlers - private static void generateRSAKey(byte[] scratchPad) { + private void generateRSAKey(byte[] scratchPad) { // Validate RSA Key validateRSAKey(scratchPad); // Now generate 2048 bit RSA keypair for the given exponent @@ -3957,16 +3648,16 @@ private static void generateRSAKey(byte[] scratchPad) { data[SECRET] = KMByteBlob.instance((short) 256); seProvider.createAsymmetricKey( KMType.RSA, - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length(), - KMByteBlob.cast(data[PUB_KEY]).getBuffer(), - KMByteBlob.cast(data[PUB_KEY]).getStartOff(), - KMByteBlob.cast(data[PUB_KEY]).length(), + KMByteBlob.getBuffer(data[SECRET]), + KMByteBlob.getStartOff(data[SECRET]), + KMByteBlob.length(data[SECRET]), + KMByteBlob.getBuffer(data[PUB_KEY]), + KMByteBlob.getStartOff(data[PUB_KEY]), + KMByteBlob.length(data[PUB_KEY]), lengths); data[KEY_BLOB] = KMArray.instance((short) 5); - KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_PUB_KEY, data[PUB_KEY]); + KMArray.add(data[KEY_BLOB], KEY_BLOB_PUB_KEY, data[PUB_KEY]); } private static void validateAESKey() { @@ -3977,20 +3668,20 @@ private static void validateAESKey() { // Read Block mode - array of byte values if(KMTag.isPresent(data[KEY_PARAMETERS],KMType.ENUM_ARRAY_TAG,KMType.BLOCK_MODE)){ short blockModes = - KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE); // If it is a GCM mode - if (KMEnumArrayTag.cast(blockModes).contains(KMType.GCM)){ + if (KMEnumArrayTag.contains(blockModes, KMType.GCM)){ // Min mac length must be present KMTag.assertPresence(data[KEY_PARAMETERS],KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, KMError.MISSING_MIN_MAC_LENGTH); short macLength = - KMKeyParameters.findTag(KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, data[KEY_PARAMETERS]); - macLength = KMIntegerTag.cast(macLength).getValue(); + KMKeyParameters.findTag(data[KEY_PARAMETERS], KMType.UINT_TAG, KMType.MIN_MAC_LENGTH); + macLength = KMIntegerTag.getValue(macLength); // Validate the MIN_MAC_LENGTH for AES - should be multiple of 8, less then 128 bits // and greater the 96 bits - if (KMInteger.cast(macLength).getSignificantShort() != 0 - || KMInteger.cast(macLength).getShort() > 128 - || KMInteger.cast(macLength).getShort() < 96 - || (KMInteger.cast(macLength).getShort() % 8) != 0) { + if (KMInteger.getSignificantShort(macLength) != 0 + || KMInteger.getShort(macLength) > 128 + || KMInteger.getShort(macLength) < 96 + || (KMInteger.getShort(macLength) % 8) != 0) { KMException.throwIt(KMError.UNSUPPORTED_MIN_MAC_LENGTH); } } @@ -4007,7 +3698,7 @@ private static void generateAESKey(byte[] scratchPad) { data[KEY_BLOB] = KMArray.instance((short) 4); } - private static void validateECKeys() { + public void validateECKeys() { // Read key size short eccurve = KMEnumTag.getValue(KMType.ECCURVE, data[KEY_PARAMETERS]); if(!KMTag.isValidKeySize(data[KEY_PARAMETERS])){ @@ -4019,7 +3710,7 @@ private static void validateECKeys() { } } - private static void generateECKeys(byte[] scratchPad) { + private void generateECKeys(byte[] scratchPad) { validateECKeys(); short[] lengths = tmpVariables; seProvider.createAsymmetricKey(KMType.EC, scratchPad, (short) 0, (short) 128, scratchPad, (short) 128, @@ -4027,7 +3718,7 @@ private static void generateECKeys(byte[] scratchPad) { data[PUB_KEY] = KMByteBlob.instance(scratchPad, (short) 128, lengths[1]); data[SECRET] = KMByteBlob.instance(scratchPad, (short) 0, lengths[0]); data[KEY_BLOB] = KMArray.instance((short) 5); - KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_PUB_KEY, data[PUB_KEY]); + KMArray.add(data[KEY_BLOB], KEY_BLOB_PUB_KEY, data[PUB_KEY]); } private static void validateTDESKey() { @@ -4087,8 +3778,8 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { short provOsVersion = repository.getOsVersion(); short status = KMInteger.unsignedByteArrayCompare( - KMInteger.cast(provOsVersion).getBuffer(), - KMInteger.cast(provOsVersion).getStartOff(), + KMInteger.getBuffer(provOsVersion), + KMInteger.getStartOff(provOsVersion), scratchPad, (short) 0, len); @@ -4106,8 +3797,8 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { short osPatch = repository.getOsPatch(); short status = KMInteger.unsignedByteArrayCompare( - KMInteger.cast(osPatch).getBuffer(), - KMInteger.cast(osPatch).getStartOff(), + KMInteger.getBuffer(osPatch), + KMInteger.getStartOff(osPatch), scratchPad, (short) 0, len); @@ -4118,6 +3809,7 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { } } } + protected static short getBootPatchLevel(byte[] scratchPad){ Util.arrayFillNonAtomic(scratchPad,(short)0, BOOT_PATCH_LVL_SIZE, (byte)0); short len = seProvider.getBootPatchLevel(scratchPad,(short)0); @@ -4127,22 +3819,9 @@ protected static short getBootPatchLevel(byte[] scratchPad){ return KMInteger.uint_32(scratchPad, (short)0); } - private static void makeKeyCharacteristics(byte[] scratchPad) { - /*short osVersion = repository.getOsVersion(); - short osPatch = repository.getOsPatch(); - short vendorPatch = repository.getVendorPatchLevel(); - short bootPatch = getBootPatchLevel(scratchPad); - data[SB_PARAMETERS] = KMKeyParameters.makeSbEnforced( - data[KEY_PARAMETERS], (byte) data[ORIGIN], osVersion, osPatch, vendorPatch, bootPatch, scratchPad); - data[TEE_PARAMETERS] = KMKeyParameters.makeTeeEnforced(data[KEY_PARAMETERS],scratchPad); - data[SW_PARAMETERS] = KMKeyParameters.makeKeystoreEnforced(data[KEY_PARAMETERS],scratchPad); - data[HW_PARAMETERS] = KMKeyParameters.makeHwEnforced(data[SB_PARAMETERS], data[TEE_PARAMETERS]); - data[KEY_CHARACTERISTICS] = KMKeyCharacteristics.instance(); - KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).setStrongboxEnforced(data[SB_PARAMETERS]); - KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).setKeystoreEnforced(data[SW_PARAMETERS]); - KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).setTeeEnforced(data[TEE_PARAMETERS]);*/ + private void makeKeyCharacteristics(byte[] scratchPad) { data[KEY_CHARACTERISTICS] = - specification.makeKeyCharacteristics( + makeKeyCharacteristics( data[KEY_PARAMETERS], repository.getOsVersion(), repository.getOsPatch(), @@ -4150,13 +3829,13 @@ private static void makeKeyCharacteristics(byte[] scratchPad) { getBootPatchLevel(scratchPad), data[ORIGIN], scratchPad); - data[TEE_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced(); - data[SW_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getKeystoreEnforced(); - data[SB_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getStrongboxEnforced(); - data[HW_PARAMETERS] = specification.getHardwareParamters(data[SB_PARAMETERS], data[TEE_PARAMETERS]); + data[TEE_PARAMETERS] = KMKeyCharacteristics.getTeeEnforced(data[KEY_CHARACTERISTICS]); + data[SW_PARAMETERS] = KMKeyCharacteristics.getKeystoreEnforced(data[KEY_CHARACTERISTICS]); + data[SB_PARAMETERS] = KMKeyCharacteristics.getStrongboxEnforced(data[KEY_CHARACTERISTICS]); + data[HW_PARAMETERS] = getHardwareParamters(data[SB_PARAMETERS], data[TEE_PARAMETERS]); } - private static void createEncryptedKeyBlob(byte[] scratchPad) { + private void createEncryptedKeyBlob(byte[] scratchPad) { // make root of trust blob data[ROT] = readROT(scratchPad); if (data[ROT] == KMType.INVALID_VALUE) { @@ -4170,9 +3849,9 @@ private static void createEncryptedKeyBlob(byte[] scratchPad) { // encrypt the secret and cryptographically attach that to authorization data encryptSecret(scratchPad); // create key blob array - KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_SECRET, data[SECRET]); - KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_AUTH_TAG, data[AUTH_TAG]); - KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_NONCE, data[NONCE]); + KMArray.add(data[KEY_BLOB], KEY_BLOB_SECRET, data[SECRET]); + KMArray.add(data[KEY_BLOB], KEY_BLOB_AUTH_TAG, data[AUTH_TAG]); + KMArray.add(data[KEY_BLOB], KEY_BLOB_NONCE, data[NONCE]); //TODO remove the following temporary creation of keyblob. /* short tempChar = KMKeyCharacteristics.instance(); @@ -4182,9 +3861,9 @@ private static void createEncryptedKeyBlob(byte[] scratchPad) { KMKeyCharacteristics.cast(tempChar).setKeystoreEnforced(emptyParam); KMKeyCharacteristics.cast(tempChar).setTeeEnforced(data[TEE_PARAMETERS]); KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_PARAMS, tempChar);*/ - short keyChars = specification.makeKeyCharacteristicsForKeyblob(data[SW_PARAMETERS], data[SB_PARAMETERS], + short keyChars = makeKeyCharacteristicsForKeyblob(data[SW_PARAMETERS], data[SB_PARAMETERS], data[TEE_PARAMETERS]); - KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_PARAMS, keyChars); + KMArray.add(data[KEY_BLOB], KEY_BLOB_PARAMS, keyChars); // allocate reclaimable memory. short buffer = repository.alloc((short) 1024); @@ -4200,27 +3879,27 @@ private short parseEncryptedKeyBlob(short keyBlob, short appId, short appData, b } try { parsedBlob = decoder.decodeArray(keyBlob(), - KMByteBlob.cast(keyBlob).getBuffer(), - KMByteBlob.cast(keyBlob).getStartOff(), - KMByteBlob.cast(keyBlob).length()); - if (KMArray.cast(parsedBlob).length() < 4) { + KMByteBlob.getBuffer(keyBlob), + KMByteBlob.getStartOff(keyBlob), + KMByteBlob.length(keyBlob)); + if (KMArray.length(parsedBlob) < 4) { KMException.throwIt(KMError.INVALID_KEY_BLOB); } // initialize data - data[SECRET] = KMArray.cast(parsedBlob).get(KEY_BLOB_SECRET); - data[NONCE]= KMArray.cast(parsedBlob).get(KEY_BLOB_NONCE); - data[AUTH_TAG] = KMArray.cast(parsedBlob).get(KEY_BLOB_AUTH_TAG); - data[KEY_CHARACTERISTICS] = KMArray.cast(parsedBlob).get(KEY_BLOB_PARAMS); + data[SECRET] = KMArray.get(parsedBlob, KEY_BLOB_SECRET); + data[NONCE]= KMArray.get(parsedBlob, KEY_BLOB_NONCE); + data[AUTH_TAG] = KMArray.get(parsedBlob, KEY_BLOB_AUTH_TAG); + data[KEY_CHARACTERISTICS] = KMArray.get(parsedBlob, KEY_BLOB_PARAMS); data[PUB_KEY] = KMType.INVALID_VALUE; - if (KMArray.cast(parsedBlob).length() == 5) { - data[PUB_KEY] = KMArray.cast(parsedBlob).get(KEY_BLOB_PUB_KEY); + if (KMArray.length(parsedBlob) == 5) { + data[PUB_KEY] = KMArray.get(parsedBlob, KEY_BLOB_PUB_KEY); } - data[TEE_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced(); - data[SB_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getStrongboxEnforced(); - data[SW_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getKeystoreEnforced(); - data[HW_PARAMETERS] = specification.getHardwareParamters( data[SB_PARAMETERS], data[TEE_PARAMETERS]); + data[TEE_PARAMETERS] = KMKeyCharacteristics.getTeeEnforced(data[KEY_CHARACTERISTICS]); + data[SB_PARAMETERS] = KMKeyCharacteristics.getStrongboxEnforced(data[KEY_CHARACTERISTICS]); + data[SW_PARAMETERS] = KMKeyCharacteristics.getKeystoreEnforced(data[KEY_CHARACTERISTICS]); + data[HW_PARAMETERS] = getHardwareParamters( data[SB_PARAMETERS], data[TEE_PARAMETERS]); data[HIDDEN_PARAMETERS] = KMKeyParameters.makeHidden(appId, appData, rot, scratchPad); data[KEY_BLOB] = parsedBlob; @@ -4228,7 +3907,7 @@ private short parseEncryptedKeyBlob(short keyBlob, short appId, short appData, b makeAuthData(scratchPad); // Decrypt Secret and verify auth tag decryptSecret(scratchPad); - KMArray.cast(parsedBlob).add(KEY_BLOB_SECRET, data[SECRET]); + KMArray.add(parsedBlob, KEY_BLOB_SECRET, data[SECRET]); } catch (Exception e) { KMException.throwIt(KMError.INVALID_KEY_BLOB); } @@ -4255,69 +3934,69 @@ private void decryptSecret(byte[] scratchPad) { // derive master key - stored in derivedKey short len = deriveKey(scratchPad); if (!seProvider.aesGCMDecrypt( - KMByteBlob.cast(data[DERIVED_KEY]).getBuffer(), - KMByteBlob.cast(data[DERIVED_KEY]).getStartOff(), - KMByteBlob.cast(data[DERIVED_KEY]).length(), - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length(), + KMByteBlob.getBuffer(data[DERIVED_KEY]), + KMByteBlob.getStartOff(data[DERIVED_KEY]), + KMByteBlob.length(data[DERIVED_KEY]), + KMByteBlob.getBuffer(data[SECRET]), + KMByteBlob.getStartOff(data[SECRET]), + KMByteBlob.length(data[SECRET]), scratchPad, (short) 0, - KMByteBlob.cast(data[NONCE]).getBuffer(), - KMByteBlob.cast(data[NONCE]).getStartOff(), - KMByteBlob.cast(data[NONCE]).length(), + KMByteBlob.getBuffer(data[NONCE]), + KMByteBlob.getStartOff(data[NONCE]), + KMByteBlob.length(data[NONCE]), repository.getHeap(), data[AUTH_DATA], data[AUTH_DATA_LENGTH], - KMByteBlob.cast(data[AUTH_TAG]).getBuffer(), - KMByteBlob.cast(data[AUTH_TAG]).getStartOff(), - KMByteBlob.cast(data[AUTH_TAG]).length())) { + KMByteBlob.getBuffer(data[AUTH_TAG]), + KMByteBlob.getStartOff(data[AUTH_TAG]), + KMByteBlob.length(data[AUTH_TAG]))) { KMException.throwIt(KMError.INVALID_KEY_BLOB); } // Copy the decrypted secret data[SECRET] = - KMByteBlob.instance(scratchPad, (short) 0, KMByteBlob.cast(data[SECRET]).length()); + KMByteBlob.instance(scratchPad, (short) 0, KMByteBlob.length(data[SECRET])); } - private static void encryptSecret(byte[] scratchPad) { + private void encryptSecret(byte[] scratchPad) { // make nonce data[NONCE] = KMByteBlob.instance((short) AES_GCM_NONCE_LENGTH); data[AUTH_TAG] = KMByteBlob.instance(AES_GCM_AUTH_TAG_LENGTH); Util.arrayCopyNonAtomic( - KMByteBlob.cast(data[NONCE]).getBuffer(), - KMByteBlob.cast(data[NONCE]).getStartOff(), + KMByteBlob.getBuffer(data[NONCE]), + KMByteBlob.getStartOff(data[NONCE]), scratchPad, (short) 0, - KMByteBlob.cast(data[NONCE]).length()); + KMByteBlob.length(data[NONCE])); seProvider.newRandomNumber( - KMByteBlob.cast(data[NONCE]).getBuffer(), - KMByteBlob.cast(data[NONCE]).getStartOff(), - KMByteBlob.cast(data[NONCE]).length()); + KMByteBlob.getBuffer(data[NONCE]), + KMByteBlob.getStartOff(data[NONCE]), + KMByteBlob.length(data[NONCE])); // derive master key - stored in derivedKey short len = deriveKey(scratchPad); len = seProvider.aesGCMEncrypt( - KMByteBlob.cast(data[DERIVED_KEY]).getBuffer(), - KMByteBlob.cast(data[DERIVED_KEY]).getStartOff(), - KMByteBlob.cast(data[DERIVED_KEY]).length(), - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length(), + KMByteBlob.getBuffer(data[DERIVED_KEY]), + KMByteBlob.getStartOff(data[DERIVED_KEY]), + KMByteBlob.length(data[DERIVED_KEY]), + KMByteBlob.getBuffer(data[SECRET]), + KMByteBlob.getStartOff(data[SECRET]), + KMByteBlob.length(data[SECRET]), scratchPad, (short) 0, - KMByteBlob.cast(data[NONCE]).getBuffer(), - KMByteBlob.cast(data[NONCE]).getStartOff(), - KMByteBlob.cast(data[NONCE]).length(), + KMByteBlob.getBuffer(data[NONCE]), + KMByteBlob.getStartOff(data[NONCE]), + KMByteBlob.length(data[NONCE]), repository.getHeap(), data[AUTH_DATA], data[AUTH_DATA_LENGTH], - KMByteBlob.cast(data[AUTH_TAG]).getBuffer(), - KMByteBlob.cast(data[AUTH_TAG]).getStartOff(), - KMByteBlob.cast(data[AUTH_TAG]).length()); + KMByteBlob.getBuffer(data[AUTH_TAG]), + KMByteBlob.getStartOff(data[AUTH_TAG]), + KMByteBlob.length(data[AUTH_TAG])); - if (len > 0 && len != KMByteBlob.cast(data[SECRET]).length()) { + if (len > 0 && len != KMByteBlob.length(data[SECRET])) { KMException.throwIt(KMError.INVALID_KEY_BLOB); } data[SECRET] = KMByteBlob.instance(scratchPad, (short)0, len); } - private static void makeAuthData(byte[] scratchPad) { + private void makeAuthData(byte[] scratchPad) { /*short arrayLen = 2; if (KMArray.cast(data[KEY_BLOB]).length() == 5) { arrayLen = 3; @@ -4330,16 +4009,16 @@ private static void makeAuthData(byte[] scratchPad) { KMArray.cast(params).add((short) 2, data[PUB_KEY]); }*/ short params = - specification.concatParamsForAuthData(data[KEY_BLOB], data[HW_PARAMETERS], + concatParamsForAuthData(data[KEY_BLOB], data[HW_PARAMETERS], data[SW_PARAMETERS], data[HIDDEN_PARAMETERS], data[PUB_KEY]); short authIndex = repository.alloc(MAX_AUTH_DATA_SIZE); short index = 0; short len = 0; - short paramsLen = KMArray.cast(params).length(); + short paramsLen = KMArray.length(params); Util.arrayFillNonAtomic(repository.getHeap(), authIndex, (short) MAX_AUTH_DATA_SIZE, (byte) 0); while (index < paramsLen) { - short tag = KMArray.cast(params).get(index); + short tag = KMArray.get(params, index); len = encoder.encode(tag, repository.getHeap(), (short) (authIndex + 32)); Util.arrayCopyNonAtomic(repository.getHeap(), (short) authIndex, repository.getHeap(), (short) (authIndex + len + 32), (short) 32); @@ -4354,21 +4033,7 @@ private static void makeAuthData(byte[] scratchPad) { data[AUTH_DATA_LENGTH] = len; } - private static short addPtrToAAD(short dataArrPtr, byte[] aadBuf, short offset) { - short index = (short) (offset * 2); - short tagInd = 0; - short tagPtr; - short arrLen = KMArray.cast(dataArrPtr).length(); - while (tagInd < arrLen) { - tagPtr = KMArray.cast(dataArrPtr).get(tagInd); - Util.setShort(aadBuf, index, tagPtr); - index += 2; - tagInd++; - } - return tagInd; - } - - private static short deriveKey(byte[] scratchPad) { + private short deriveKey(byte[] scratchPad) { // KeyDerivation: // 1. Do HMAC Sign, Auth data. // 2. HMAC Sign generates an output of 32 bytes length. @@ -4389,58 +4054,43 @@ private static short deriveKey(byte[] scratchPad) { return len; } - public static void sendError(APDU apdu, short err) { + public void sendError(APDU apdu, short err) { short resp = KMArray.instance((short)1); err = KMError.translate(err); short error = KMInteger.uint_16(err); - KMArray.cast(resp).add((short)0, error); + KMArray.add(resp, (short)0, error); sendOutgoing(apdu, resp); } private short addIntegers(short authTime, short timeStamp, byte[] scratchPad) { Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 24, (byte) 0); Util.arrayCopyNonAtomic( - KMInteger.cast(authTime).getBuffer(), - KMInteger.cast(authTime).getStartOff(), + KMInteger.getBuffer(authTime), + KMInteger.getStartOff(authTime), scratchPad, - (short) (8 - KMInteger.cast(timeStamp).length()), - KMInteger.cast(timeStamp).length()); + (short) (8 - KMInteger.length(timeStamp)), + KMInteger.length(timeStamp)); // Copy timestamp to scratchpad Util.arrayCopyNonAtomic( - KMInteger.cast(timeStamp).getBuffer(), - KMInteger.cast(timeStamp).getStartOff(), + KMInteger.getBuffer(timeStamp), + KMInteger.getStartOff(timeStamp), scratchPad, - (short) (16 - KMInteger.cast(timeStamp).length()), - KMInteger.cast(timeStamp).length()); + (short) (16 - KMInteger.length(timeStamp)), + KMInteger.length(timeStamp)); // add authTime in millis to timestamp. KMUtils.add(scratchPad, (short) 0, (short) 8, (short) 16); return KMInteger.uint_64(scratchPad, (short) 16); } - private void add(byte[] buf, short op1, short op2, short result) { - byte index = 7; - byte carry = 0; - short tmp; - while (index >= 0) { - tmp = (short) (buf[(short) (op1 + index)] + buf[(short) (op2 + index)] + carry); - carry = 0; - if (tmp > 255) { - carry = 1; // max unsigned byte value is 255 - } - buf[(short) (result + index)] = (byte) (tmp & (byte) 0xFF); - index--; - } - } - public void powerReset() { //TODO handle power reset signal. releaseAllOperations(); resetWrappingKey(); } - public static void generateRkpKey(byte[] scratchPad, short keyParams) { + public void generateRkpKey(byte[] scratchPad, short keyParams) { data[KEY_PARAMETERS] = keyParams; generateECKeys(scratchPad); // create key blob @@ -4448,6 +4098,7 @@ public static void generateRkpKey(byte[] scratchPad, short keyParams) { makeKeyCharacteristics(scratchPad); createEncryptedKeyBlob(scratchPad); } + public static short getPubKey() { return data[PUB_KEY]; } @@ -4475,9 +4126,9 @@ public static short encodeToApduBuffer(short object, byte[] apduBuf, short apduO return len; } - public static short validateCertChain(boolean validateEekRoot, byte expCertAlg, + public short validateCertChain(boolean validateEekRoot, byte expCertAlg, byte expLeafCertAlg, short certChainArr, byte[] scratchPad, Object[] authorizedEekRoots) { - short len = KMArray.cast(certChainArr).length(); + short len = KMArray.length(certChainArr); short coseHeadersExp = KMCoseHeaders.exp(); //prepare exp for coseky short coseKeyExp = KMCoseKey.exp(); @@ -4490,20 +4141,20 @@ public static short validateCertChain(boolean validateEekRoot, byte expCertAlg, short alg = expCertAlg; short index; for (index = 0; index < len; index++) { - ptr1 = KMArray.cast(certChainArr).get(index); + ptr1 = KMArray.get(certChainArr, index); // validate protected Headers - ptr2 = KMArray.cast(ptr1).get(KMCose.COSE_SIGN1_PROTECTED_PARAMS_OFFSET); - ptr2 = decoder.decode(coseHeadersExp, KMByteBlob.cast(ptr2).getBuffer(), - KMByteBlob.cast(ptr2).getStartOff(), KMByteBlob.cast(ptr2).length()); + ptr2 = KMArray.get(ptr1, KMCose.COSE_SIGN1_PROTECTED_PARAMS_OFFSET); + ptr2 = decoder.decode(coseHeadersExp, KMByteBlob.getBuffer(ptr2), + KMByteBlob.getStartOff(ptr2), KMByteBlob.length(ptr2)); if (!KMCoseHeaders.cast(ptr2).isDataValid(alg, KMType.INVALID_VALUE)) { KMException.throwIt(KMError.STATUS_FAILED); } // parse and get the public key from payload. - ptr2 = KMArray.cast(ptr1).get(KMCose.COSE_SIGN1_PAYLOAD_OFFSET); - ptr2 = decoder.decode(coseKeyExp, KMByteBlob.cast(ptr2).getBuffer(), - KMByteBlob.cast(ptr2).getStartOff(), KMByteBlob.cast(ptr2).length()); + ptr2 = KMArray.get(ptr1, KMCose.COSE_SIGN1_PAYLOAD_OFFSET); + ptr2 = decoder.decode(coseKeyExp, KMByteBlob.getBuffer(ptr2), + KMByteBlob.getStartOff(ptr2), KMByteBlob.length(ptr2)); if ((index == (short) (len - 1)) && len > 1) { alg = expLeafCertAlg; } @@ -4535,17 +4186,17 @@ public static short validateCertChain(boolean validateEekRoot, byte expCertAlg, } // Validate signature. signStructure = - KMCose.constructCoseSignStructure( - KMArray.cast(ptr1).get(KMCose.COSE_SIGN1_PROTECTED_PARAMS_OFFSET), + kmCoseInst.constructCoseSignStructure( + KMArray.get(ptr1, KMCose.COSE_SIGN1_PROTECTED_PARAMS_OFFSET), KMByteBlob.instance((short) 0), - KMArray.cast(ptr1).get(KMCose.COSE_SIGN1_PAYLOAD_OFFSET)); - encodedLen = KMKeymasterApplet.encodeToApduBuffer(signStructure, scratchPad, - keySize, KMKeymasterApplet.MAX_COSE_BUF_SIZE); + KMArray.get(ptr1, KMCose.COSE_SIGN1_PAYLOAD_OFFSET)); + encodedLen = KMKeymasterDevice.encodeToApduBuffer(signStructure, scratchPad, + keySize, KMKeymasterDevice.MAX_COSE_BUF_SIZE); if (!seProvider.ecVerify256(scratchPad, (short) 0, keySize, scratchPad, keySize, encodedLen, - KMByteBlob.cast(KMArray.cast(ptr1).get(KMCose.COSE_SIGN1_SIGNATURE_OFFSET)).getBuffer(), - KMByteBlob.cast(KMArray.cast(ptr1).get(KMCose.COSE_SIGN1_SIGNATURE_OFFSET)).getStartOff(), - KMByteBlob.cast(KMArray.cast(ptr1).get(KMCose.COSE_SIGN1_SIGNATURE_OFFSET)).length())) { + KMByteBlob.getBuffer(KMArray.get(ptr1, KMCose.COSE_SIGN1_SIGNATURE_OFFSET)), + KMByteBlob.getStartOff(KMArray.get(ptr1, KMCose.COSE_SIGN1_SIGNATURE_OFFSET)), + KMByteBlob.length(KMArray.get(ptr1, KMCose.COSE_SIGN1_SIGNATURE_OFFSET)))) { KMException.throwIt(KMError.STATUS_FAILED); } prevCoseKey = ptr2; @@ -4554,14 +4205,14 @@ public static short validateCertChain(boolean validateEekRoot, byte expCertAlg, } - public static short generateBcc(boolean testMode, byte[] scratchPad) { + public short generateBcc(boolean testMode, byte[] scratchPad) { if (!testMode && seProvider.isProvisionLocked()) { KMException.throwIt(KMError.STATUS_FAILED); } KMDeviceUniqueKey deviceUniqueKey = seProvider.getDeviceUniqueKey(testMode); short temp = deviceUniqueKey.getPublicKey(scratchPad, (short) 0); short coseKey = - KMCose.constructCoseKey( + kmCoseInst.constructCoseKey( KMInteger.uint_8(KMCose.COSE_KEY_TYPE_EC2), KMType.INVALID_VALUE, KMNInteger.uint_8(KMCose.COSE_ALG_ES256), @@ -4573,11 +4224,11 @@ public static short generateBcc(boolean testMode, byte[] scratchPad) { KMType.INVALID_VALUE, false ); - temp = KMKeymasterApplet.encodeToApduBuffer(coseKey, scratchPad, (short) 0, - KMKeymasterApplet.MAX_COSE_BUF_SIZE); + temp = KMKeymasterDevice.encodeToApduBuffer(coseKey, scratchPad, (short) 0, + KMKeymasterDevice.MAX_COSE_BUF_SIZE); // Construct payload. short payload = - KMCose.constructCoseCertPayload( + kmCoseInst.constructCoseCertPayload( KMCosePairTextStringTag.instance(KMInteger.uint_8(KMCose.ISSUER), KMTextString.instance(KMCose.TEST_ISSUER_NAME, (short) 0, (short) KMCose.TEST_ISSUER_NAME.length)), @@ -4591,17 +4242,17 @@ public static short generateBcc(boolean testMode, byte[] scratchPad) { (short) KMCose.KEY_USAGE_SIGN.length)) ); // temp temporarily holds the length of encoded cert payload. - temp = KMKeymasterApplet.encodeToApduBuffer(payload, scratchPad, (short) 0, - KMKeymasterApplet.MAX_COSE_BUF_SIZE); + temp = KMKeymasterDevice.encodeToApduBuffer(payload, scratchPad, (short) 0, + KMKeymasterDevice.MAX_COSE_BUF_SIZE); payload = KMByteBlob.instance(scratchPad, (short) 0, temp); // protected header short protectedHeader = - KMCose.constructHeaders(KMNInteger.uint_8(KMCose.COSE_ALG_ES256), KMType.INVALID_VALUE, + kmCoseInst.constructHeaders(KMNInteger.uint_8(KMCose.COSE_ALG_ES256), KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE); // temp temporarily holds the length of encoded headers. - temp = KMKeymasterApplet.encodeToApduBuffer(protectedHeader, scratchPad, (short) 0, - KMKeymasterApplet.MAX_COSE_BUF_SIZE); + temp = KMKeymasterDevice.encodeToApduBuffer(protectedHeader, scratchPad, (short) 0, + KMKeymasterDevice.MAX_COSE_BUF_SIZE); protectedHeader = KMByteBlob.instance(scratchPad, (short) 0, temp); //unprotected headers. @@ -4610,11 +4261,11 @@ public static short generateBcc(boolean testMode, byte[] scratchPad) { // construct cose sign structure. short coseSignStructure = - KMCose.constructCoseSignStructure(protectedHeader, KMByteBlob.instance((short) 0), payload); + kmCoseInst.constructCoseSignStructure(protectedHeader, KMByteBlob.instance((short) 0), payload); // temp temporarily holds the length of encoded sign structure. // Encode cose Sign_Structure. - temp = KMKeymasterApplet.encodeToApduBuffer(coseSignStructure, scratchPad, (short) 0, - KMKeymasterApplet.MAX_COSE_BUF_SIZE); + temp = KMKeymasterDevice.encodeToApduBuffer(coseSignStructure, scratchPad, (short) 0, + KMKeymasterDevice.MAX_COSE_BUF_SIZE); // do sign short len = seProvider.ecSign256( @@ -4629,34 +4280,330 @@ public static short generateBcc(boolean testMode, byte[] scratchPad) { // construct cose_sign1 short coseSign1 = - KMCose.constructCoseSign1(protectedHeader, unprotectedHeader, payload, coseSignStructure); + kmCoseInst.constructCoseSign1(protectedHeader, unprotectedHeader, payload, coseSignStructure); // [Cose_Key, Cose_Sign1] short bcc = KMArray.instance((short) 2); - KMArray.cast(bcc).add((short) 0, coseKey); - KMArray.cast(bcc).add((short) 1, coseSign1); + KMArray.add(bcc, (short) 0, coseKey); + KMArray.add(bcc, (short) 1, coseSign1); return bcc; } private void updateTrustedConfirmationOperation(KMOperationState op) { if (op.isTrustedConfirmationRequired()) { - op.getTrustedConfirmationSigner().update(KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), KMByteBlob.cast(data[INPUT_DATA]).length()); + op.getTrustedConfirmationSigner().update(KMByteBlob.getBuffer(data[INPUT_DATA]), + KMByteBlob.getStartOff(data[INPUT_DATA]), KMByteBlob.length(data[INPUT_DATA])); } } private void finishTrustedConfirmationOperation(KMOperationState op) { // Perform trusted confirmation if required if (op.isTrustedConfirmationRequired()) { - short confToken = specification.getConfirmationToken(data[CONFIRMATION_TOKEN], data[KEY_PARAMETERS]); - boolean verified = op.getTrustedConfirmationSigner().verify(KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), KMByteBlob.cast(data[INPUT_DATA]).length(), - KMByteBlob.cast(confToken).getBuffer(), - KMByteBlob.cast(confToken).getStartOff(), - KMByteBlob.cast(confToken).length()); + short confToken = getConfirmationToken(data[CONFIRMATION_TOKEN], data[KEY_PARAMETERS]); + boolean verified = op.getTrustedConfirmationSigner().verify(KMByteBlob.getBuffer(data[INPUT_DATA]), + KMByteBlob.getStartOff(data[INPUT_DATA]), KMByteBlob.length(data[INPUT_DATA]), + KMByteBlob.getBuffer(confToken), + KMByteBlob.getStartOff(confToken), + KMByteBlob.length(confToken)); if (!verified) { KMException.throwIt(KMError.NO_USER_CONFIRMATION); } } } + + public short getHardwareInfo() { + short respPtr = KMArray.instance((short) 4); + KMArray.add(respPtr, (short) 0, buildErrorStatus(KMError.OK)); + KMArray.add(respPtr, (short) 1, KMEnum.instance(KMType.HARDWARE_TYPE, KMType.STRONGBOX)); + KMArray.add(respPtr, + (short) 2, + KMByteBlob.instance( + JAVACARD_KEYMASTER_DEVICE, (short) 0, (short) JAVACARD_KEYMASTER_DEVICE.length)); + KMArray.add(respPtr, (short) 3, KMByteBlob.instance(GOOGLE, (short) 0, (short) GOOGLE.length)); + return respPtr; + } + + public short makeKeyCharacteristics(short keyParams, short osVersion, short osPatch, + short vendorPatch, short bootPatch, short origin, byte[] scratchPad) { + short strongboxParams = KMKeyParameters.makeSbEnforced( + keyParams, (byte) origin, osVersion, osPatch, vendorPatch, bootPatch, scratchPad); + short teeParams = KMKeyParameters.makeTeeEnforced(keyParams, scratchPad); + short swParams = KMKeyParameters.makeKeystoreEnforced(keyParams, scratchPad); + short hwParams = KMKeyParameters.makeHwEnforced(strongboxParams, teeParams); + short keyCharacteristics = KMKeyCharacteristics.instance2(); + KMKeyCharacteristics.setStrongboxEnforced(keyCharacteristics, hwParams); + KMKeyCharacteristics.setKeystoreEnforced(keyCharacteristics, swParams); + return keyCharacteristics; + } + + public short makeKeyCharacteristicsForKeyblob(short swParams, short sbParams, short teeParams) { + short keyChars = KMKeyCharacteristics.instance2(); + KMKeyCharacteristics.setStrongboxEnforced(keyChars, sbParams); + KMKeyCharacteristics.setKeystoreEnforced(keyChars, swParams); + return keyChars; + } + + public short getKeyCharacteristicsExp() { + return KMKeyCharacteristics.keymasterExp(); + } + + public void validateEarlyBoot() { + if (repository.getEarlyBootEndedStatus()) { + //Validate early boot + KMTag.assertAbsence(data[KEY_PARAMETERS], KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, + KMError.INVALID_KEY_BLOB); + } + } + + public short getHardwareParamters(short sbParams, short teeParams) { + return sbParams; + } + + public short concatParamsForAuthData(short keyBlobPtr, short hwParams, short swParams, + short hiddenParams, short pubKey) { + short arrayLen = 3; + if (pubKey != KMType.INVALID_VALUE) { + arrayLen = 4; + } + short params = KMArray.instance((short) arrayLen); + KMArray.add(params, (short) 0, KMKeyParameters.getVals(hwParams)); + KMArray.add(params, (short) 1, KMKeyParameters.getVals(swParams)); + KMArray.add(params, (short) 2, KMKeyParameters.getVals(hiddenParams)); + if (4 == arrayLen) { + KMArray.add(params, (short) 3, pubKey); + } + return params; + } + + public short getSupportedAttestationMode(short attChallenge) { + return KMType.FACTORY_PROVISIONED_ATTEST_CERT; + } + + public KMAttestationCert makeCommonCert(short swParams, short hwParams, short keyParams, + byte[] scratchPad, KMSEProvider seProvider) { + boolean rsaCert = (KMEnumTag.getValue(KMType.ALGORITHM, hwParams) == KMType.RSA); + KMAttestationCert cert = KMAttestationCertImpl.instance(rsaCert, seProvider); + // notBefore + short notBefore = + KMKeyParameters.findTag(swParams, KMType.DATE_TAG, KMType.ACTIVE_DATETIME); + if (notBefore == KMType.INVALID_VALUE) { + notBefore = + KMKeyParameters.findTag(swParams, KMType.DATE_TAG, KMType.CREATION_DATETIME); + if (notBefore == KMType.INVALID_VALUE) { + KMException.throwIt(KMError.INVALID_KEY_BLOB); + } + } + notBefore = KMIntegerTag.getValue(notBefore); + cert.notBefore(notBefore, false, scratchPad); + // notAfter + // expiry time - byte blob + boolean derEncoded = false; + short notAfter = + KMKeyParameters.findTag(swParams, KMType.DATE_TAG, KMType.USAGE_EXPIRE_DATETIME); + if (notAfter == KMType.INVALID_VALUE) { + notAfter = getProvisionedCertificateData(seProvider, KMSEProvider.CERTIFICATE_EXPIRY); + derEncoded = true; + } + cert.notAfter(notAfter, derEncoded, scratchPad); + // SubjectName + cert.subjectName(KMByteBlob.instance(X509Subject, (short) 0, (short) X509Subject.length)); + // Serial + short serialNumber = KMByteBlob.instance((short) 1); + KMByteBlob.add(serialNumber, (short) 0, SERIAL_NUM); + cert.serialNumber(serialNumber); + // Issuer. + cert.issuer(getProvisionedCertificateData(seProvider, KMSEProvider.CERTIFICATE_ISSUER)); + return cert; + } + + private short getProvisionedCertificateData(KMSEProvider kmseProvider, byte dataType) { + short len = seProvider.getProvisionedDataLength(dataType); + if (len == 0) { + KMException.throwIt(KMError.INVALID_DATA); + } + short ptr = KMByteBlob.instance(len); + seProvider.readProvisionedData( + dataType, + KMByteBlob.getBuffer(ptr), + KMByteBlob.getStartOff(ptr)); + return ptr; + } + + public short getConfirmationToken(short confToken, short keyParams) { + short cToken = + KMKeyParameters.findTag(keyParams, KMType.BYTES_TAG, KMType.CONFIRMATION_TOKEN); + if (cToken == KMType.INVALID_VALUE) { + KMException.throwIt(KMError.NO_USER_CONFIRMATION); + } + return KMByteTag.getValue(cToken); + } + + public short getKMVerificationTokenExp() { + return KMVerificationToken.verificationTokenExp(); + } + + public short getMacFromVerificationToken(short verToken) { + return KMVerificationToken.getMac(verToken, (short) 0x04); + } + + public short getMgf1Digest(short keyParams, short hwParams) { + return KMType.SHA1; + } + +//This function masks the error code with POWER_RESET_MASK_FLAG + // in case if card reset event occurred. The clients of the Applet + // has to extract the power reset status from the error code and + // process accordingly. + public short buildErrorStatus(short err) { + short int32Ptr = KMInteger.instance((short) 4); + short powerResetStatus = 0; + if (seProvider.isPowerReset(true)) { + powerResetStatus = POWER_RESET_MASK_FLAG; + } + Util.setShort(KMInteger.getBuffer(int32Ptr), + KMInteger.getStartOff(int32Ptr), + powerResetStatus); + + Util.setShort(KMInteger.getBuffer(int32Ptr), + (short) (KMInteger.getStartOff(int32Ptr) + 2), + err); + return int32Ptr; + } + + public short generateAttestKeyExp() { + // Arguments + short keyParams = KMKeyParameters.expAny(); + short keyBlob = KMByteBlob.exp(); + short argsProto = KMArray.instance((short) 2); + KMArray.add(argsProto, (short) 0, keyBlob); + KMArray.add(argsProto, (short) 1, keyParams); + return argsProto; + } + + public void getAttestKeyInputParameters(short arrPtr, short[] data, byte keyBlobOff, + byte keyParametersOff, + byte attestKeyBlobOff, byte attestKeyParamsOff, byte attestKeyIssuerOff) { + data[keyBlobOff] = KMArray.get(arrPtr, (short) 0); + data[keyParametersOff] = KMArray.get(arrPtr, (short) 1); + data[attestKeyBlobOff] = KMType.INVALID_VALUE; + data[attestKeyParamsOff] = KMType.INVALID_VALUE; + data[attestKeyIssuerOff] = KMType.INVALID_VALUE; + } + + public short prepareBeginResp(short paramsPtr, short opHandlePtr, short bufModPtr, + short macLengthPtr) { + short resp = KMArray.instance((short) 3); + KMArray.add(resp, (short) 0, KMInteger.uint_16(KMError.OK)); + KMArray.add(resp, (short) 1, paramsPtr); + KMArray.add(resp, (short) 2, opHandlePtr); + return resp; + } + + public short prepareFinishExp() { + short byteBlob = KMByteBlob.exp(); + short cmd = KMArray.instance((short) 6); + KMArray.add(cmd, (short) 0, KMInteger.exp());//op handle + short keyParam = KMKeyParameters.exp(); + KMArray.add(cmd, (short) 1, keyParam);// Key Parameters + KMArray.add(cmd, (short) 2, byteBlob);// input data + KMArray.add(cmd, (short) 3, byteBlob); // signature + short authToken = KMHardwareAuthToken.exp(); + KMArray.add(cmd, (short) 4, authToken); // auth token + short verToken = getKMVerificationTokenExp(); + KMArray.add(cmd, (short) 5, verToken); // time stamp token + return cmd; + } + + public short prepareUpdateExp() { + short cmd = KMArray.instance((short) 5); + // Arguments + short keyParams = KMKeyParameters.exp(); + KMArray.add(cmd, (short) 0, KMInteger.exp()); + KMArray.add(cmd, (short) 1, keyParams); + KMArray.add(cmd, (short) 2, KMByteBlob.exp()); + short authToken = KMHardwareAuthToken.exp(); + KMArray.add(cmd, (short) 3, authToken); + short verToken = getKMVerificationTokenExp(); + KMArray.add(cmd, (short) 4, verToken); + return cmd; + } + + public void getUpdateInputParameters(short arrPtr, short[] data, byte opHandleOff, + byte keyParametersOff, byte inputDataOff, byte hwTokenOff, + byte verToken) { + data[opHandleOff] = KMArray.get(arrPtr, (short) 0); + data[keyParametersOff] = KMArray.get(arrPtr, (short) 1); + data[inputDataOff] = KMArray.get(arrPtr, (short) 2); + data[hwTokenOff] = KMArray.get(arrPtr, (short) 3); + data[verToken] = KMArray.get(arrPtr, (short) 4); + } + + public void getFinishInputParameters(short arrPtr, short[] data, byte opHandleOff, + byte keyParametersOff, byte inputDataOff, byte signDataOff, byte hwTokenOff, byte verToken, + byte confToken) { + data[opHandleOff] = KMArray.get(arrPtr, (short) 0); + data[keyParametersOff] = KMArray.get(arrPtr, (short) 1); + data[inputDataOff] = KMArray.get(arrPtr, (short) 2); + data[signDataOff] = KMArray.get(arrPtr, (short) 3); + data[hwTokenOff] = KMArray.get(arrPtr, (short) 4); + data[verToken] = KMArray.get(arrPtr, (short) 5); + data[confToken] = KMType.INVALID_VALUE; + } + + public short prepareFinishResp(short outputPtr) { + short keyParam = KMArray.instance((short) 0); + keyParam = KMKeyParameters.instance(keyParam); + short resp = KMArray.instance((short) 3); + KMArray.add(resp, (short) 0, KMInteger.uint_16(KMError.OK)); + KMArray.add(resp, (short) 1, keyParam); + KMArray.add(resp, (short) 2, outputPtr); + return resp; + } + + public short prepareUpdateResp(short outputPtr, short inputConsumedPtr) { + short resp = KMArray.instance((short) 4); + KMArray.add(resp, (short) 0, KMInteger.uint_16(KMError.OK)); + KMArray.add(resp, (short) 1, inputConsumedPtr); + short keyParm = KMKeyParameters.instance(KMArray.instance((short) 0)); + KMArray.add(resp, (short) 2, keyParm); + KMArray.add(resp, (short) 3, outputPtr); + return resp; + } + + public short validateApduHeader(APDU apdu) { + byte[] apduBuffer = apdu.getBuffer(); + byte apduClass = apduBuffer[ISO7816.OFFSET_CLA]; + short P1P2 = Util.getShort(apduBuffer, ISO7816.OFFSET_P1); + + // Validate APDU Header. + if ((apduClass != CLA_ISO7816_NO_SM_NO_CHAN)) { + return ISO7816.SW_CLA_NOT_SUPPORTED; + } + // Validate P1P2. + if (P1P2 != KEYMASTER_HAL_VERSION) { + return ISO7816.SW_INCORRECT_P1P2; + } + return KMError.OK; + } + + public boolean isAssociatedDataTagSupported() { + return true; + } + + void assertPrivateOperation(short purpose, short algorithm) { + switch(algorithm) { + case KMType.RSA: + if (purpose == KMType.ENCRYPT || purpose == KMType.VERIFY) { + KMException.throwIt(KMError.PUBLIC_KEY_OPERATION); + } + break; + case KMType.EC: + if (purpose == KMType.VERIFY) { + KMException.throwIt(KMError.PUBLIC_KEY_OPERATION); + } + break; + default: + break; + } + } } diff --git a/Applet/src/com/android/javacard/kmdevice/KMKeymintDevice.java b/Applet/src/com/android/javacard/kmdevice/KMKeymintDevice.java new file mode 100644 index 00000000..3b1c8f6f --- /dev/null +++ b/Applet/src/com/android/javacard/kmdevice/KMKeymintDevice.java @@ -0,0 +1,415 @@ +package com.android.javacard.kmdevice; + +import javacard.framework.APDU; +import javacard.framework.ISO7816; +import javacard.framework.Util; +import javacard.security.CryptoException; + +public class KMKeymintDevice extends KMKeymasterDevice { + + public static byte[] JAVACARD_KEYMINT_DEVICE; + private static byte[] GOOGLE; + + private static byte[] dec319999Ms; + + private static byte[] dec319999; + + private static byte[] jan01970; + + public KMKeymintDevice(KMSEProvider seImpl, KMRepository repoInst, KMDecoder decoderInst) { + super(seImpl, repoInst, decoderInst); + initStatics(); + } + + public static void initStatics() { + JAVACARD_KEYMINT_DEVICE = new byte[] { + 0x4a, 0x61, 0x76, 0x61, 0x63, 0x61, 0x72, 0x64, + 0x4b, 0x65, 0x79, 0x6d, 0x69, 0x6e, 0x74, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + }; + GOOGLE = new byte[] {0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65}; + dec319999Ms = new byte[] {(byte) 0, (byte) 0, (byte) 0xE6, (byte) 0x77, + (byte) 0xD2, (byte) 0x1F, (byte) 0xD8, (byte) 0x18}; + dec319999 = new byte[] { + 0x39, 0x39, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, + 0x39, 0x35, 0x39, 0x5a, + }; + jan01970 = new byte[] { + 0x37, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, + }; + } + + @Override + public short getHardwareInfo() { + final byte version = 1; + // Make the response + short respPtr = KMArray.instance((short) 6); + KMArray.add(respPtr, (short) 0, buildErrorStatus(KMError.OK)); + KMArray.add(respPtr, (short) 1, KMInteger.uint_8(version)); + KMArray.add(respPtr, (short) 2, KMEnum.instance(KMType.HARDWARE_TYPE, KMType.STRONGBOX)); + KMArray.add(respPtr, + (short) 3, + KMByteBlob.instance( + JAVACARD_KEYMINT_DEVICE, (short) 0, (short) JAVACARD_KEYMINT_DEVICE.length)); + KMArray.add(respPtr, (short) 4, KMByteBlob.instance(GOOGLE, (short) 0, (short) GOOGLE.length)); + KMArray.add(respPtr, (short) 5, KMInteger.uint_8((byte) 1)); + return respPtr; + } + + @Override + public short makeKeyCharacteristics(short keyParams, short osVersion, short osPatch, + short vendorPatch, short bootPatch, short origin, byte[] scratchPad) { + short strongboxParams = KMKeyParameters.makeSbEnforced( + keyParams, (byte) origin, osVersion, osPatch, vendorPatch, bootPatch, scratchPad); + short teeParams = KMKeyParameters.makeTeeEnforced(keyParams, scratchPad); + short swParams = KMKeyParameters.makeKeystoreEnforced(keyParams, scratchPad); + //short emptyParam = KMArray.instance((short) 0); + short keyCharacteristics = KMKeyCharacteristics.instance(); + KMKeyCharacteristics.setStrongboxEnforced(keyCharacteristics, strongboxParams); + KMKeyCharacteristics.setKeystoreEnforced(keyCharacteristics, swParams); + KMKeyCharacteristics.setTeeEnforced(keyCharacteristics, teeParams); + return keyCharacteristics; + } + + @Override + public short makeKeyCharacteristicsForKeyblob(short swParams, short sbParams, short teeParams) { + short keyChars = KMKeyCharacteristics.instance(); + short emptyParam = KMArray.instance((short) 0); + emptyParam = KMKeyParameters.instance(emptyParam); + KMKeyCharacteristics.setStrongboxEnforced(keyChars, sbParams); + KMKeyCharacteristics.setKeystoreEnforced(keyChars, emptyParam); + KMKeyCharacteristics.setTeeEnforced(keyChars, teeParams); + return keyChars; + } + + @Override + public short getKeyCharacteristicsExp() { + return KMKeyCharacteristics.keymintExp(); + } + + @Override + public short getHardwareParamters(short sbParams, short teeParams) { + return KMKeyParameters.makeHwEnforced(sbParams, teeParams); + } + + @Override + public short concatParamsForAuthData(short keyBlobPtr, short hwParams, short swParams, + short hiddenParams, short pubKey) { + short arrayLen = 2; + if (pubKey != KMType.INVALID_VALUE) { + arrayLen = 3; + } + short params = KMArray.instance((short) arrayLen); + KMArray.add(params, (short) 0, KMKeyParameters.getVals(hwParams)); + KMArray.add(params, (short) 1, KMKeyParameters.getVals(hiddenParams)); + if (3 == arrayLen) { + KMArray.add(params, (short) 2, pubKey); + } + return params; + } + + @Override + public short getSupportedAttestationMode(short attChallenge) { + // Attestation challenge present then it is an error because no factory provisioned attest key + short mode = KMType.NO_CERT; //TODO check what should be the default value + if (attChallenge != KMType.INVALID_VALUE && KMByteBlob.length(attChallenge) > 0) { + KMException.throwIt(KMError.ATTESTATION_KEYS_NOT_PROVISIONED); + } + if(KMEnumArrayTag.contains(KMType.PURPOSE, KMType.ATTEST_KEY, data[HW_PARAMETERS]) || + KMEnumArrayTag.contains(KMType.PURPOSE, KMType.SIGN, data[HW_PARAMETERS])) { + mode = KMType.SELF_SIGNED_CERT; + }else{ + mode = KMType.FAKE_CERT; + } + return mode; + } + + @Override + public KMAttestationCert makeCommonCert(short swParams, short hwParams, short keyParams, + byte[] scratchPad, KMSEProvider seProvider) { + short alg = KMKeyParameters.findTag(keyParams, KMType.ENUM_TAG, KMType.ALGORITHM); + boolean rsaCert = KMEnumTag.getValue(alg) == KMType.RSA; + KMAttestationCert cert = KMAttestationCertImpl.instance(rsaCert, seProvider); + + // Validity period must be specified + short notBefore = KMKeyParameters.findTag(keyParams, KMType.DATE_TAG, KMType.CERTIFICATE_NOT_BEFORE); + if (notBefore == KMType.INVALID_VALUE) { + KMException.throwIt(KMError.MISSING_NOT_BEFORE); + } + notBefore = KMIntegerTag.getValue(notBefore); + short notAfter = KMKeyParameters.findTag(keyParams, KMType.DATE_TAG, KMType.CERTIFICATE_NOT_AFTER); + if (notAfter == KMType.INVALID_VALUE) { + KMException.throwIt(KMError.MISSING_NOT_AFTER); + } + notAfter = KMIntegerTag.getValue(notAfter); + // VTS sends notBefore == Epoch. + Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 8, (byte) 0); + short epoch = KMInteger.instance(scratchPad, (short) 0, (short) 8); + short end = KMInteger.instance(dec319999Ms, (short) 0, (short) dec319999Ms.length); + if (KMInteger.compare(notBefore, epoch) == 0) { + cert.notBefore(KMByteBlob.instance(jan01970, (short) 0, (short) jan01970.length), + true, scratchPad); + } else { + cert.notBefore(notBefore, false, scratchPad); + } + // VTS sends notAfter == Dec 31st 9999 + if (KMInteger.compare(notAfter, end) == 0) { + cert.notAfter(KMByteBlob.instance(dec319999, (short) 0, (short) dec319999.length), + true, scratchPad); + } else { + cert.notAfter(notAfter, false, scratchPad); + } + // Serial number + short serialNum = + KMKeyParameters.findTag(keyParams, KMType.BIGNUM_TAG, KMType.CERTIFICATE_SERIAL_NUM); + if (serialNum != KMType.INVALID_VALUE) { + serialNum = KMBignumTag.getValue(serialNum); + } else { + serialNum = KMByteBlob.instance((short) 1); + KMByteBlob.add(serialNum, (short) 0, (byte) 1); + } + cert.serialNumber(serialNum); + return cert; + } + + @Override + public short getMgf1Digest(short keyParams, short hwParams) { + short mgfDigest = KMKeyParameters.findTag(keyParams, KMType.ENUM_ARRAY_TAG, + KMType.RSA_OAEP_MGF_DIGEST); + if (mgfDigest != KMType.INVALID_VALUE) { + if (KMEnumArrayTag.length(mgfDigest) != 1) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + mgfDigest = KMEnumArrayTag.get(mgfDigest, (short) 0); + if (mgfDigest == KMType.DIGEST_NONE) { + KMException.throwIt(KMError.UNSUPPORTED_MGF_DIGEST); + } + if (!KMEnumArrayTag + .contains(KMType.RSA_OAEP_MGF_DIGEST, mgfDigest, hwParams)) { + KMException.throwIt(KMError.INCOMPATIBLE_MGF_DIGEST); + } + if (mgfDigest != KMType.SHA1 && mgfDigest != KMType.SHA2_256) { + KMException.throwIt(KMError.UNSUPPORTED_MGF_DIGEST); + } + } + return mgfDigest; + } + + @Override + public void beginKeyAgreementOperation(KMOperationState op) { + if (op.getAlgorithm() != KMType.EC) + KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); + + op.setOperation( + seProvider.initAsymmetricOperation( + (byte) op.getPurpose(), + (byte)op.getAlgorithm(), + (byte)op.getPadding(), + (byte)op.getDigest(), + KMType.DIGEST_NONE, /* No MGF1 Digest */ + KMByteBlob.getBuffer(data[SECRET]), + KMByteBlob.getStartOff(data[SECRET]), + KMByteBlob.length(data[SECRET]), + null, + (short) 0, + (short) 0)); + } + + @Override + public void finishKeyAgreementOperation(KMOperationState op, byte[] scratchPad) { + try { + KMPKCS8Decoder pkcs8 = KMPKCS8Decoder.instance(); + short blob = pkcs8.decodeEcSubjectPublicKeyInfo(data[INPUT_DATA]); + short len = op.getOperation().finish( + KMByteBlob.getBuffer(blob), + KMByteBlob.getStartOff(blob), + KMByteBlob.length(blob), + scratchPad, + (short) 0 + ); + data[OUTPUT_DATA] = KMByteBlob.instance((short) 32); + Util.arrayCopyNonAtomic( + scratchPad, + (short) 0, + KMByteBlob.getBuffer(data[OUTPUT_DATA]), + KMByteBlob.getStartOff(data[OUTPUT_DATA]), + len); + } catch (CryptoException e) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + } + + @Override + public short getConfirmationToken(short confToken, short keyParams) { + if (0 == KMByteBlob.length(confToken)) { + KMException.throwIt(KMError.NO_USER_CONFIRMATION); + } + return confToken; + } + + @Override + public short getKMVerificationTokenExp() { + return KMVerificationToken.timeStampTokenExp(); + } + + @Override + public short getMacFromVerificationToken(short verToken) { + return KMVerificationToken.getMac(verToken, (short) 0x02); + } + + @Override + public void validateECKeys() { + // Read key size + short eccurve = KMEnumTag.getValue(KMType.ECCURVE, data[KEY_PARAMETERS]); + if (eccurve == KMType.INVALID_VALUE) { + KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE); + } else { + if (eccurve != KMType.P_256) { + KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE); + } + } + } + + @Override + public short buildErrorStatus(short err) { + return KMInteger.uint_16(err); + } + + @Override + public short generateAttestKeyExp() { + short params = KMKeyParameters.expAny(); + short blob = KMByteBlob.exp(); + // Array of expected arguments + short cmd = KMArray.instance((short) 5); + KMArray.add(cmd, (short) 0, blob); //key blob + KMArray.add(cmd, (short) 1, params); //keyparamters to be attested. + KMArray.add(cmd, (short) 2, blob); //attest key blob + KMArray.add(cmd, (short) 3, params); //attest key params + KMArray.add(cmd, (short) 4, blob); //attest issuer + return cmd; + } + + @Override + public void getAttestKeyInputParameters(short arrPtr, short[] data, byte keyBlobOff, + byte keyParametersOff, + byte attestKeyBlobOff, byte attestKeyParamsOff, byte attestKeyIssuerOff) { + data[keyBlobOff] = KMArray.get(arrPtr, (short) 0); + data[keyParametersOff] = KMArray.get(arrPtr, (short) 1); + data[attestKeyBlobOff] = KMArray.get(arrPtr, (short) 2); + data[attestKeyParamsOff] = KMArray.get(arrPtr, (short) 3); + data[attestKeyIssuerOff] = KMArray.get(arrPtr, (short) 4); + } + + @Override + public short prepareBeginResp(short paramsPtr, short opHandlePtr, short bufModePtr, + short macLengthPtr) { + short resp = KMArray.instance((short) 5); + KMArray.add(resp, (short) 0, KMInteger.uint_16(KMError.OK)); + KMArray.add(resp, (short) 1, paramsPtr); + KMArray.add(resp, (short) 2, opHandlePtr); + KMArray.add(resp, (short) 3, bufModePtr); + KMArray.add(resp, (short) 4, macLengthPtr); + return resp; + } + + @Override + public short prepareFinishExp() { + short byteBlob = KMByteBlob.exp(); + short cmd = KMArray.instance((short) 6); + KMArray.add(cmd, (short) 0, KMInteger.exp());//op handle + KMArray.add(cmd, (short) 1, byteBlob);// input data + KMArray.add(cmd, (short) 2, byteBlob); // signature + short authToken = KMHardwareAuthToken.exp(); + KMArray.add(cmd, (short) 3, authToken); // auth token + short verToken = getKMVerificationTokenExp(); + KMArray.add(cmd, (short) 4, verToken); // time stamp token + KMArray.add(cmd, (short) 5, byteBlob); // confirmation token + return cmd; + } + + @Override + public short prepareUpdateExp() { + short cmd = KMArray.instance((short) 4); + // Arguments + KMArray.add(cmd, (short) 0, KMInteger.exp()); + KMArray.add(cmd,(short) 1, KMByteBlob.exp()); + short authToken = KMHardwareAuthToken.exp(); + KMArray.add(cmd,(short) 2, authToken); + short verToken = getKMVerificationTokenExp(); + KMArray.add(cmd,(short) 3, verToken); + return cmd; + } + + @Override + public void getUpdateInputParameters(short arrPtr, short[] data, byte opHandleOff, + byte keyParametersOff, byte inputDataOff, byte hwTokenOff, + byte verToken) { + data[opHandleOff] = KMArray.get(arrPtr, (short) 0); + data[inputDataOff] = KMArray.get(arrPtr, (short) 1); + data[hwTokenOff] = KMArray.get(arrPtr, (short) 2); + data[verToken] = KMArray.get(arrPtr, (short) 3); + } + + @Override + public void getFinishInputParameters(short arrPtr, short[] data, byte opHandleOff, + byte keyParametersOff, byte inputDataOff, byte signDataOff, byte hwTokenOff, byte verToken, + byte confToken) { + data[opHandleOff] = KMArray.get(arrPtr, (short) 0); + data[inputDataOff] = KMArray.get(arrPtr, (short) 1); + data[signDataOff] = KMArray.get(arrPtr, (short) 2); + data[hwTokenOff] = KMArray.get(arrPtr, (short) 3); + data[verToken] = KMArray.get(arrPtr, (short) 4); + data[confToken] = KMArray.get(arrPtr, (short) 5); + } + + @Override + public short prepareFinishResp(short outputPtr) { + short resp = KMArray.instance((short) 2); + KMArray.add(resp, (short) 0, KMInteger.uint_16(KMError.OK)); + KMArray.add(resp, (short) 1, outputPtr); + return resp; + } + + @Override + public short prepareUpdateResp(short outputPtr, short inputConsumedPtr) { + short resp = KMArray.instance((short) 2); + KMArray.add(resp, (short) 0, KMInteger.uint_16(KMError.OK)); + KMArray.add(resp, (short) 1, outputPtr); + return resp; + } + + + @Override + public short validateApduHeader(APDU apdu) { + byte[] apduBuffer = apdu.getBuffer(); + short P1P2 = Util.getShort(apduBuffer, ISO7816.OFFSET_P1); + byte ins = apduBuffer[ISO7816.OFFSET_INS]; + switch (ins) { + case INS_GET_CERT_CHAIN_CMD: + return KMError.UNSUPPORTED_INSTRUCTION; + } + if (P1P2 != KEYMINT_HAL_VERSION) { + return KMError.INVALID_P1P2; + } + return KMError.OK; + } + + @Override + public void updateAAD(KMOperationState op, byte finish) { + return; + } + + @Override + public void validatePurpose(short params) { + short attKeyPurpose = + KMKeyParameters.findTag(params, KMType.ENUM_ARRAY_TAG, KMType.PURPOSE); + // ATTEST_KEY cannot be combined with any other purpose. + if (attKeyPurpose != KMType.INVALID_VALUE + && KMEnumArrayTag.contains(attKeyPurpose, KMType.ATTEST_KEY) + && KMEnumArrayTag.length(attKeyPurpose) > 1) { + KMException.throwIt(KMError.INCOMPATIBLE_PURPOSE); + } + } + +} diff --git a/Applet/src/com/android/javacard/keymaster/KMMap.java b/Applet/src/com/android/javacard/kmdevice/KMMap.java similarity index 87% rename from Applet/src/com/android/javacard/keymaster/KMMap.java rename to Applet/src/com/android/javacard/kmdevice/KMMap.java index 4b559fa3..02b3831f 100644 --- a/Applet/src/com/android/javacard/keymaster/KMMap.java +++ b/Applet/src/com/android/javacard/kmdevice/KMMap.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -56,7 +56,7 @@ public static short instance(short length, byte type) { return ptr; } - public static KMMap cast(short ptr) { + private static KMMap cast(short ptr) { if (heap[ptr] != MAP_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -150,4 +150,30 @@ public short length() { public byte[] getBuffer() { return heap; } + + public static void add(short bPtr, short index, short keyPtr, short valPtr) { + KMMap.cast(bPtr).add(index, keyPtr, valPtr); + } + + public static short getKeyValue(short bPtr, short index) { + return KMMap.cast(bPtr).getKeyValue(index); + } + + public static void swap(short bPtr, short index1, short index2) { + KMMap.cast(bPtr).swap(index1, index2); + } + + public static short getKey(short bPtr, short index) { + return KMMap.cast(bPtr).getKey(index); + } + + public static short length(short bPtr) { + return KMMap.cast(bPtr).length(); + } + + public static void canonicalize(short bPtr) { + KMMap.cast(bPtr).canonicalize(); + } + + } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMMasterKey.java b/Applet/src/com/android/javacard/kmdevice/KMMasterKey.java similarity index 87% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMMasterKey.java rename to Applet/src/com/android/javacard/kmdevice/KMMasterKey.java index 6eab5e56..1c5125e6 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMMasterKey.java +++ b/Applet/src/com/android/javacard/kmdevice/KMMasterKey.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.javacard.seprovider; +package com.android.javacard.kmdevice; /** * KMMasterKey is a marker interface and the SE Provider has to implement this interface. Internally @@ -21,5 +21,8 @@ * master key is maintained by the SEProvider. */ public interface KMMasterKey { - + + public byte getKey(byte[] keyData, short kOff); + + public short getKeySizeBits(); } diff --git a/Applet/src/com/android/javacard/keymaster/KMNInteger.java b/Applet/src/com/android/javacard/kmdevice/KMNInteger.java similarity index 69% rename from Applet/src/com/android/javacard/keymaster/KMNInteger.java rename to Applet/src/com/android/javacard/kmdevice/KMNInteger.java index c9f8e5ab..ef6dc8b6 100644 --- a/Applet/src/com/android/javacard/keymaster/KMNInteger.java +++ b/Applet/src/com/android/javacard/kmdevice/KMNInteger.java @@ -14,13 +14,13 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.Util; -public class KMNInteger extends KMInteger { +public class KMNInteger extends KMType { private static KMNInteger prototype; public static final byte SIGNED_MASK = (byte) 0x80; @@ -67,7 +67,7 @@ public static short instance(byte[] num, short srcOff, short length) { } } - public static KMNInteger cast(short ptr) { + private static KMNInteger cast(short ptr) { byte[] heap = repository.getHeap(); if (heap[ptr] != NEG_INTEGER_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); @@ -111,14 +111,69 @@ public static short uint_64(byte[] num, short offset) { Util.arrayCopy(num, offset, heap, (short) (ptr + TLV_HEADER_SIZE), KMInteger.UINT_64); return ptr; } - - @Override - protected short getBaseOffset() { + + private short getStartOff() { + return (short) (getBaseOffset() + TLV_HEADER_SIZE); + } + + private short getShort() { + return Util.getShort(heap, (short) (getStartOff() + 2)); + } + + private short getBaseOffset() { return instanceTable[KM_NEG_INTEGER_OFFSET]; } - + + private short length() { + return Util.getShort(heap, (short) (getBaseOffset() + 1)); + } + + private short getSignificantShort() { + return Util.getShort(heap, getStartOff()); + } + + private void getValue(byte[] dest, short destOff, short length) { + if (length < length()) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } + if (length > length()) { + length = length(); + destOff += length; + } + Util.arrayCopyNonAtomic(heap, getStartOff(), dest, destOff, length); + } + + private byte[] getBuffer() { + return heap; + } + public static boolean isSignedInteger(byte[] num, short offset) { byte val = num[offset]; return SIGNED_MASK == (val & SIGNED_MASK); } + + public static short getShort(short bPtr) { + return KMNInteger.cast(bPtr).getShort(); + } + + public static short getStartOff(short bPtr) { + return KMNInteger.cast(bPtr).getStartOff(); + } + + public static short getSignificantShort(short bPtr) { + return KMNInteger.cast(bPtr).getSignificantShort(); + } + + public static void getValue(short bPtr, byte[] dest, short destOff, short length) { + KMNInteger.cast(bPtr).getValue(dest, destOff, length); + } + + public static short length(short bPtr) { + return KMNInteger.cast(bPtr).length(); + } + + public static byte[] getBuffer(short bPtr) { + return KMNInteger.cast(bPtr).getBuffer(); + } + } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperation.java b/Applet/src/com/android/javacard/kmdevice/KMOperation.java similarity index 98% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperation.java rename to Applet/src/com/android/javacard/kmdevice/KMOperation.java index b73d58d1..b3341231 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperation.java +++ b/Applet/src/com/android/javacard/kmdevice/KMOperation.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.javacard.seprovider; +package com.android.javacard.kmdevice; /** * KMOperation represents a persistent operation started by keymaster hal's beginOperation function. diff --git a/Applet/src/com/android/javacard/keymaster/KMOperationState.java b/Applet/src/com/android/javacard/kmdevice/KMOperationState.java similarity index 94% rename from Applet/src/com/android/javacard/keymaster/KMOperationState.java rename to Applet/src/com/android/javacard/kmdevice/KMOperationState.java index 83370b8e..70dcc834 100644 --- a/Applet/src/com/android/javacard/keymaster/KMOperationState.java +++ b/Applet/src/com/android/javacard/kmdevice/KMOperationState.java @@ -14,10 +14,8 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; -import com.android.javacard.seprovider.KMException; -import com.android.javacard.seprovider.KMOperation; import javacard.framework.JCSystem; import javacard.framework.Util; @@ -185,14 +183,14 @@ public short getUserSecureId() { short obj; while (index < length) { obj = KMInteger.instance(userSecureIds, (short) (offset + index * 8), (short) 8); - KMArray.cast(arrObj).add(index, obj); + KMArray.add(arrObj, index, obj); index++; } return KMIntegerArrayTag.instance(KMType.ULONG_ARRAY_TAG, KMType.USER_SECURE_ID, arrObj); } public void setUserSecureId(short integerArrayPtr) { - short length = KMIntegerArrayTag.cast(integerArrayPtr).length(); + short length = KMIntegerArrayTag.length(integerArrayPtr); if (length > MAX_SECURE_USER_IDS) { KMException.throwIt(KMError.INVALID_KEY_BLOB); } @@ -202,13 +200,13 @@ public void setUserSecureId(short integerArrayPtr) { short offset = 0; offset = Util.setShort(userSecureIds, offset, length); while (index < length) { - obj = KMIntegerArrayTag.cast(integerArrayPtr).get(index); + obj = KMIntegerArrayTag.get(integerArrayPtr, index); Util.arrayCopyNonAtomic( - KMInteger.cast(obj).getBuffer(), - KMInteger.cast(obj).getStartOff(), + KMInteger.getBuffer(obj), + KMInteger.getStartOff(obj), userSecureIds, - (short) (8 - KMInteger.cast(obj).length() + offset + 8 * index), - KMInteger.cast(obj).length() + (short) (8 - KMInteger.length(obj) + offset + 8 * index), + KMInteger.length(obj) ); index++; } diff --git a/Applet/src/com/android/javacard/keymaster/KMPKCS8Decoder.java b/Applet/src/com/android/javacard/kmdevice/KMPKCS8Decoder.java similarity index 75% rename from Applet/src/com/android/javacard/keymaster/KMPKCS8Decoder.java rename to Applet/src/com/android/javacard/kmdevice/KMPKCS8Decoder.java index eb860e2d..8afb1516 100644 --- a/Applet/src/com/android/javacard/keymaster/KMPKCS8Decoder.java +++ b/Applet/src/com/android/javacard/kmdevice/KMPKCS8Decoder.java @@ -1,6 +1,5 @@ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; -import com.android.javacard.seprovider.KMException; import javacard.framework.Util; public class KMPKCS8Decoder { @@ -10,19 +9,9 @@ public class KMPKCS8Decoder { public static final byte ASN1_A0_TAG = (byte) 0xA0; public static final byte ASN1_A1_TAG = (byte) 0xA1; public static final byte ASN1_BIT_STRING = 0x03; - public static final byte[] EC_CURVE = { - 0x06,0x08,0x2a,(byte)0x86,0x48,(byte)0xce,0x3d,0x03, - 0x01,0x07 - }; - public static final byte[] RSA_ALGORITHM = { - 0x06,0x09,0x2A,(byte)0x86,0x48,(byte)0x86, - (byte)0xF7,0x0D,0x01,0x01,0x01,0x05,0x00 - }; - public static final byte[] EC_ALGORITHM = { - 0x06,0x07,0x2a,(byte)0x86,0x48,(byte)0xce, - 0x3d,0x02,0x01,0x06,0x08,0x2a,(byte)0x86,0x48, - (byte)0xce,0x3d,0x03,0x01,0x07 - }; + public static byte[] EC_CURVE; + public static byte[] RSA_ALGORITHM; + public static byte[] EC_ALGORITHM; private byte[] data; private short start; private short length; @@ -34,6 +23,22 @@ private KMPKCS8Decoder(){ cur = 0; } + public static void initStatics() { + EC_CURVE = new byte[] { + 0x06,0x08,0x2a,(byte)0x86,0x48,(byte)0xce,0x3d,0x03, + 0x01,0x07 + }; + RSA_ALGORITHM = new byte[] { + 0x06,0x09,0x2A,(byte)0x86,0x48,(byte)0x86, + (byte)0xF7,0x0D,0x01,0x01,0x01,0x05,0x00 + }; + EC_ALGORITHM = new byte[] { + 0x06,0x07,0x2a,(byte)0x86,0x48,(byte)0xce, + 0x3d,0x02,0x01,0x06,0x08,0x2a,(byte)0x86,0x48, + (byte)0xce,0x3d,0x03,0x01,0x07 + }; + } + public short decodeRsa(short blob){ init(blob); decodeCommon((short)0, RSA_ALGORITHM); @@ -53,10 +58,10 @@ public short decodeEcSubjectPublicKeyInfo(short blob) { short ecPublicInfo = KMByteBlob.instance(len); getBytes(ecPublicInfo); if(Util.arrayCompare( - KMByteBlob.cast(ecPublicInfo).getBuffer(), - KMByteBlob.cast(ecPublicInfo).getStartOff(), + KMByteBlob.getBuffer(ecPublicInfo), + KMByteBlob.getStartOff(ecPublicInfo), EC_ALGORITHM, - (short)0,KMByteBlob.cast(ecPublicInfo).length()) !=0){ + (short)0,KMByteBlob.length(ecPublicInfo)) !=0){ KMException.throwIt(KMError.UNKNOWN_ERROR); } len = header(ASN1_BIT_STRING); @@ -88,19 +93,19 @@ public short decodeRsaPrivateKey(short version){ len = header(ASN1_INTEGER); short privKey = KMByteBlob.instance(len); getBytes(privKey); - KMArray.cast(resp).add((short)0, modulus); - KMArray.cast(resp).add((short)1, pubKey); - KMArray.cast(resp).add((short)2, privKey); + KMArray.add(resp, (short)0, modulus); + KMArray.add(resp, (short)1, pubKey); + KMArray.add(resp, (short)2, privKey); return resp; } private void updateModulus(short blob) { - byte[] buffer = KMByteBlob.cast(blob).getBuffer(); - short startOff = KMByteBlob.cast(blob).getStartOff(); - short len = KMByteBlob.cast(blob).length(); + byte[] buffer = KMByteBlob.getBuffer(blob); + short startOff = KMByteBlob.getStartOff(blob); + short len = KMByteBlob.length(blob); if(0 == buffer[startOff] && len > 256) { - KMByteBlob.cast(blob).setStartOff(++startOff); - KMByteBlob.cast(blob).setLength(--len); + KMByteBlob.setStartOff(blob, ++startOff); + KMByteBlob.setLength(blob, --len); } } @@ -115,10 +120,10 @@ public void decodeCommon(short version, byte[] alg){ short blob = KMByteBlob.instance(len); getBytes(blob); if(Util.arrayCompare( - KMByteBlob.cast(blob).getBuffer(), - KMByteBlob.cast(blob).getStartOff(), + KMByteBlob.getBuffer(blob), + KMByteBlob.getStartOff(blob), alg, - (short)0,KMByteBlob.cast(blob).length()) !=0){ + (short)0,KMByteBlob.length(blob)) !=0){ KMException.throwIt(KMError.UNKNOWN_ERROR); } } @@ -144,8 +149,8 @@ public short decodeEcPrivateKey(short version){ if(unusedBits != 0) KMException.throwIt(KMError.UNIMPLEMENTED); short pubKey = KMByteBlob.instance((short)(len -1)); getBytes(pubKey); - KMArray.cast(resp).add((short)0, pubKey); - KMArray.cast(resp).add((short)1, privKey); + KMArray.add(resp, (short)0, pubKey); + KMArray.add(resp, (short)1, privKey); return resp; } private void validateTag0IfPresent(){ @@ -174,9 +179,9 @@ private short getShort(){ } private void getBytes(short blob){ - short len = KMByteBlob.cast(blob).length(); - Util.arrayCopyNonAtomic(data, cur, KMByteBlob.cast(blob).getBuffer(), - KMByteBlob.cast(blob).getStartOff(), len); + short len = KMByteBlob.length(blob); + Util.arrayCopyNonAtomic(data, cur, KMByteBlob.getBuffer(blob), + KMByteBlob.getStartOff(blob), len); incrementCursor(len); } @@ -197,9 +202,9 @@ public static KMPKCS8Decoder instance() { } public void init(short blob) { - data = KMByteBlob.cast(blob).getBuffer(); - start = KMByteBlob.cast(blob).getStartOff(); - length = KMByteBlob.cast(blob).length(); + data = KMByteBlob.getBuffer(blob); + start = KMByteBlob.getStartOff(blob); + length = KMByteBlob.length(blob); cur = start; } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPreSharedKey.java b/Applet/src/com/android/javacard/kmdevice/KMPreSharedKey.java similarity index 95% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPreSharedKey.java rename to Applet/src/com/android/javacard/kmdevice/KMPreSharedKey.java index 86bb1df9..268f9a8e 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPreSharedKey.java +++ b/Applet/src/com/android/javacard/kmdevice/KMPreSharedKey.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.javacard.seprovider; +package com.android.javacard.kmdevice; /** * KMPreSharedKey is a marker interface and the SE Provider has to implement this interface. diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/kmdevice/KMRepository.java similarity index 89% rename from Applet/src/com/android/javacard/keymaster/KMRepository.java rename to Applet/src/com/android/javacard/kmdevice/KMRepository.java index 03791210..364fe0d8 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/src/com/android/javacard/kmdevice/KMRepository.java @@ -14,12 +14,9 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; -import com.android.javacard.seprovider.KMException; -import com.android.javacard.seprovider.KMUpgradable; import org.globalplatform.upgrade.Element; - import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.JCSystem; @@ -67,6 +64,7 @@ public class KMRepository implements KMUpgradable { public static final short AUTH_TAG_LENGTH = 16; public static final short AUTH_TAG_COUNTER_SIZE = 4; public static final short AUTH_TAG_ENTRY_SIZE = (AUTH_TAG_LENGTH + AUTH_TAG_COUNTER_SIZE + 1); + public static byte[] zero; // Class Attributes private byte[] heap; @@ -78,6 +76,10 @@ public class KMRepository implements KMUpgradable { // Singleton instance private static KMRepository repository; + public static void initStatics() { + zero = new byte[]{0, 0, 0, 0, 0, 0, 0, 0}; + } + public static KMRepository instance() { return repository; } @@ -187,9 +189,7 @@ private void clearDataEntry(short id) { 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)); - JCSystem.beginTransaction(); - Util.arrayFillNonAtomic(dataTable, dataPtr, dataLen, (byte) 0); - JCSystem.commitTransaction(); + Util.arrayFill(dataTable, dataPtr, dataLen, (byte) 0); } } @@ -202,8 +202,8 @@ private void writeDataEntry(short id, byte[] buf, short offset, short len) { JCSystem.beginTransaction(); 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); JCSystem.commitTransaction(); + Util.arrayCopy(buf, offset, dataTable, dataPtr, len); } else { if (len != dataLen) { KMException.throwIt(KMError.UNKNOWN_ERROR); @@ -246,19 +246,17 @@ public short readData(short id) { short len = dataLength(id); if (len != 0) { short blob = KMByteBlob.instance(dataLength(id)); - readDataEntry(id, KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff()); + readDataEntry(id, KMByteBlob.getBuffer(blob), KMByteBlob.getStartOff(blob)); return blob; } return KMType.INVALID_VALUE; } - private static final byte[] zero = {0, 0, 0, 0, 0, 0, 0, 0}; - public short getOsVersion() { short blob = readData(BOOT_OS_VERSION); if (blob != KMType.INVALID_VALUE) { return KMInteger.uint_32( - KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff()); + KMByteBlob.getBuffer(blob), KMByteBlob.getStartOff(blob)); } else { return KMInteger.uint_32(zero, (short) 0); } @@ -268,7 +266,7 @@ public short getVendorPatchLevel() { short blob = readData(VENDOR_PATCH_LEVEL); if (blob != KMType.INVALID_VALUE) { return KMInteger.uint_32( - KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff()); + KMByteBlob.getBuffer(blob), KMByteBlob.getStartOff(blob)); } else { return KMInteger.uint_32(zero, (short) 0); } @@ -278,7 +276,7 @@ public short getOsPatch() { short blob = readData(BOOT_OS_PATCH_LEVEL); if (blob != KMType.INVALID_VALUE) { return KMInteger.uint_32( - KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff()); + KMByteBlob.getBuffer(blob), KMByteBlob.getStartOff(blob)); } else { return KMInteger.uint_32(zero, (short) 0); } @@ -289,7 +287,7 @@ private boolean readBoolean(short id) { if (blob == KMType.INVALID_VALUE) { KMException.throwIt(KMError.INVALID_DATA); } - return (byte) ((getHeap())[KMByteBlob.cast(blob).getStartOff()]) == 0x01; + return (byte) ((getHeap())[KMByteBlob.getStartOff(blob)]) == 0x01; } public boolean getDeviceLock() { @@ -311,8 +309,8 @@ public boolean getBootEndedStatus() { public short getDeviceTimeStamp() { short blob = readData(DEVICE_LOCKED_TIME); if (blob != KMType.INVALID_VALUE) { - return KMInteger.uint_64(KMByteBlob.cast(blob).getBuffer(), - KMByteBlob.cast(blob).getStartOff()); + return KMInteger.uint_64(KMByteBlob.getBuffer(blob), + KMByteBlob.getStartOff(blob)); } else { return KMInteger.uint_64(zero, (short) 0); } @@ -387,7 +385,7 @@ private void writeAuthTagState(byte[] buf, short offset, byte state) { public boolean persistAuthTag(short authTag) { - if (KMByteBlob.cast(authTag).length() != AUTH_TAG_LENGTH) { + if (KMByteBlob.length(authTag) != AUTH_TAG_LENGTH) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); } @@ -396,8 +394,8 @@ public boolean persistAuthTag(short authTag) { byte[] scratchPad = getHeap(); writeAuthTagState(getHeap(), authTagEntry, (byte) 1); Util.arrayCopyNonAtomic( - KMByteBlob.cast(authTag).getBuffer(), - KMByteBlob.cast(authTag).getStartOff(), + KMByteBlob.getBuffer(authTag), + KMByteBlob.getStartOff(authTag), getHeap(), (short) (authTagEntry + 1), AUTH_TAG_LENGTH); Util.setShort(getHeap(), (short) (authTagEntry + AUTH_TAG_LENGTH + 1 + 2), (short) 1); @@ -427,7 +425,7 @@ public boolean isAuthTagPersisted(short authTag) { } private short findTag(short authTag) { - if (KMByteBlob.cast(authTag).length() != AUTH_TAG_LENGTH) { + if (KMByteBlob.length(authTag) != AUTH_TAG_LENGTH) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); } short index = 0; @@ -441,8 +439,8 @@ private short findTag(short authTag) { Util.arrayCompare( getHeap(), (short) (offset + 1), - KMByteBlob.cast(authTag).getBuffer(), - KMByteBlob.cast(authTag).getStartOff(), + KMByteBlob.getBuffer(authTag), + KMByteBlob.getStartOff(authTag), AUTH_TAG_LENGTH); if (found == 0) { return (short) (index + AUTH_TAG_1); @@ -459,8 +457,8 @@ public short getRateLimitedKeyCount(short authTag, byte[] out, short outOff) { if (tag != KMType.INVALID_VALUE) { blob = readData(tag); Util.arrayCopyNonAtomic( - KMByteBlob.cast(blob).getBuffer(), - (short) (KMByteBlob.cast(blob).getStartOff() + AUTH_TAG_LENGTH + 1), + KMByteBlob.getBuffer(blob), + (short) (KMByteBlob.getStartOff(blob) + AUTH_TAG_LENGTH + 1), out, outOff, AUTH_TAG_COUNTER_SIZE); @@ -476,13 +474,13 @@ public void setRateLimitedKeyCount(short authTag, byte[] buf, short off, short l Util.arrayCopyNonAtomic( buf, off, - KMByteBlob.cast(dataPtr).getBuffer(), - (short) (KMByteBlob.cast(dataPtr).getStartOff() + AUTH_TAG_LENGTH + 1), + KMByteBlob.getBuffer(dataPtr), + (short) (KMByteBlob.getStartOff(dataPtr) + AUTH_TAG_LENGTH + 1), len); writeDataEntry(tag, - KMByteBlob.cast(dataPtr).getBuffer(), - KMByteBlob.cast(dataPtr).getStartOff(), - KMByteBlob.cast(dataPtr).length()); + KMByteBlob.getBuffer(dataPtr), + KMByteBlob.getStartOff(dataPtr), + KMByteBlob.length(dataPtr)); } } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java b/Applet/src/com/android/javacard/kmdevice/KMSEProvider.java similarity index 99% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java rename to Applet/src/com/android/javacard/kmdevice/KMSEProvider.java index 8252ca7f..d1636eb0 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java +++ b/Applet/src/com/android/javacard/kmdevice/KMSEProvider.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.javacard.seprovider; +package com.android.javacard.kmdevice; + /** * KMSEProvider is facade to use SE specific methods. The main intention of this interface is to @@ -774,6 +775,8 @@ void persistProvisionData(byte[] buf, short certChainOff, short certChainLen, * @return Instance of the KMAttestationKey. */ KMAttestationKey getAttestationKey(); + + public boolean isPowerReset(boolean isForStatusUpdate); } diff --git a/Applet/src/com/android/javacard/keymaster/KMSimpleValue.java b/Applet/src/com/android/javacard/kmdevice/KMSimpleValue.java similarity index 89% rename from Applet/src/com/android/javacard/keymaster/KMSimpleValue.java rename to Applet/src/com/android/javacard/kmdevice/KMSimpleValue.java index 794f3f92..135f9142 100644 --- a/Applet/src/com/android/javacard/keymaster/KMSimpleValue.java +++ b/Applet/src/com/android/javacard/kmdevice/KMSimpleValue.java @@ -1,4 +1,4 @@ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -32,7 +32,7 @@ public short length() { return Util.getShort(heap, (short) (instanceTable[KM_SIMPLE_VALUE_OFFSET] + 1)); } - public static KMSimpleValue cast(short ptr) { + private static KMSimpleValue cast(short ptr) { if (heap[ptr] != SIMPLE_VALUE_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -55,6 +55,10 @@ public byte getValue() { return heap[(short) (instanceTable[KM_SIMPLE_VALUE_OFFSET] + 3)]; } + public static byte getValue(short bPtr) { + return KMSimpleValue.cast(bPtr).getValue(); + } + private static boolean isSimpleValueValid(byte value) { switch (value) { case TRUE: diff --git a/Applet/src/com/android/javacard/keymaster/KMTag.java b/Applet/src/com/android/javacard/kmdevice/KMTag.java similarity index 82% rename from Applet/src/com/android/javacard/keymaster/KMTag.java rename to Applet/src/com/android/javacard/kmdevice/KMTag.java index 0cac460e..670ada1d 100644 --- a/Applet/src/com/android/javacard/keymaster/KMTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMTag.java @@ -14,9 +14,8 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; -import com.android.javacard.seprovider.KMException; import javacard.framework.Util; /** @@ -29,11 +28,11 @@ * of KMType. */ public class KMTag extends KMType { - public static short getTagType(short ptr) { + public static short getKMTagType(short ptr) { return Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)); } - public static short getKey(short ptr) { + public static short getKMTagKey(short ptr) { return Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE + 2)); } @@ -49,7 +48,7 @@ public static void assertAbsence(short params, short tagType, short tagKey, shor } public static boolean isPresent(short params, short tagType, short tagKey){ - short tag = KMKeyParameters.findTag(tagType, tagKey, params); + short tag = KMKeyParameters.findTag(params, tagType, tagKey); return tag != KMType.INVALID_VALUE; } @@ -76,24 +75,24 @@ public static void assertTrue(boolean condition, short error){ } public static boolean isValidPublicExponent(short params) { - short pubExp = KMKeyParameters.findTag(KMType.ULONG_TAG, KMType.RSA_PUBLIC_EXPONENT, params); + short pubExp = KMKeyParameters.findTag(params, KMType.ULONG_TAG, KMType.RSA_PUBLIC_EXPONENT); if(pubExp == KMType.INVALID_VALUE){ return false; } - pubExp = KMIntegerTag.cast(pubExp).getValue(); - if(!(KMInteger.cast(pubExp).getShort() == 0x01 && - KMInteger.cast(pubExp).getSignificantShort() == 0x01)){ + pubExp = KMIntegerTag.getValue(pubExp); + if(!(KMInteger.getShort(pubExp) == 0x01 && + KMInteger.getSignificantShort(pubExp) == 0x01)){ return false; } return true; } public static boolean isValidKeySize(short params){ - short keysize = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, params); + short keysize = KMKeyParameters.findTag(params, KMType.UINT_TAG, KMType.KEYSIZE); if(keysize == KMType.INVALID_VALUE){ return false; } short alg = KMEnumTag.getValue(KMType.ALGORITHM, params); - return KMIntegerTag.cast(keysize).isValidKeySize((byte)alg); + return KMIntegerTag.isValidKeySize(keysize, (byte)alg); } } diff --git a/Applet/src/com/android/javacard/keymaster/KMTextString.java b/Applet/src/com/android/javacard/kmdevice/KMTextString.java similarity index 74% rename from Applet/src/com/android/javacard/keymaster/KMTextString.java rename to Applet/src/com/android/javacard/kmdevice/KMTextString.java index 310cfa01..8f4e332b 100644 --- a/Applet/src/com/android/javacard/keymaster/KMTextString.java +++ b/Applet/src/com/android/javacard/kmdevice/KMTextString.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -25,8 +25,7 @@ * extends KMByteBlob by specifying value field as zero or more sequence of bytes. struct{ byte * TEXT_STR_TYPE; short length; sequence of bytes} */ -public class KMTextString extends KMByteBlob { - private static short OFFSET_SIZE = 2; +public class KMTextString extends KMType { private static KMTextString prototype; @@ -48,9 +47,7 @@ public static short exp() { // return an empty byte blob instance public static short instance(short length) { - short ptr = KMType.instance(TEXT_STRING_TYPE, (short) (length + OFFSET_SIZE)); - Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), - (short) (ptr + TLV_HEADER_SIZE + OFFSET_SIZE)); + short ptr = KMType.instance(TEXT_STRING_TYPE, (short) (length )); Util.setShort(heap, (short)(ptr + 1), length); return ptr; } @@ -59,12 +56,12 @@ public static short instance(short length) { public static short instance(byte[] buf, short startOff, short length) { short ptr = instance(length); Util.arrayCopyNonAtomic(buf, startOff, heap, - (short) (ptr + TLV_HEADER_SIZE + OFFSET_SIZE), length); + (short) (ptr + TLV_HEADER_SIZE), length); return ptr; } // cast the ptr to KMTextString - public static KMTextString cast(short ptr) { + private static KMTextString cast(short ptr) { if (heap[ptr] != TEXT_STRING_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -77,4 +74,30 @@ public static KMTextString cast(short ptr) { protected short getBaseOffset() { return instanceTable[KM_TEXT_STRING_OFFSET]; } + + // Get the length of the blob + private short length() { + return Util.getShort(heap, (short) (getBaseOffset() + 1)); + } + + private byte[] getBuffer() { + return heap; + } + + // Get the start of blob + public short getStartOff() { + return (short)(getBaseOffset() + TLV_HEADER_SIZE); + } + + public static short length(short bPtr) { + return cast(bPtr).length(); + } + + public static byte[] getBuffer(short bPtr) { + return cast(bPtr).getBuffer(); + } + + public static short getStartOff(short bPtr) { + return cast(bPtr).getStartOff(); + } } diff --git a/Applet/src/com/android/javacard/keymaster/KMType.java b/Applet/src/com/android/javacard/kmdevice/KMType.java similarity index 98% rename from Applet/src/com/android/javacard/keymaster/KMType.java rename to Applet/src/com/android/javacard/kmdevice/KMType.java index 5be6796d..4e86580a 100644 --- a/Applet/src/com/android/javacard/keymaster/KMType.java +++ b/Applet/src/com/android/javacard/kmdevice/KMType.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -370,15 +370,15 @@ public static void initialize() { KMType.heap = repository.getHeap(); } - public static byte getType(short ptr) { + public static byte getKMType(short ptr) { return heap[ptr]; } - public static short length(short ptr) { + public static short getKMTypeLength(short ptr) { return Util.getShort(heap, (short) (ptr + 1)); } - public static short getValue(short ptr) { + public static short getKMTypeValue(short ptr) { return Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)); } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMUpgradable.java b/Applet/src/com/android/javacard/kmdevice/KMUpgradable.java similarity index 95% rename from Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMUpgradable.java rename to Applet/src/com/android/javacard/kmdevice/KMUpgradable.java index 9bca1c8c..905c8bd0 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMUpgradable.java +++ b/Applet/src/com/android/javacard/kmdevice/KMUpgradable.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.javacard.seprovider; +package com.android.javacard.kmdevice; import org.globalplatform.upgrade.Element; diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/src/com/android/javacard/kmdevice/KMUtils.java similarity index 85% rename from Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java rename to Applet/src/com/android/javacard/kmdevice/KMUtils.java index f21eb868..00c60ae0 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/src/com/android/javacard/kmdevice/KMUtils.java @@ -13,51 +13,71 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.javacard.keymaster; - -import com.android.javacard.seprovider.KMException; +package com.android.javacard.kmdevice; import javacard.framework.Util; public class KMUtils { // 64 bit unsigned calculations for time - public static final byte[] oneSecMsec = { - 0, 0, 0, 0, 0, 0, 0x03, (byte) 0xE8}; // 1000 msec - public static final byte[] oneMinMsec = { - 0, 0, 0, 0, 0, 0, (byte) 0xEA, 0x60}; // 60000 msec - public static final byte[] oneHourMsec = { - 0, 0, 0, 0, 0, 0x36, (byte) 0xEE, (byte) 0x80}; // 3600000 msec - public static final byte[] oneDayMsec = { - 0, 0, 0, 0, 0x05, 0x26, 0x5C, 0x00}; // 86400000 msec - public static final byte[] oneMonthMsec = { - 0, 0, 0, 0, (byte) 0x9C, (byte) 0xBE, (byte) 0xBD, 0x50}; // 2629746000 msec - public static final byte[] leapYearMsec = { - 0, 0, 0, 0x07, (byte) 0x5C, (byte) 0xD7, (byte) 0x88, 0x00}; //31622400000; - public static final byte[] yearMsec = { - 0, 0, 0, 0x07, 0x57, (byte) 0xB1, 0x2C, 0x00}; //31536000000 + public static byte[] oneSecMsec; // 1000 msec + public static byte[] oneMinMsec; // 60000 msec + public static byte[] oneHourMsec; // 3600000 msec + public static byte[] oneDayMsec; // 86400000 msec + public static byte[] oneMonthMsec; // 2629746000 msec + public static byte[] leapYearMsec; //31622400000; + public static byte[] yearMsec; //31536000000 //Leap year(366) + 3 * 365 - public static final byte[] fourYrsMsec = { - 0, 0, 0, 0x1D, 0x63, (byte) 0xEB, 0x0C, 0x00};//126230400000 - public static final byte[] firstJan2020 = { - 0, 0, 0x01, 0x6F, 0x5E, 0x66, (byte) 0xE8, 0x00}; // 1577836800000 msec - public static final byte[] firstJan2051 = { - 0, 0, 0x02, 0x53, 0x26, (byte) 0x0E, (byte) 0x1C, 0x00}; // 2556144000000 + public static byte[] fourYrsMsec;//126230400000 + public static byte[] firstJan2020; // 1577836800000 msec + public static byte[] firstJan2051; // 2556144000000 // msec - public static final byte[] febMonthLeapMSec = { - 0, 0, 0, 0, (byte) 0x95, 0x58, 0x6C, 0x00}; //2505600000 - public static final byte[] febMonthMsec = { - 0, 0, 0, 0, (byte) 0x90, 0x32, 0x10, 0x00}; //2419200000 - public static final byte[] ThirtyOneDaysMonthMsec = { - 0, 0, 0, 0, (byte) 0x9F, (byte) 0xA5, 0x24, 0x00};//2678400000 - public static final byte[] ThirtDaysMonthMsec = { - 0, 0, 0, 0, (byte) 0x9A, 0x7E, (byte) 0xC8, 0x00};//2592000000 + public static byte[] febMonthLeapMSec; //2505600000 + public static byte[] febMonthMsec; //2419200000 + public static byte[] ThirtyOneDaysMonthMsec;//2678400000 + public static byte[] ThirtDaysMonthMsec;//2592000000 public static final short year2051 = 2051; public static final short year2020 = 2020; // Convert to milliseconds constants - public static final byte[] SEC_TO_MILLIS_SHIFT_POS = {9, 8, 7, 6, 5, 3}; + public static byte[] SEC_TO_MILLIS_SHIFT_POS; // -------------------------------------- + public static void initStatics() { + oneSecMsec = new byte[] { + 0, 0, 0, 0, 0, 0, 0x03, (byte) 0xE8}; // 1000 msec + oneMinMsec = new byte[] { + 0, 0, 0, 0, 0, 0, (byte) 0xEA, 0x60}; // 60000 msec + oneHourMsec = new byte[] { + 0, 0, 0, 0, 0, 0x36, (byte) 0xEE, (byte) 0x80}; // 3600000 msec + oneDayMsec = new byte[] { + 0, 0, 0, 0, 0x05, 0x26, 0x5C, 0x00}; // 86400000 msec + oneMonthMsec = new byte[] { + 0, 0, 0, 0, (byte) 0x9C, (byte) 0xBE, (byte) 0xBD, 0x50}; // 2629746000 msec + leapYearMsec = new byte[] { + 0, 0, 0, 0x07, (byte) 0x5C, (byte) 0xD7, (byte) 0x88, 0x00}; //31622400000; + yearMsec = new byte[] { + 0, 0, 0, 0x07, 0x57, (byte) 0xB1, 0x2C, 0x00}; //31536000000 + //Leap year(366) + 3 * 365 + fourYrsMsec = new byte[] { + 0, 0, 0, 0x1D, 0x63, (byte) 0xEB, 0x0C, 0x00};//126230400000 + firstJan2020 = new byte[] { + 0, 0, 0x01, 0x6F, 0x5E, 0x66, (byte) 0xE8, 0x00}; // 1577836800000 msec + firstJan2051 = new byte[] { + 0, 0, 0x02, 0x53, 0x26, (byte) 0x0E, (byte) 0x1C, 0x00}; // 2556144000000 + // msec + febMonthLeapMSec = new byte[] { + 0, 0, 0, 0, (byte) 0x95, 0x58, 0x6C, 0x00}; //2505600000 + febMonthMsec = new byte[] { + 0, 0, 0, 0, (byte) 0x90, 0x32, 0x10, 0x00}; //2419200000 + ThirtyOneDaysMonthMsec = new byte[] { + 0, 0, 0, 0, (byte) 0x9F, (byte) 0xA5, 0x24, 0x00};//2678400000 + ThirtDaysMonthMsec = new byte[] { + 0, 0, 0, 0, (byte) 0x9A, 0x7E, (byte) 0xC8, 0x00};//2592000000 + // Convert to milliseconds constants + SEC_TO_MILLIS_SHIFT_POS = new byte[] {9, 8, 7, 6, 5, 3}; + + } + public static short convertToDate(short time, byte[] scratchPad, boolean utcFlag) { @@ -70,10 +90,9 @@ public static short convertToDate(short time, byte[] scratchPad, byte Z = 0x5A; boolean from2020 = true; Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); - Util.arrayCopyNonAtomic(KMInteger.cast(time).getBuffer(), - KMInteger.cast(time).getStartOff(), scratchPad, - (short) (8 - KMInteger.cast(time).length()), KMInteger.cast(time) - .length()); + Util.arrayCopyNonAtomic(KMInteger.getBuffer(time), + KMInteger.getStartOff(time), scratchPad, + (short) (8 - KMInteger.length(time)), KMInteger.length(time)); // If the time is less then 1 Jan 2020 then it is an error if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2020, (short) 0, (short) 8) < 0) { diff --git a/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java b/Applet/src/com/android/javacard/kmdevice/KMVerificationToken.java similarity index 59% rename from Applet/src/com/android/javacard/keymaster/KMVerificationToken.java rename to Applet/src/com/android/javacard/kmdevice/KMVerificationToken.java index f10f049e..29d09f2b 100644 --- a/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java +++ b/Applet/src/com/android/javacard/kmdevice/KMVerificationToken.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.javacard.keymaster; +package com.android.javacard.kmdevice; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -41,24 +41,22 @@ public class KMVerificationToken extends KMType { private KMVerificationToken() { } - public static short exp1() { + public static short timeStampTokenExp() { short arrPtr = KMArray.instance((short) 3); - KMArray arr = KMArray.cast(arrPtr); - arr.add(CHALLENGE, KMInteger.exp()); - arr.add(TIMESTAMP, KMInteger.exp()); - arr.add(MAC1, KMByteBlob.exp()); + KMArray.add(arrPtr, CHALLENGE, KMInteger.exp()); + KMArray.add(arrPtr, TIMESTAMP, KMInteger.exp()); + KMArray.add(arrPtr, MAC1, KMByteBlob.exp()); return instance(arrPtr); } - public static short exp2() { + public static short verificationTokenExp() { short arrPtr = KMArray.instance((short) 5); - KMArray arr = KMArray.cast(arrPtr); - arr.add(CHALLENGE, KMInteger.exp()); - arr.add(TIMESTAMP, KMInteger.exp()); + KMArray.add(arrPtr, CHALLENGE, KMInteger.exp()); + KMArray.add(arrPtr, TIMESTAMP, KMInteger.exp()); //arr.add(PARAMETERS_VERIFIED, KMKeyParameters.exp()); - arr.add(PARAMETERS_VERIFIED, KMByteBlob.exp()); - arr.add(SECURITY_LEVEL, KMEnum.instance(KMType.HARDWARE_TYPE)); - arr.add(MAC2, KMByteBlob.exp()); + KMArray.add(arrPtr, PARAMETERS_VERIFIED, KMByteBlob.exp()); + KMArray.add(arrPtr, SECURITY_LEVEL, KMEnum.instance(KMType.HARDWARE_TYPE)); + KMArray.add(arrPtr, MAC2, KMByteBlob.exp()); return instance(arrPtr); } @@ -72,26 +70,23 @@ private static KMVerificationToken proto(short ptr) { public static short instance1() { short arrPtr = KMArray.instance((short) 3); - KMArray arr = KMArray.cast(arrPtr); - arr.add(CHALLENGE, KMInteger.uint_16((short) 0)); - arr.add(TIMESTAMP, KMInteger.uint_16((short) 0)); - arr.add(MAC1, KMByteBlob.instance((short) 0)); + KMArray.add(arrPtr, CHALLENGE, KMInteger.uint_16((short) 0)); + KMArray.add(arrPtr, TIMESTAMP, KMInteger.uint_16((short) 0)); + KMArray.add(arrPtr, MAC1, KMByteBlob.instance((short) 0)); return instance(arrPtr); } public static short instance2() { short arrPtr = KMArray.instance((short) 5); - KMArray arr = KMArray.cast(arrPtr); - arr.add(CHALLENGE, KMInteger.uint_16((short) 0)); - arr.add(TIMESTAMP, KMInteger.uint_16((short) 0)); - arr.add(PARAMETERS_VERIFIED, KMByteBlob.instance((short) 0)); - arr.add(SECURITY_LEVEL, KMEnum.instance(KMType.HARDWARE_TYPE, KMType.STRONGBOX)); - arr.add(MAC2, KMByteBlob.instance((short) 0)); + KMArray.add(arrPtr, CHALLENGE, KMInteger.uint_16((short) 0)); + KMArray.add(arrPtr, TIMESTAMP, KMInteger.uint_16((short) 0)); + KMArray.add(arrPtr, PARAMETERS_VERIFIED, KMByteBlob.instance((short) 0)); + KMArray.add(arrPtr, SECURITY_LEVEL, KMEnum.instance(KMType.HARDWARE_TYPE, KMType.STRONGBOX)); + KMArray.add(arrPtr, MAC2, KMByteBlob.instance((short) 0)); return instance(arrPtr); } public static short instance(short vals) { - KMArray arr = KMArray.cast(vals); - if (arr.length() != 3 && arr.length() != 5) { + if (KMArray.length(vals) != 3 && KMArray.length(vals) != 5) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } short ptr = KMType.instance(VERIFICATION_TOKEN_TYPE, (short) 2); @@ -99,7 +94,7 @@ public static short instance(short vals) { return ptr; } - public static KMVerificationToken cast(short ptr) { + private static KMVerificationToken cast(short ptr) { if (heap[ptr] != VERIFICATION_TOKEN_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -116,33 +111,63 @@ public short getVals() { public short length() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).length(); + return KMArray.length(arrPtr); } public short getChallenge() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).get(CHALLENGE); + return KMArray.get(arrPtr, CHALLENGE); } public void setChallenge(short vals) { - KMInteger.cast(vals); + KMInteger.validate(vals); short arrPtr = getVals(); - KMArray.cast(arrPtr).add(CHALLENGE, vals); + KMArray.add(arrPtr, CHALLENGE, vals); } public short getTimestamp() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).get(TIMESTAMP); + return KMArray.get(arrPtr, TIMESTAMP); } public void setTimestamp(short vals) { - KMInteger.cast(vals); + KMInteger.validate(vals); short arrPtr = getVals(); - KMArray.cast(arrPtr).add(TIMESTAMP, vals); + KMArray.add(arrPtr, TIMESTAMP, vals); } public short getMac(short macIndex) { short arrPtr = getVals(); - return KMArray.cast(arrPtr).get(macIndex); + return KMArray.get(arrPtr, macIndex); } + + + public static short getVals(short bPtr) { + return KMVerificationToken.cast(bPtr).getVals(); + } + + public static short length(short bPtr) { + return KMVerificationToken.cast(bPtr).length(); + } + + public static short getChallenge(short bPtr) { + return KMVerificationToken.cast(bPtr).getChallenge(); + } + + public static void setChallenge(short bPtr, short vals) { + KMVerificationToken.cast(bPtr).setChallenge(vals); + } + + public static short getTimestamp(short bPtr) { + return KMVerificationToken.cast(bPtr).getTimestamp(); + } + + public static void setTimestamp(short bPtr, short vals) { + KMVerificationToken.cast(bPtr).setTimestamp(vals); + } + + public static short getMac(short bPtr, short macIndex) { + return KMVerificationToken.cast(bPtr).getMac(macIndex); + } + } diff --git a/Applet/src/com/android/javacard/keymaster/RemotelyProvisionedComponentDevice.java b/Applet/src/com/android/javacard/kmdevice/RemotelyProvisionedComponentDevice.java similarity index 73% rename from Applet/src/com/android/javacard/keymaster/RemotelyProvisionedComponentDevice.java rename to Applet/src/com/android/javacard/kmdevice/RemotelyProvisionedComponentDevice.java index adc1684a..9026eadd 100644 --- a/Applet/src/com/android/javacard/keymaster/RemotelyProvisionedComponentDevice.java +++ b/Applet/src/com/android/javacard/kmdevice/RemotelyProvisionedComponentDevice.java @@ -13,12 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.javacard.keymaster; - -import com.android.javacard.seprovider.KMDeviceUniqueKey; -import com.android.javacard.seprovider.KMException; -import com.android.javacard.seprovider.KMOperation; -import com.android.javacard.seprovider.KMSEProvider; +package com.android.javacard.kmdevice; import javacard.framework.APDU; import javacard.framework.ISO7816; @@ -47,49 +42,34 @@ public class RemotelyProvisionedComponentDevice { private static final byte BOOT_PATCH_LEVEL_ID = 0x02; private static final byte VENDOR_PATCH_LEVEL_ID = 0x03; // Device Info labels - public static final byte[] BRAND = {0x62, 0x72, 0x61, 0x6E, 0x64}; - public static final byte[] MANUFACTURER = {0x6D, 0x61, 0x6E, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, - 0x72, 0x65, 0x72}; - public static final byte[] PRODUCT = {0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74}; - public static final byte[] MODEL = {0x6D, 0x6F, 0x64, 0x65, 0x6C}; - public static final byte[] BOARD = {0x62, 0x6F, 0x61, 0x72, 0x64}; - public static final byte[] VB_STATE = {0x76, 0x62, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65}; - public static final byte[] BOOTLOADER_STATE = - {0x62, 0x6F, 0x6F, 0x74, 0x6C, 0x6F, 0x61, 0x64, 0x65, 0x72, 0x5F, 0x73, 0x74, 0x61, 0x74, - 0x65}; - public static final byte[] VB_META_DIGEST = - {0X76, 0X62, 0X6D, 0X65, 0X74, 0X61, 0X5F, 0X64, 0X69, 0X67, 0X65, 0X73, 0X74}; - public static final byte[] OS_VERSION = {0x6F, 0x73, 0x5F, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, - 0x6E}; - public static final byte[] SYSTEM_PATCH_LEVEL = - {0x73, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x5F, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5F, 0x6C, 0x65, - 0x76, 0x65, 0x6C}; - public static final byte[] BOOT_PATCH_LEVEL = - {0x62, 0x6F, 0x6F, 0x74, 0x5F, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5F, 0x6C, 0x65, 0x76, 0x65, - 0x6C}; - public static final byte[] VENDOR_PATCH_LEVEL = - {0x76, 0x65, 0x6E, 0x64, 0x6F, 0x72, 0x5F, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5F, 0x6C, 0x65, - 0x76, 0x65, 0x6C}; - public static final byte[] DEVICE_INFO_VERSION = - {0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E}; - public static final byte[] SECURITY_LEVEL = - {0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5F, 0x6C, 0x65, 0x76, 0x65, 0x6C}; - public static final byte[] ATTEST_ID_STATE = - {0x61, 0x74, 0x74, 0x5f, 0x69, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65}; + public static byte[] BRAND; + public static byte[] MANUFACTURER; + public static byte[] PRODUCT; + public static byte[] MODEL; + public static byte[] BOARD; + public static byte[] VB_STATE; + public static byte[] BOOTLOADER_STATE; + public static byte[] VB_META_DIGEST; + public static byte[] OS_VERSION; + public static byte[] SYSTEM_PATCH_LEVEL; + public static byte[] BOOT_PATCH_LEVEL; + public static byte[] VENDOR_PATCH_LEVEL; + public static byte[] DEVICE_INFO_VERSION; + public static byte[] SECURITY_LEVEL; + public static byte[] ATTEST_ID_STATE; // Verified boot state values - public static final byte[] VB_STATE_GREEN = {0x67, 0x72, 0x65, 0x65, 0x6E}; - public static final byte[] VB_STATE_YELLOW = {0x79, 0x65, 0x6C, 0x6C, 0x6F, 0x77}; - public static final byte[] VB_STATE_ORANGE = {0x6F, 0x72, 0x61, 0x6E, 0x67, 0x65}; - public static final byte[] VB_STATE_RED = {0x72, 0x65, 0x64}; + public static byte[] VB_STATE_GREEN; + public static byte[] VB_STATE_YELLOW; + public static byte[] VB_STATE_ORANGE; + public static byte[] VB_STATE_RED; // Boot loader state values - public static final byte[] UNLOCKED = {0x75, 0x6E, 0x6C, 0x6F, 0x63, 0x6B, 0x65, 0x64}; - public static final byte[] LOCKED = {0x6C, 0x6F, 0x63, 0x6B, 0x65, 0x64}; + public static byte[] UNLOCKED; + public static byte[] LOCKED; // Device info CDDL schema version public static final byte DI_SCHEMA_VERSION = 1; - public static final byte[] DI_SECURITY_LEVEL = {0x73, 0x74, 0x72, 0x6F, 0x6E, 0x67, 0x62, 0x6F, - 0x78}; - public static final byte[] ATTEST_ID_LOCKED = {0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64}; - public static final byte[] ATTEST_ID_OPEN = {0x6f, 0x70, 0x65, 0x6e}; + public static byte[] DI_SECURITY_LEVEL; + public static byte[] ATTEST_ID_LOCKED; + public static byte[] ATTEST_ID_OPEN; private static final short MAX_SEND_DATA = 1024; // more data or no data private static final byte MORE_DATA = 0x01; // flag to denote more data to retrieve @@ -138,20 +118,70 @@ public class RemotelyProvisionedComponentDevice { private Object[] operation; private short[] dataIndex; public static Object[] authorizedEekRoots; + private KMKeymasterDevice KMAppletInst; + private KMCose kmCoseInst; - public RemotelyProvisionedComponentDevice(KMEncoder encoder, KMDecoder decoder, + public RemotelyProvisionedComponentDevice(KMKeymasterDevice KMApplet, KMEncoder encoder, KMDecoder decoder, KMRepository repository, KMSEProvider seProvider) { this.encoder = encoder; this.decoder = decoder; this.repository = repository; this.seProvider = seProvider; + this.KMAppletInst = KMApplet; data = JCSystem.makeTransientByteArray(DATA_SIZE, JCSystem.CLEAR_ON_RESET); operation = JCSystem.makeTransientObjectArray((short) 1, JCSystem.CLEAR_ON_RESET); dataIndex = JCSystem.makeTransientShortArray((short) 1, JCSystem.CLEAR_ON_RESET); operation[0] = null; createAuthorizedEEKRoot(); + kmCoseInst = KMCose.getInstance(); } + public static void initStatics() { + // Device Info labels + BRAND = new byte[] {0x62, 0x72, 0x61, 0x6E, 0x64}; + MANUFACTURER = new byte[] {0x6D, 0x61, 0x6E, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, + 0x72, 0x65, 0x72}; + PRODUCT = new byte[] {0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74}; + MODEL = new byte[] {0x6D, 0x6F, 0x64, 0x65, 0x6C}; + BOARD = new byte[] {0x62, 0x6F, 0x61, 0x72, 0x64}; + VB_STATE = new byte[] {0x76, 0x62, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65}; + BOOTLOADER_STATE = new byte[] + {0x62, 0x6F, 0x6F, 0x74, 0x6C, 0x6F, 0x61, 0x64, 0x65, 0x72, 0x5F, 0x73, 0x74, 0x61, 0x74, + 0x65}; + VB_META_DIGEST = new byte[] + {0X76, 0X62, 0X6D, 0X65, 0X74, 0X61, 0X5F, 0X64, 0X69, 0X67, 0X65, 0X73, 0X74}; + OS_VERSION = new byte[] {0x6F, 0x73, 0x5F, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, + 0x6E}; + SYSTEM_PATCH_LEVEL = new byte[] + {0x73, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x5F, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5F, 0x6C, 0x65, + 0x76, 0x65, 0x6C}; + BOOT_PATCH_LEVEL = new byte[] + {0x62, 0x6F, 0x6F, 0x74, 0x5F, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5F, 0x6C, 0x65, 0x76, 0x65, + 0x6C}; + VENDOR_PATCH_LEVEL = new byte[] + {0x76, 0x65, 0x6E, 0x64, 0x6F, 0x72, 0x5F, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5F, 0x6C, 0x65, + 0x76, 0x65, 0x6C}; + DEVICE_INFO_VERSION = new byte[] + {0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E}; + SECURITY_LEVEL = new byte[] + {0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5F, 0x6C, 0x65, 0x76, 0x65, 0x6C}; + ATTEST_ID_STATE = new byte[] + {0x61, 0x74, 0x74, 0x5f, 0x69, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65}; + // Verified boot state values + VB_STATE_GREEN = new byte[] {0x67, 0x72, 0x65, 0x65, 0x6E}; + VB_STATE_YELLOW = new byte[] {0x79, 0x65, 0x6C, 0x6C, 0x6F, 0x77}; + VB_STATE_ORANGE = new byte[] {0x6F, 0x72, 0x61, 0x6E, 0x67, 0x65}; + VB_STATE_RED = new byte[] {0x72, 0x65, 0x64}; + // Boot loader state values + UNLOCKED = new byte[] {0x75, 0x6E, 0x6C, 0x6F, 0x63, 0x6B, 0x65, 0x64}; + LOCKED = new byte[] {0x6C, 0x6F, 0x63, 0x6B, 0x65, 0x64}; + + DI_SECURITY_LEVEL = new byte[] {0x73, 0x74, 0x72, 0x6F, 0x6E, 0x67, 0x62, 0x6F, + 0x78}; + ATTEST_ID_LOCKED = new byte[] {0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64}; + ATTEST_ID_OPEN = new byte[] {0x6f, 0x70, 0x65, 0x6e}; + } + private void createAuthorizedEEKRoot() { if (authorizedEekRoots == null) { authorizedEekRoots = @@ -226,11 +256,10 @@ private void processGetRkpHwInfoCmd(APDU apdu) { // Author name - Google. final byte[] google = {0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65}; short respPtr = KMArray.instance((short) 3); - KMArray resp = KMArray.cast(respPtr); - resp.add((short) 0, KMInteger.uint_16(RKP_VERSION)); - resp.add((short) 1, KMByteBlob.instance(google, (short) 0, (short) google.length)); - resp.add((short) 2, KMInteger.uint_8(KMType.RKP_CURVE_P256)); - KMKeymasterApplet.sendOutgoing(apdu, respPtr); + KMArray.add(respPtr, (short) 0, KMInteger.uint_16(RKP_VERSION)); + KMArray.add(respPtr, (short) 1, KMByteBlob.instance(google, (short) 0, (short) google.length)); + KMArray.add(respPtr, (short) 2, KMInteger.uint_8(KMType.RKP_CURVE_P256)); + KMKeymasterDevice.sendOutgoing(apdu, respPtr); } /** @@ -239,32 +268,32 @@ private void processGetRkpHwInfoCmd(APDU apdu) { */ public void processGenerateRkpKey(APDU apdu) { short arr = KMArray.instance((short) 1); - KMArray.cast(arr).add((short) 0, KMSimpleValue.exp()); - arr = KMKeymasterApplet.receiveIncoming(apdu, arr); + KMArray.add(arr, (short) 0, KMSimpleValue.exp()); + arr = KMAppletInst.receiveIncoming(apdu, arr); // Re-purpose the apdu buffer as scratch pad. byte[] scratchPad = apdu.getBuffer(); // test mode flag. boolean testMode = - (KMSimpleValue.TRUE == KMSimpleValue.cast(KMArray.cast(arr).get((short) 0)).getValue()); - KMKeymasterApplet.generateRkpKey(scratchPad, getEcAttestKeyParameters()); - short pubKey = KMKeymasterApplet.getPubKey(); + (KMSimpleValue.TRUE == KMSimpleValue.getValue(KMArray.get(arr, (short) 0))); + KMAppletInst.generateRkpKey(scratchPad, getEcAttestKeyParameters()); + short pubKey = KMKeymasterDevice.getPubKey(); short coseMac0 = constructCoseMacForRkpKey(testMode, scratchPad, pubKey); // Encode the COSE_MAC0 object arr = KMArray.instance((short) 3); - KMArray.cast(arr).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(arr).add((short) 1, coseMac0); - KMArray.cast(arr).add((short) 2, KMKeymasterApplet.getPivateKey()); - KMKeymasterApplet.sendOutgoing(apdu, arr); + KMArray.add(arr, (short) 0, KMInteger.uint_16(KMError.OK)); + KMArray.add(arr, (short) 1, coseMac0); + KMArray.add(arr, (short) 2, KMKeymasterDevice.getPivateKey()); + KMKeymasterDevice.sendOutgoing(apdu, arr); } public void processBeginSendData(APDU apdu) throws Exception { try { initializeDataTable(); short arr = KMArray.instance((short) 3); - KMArray.cast(arr).add((short) 0, KMInteger.exp()); // Array length - KMArray.cast(arr).add((short) 1, KMInteger.exp()); // Total length of the encoded CoseKeys. - KMArray.cast(arr).add((short) 2, KMSimpleValue.exp()); - arr = KMKeymasterApplet.receiveIncoming(apdu, arr); + KMArray.add(arr, (short) 0, KMInteger.exp()); // Array length + KMArray.add(arr, (short) 1, KMInteger.exp()); // Total length of the encoded CoseKeys. + KMArray.add(arr, (short) 2, KMSimpleValue.exp()); + arr = KMAppletInst.receiveIncoming(apdu, arr); // Re-purpose the apdu buffer as scratch pad. byte[] scratchPad = apdu.getBuffer(); // Generate ephemeral mac key. @@ -274,22 +303,22 @@ public void processBeginSendData(APDU apdu) throws Exception { initHmacOperation(); // Partially encode CoseMac structure with partial payload. constructPartialPubKeysToSignMac(scratchPad, - KMInteger.cast(KMArray.cast(arr).get((short) 0)).getShort(), - KMInteger.cast(KMArray.cast(arr).get((short) 1)).getShort()); + KMInteger.getShort(KMArray.get(arr, (short) 0)), + KMInteger.getShort(KMArray.get(arr, (short) 1))); // Store the total keys in data table. dataEntryIndex = createEntry(TOTAL_KEYS_TO_SIGN, SHORT_SIZE); Util.setShort(data, dataEntryIndex, - KMInteger.cast(KMArray.cast(arr).get((short) 0)).getShort()); + KMInteger.getShort(KMArray.get(arr, (short) 0))); // Store the test mode value in data table. dataEntryIndex = createEntry(TEST_MODE, TEST_MODE_SIZE); data[dataEntryIndex] = - (KMSimpleValue.TRUE == KMSimpleValue.cast(KMArray.cast(arr).get((short) 2)).getValue()) ? + (KMSimpleValue.TRUE == KMSimpleValue.getValue(KMArray.get(arr, (short) 2))) ? TRUE : FALSE; // Store the current csr status, which is BEGIN. createEntry(GENERATE_CSR_PHASE, BYTE_SIZE); updateState(BEGIN); // Send response. - KMKeymasterApplet.sendError(apdu, KMError.OK); + KMAppletInst.sendError(apdu, KMError.OK); } catch (Exception e) { clearDataTable(); releaseOperation(); @@ -304,21 +333,21 @@ public void processUpdateKey(APDU apdu) throws Exception { validateKeysToSignCount(); short headers = KMCoseHeaders.exp(); short arrInst = KMArray.instance((short) 4); - KMArray.cast(arrInst).add((short) 0, KMByteBlob.exp()); - KMArray.cast(arrInst).add((short) 1, headers); - KMArray.cast(arrInst).add((short) 2, KMByteBlob.exp()); - KMArray.cast(arrInst).add((short) 3, KMByteBlob.exp()); + KMArray.add(arrInst, (short) 0, KMByteBlob.exp()); + KMArray.add(arrInst, (short) 1, headers); + KMArray.add(arrInst, (short) 2, KMByteBlob.exp()); + KMArray.add(arrInst, (short) 3, KMByteBlob.exp()); short arr = KMArray.exp(arrInst); - arr = KMKeymasterApplet.receiveIncoming(apdu, arr); - arrInst = KMArray.cast(arr).get((short) 0); + arr = KMAppletInst.receiveIncoming(apdu, arr); + arrInst = KMArray.get(arr, (short) 0); // Re-purpose the apdu buffer as scratch pad. byte[] scratchPad = apdu.getBuffer(); // Validate and extract the CoseKey from CoseMac0 message. short coseKey = validateAndExtractPublicKey(arrInst, scratchPad); // Encode CoseKey - short length = KMKeymasterApplet.encodeToApduBuffer(coseKey, scratchPad, (short) 0, - KMKeymasterApplet.MAX_COSE_BUF_SIZE); + short length = KMKeymasterDevice.encodeToApduBuffer(coseKey, scratchPad, (short) 0, + KMKeymasterDevice.MAX_COSE_BUF_SIZE); // Do Hmac update with input as encoded CoseKey. ((KMOperation) operation[0]).update(scratchPad, (short) 0, length); // Increment the count each time this function gets executed. @@ -332,7 +361,7 @@ public void processUpdateKey(APDU apdu) throws Exception { // Update the csr state updateState(UPDATE); // Send response. - KMKeymasterApplet.sendError(apdu, KMError.OK); + KMAppletInst.sendError(apdu, KMError.OK); } catch (Exception e) { clearDataTable(); releaseOperation(); @@ -346,13 +375,13 @@ public void processUpdateEekChain(APDU apdu) throws Exception { validateState((byte) (BEGIN | UPDATE)); short headers = KMCoseHeaders.exp(); short arrInst = KMArray.instance((short) 4); - KMArray.cast(arrInst).add((short) 0, KMByteBlob.exp()); - KMArray.cast(arrInst).add((short) 1, headers); - KMArray.cast(arrInst).add((short) 2, KMByteBlob.exp()); - KMArray.cast(arrInst).add((short) 3, KMByteBlob.exp()); + KMArray.add(arrInst, (short) 0, KMByteBlob.exp()); + KMArray.add(arrInst, (short) 1, headers); + KMArray.add(arrInst, (short) 2, KMByteBlob.exp()); + KMArray.add(arrInst, (short) 3, KMByteBlob.exp()); short arrSignPtr = KMArray.exp(arrInst); - arrInst = KMKeymasterApplet.receiveIncoming(apdu, arrSignPtr); - if (KMArray.cast(arrInst).length() == 0) { + arrInst = KMAppletInst.receiveIncoming(apdu, arrSignPtr); + if (KMArray.length(arrInst) == 0) { KMException.throwIt(KMError.STATUS_INVALID_EEK); } // Re-purpose the apdu buffer as scratch pad. @@ -361,13 +390,13 @@ public void processUpdateEekChain(APDU apdu) throws Exception { short eekKey = validateAndExtractEekPub(arrInst, scratchPad); // Store eek public key and eek id in the data table. short eekKeyId = KMCoseKey.cast(eekKey).getKeyIdentifier(); - short dataEntryIndex = createEntry(EEK_KEY_ID, KMByteBlob.cast(eekKeyId).length()); + short dataEntryIndex = createEntry(EEK_KEY_ID, KMByteBlob.length(eekKeyId)); Util.arrayCopyNonAtomic( - KMByteBlob.cast(eekKeyId).getBuffer(), - KMByteBlob.cast(eekKeyId).getStartOff(), + KMByteBlob.getBuffer(eekKeyId), + KMByteBlob.getStartOff(eekKeyId), data, dataEntryIndex, - KMByteBlob.cast(eekKeyId).length() + KMByteBlob.length(eekKeyId) ); // Convert the coseKey to a public key. short len = KMCoseKey.cast(eekKey).getEcdsa256PublicKey(scratchPad, (short) 0); @@ -375,7 +404,7 @@ public void processUpdateEekChain(APDU apdu) throws Exception { Util.arrayCopyNonAtomic(scratchPad, (short) 0, data, dataEntryIndex, len); // Update the state updateState(UPDATE); - KMKeymasterApplet.sendError(apdu, KMError.OK); + KMAppletInst.sendError(apdu, KMError.OK); } catch (Exception e) { clearDataTable(); releaseOperation(); @@ -388,21 +417,21 @@ public void processUpdateChallenge(APDU apdu) throws Exception { // The prior state can be BEGIN or UPDATE validateState((byte) (BEGIN | UPDATE)); short arr = KMArray.instance((short) 1); - KMArray.cast(arr).add((short) 0, KMByteBlob.exp()); - arr = KMKeymasterApplet.receiveIncoming(apdu, arr); + KMArray.add(arr, (short) 0, KMByteBlob.exp()); + arr = KMAppletInst.receiveIncoming(apdu, arr); // Store the challenge in the data table. - short challenge = KMArray.cast(arr).get((short) 0); - short dataEntryIndex = createEntry(CHALLENGE, KMByteBlob.cast(challenge).length()); + short challenge = KMArray.get(arr, (short) 0); + short dataEntryIndex = createEntry(CHALLENGE, KMByteBlob.length(challenge)); Util.arrayCopyNonAtomic( - KMByteBlob.cast(challenge).getBuffer(), - KMByteBlob.cast(challenge).getStartOff(), + KMByteBlob.getBuffer(challenge), + KMByteBlob.getStartOff(challenge), data, dataEntryIndex, - KMByteBlob.cast(challenge).length() + KMByteBlob.length(challenge) ); // Update the state updateState(UPDATE); - KMKeymasterApplet.sendError(apdu, KMError.OK); + KMAppletInst.sendError(apdu, KMError.OK); } catch (Exception e) { clearDataTable(); releaseOperation(); @@ -433,9 +462,9 @@ public void processFinishSendData(APDU apdu) throws Exception { short deviceInfo = createDeviceInfo(scratchPad); // Generate Nonce for AES-GCM seProvider.newRandomNumber(scratchPad, (short) 0, - KMKeymasterApplet.AES_GCM_NONCE_LENGTH); + KMKeymasterDevice.AES_GCM_NONCE_LENGTH); short nonce = KMByteBlob.instance(scratchPad, (short) 0, - KMKeymasterApplet.AES_GCM_NONCE_LENGTH); + KMKeymasterDevice.AES_GCM_NONCE_LENGTH); // Initializes cipher instance. initAesGcmOperation(scratchPad, nonce); // Encode Enc_Structure as additional data for AES-GCM. @@ -444,19 +473,19 @@ public void processFinishSendData(APDU apdu) throws Exception { short partialCipherText = KMByteBlob.instance(scratchPad, (short) 0, partialPayloadLen); short coseEncryptProtectedHeader = getCoseEncryptProtectedHeader(scratchPad); short coseEncryptUnProtectedHeader = getCoseEncryptUnprotectedHeader(scratchPad, nonce); - len = KMKeymasterApplet.encodeToApduBuffer(deviceInfo, scratchPad, - (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE); + len = KMKeymasterDevice.encodeToApduBuffer(deviceInfo, scratchPad, + (short) 0, KMKeymasterDevice.MAX_COSE_BUF_SIZE); short encodedDeviceInfo = KMByteBlob.instance(scratchPad, (short) 0, len); updateState(FINISH); short arr = KMArray.instance((short) 7); - KMArray.cast(arr).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(arr).add((short) 1, pubKeysToSignMac); - KMArray.cast(arr).add((short) 2, encodedDeviceInfo); - KMArray.cast(arr).add((short) 3, coseEncryptProtectedHeader); - KMArray.cast(arr).add((short) 4, coseEncryptUnProtectedHeader); - KMArray.cast(arr).add((short) 5, partialCipherText); - KMArray.cast(arr).add((short) 6, KMInteger.uint_8(MORE_DATA)); - KMKeymasterApplet.sendOutgoing(apdu, arr); + KMArray.add(arr, (short) 0, KMInteger.uint_16(KMError.OK)); + KMArray.add(arr, (short) 1, pubKeysToSignMac); + KMArray.add(arr, (short) 2, encodedDeviceInfo); + KMArray.add(arr, (short) 3, coseEncryptProtectedHeader); + KMArray.add(arr, (short) 4, coseEncryptUnProtectedHeader); + KMArray.add(arr, (short) 5, partialCipherText); + KMArray.add(arr, (short) 6, KMInteger.uint_8(MORE_DATA)); + KMKeymasterDevice.sendOutgoing(apdu, arr); } catch (Exception e) { clearDataTable(); releaseOperation(); @@ -496,12 +525,12 @@ public void processGetResponse(APDU apdu) throws Exception { } short data = KMByteBlob.instance(scratchPad, (short) 0, len); short arr = KMArray.instance((short) 4); - KMArray.cast(arr).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(arr).add((short) 1, data); - KMArray.cast(arr).add((short) 2, recipientStructure); + KMArray.add(arr,(short) 0, KMInteger.uint_16(KMError.OK)); + KMArray.add(arr,(short) 1, data); + KMArray.add(arr,(short) 2, recipientStructure); // represents there is more output to retrieve - KMArray.cast(arr).add((short) 3, KMInteger.uint_8(moreData)); - KMKeymasterApplet.sendOutgoing(apdu, arr); + KMArray.add(arr, (short) 3, KMInteger.uint_8(moreData)); + KMKeymasterDevice.sendOutgoing(apdu, arr); } catch (Exception e) { clearDataTable(); releaseOperation(); @@ -511,28 +540,28 @@ public void processGetResponse(APDU apdu) throws Exception { public void process(short ins, APDU apdu) throws Exception { switch (ins) { - case KMKeymasterApplet.INS_GET_RKP_HARDWARE_INFO: + case KMKeymasterDevice.INS_GET_RKP_HARDWARE_INFO: processGetRkpHwInfoCmd(apdu); break; - case KMKeymasterApplet.INS_GENERATE_RKP_KEY_CMD: + case KMKeymasterDevice.INS_GENERATE_RKP_KEY_CMD: processGenerateRkpKey(apdu); break; - case KMKeymasterApplet.INS_BEGIN_SEND_DATA_CMD: + case KMKeymasterDevice.INS_BEGIN_SEND_DATA_CMD: processBeginSendData(apdu); break; - case KMKeymasterApplet.INS_UPDATE_KEY_CMD: + case KMKeymasterDevice.INS_UPDATE_KEY_CMD: processUpdateKey(apdu); break; - case KMKeymasterApplet.INS_UPDATE_EEK_CHAIN_CMD: + case KMKeymasterDevice.INS_UPDATE_EEK_CHAIN_CMD: processUpdateEekChain(apdu); break; - case KMKeymasterApplet.INS_UPDATE_CHALLENGE_CMD: + case KMKeymasterDevice.INS_UPDATE_CHALLENGE_CMD: processUpdateChallenge(apdu); break; - case KMKeymasterApplet.INS_FINISH_SEND_DATA_CMD: + case KMKeymasterDevice.INS_FINISH_SEND_DATA_CMD: processFinishSendData(apdu); break; - case KMKeymasterApplet.INS_GET_RESPONSE_CMD: + case KMKeymasterDevice.INS_GET_RESPONSE_CMD: processGetResponse(apdu); break; default: @@ -568,8 +597,8 @@ private void updateOutputProcessingState(byte state) { private short getHmacKey(boolean testMode, byte[] scratchPad) { short macKey = KMByteBlob.instance(MAC_KEY_SIZE); - Util.arrayFillNonAtomic(KMByteBlob.cast(macKey).getBuffer(), - KMByteBlob.cast(macKey).getStartOff(), MAC_KEY_SIZE, (byte) 0); + Util.arrayFillNonAtomic(KMByteBlob.getBuffer(macKey), + KMByteBlob.getStartOff(macKey), MAC_KEY_SIZE, (byte) 0); if (!testMode) { Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) (2 * MAC_KEY_SIZE), (byte) 0); short len = @@ -583,8 +612,8 @@ private short getHmacKey(boolean testMode, byte[] scratchPad) { KMCose.MAC_DERIVE_KEY_CTX, (short) 0, (short) KMCose.MAC_DERIVE_KEY_CTX.length, - KMByteBlob.cast(macKey).getBuffer(), - KMByteBlob.cast(macKey).getStartOff(), + KMByteBlob.getBuffer(macKey), + KMByteBlob.getStartOff(macKey), MAC_KEY_SIZE ); if (len != MAC_KEY_SIZE) { @@ -611,18 +640,18 @@ private short validateAndExtractPublicKey(short coseMacPtr, byte[] scratchPad) { short macKey = getHmacKey(testMode, scratchPad); // validate protected Headers - short ptr = KMArray.cast(coseMacPtr).get(KMCose.COSE_MAC0_PROTECTED_PARAMS_OFFSET); - ptr = decoder.decode(coseHeadersExp, KMByteBlob.cast(ptr).getBuffer(), - KMByteBlob.cast(ptr).getStartOff(), KMByteBlob.cast(ptr).length()); + short ptr = KMArray.get(coseMacPtr, KMCose.COSE_MAC0_PROTECTED_PARAMS_OFFSET); + ptr = decoder.decode(coseHeadersExp, KMByteBlob.getBuffer(ptr), + KMByteBlob.getStartOff(ptr), KMByteBlob.length(ptr)); if (!KMCoseHeaders.cast(ptr).isDataValid(KMCose.COSE_ALG_HMAC_256, KMType.INVALID_VALUE)) { KMException.throwIt(KMError.STATUS_FAILED); } // Validate payload. - ptr = KMArray.cast(coseMacPtr).get(KMCose.COSE_MAC0_PAYLOAD_OFFSET); - ptr = decoder.decode(coseKeyExp, KMByteBlob.cast(ptr).getBuffer(), - KMByteBlob.cast(ptr).getStartOff(), KMByteBlob.cast(ptr).length()); + ptr = KMArray.get(coseMacPtr, KMCose.COSE_MAC0_PAYLOAD_OFFSET); + ptr = decoder.decode(coseKeyExp, KMByteBlob.getBuffer(ptr), + KMByteBlob.getStartOff(ptr), KMByteBlob.length(ptr)); if (!KMCoseKey.cast(ptr).isDataValid(KMCose.COSE_KEY_TYPE_EC2, KMType.INVALID_VALUE, KMCose.COSE_ALG_ES256, KMType.INVALID_VALUE, KMCose.COSE_ECCURVE_256)) { @@ -638,25 +667,24 @@ private short validateAndExtractPublicKey(short coseMacPtr, byte[] scratchPad) { // Compute CoseMac Structure and compare the macs. short macStructure = - KMCose.constructCoseMacStructure(KMArray.cast(coseMacPtr).get( + kmCoseInst.constructCoseMacStructure(KMArray.get(coseMacPtr, KMCose.COSE_MAC0_PROTECTED_PARAMS_OFFSET), KMByteBlob.instance((short) 0), - KMArray.cast(coseMacPtr).get(KMCose.COSE_MAC0_PAYLOAD_OFFSET)); - short encodedLen = KMKeymasterApplet.encodeToApduBuffer(macStructure, scratchPad, (short) 0, - KMKeymasterApplet.MAX_COSE_BUF_SIZE); + KMArray.get(coseMacPtr, KMCose.COSE_MAC0_PAYLOAD_OFFSET)); + short encodedLen = KMKeymasterDevice.encodeToApduBuffer(macStructure, scratchPad, (short) 0, + KMKeymasterDevice.MAX_COSE_BUF_SIZE); - short hmacLen = seProvider.hmacSign(KMByteBlob.cast(macKey).getBuffer(), - KMByteBlob.cast(macKey).getStartOff(), + short hmacLen = seProvider.hmacSign(KMByteBlob.getBuffer(macKey), + KMByteBlob.getStartOff(macKey), (short) 32, scratchPad, (short) 0, encodedLen, scratchPad, encodedLen); - if (hmacLen != KMByteBlob.cast( - KMArray.cast(coseMacPtr).get(KMCose.COSE_MAC0_TAG_OFFSET)).length()) { + if (hmacLen != KMByteBlob.length(KMArray.get(coseMacPtr, KMCose.COSE_MAC0_TAG_OFFSET))) { KMException.throwIt(KMError.STATUS_INVALID_MAC); } if (0 != Util.arrayCompare(scratchPad, encodedLen, - KMByteBlob.cast(KMArray.cast(coseMacPtr).get(KMCose.COSE_MAC0_TAG_OFFSET)).getBuffer(), - KMByteBlob.cast(KMArray.cast(coseMacPtr).get(KMCose.COSE_MAC0_TAG_OFFSET)).getStartOff(), + KMByteBlob.getBuffer(KMArray.get(coseMacPtr, KMCose.COSE_MAC0_TAG_OFFSET)), + KMByteBlob.getStartOff(KMArray.get(coseMacPtr, KMCose.COSE_MAC0_TAG_OFFSET)), hmacLen)) { KMException.throwIt(KMError.STATUS_INVALID_MAC); } @@ -676,8 +704,7 @@ private short validateAndExtractPublicKey(short coseMacPtr, byte[] scratchPad) { private short validateAndExtractEekPub(short eekArr, byte[] scratchPad) { short leafPubKey = 0; try { - leafPubKey = - KMKeymasterApplet.validateCertChain( + leafPubKey = KMAppletInst.validateCertChain( (TRUE == data[getEntry(TEST_MODE)]) ? false : true, // validate EEK root KMCose.COSE_ALG_ES256, KMCose.COSE_ALG_ECDH_ES_HKDF_256, @@ -727,28 +754,28 @@ private void constructPartialPubKeysToSignMac(byte[] scratchPad, short arrayLeng short encodedCoseKeysLen) { short ptr; short len; - short headerPtr = KMCose.constructHeaders( + short headerPtr = kmCoseInst.constructHeaders( KMInteger.uint_8(KMCose.COSE_ALG_HMAC_256), KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE); // Encode the protected header as byte blob. - len = KMKeymasterApplet.encodeToApduBuffer(headerPtr, scratchPad, (short) 0, - KMKeymasterApplet.MAX_COSE_BUF_SIZE); + len = KMKeymasterDevice.encodeToApduBuffer(headerPtr, scratchPad, (short) 0, + KMKeymasterDevice.MAX_COSE_BUF_SIZE); short protectedHeader = KMByteBlob.instance(scratchPad, (short) 0, len); // create MAC_Structure ptr = - KMCose.constructCoseMacStructure(protectedHeader, + kmCoseInst.constructCoseMacStructure(protectedHeader, KMByteBlob.instance((short) 0), KMType.INVALID_VALUE); // Encode the Mac_structure and do HMAC_Sign to produce the tag for COSE_MAC0 - len = KMKeymasterApplet.encodeToApduBuffer(ptr, scratchPad, (short) 0, - KMKeymasterApplet.MAX_COSE_BUF_SIZE); + len = KMKeymasterDevice.encodeToApduBuffer(ptr, scratchPad, (short) 0, + KMKeymasterDevice.MAX_COSE_BUF_SIZE); // Construct partial payload - Bstr Header + Array Header // The maximum combined length of bstr header and array header length is 6 bytes. // The lengths will never exceed Max SHORT value. short arrPtr = KMArray.instance(arrayLength); for (short i = 0; i < arrayLength; i++) { - KMArray.cast(arrPtr).add(i, KMType.INVALID_VALUE); + KMArray.add(arrPtr, i, KMType.INVALID_VALUE); } arrayLength = encoder.getEncodedLength(arrPtr); short bufIndex = repository.alloc((short) 6); @@ -763,33 +790,6 @@ private void constructPartialPubKeysToSignMac(byte[] scratchPad, short arrayLeng ((KMOperation) operation[0]).update(scratchPad, (short) 0, (short) (len + partialPayloadLen)); } - private static short getAttestKeyParameters() { - short tagIndex = 0; - short arrPtr = KMArray.instance((short) 6); - // Key size - 256 - short keySize = KMIntegerTag - .instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short) 256)); - // Digest - SHA256 - short byteBlob = KMByteBlob.instance((short) 1); - KMByteBlob.cast(byteBlob).add((short) 0, KMType.SHA2_256); - short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); - // Purpose - Attest - byteBlob = KMByteBlob.instance((short) 1); - KMByteBlob.cast(byteBlob).add((short) 0, KMType.ATTEST_KEY); - short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob); - - KMArray.cast(arrPtr).add(tagIndex++, purpose); - // Algorithm - EC - KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, KMType.EC)); - KMArray.cast(arrPtr).add(tagIndex++, keySize); - KMArray.cast(arrPtr).add(tagIndex++, digest); - // Curve - P256 - KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ECCURVE, KMType.P_256)); - // No Authentication is required to use this key. - KMArray.cast(arrPtr).add(tagIndex, KMBoolTag.instance(KMType.NO_AUTH_REQUIRED)); - return KMKeyParameters.instance(arrPtr); - } - private short createSignedMac(KMDeviceUniqueKey deviceUniqueKey, byte[] scratchPad, short deviceMapPtr, short pubKeysToSign) { // Challenge @@ -802,28 +802,28 @@ private short createSignedMac(KMDeviceUniqueKey deviceUniqueKey, byte[] scratchP /* Prepare AAD */ short aad = KMArray.instance((short) 3); - KMArray.cast(aad).add((short) 0, challengePtr); - KMArray.cast(aad).add((short) 1, deviceMapPtr); - KMArray.cast(aad).add((short) 2, pubKeysToSign); - aad = KMKeymasterApplet.encodeToApduBuffer(aad, scratchPad, - (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE); + KMArray.add(aad, (short) 0, challengePtr); + KMArray.add(aad, (short) 1, deviceMapPtr); + KMArray.add(aad, (short) 2, pubKeysToSign); + aad = KMKeymasterDevice.encodeToApduBuffer(aad, scratchPad, + (short) 0, KMKeymasterDevice.MAX_COSE_BUF_SIZE); aad = KMByteBlob.instance(scratchPad, (short) 0, aad); /* construct protected header */ - short protectedHeaders = KMCose.constructHeaders( + short protectedHeaders = kmCoseInst.constructHeaders( KMNInteger.uint_8(KMCose.COSE_ALG_ES256), KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE); - protectedHeaders = KMKeymasterApplet.encodeToApduBuffer(protectedHeaders, scratchPad, - (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE); + protectedHeaders = KMKeymasterDevice.encodeToApduBuffer(protectedHeaders, scratchPad, + (short) 0, KMKeymasterDevice.MAX_COSE_BUF_SIZE); protectedHeaders = KMByteBlob.instance(scratchPad, (short) 0, protectedHeaders); /* construct cose sign structure */ short signStructure = - KMCose.constructCoseSignStructure(protectedHeaders, aad, ephmeralMacKey); - signStructure = KMKeymasterApplet.encodeToApduBuffer(signStructure, scratchPad, - (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE); + kmCoseInst.constructCoseSignStructure(protectedHeaders, aad, ephmeralMacKey); + signStructure = KMKeymasterDevice.encodeToApduBuffer(signStructure, scratchPad, + (short) 0, KMKeymasterDevice.MAX_COSE_BUF_SIZE); short len = seProvider.ecSign256( deviceUniqueKey, @@ -840,7 +840,7 @@ private short createSignedMac(KMDeviceUniqueKey deviceUniqueKey, byte[] scratchP unprotectedHeader = KMCoseHeaders.instance(unprotectedHeader); /* construct Cose_Sign1 */ - return KMCose.constructCoseSign1(protectedHeaders, unprotectedHeader, + return kmCoseInst.constructCoseSign1(protectedHeaders, unprotectedHeader, ephmeralMacKey, signStructure); } @@ -933,11 +933,11 @@ private short createDeviceInfo(byte[] scratchpad) { short index = 0; while (index < (short) deviceIds.length) { if (deviceIds[index] != KMType.INVALID_VALUE) { - KMMap.cast(map).add(mapIndex++, deviceIds[index], deviceIds[(short) (index + 1)]); + KMMap.add(map, mapIndex++, deviceIds[index], deviceIds[(short) (index + 1)]); } index += 2; } - KMMap.cast(map).canonicalize(); + KMMap.canonicalize(map); return map; } @@ -1025,8 +1025,8 @@ private short getBootParams(byte bootParam, byte[] scratchPad) { if (bootParam == OS_VERSION_ID) { value = KMTextString - .instance(KMInteger.cast(value).getBuffer(), KMInteger.cast(value).getStartOff(), - KMInteger.cast(value).length()); + .instance(KMInteger.getBuffer(value), KMInteger.getStartOff(value), + KMInteger.length(value)); } return value; } @@ -1044,23 +1044,23 @@ private short ecdhHkdfDeriveKey(byte[] privKeyA, short privKeyAOff, short privKe key = KMByteBlob.instance(scratchPad, (short) 0, key); short kdfContext = - KMCose.constructKdfContext(pubKeyA, pubKeyAOff, pubKeyALen, pubKeyB, pubKeyBOff, pubKeyBLen, + kmCoseInst.constructKdfContext(pubKeyA, pubKeyAOff, pubKeyALen, pubKeyB, pubKeyBOff, pubKeyBLen, true); - kdfContext = KMKeymasterApplet - .encodeToApduBuffer(kdfContext, scratchPad, (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE); + kdfContext = KMKeymasterDevice + .encodeToApduBuffer(kdfContext, scratchPad, (short) 0, KMKeymasterDevice.MAX_COSE_BUF_SIZE); kdfContext = KMByteBlob.instance(scratchPad, (short) 0, kdfContext); Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 32, (byte) 0); seProvider.hkdf( - KMByteBlob.cast(key).getBuffer(), - KMByteBlob.cast(key).getStartOff(), - KMByteBlob.cast(key).length(), + KMByteBlob.getBuffer(key), + KMByteBlob.getStartOff(key), + KMByteBlob.length(key), scratchPad, (short) 0, (short) 32, - KMByteBlob.cast(kdfContext).getBuffer(), - KMByteBlob.cast(kdfContext).getStartOff(), - KMByteBlob.cast(kdfContext).length(), + KMByteBlob.getBuffer(kdfContext), + KMByteBlob.getStartOff(kdfContext), + KMByteBlob.length(kdfContext), scratchPad, (short) 32, // offset (short) 32 // Length of expected output. @@ -1089,8 +1089,8 @@ private short generateEphemeralEcKey(byte[] scratchPad) { Util.arrayCopyNonAtomic( scratchPad, (short) 0, - KMByteBlob.cast(ptr).getBuffer(), - KMByteBlob.cast(ptr).getStartOff(), + KMByteBlob.getBuffer(ptr), + KMByteBlob.getStartOff(ptr), lengths[0]); //Store ephemeral public key in data table for later usage. short dataEntryIndex = createEntry(EPHEMERAL_PUB_KEY, lengths[1]); @@ -1129,9 +1129,9 @@ private void initAesGcmOperation(byte[] scratchPad, short nonce) { // Generate session key short sessionKeyLen = ecdhHkdfDeriveKey( - KMByteBlob.cast(privKey).getBuffer(), /* Ephemeral Private Key */ - KMByteBlob.cast(privKey).getStartOff(), - KMByteBlob.cast(privKey).length(), + KMByteBlob.getBuffer(privKey), /* Ephemeral Private Key */ + KMByteBlob.getStartOff(privKey), + KMByteBlob.length(privKey), data, /* Ephemeral Public key */ pubKeyIndex, getEntryLength(EPHEMERAL_PUB_KEY), @@ -1151,10 +1151,10 @@ private void initAesGcmOperation(byte[] scratchPad, short nonce) { scratchPad, /* key */ (short) 0, sessionKeyLen, - KMByteBlob.cast(nonce).getBuffer(), /* nonce */ - KMByteBlob.cast(nonce).getStartOff(), - KMByteBlob.cast(nonce).length(), - (short) (KMKeymasterApplet.AES_GCM_AUTH_TAG_LENGTH * 8) + KMByteBlob.getBuffer(nonce), /* nonce */ + KMByteBlob.getStartOff(nonce), + KMByteBlob.length(nonce), + (short) (KMKeymasterDevice.AES_GCM_AUTH_TAG_LENGTH * 8) ); if (operation[0] == null) { KMException.throwIt(KMError.STATUS_FAILED); @@ -1162,22 +1162,22 @@ private void initAesGcmOperation(byte[] scratchPad, short nonce) { } private short processRecipientStructure(byte[] scratchPad) { - short protectedHeaderRecipient = KMCose.constructHeaders( + short protectedHeaderRecipient = kmCoseInst.constructHeaders( KMNInteger.uint_8(KMCose.COSE_ALG_ECDH_ES_HKDF_256), KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE); // Encode the protected header as byte blob. - protectedHeaderRecipient = KMKeymasterApplet + protectedHeaderRecipient = KMKeymasterDevice .encodeToApduBuffer(protectedHeaderRecipient, scratchPad, (short) 0, - KMKeymasterApplet.MAX_COSE_BUF_SIZE); + KMKeymasterDevice.MAX_COSE_BUF_SIZE); protectedHeaderRecipient = KMByteBlob.instance(scratchPad, (short) 0, protectedHeaderRecipient); /* Construct unprotected headers */ short pubKeyIndex = getEntry(EPHEMERAL_PUB_KEY); // prepare cosekey short coseKey = - KMCose.constructCoseKey( + kmCoseInst.constructCoseKey( KMInteger.uint_8(KMCose.COSE_KEY_TYPE_EC2), KMType.INVALID_VALUE, KMNInteger.uint_8(KMCose.COSE_ALG_ES256), @@ -1192,11 +1192,11 @@ private short processRecipientStructure(byte[] scratchPad) { short keyIdentifierPtr = KMByteBlob .instance(data, getEntry(EEK_KEY_ID), getEntryLength(EEK_KEY_ID)); short unprotectedHeaderRecipient = - KMCose.constructHeaders(KMType.INVALID_VALUE, keyIdentifierPtr, KMType.INVALID_VALUE, + kmCoseInst.constructHeaders(KMType.INVALID_VALUE, keyIdentifierPtr, KMType.INVALID_VALUE, coseKey); // Construct recipients structure. - return KMCose.constructRecipientsStructure(protectedHeaderRecipient, unprotectedHeaderRecipient, + return kmCoseInst.constructRecipientsStructure(protectedHeaderRecipient, unprotectedHeaderRecipient, KMSimpleValue.instance(KMSimpleValue.NULL)); } @@ -1244,9 +1244,9 @@ private short processBcc(byte[] scratchPad) { boolean testMode = (TRUE == data[getEntry(TEST_MODE)]) ? true : false; short len; if (testMode) { - short bcc = KMKeymasterApplet.generateBcc(true, scratchPad); - len = KMKeymasterApplet - .encodeToApduBuffer(bcc, scratchPad, (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE); + short bcc = KMAppletInst.generateBcc(true, scratchPad); + len = KMKeymasterDevice + .encodeToApduBuffer(bcc, scratchPad, (short) 0, KMKeymasterDevice.MAX_COSE_BUF_SIZE); } else { byte[] bcc = seProvider.getBootCertificateChain(); len = Util.getShort(bcc, (short) 0); @@ -1266,19 +1266,19 @@ private short processBcc(byte[] scratchPad) { // AAD is the CoseEncrypt structure private void processAesGcmUpdateAad(byte[] scratchPad) { - short protectedHeader = KMCose.constructHeaders( + short protectedHeader = kmCoseInst.constructHeaders( KMInteger.uint_8(KMCose.COSE_ALG_AES_GCM_256), KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE); // Encode the protected header as byte blob. - protectedHeader = KMKeymasterApplet.encodeToApduBuffer(protectedHeader, scratchPad, (short) 0, - KMKeymasterApplet.MAX_COSE_BUF_SIZE); + protectedHeader = KMKeymasterDevice.encodeToApduBuffer(protectedHeader, scratchPad, (short) 0, + KMKeymasterDevice.MAX_COSE_BUF_SIZE); protectedHeader = KMByteBlob.instance(scratchPad, (short) 0, protectedHeader); short coseEncryptStr = - KMCose.constructCoseEncryptStructure(protectedHeader, KMByteBlob.instance((short) 0)); - coseEncryptStr = KMKeymasterApplet.encodeToApduBuffer(coseEncryptStr, scratchPad, (short) 0, - KMKeymasterApplet.MAX_COSE_BUF_SIZE); + kmCoseInst.constructCoseEncryptStructure(protectedHeader, KMByteBlob.instance((short) 0)); + coseEncryptStr = KMKeymasterDevice.encodeToApduBuffer(coseEncryptStr, scratchPad, (short) 0, + KMKeymasterDevice.MAX_COSE_BUF_SIZE); ((KMOperation) operation[0]).updateAAD(scratchPad, (short) 0, coseEncryptStr); } @@ -1291,13 +1291,13 @@ private short processSignedMac(byte[] scratchPad, short pubKeysToSignMac, short //Prepare partial data for encryption. short arrLength = (short) (isAdditionalCertificateChainPresent() ? 3 : 2); short arr = KMArray.instance(arrLength); - KMArray.cast(arr).add((short) 0, signedMac); - KMArray.cast(arr).add((short) 1, KMType.INVALID_VALUE); + KMArray.add(arr, (short) 0, signedMac); + KMArray.add(arr, (short) 1, KMType.INVALID_VALUE); if (arrLength == 3) { - KMArray.cast(arr).add((short) 2, KMType.INVALID_VALUE); + KMArray.add(arr, (short) 2, KMType.INVALID_VALUE); } - short len = KMKeymasterApplet - .encodeToApduBuffer(arr, scratchPad, (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE); + short len = KMKeymasterDevice + .encodeToApduBuffer(arr, scratchPad, (short) 0, KMKeymasterDevice.MAX_COSE_BUF_SIZE); short cipherTextLen = ((KMOperation) operation[0]) .update(scratchPad, (short) 0, len, scratchPad, len); Util.arrayCopyNonAtomic( @@ -1312,92 +1312,71 @@ private short processSignedMac(byte[] scratchPad, short pubKeysToSignMac, short private short getCoseEncryptProtectedHeader(byte[] scratchPad) { // CoseEncrypt protected headers. - short protectedHeader = KMCose.constructHeaders( + short protectedHeader = kmCoseInst.constructHeaders( KMInteger.uint_8(KMCose.COSE_ALG_AES_GCM_256), KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE); // Encode the protected header as byte blob. - protectedHeader = KMKeymasterApplet.encodeToApduBuffer(protectedHeader, scratchPad, (short) 0, - KMKeymasterApplet.MAX_COSE_BUF_SIZE); + protectedHeader = KMKeymasterDevice.encodeToApduBuffer(protectedHeader, scratchPad, (short) 0, + KMKeymasterDevice.MAX_COSE_BUF_SIZE); return KMByteBlob.instance(scratchPad, (short) 0, protectedHeader); } private short getCoseEncryptUnprotectedHeader(byte[] scratchPad, short nonce) { /* CoseEncrypt unprotected headers */ - return KMCose + return kmCoseInst .constructHeaders(KMType.INVALID_VALUE, KMType.INVALID_VALUE, nonce, KMType.INVALID_VALUE); } - private short constructCoseEncryptHeaders(byte[] scratchPad, short nonce) { - // CoseEncrypt protected headers. - short protectedHeader = KMCose.constructHeaders( - KMInteger.uint_8(KMCose.COSE_ALG_AES_GCM_256), - KMType.INVALID_VALUE, - KMType.INVALID_VALUE, - KMType.INVALID_VALUE); - // Encode the protected header as byte blob. - protectedHeader = KMKeymasterApplet.encodeToApduBuffer(protectedHeader, scratchPad, (short) 0, - KMKeymasterApplet.MAX_COSE_BUF_SIZE); - protectedHeader = KMByteBlob.instance(scratchPad, (short) 0, protectedHeader); - /* CoseEncrypt unprotected headers */ - short unprotectedHeader = - KMCose.constructHeaders(KMType.INVALID_VALUE, KMType.INVALID_VALUE, nonce, - KMType.INVALID_VALUE); - // Construct partial CoseEncrypt - return KMCose.constructCoseEncrypt(protectedHeader, unprotectedHeader, KMType.INVALID_VALUE, - KMType.INVALID_VALUE); - } - - private short constructCoseMacForRkpKey(boolean testMode, byte[] scratchPad, short pubKey) { // prepare cosekey short coseKey = - KMCose.constructCoseKey( + kmCoseInst.constructCoseKey( KMInteger.uint_8(KMCose.COSE_KEY_TYPE_EC2), KMType.INVALID_VALUE, KMNInteger.uint_8(KMCose.COSE_ALG_ES256), KMType.INVALID_VALUE, KMInteger.uint_8(KMCose.COSE_ECCURVE_256), - KMByteBlob.cast(pubKey).getBuffer(), - KMByteBlob.cast(pubKey).getStartOff(), - KMByteBlob.cast(pubKey).length(), + KMByteBlob.getBuffer(pubKey), + KMByteBlob.getStartOff(pubKey), + KMByteBlob.length(pubKey), KMType.INVALID_VALUE, testMode); // Encode the cose key and make it as payload. - short len = KMKeymasterApplet - .encodeToApduBuffer(coseKey, scratchPad, (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE); + short len = KMKeymasterDevice + .encodeToApduBuffer(coseKey, scratchPad, (short) 0, KMKeymasterDevice.MAX_COSE_BUF_SIZE); short payload = KMByteBlob.instance(scratchPad, (short) 0, len); // Get the mackey. short macKey = getHmacKey(testMode, scratchPad); // Prepare protected header, which is required to construct the COSE_MAC0 - short headerPtr = KMCose.constructHeaders( + short headerPtr = kmCoseInst.constructHeaders( KMInteger.uint_8(KMCose.COSE_ALG_HMAC_256), KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE); // Encode the protected header as byte blob. - len = KMKeymasterApplet - .encodeToApduBuffer(headerPtr, scratchPad, (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE); + len = KMKeymasterDevice + .encodeToApduBuffer(headerPtr, scratchPad, (short) 0, KMKeymasterDevice.MAX_COSE_BUF_SIZE); short protectedHeader = KMByteBlob.instance(scratchPad, (short) 0, len); // create MAC_Structure short macStructure = - KMCose.constructCoseMacStructure(protectedHeader, KMByteBlob.instance((short) 0), payload); + kmCoseInst.constructCoseMacStructure(protectedHeader, KMByteBlob.instance((short) 0), payload); // Encode the Mac_structure and do HMAC_Sign to produce the tag for COSE_MAC0 - len = KMKeymasterApplet.encodeToApduBuffer(macStructure, scratchPad, (short) 0, - KMKeymasterApplet.MAX_COSE_BUF_SIZE); + len = KMKeymasterDevice.encodeToApduBuffer(macStructure, scratchPad, (short) 0, + KMKeymasterDevice.MAX_COSE_BUF_SIZE); // HMAC Sign. short hmacLen = seProvider - .hmacSign(KMByteBlob.cast(macKey).getBuffer(), KMByteBlob.cast(macKey).getStartOff(), + .hmacSign(KMByteBlob.getBuffer(macKey), KMByteBlob.getStartOff(macKey), (short) 32, scratchPad, (short) 0, len, scratchPad, len); // Create COSE_MAC0 object short coseMac0 = - KMCose + kmCoseInst .constructCoseMac0(protectedHeader, KMCoseHeaders.instance(KMArray.instance((short) 0)), payload, KMByteBlob.instance(scratchPad, len, hmacLen)); - len = KMKeymasterApplet - .encodeToApduBuffer(coseMac0, scratchPad, (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE); + len = KMKeymasterDevice + .encodeToApduBuffer(coseMac0, scratchPad, (short) 0, KMKeymasterDevice.MAX_COSE_BUF_SIZE); return KMByteBlob.instance(scratchPad, (short) 0, len); } @@ -1409,22 +1388,22 @@ private short getEcAttestKeyParameters() { .instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short) 256)); // Digest - SHA256 short byteBlob = KMByteBlob.instance((short) 1); - KMByteBlob.cast(byteBlob).add((short) 0, KMType.SHA2_256); + KMByteBlob.add(byteBlob, (short) 0, KMType.SHA2_256); short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); // Purpose - Attest byteBlob = KMByteBlob.instance((short) 1); - KMByteBlob.cast(byteBlob).add((short) 0, KMType.ATTEST_KEY); + KMByteBlob.add(byteBlob, (short) 0, KMType.ATTEST_KEY); short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob); - KMArray.cast(arrPtr).add(tagIndex++, purpose); + KMArray.add(arrPtr, tagIndex++, purpose); // Algorithm - EC - KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, KMType.EC)); - KMArray.cast(arrPtr).add(tagIndex++, keySize); - KMArray.cast(arrPtr).add(tagIndex++, digest); + KMArray.add(arrPtr, tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, KMType.EC)); + KMArray.add(arrPtr, tagIndex++, keySize); + KMArray.add(arrPtr, tagIndex++, digest); // Curve - P256 - KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ECCURVE, KMType.P_256)); + KMArray.add(arrPtr, tagIndex++, KMEnumTag.instance(KMType.ECCURVE, KMType.P_256)); // No Authentication is required to use this key. - KMArray.cast(arrPtr).add(tagIndex, KMBoolTag.instance(KMType.NO_AUTH_REQUIRED)); + KMArray.add(arrPtr, tagIndex, KMBoolTag.instance(KMType.NO_AUTH_REQUIRED)); return KMKeyParameters.instance(arrPtr); } }