From 9defa529270d10be94d6293fc8d2ad03d93f3644 Mon Sep 17 00:00:00 2001 From: subrahmanyaman Date: Fri, 18 Mar 2022 21:28:08 +0000 Subject: [PATCH] Ported latest changes to JCardSim --- .../keymaster/KMAttestationCertImpl.java | 84 +-- .../javacard/keymaster/KMJCardSimApplet.java | 214 ++++---- .../android/javacard/keymaster/KMUtils.java | 15 +- .../seprovider/KMDataStoreConstants.java | 12 + .../javacard/seprovider/KMHmacKey.java | 29 +- .../javacard/seprovider/KMJCardSimulator.java | 498 +++--------------- .../javacard/seprovider/KMRkpMacKey.java | 5 + .../javacard/seprovider/KMSEProvider.java | 201 ++++--- ProvisioningTool/sample_json_keymint_cf.txt | 2 +- 9 files changed, 372 insertions(+), 688 deletions(-) create mode 100644 Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMDataStoreConstants.java create mode 100644 Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMRkpMacKey.java diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index b0d633b2..a65148a5 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -89,6 +89,37 @@ public class KMAttestationCertImpl implements KMAttestationCert { 0x05, 0x00 }; + + + // 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.ALLOW_WHILE_ON_BODY, + KMType.USAGE_COUNT_LIMIT, + KMType.USAGE_EXPIRE_DATETIME, + KMType.ORIGINATION_EXPIRE_DATETIME, + KMType.ACTIVE_DATETIME, + }; + + // 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.UNLOCKED_DEVICE_REQUIRED, + KMType.TRUSTED_CONFIRMATION_REQUIRED, + KMType.AUTH_TIMEOUT, KMType.USER_AUTH_TYPE, + KMType.NO_AUTH_REQUIRED, KMType.EARLY_BOOT_ONLY, + KMType.ROLLBACK_RESISTANCE, KMType.RSA_OAEP_MGF_DIGEST, + KMType.RSA_PUBLIC_EXPONENT, KMType.ECCURVE, + KMType.PADDING, KMType.DIGEST, + KMType.KEYSIZE, KMType.ALGORITHM, KMType.PURPOSE + }; + // 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 = { @@ -119,7 +150,6 @@ public class KMAttestationCertImpl implements KMAttestationCert { private static short stackPtr; private static short bufStart; private static short bufLength; - private static KMSEProvider seProvider; private static short uniqueId; private static short attChallenge; @@ -134,6 +164,7 @@ public class KMAttestationCertImpl implements KMAttestationCert { private static byte keyUsage; private static byte unusedBits; private static KMAttestationCert inst; + private static KMSEProvider seProvider; private static boolean rsaCert; private static byte deviceLocked; private static short verifiedBootKey; @@ -241,9 +272,9 @@ public KMAttestationCert notBefore(short obj, boolean derEncoded, byte[] scratch 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 + // compare if the expiry time is greater then 2050 then use generalized // time format else use utc time format. - short tmpVar = KMInteger.uint_64(KMUtils.firstJan2051, (short) 0); + short tmpVar = KMInteger.uint_64(KMUtils.firstJan2050, (short) 0); if (KMInteger.compare(usageExpiryTimeObj, tmpVar) >= 0) { usageExpiryTimeObj = KMUtils.convertToDate(usageExpiryTimeObj, scratchPad, false); @@ -330,7 +361,7 @@ private void createKeyUsage(short tag) { } } -//TODO Serial number, X509Version needa to be passed as parameter + //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) { @@ -505,44 +536,27 @@ private static void pushKeyDescription() { 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; + short length = (short) swTagIds.length; do { - pushParams(swParams, swParamsIndex, tagIds[index]); - } while (++index < tagIds.length); + pushParams(swParams, swParamsIndex, swTagIds[index]); + } while (++index < 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; + short length = (short) hwTagIds.length; do { - if (tagIds[index] == KMType.ROOT_OF_TRUST) { + if (hwTagIds[index] == KMType.ROOT_OF_TRUST) { pushRoT(); continue; } - if (pushParams(hwParams, hwParamsIndex, tagIds[index])) { + if (pushParams(hwParams, hwParamsIndex, hwTagIds[index])) { continue; } - } while (++index < tagIds.length); + } while (++index < length); pushSequenceHeader((short) (last - stackPtr)); } @@ -872,7 +886,6 @@ public short getCertLength() { return certLength; } - public void build(short attSecret, short attMod, boolean rsaSign, boolean fakeCert) { stackPtr = (short)(bufStart + bufLength); short last = stackPtr; @@ -900,12 +913,11 @@ else if (rsaSign) { pushTbsCert(rsaCert, rsaSign); tbsStart = stackPtr; tbsLength = (short) (tbsLength - tbsStart); - KMJCardSimulator provider = KMJCardSimulator.getInstance(); if(attSecret != KMType.INVALID_VALUE){ // Sign with the attestation key // The pubKey is the modulus. if (rsaSign) { - sigLen = provider + sigLen = seProvider .rsaSign256Pkcs1( KMByteBlob.cast(attSecret).getBuffer(), KMByteBlob.cast(attSecret).getStartOff(), @@ -920,7 +932,7 @@ else if (rsaSign) { signatureOffset); if(sigLen > RSA_SIG_LEN) KMException.throwIt(KMError.UNKNOWN_ERROR); } else { - sigLen = provider + sigLen = seProvider .ecSign256( KMByteBlob.cast(attSecret).getBuffer(), KMByteBlob.cast(attSecret).getStartOff(), @@ -936,7 +948,7 @@ else if (rsaSign) { stackPtr = signatureOffset; pushBitStringHeader((byte) 0, sigLen); }else if(!fakeCert){ // no attestation key provisioned in the factory - KMException.throwIt(KMError.ATTESTATION_KEYS_NOT_PROVISIONED); + KMException.throwIt(KMError.ATTESTATION_KEYS_NOT_PROVISIONED); } last = (short)(signatureOffset+sigLen); // Add certificate sequence header @@ -944,10 +956,9 @@ else if (rsaSign) { pushSequenceHeader((short) (last - stackPtr)); certStart = stackPtr; certLength = (short)(last - certStart); - print(stack, getCertStart(), getCertLength()); + //print(stack, getCertStart(), getCertLength()); } - @Override public void build() { if(certMode == KMType.FAKE_CERT) { @@ -986,7 +997,7 @@ public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, KMByteBlob.cast(mKeyData).getBuffer(), /* Key */ KMByteBlob.cast(mKeyData).getStartOff()); /* Key start*/ timeOffset = KMByteBlob.instance((short) 32); - appIdOff = KMJCardSimulator.getInstance().hmacSign( + appIdOff = seProvider.hmacSign( KMByteBlob.cast(mKeyData).getBuffer(), /* Key */ KMByteBlob.cast(mKeyData).getStartOff(), /* Key start*/ KMByteBlob.cast(mKeyData).length(), /* Key length*/ @@ -1049,6 +1060,7 @@ public KMAttestationCert rsaAttestKey(short attestPrivExp, short attestMod, byte 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 ++){ diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java index a2c81488..f38f7d31 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java @@ -18,12 +18,16 @@ import com.android.javacard.seprovider.KMDeviceUniqueKey; import com.android.javacard.seprovider.KMException; import com.android.javacard.seprovider.KMJCardSimulator; +import com.licel.jcardsim.smartcardio.JCardSimProvider; import javacard.framework.APDU; import javacard.framework.ISO7816; +import javacard.framework.ISOException; import javacard.framework.Util; +import javacard.security.CryptoException; public class KMJCardSimApplet extends KMKeymasterApplet { + 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_ATTEST_IDS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 1; @@ -36,9 +40,14 @@ public class KMJCardSimApplet extends KMKeymasterApplet { INS_KEYMINT_PROVIDER_APDU_START + 6; private static final byte INS_PROVISION_ADDITIONAL_CERT_CHAIN_CMD = INS_KEYMINT_PROVIDER_APDU_START + 7; + private static final byte INS_SET_BOOT_ENDED_CMD = + INS_KEYMINT_PROVIDER_APDU_START + 8; + 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; @@ -48,12 +57,12 @@ public class KMJCardSimApplet extends KMKeymasterApplet { 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; + + // Package version. + protected short packageVersion; KMJCardSimApplet() { super(new KMJCardSimulator()); @@ -80,60 +89,115 @@ public void process(APDU apdu) { } } short apduIns = validateApdu(apdu); + if (apduIns == KMType.INVALID_VALUE) { + return; + } if (((KMJCardSimulator) seProvider).isPowerReset()) { super.powerReset(); } - if (((KMJCardSimulator) seProvider).isProvisionLocked()) { + + if (kmDataStore.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 + kmDataStore.setBootEndedStatus(true); + sendError(apdu, KMError.OK); + break; + + case INS_GET_PROVISION_STATUS_CMD: + processGetProvisionStatusCmd(apdu); + break; + default: super.process(apdu); break; } return; } - if (apduIns == KMType.INVALID_VALUE) { - return; - } + switch (apduIns) { case INS_PROVISION_ATTEST_IDS_CMD: processProvisionAttestIdsCmd(apdu); - provisionStatus |= PROVISION_STATUS_ATTEST_IDS; + kmDataStore.setProvisionStatus(PROVISION_STATUS_ATTEST_IDS); sendError(apdu, KMError.OK); break; + case INS_PROVISION_PRESHARED_SECRET_CMD: processProvisionPreSharedSecretCmd(apdu); - provisionStatus |= PROVISION_STATUS_PRESHARED_SECRET; + kmDataStore.setProvisionStatus(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); + // Allow other commands only if provision is completed. + if (isProvisioningComplete()) { + super.process(apdu); + } else { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } break; } + } catch (KMException exception) { + sendError(apdu, KMException.reason()); + } catch (ISOException exp) { + sendError(apdu, mapISOErrorToKMError(exp.getReason())); + } catch (CryptoException e) { + sendError(apdu, mapCryptoErrorToKMError(e.getReason())); + } catch (Exception e) { + sendError(apdu, KMError.GENERIC_UNKNOWN_ERROR); } finally { repository.clean(); } } + + private boolean isProvisioningComplete() { + short dInex = repository.allocReclaimableMemory((short)1); + byte data[] = repository.getHeap(); + kmDataStore.getProvisionStatus(data, dInex); + boolean result = false; + if ((0 != (data[dInex] & PROVISION_STATUS_DEVICE_UNIQUE_KEY)) + && (0 != (data[dInex] & PROVISION_STATUS_ADDITIONAL_CERT_CHAIN)) + && (0 != (data[dInex] & PROVISION_STATUS_PRESHARED_SECRET))) { + result = true; + } + repository.reclaimMemory((short)1); + return result; + } + + private void processLockProvisioningCmd(APDU apdu) { + if (isProvisioningComplete()) { + kmDataStore.setProvisionLocked(); + kmDataStore.setProvisionStatus(PROVISION_STATUS_PROVISIONING_LOCKED); + sendError(apdu, KMError.OK); + } else { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } + } private void processProvisionAttestIdsCmd(APDU apdu) { short keyparams = KMKeyParameters.exp(); @@ -162,7 +226,7 @@ public void setAttestationIds(short attIdVals) { KMException.throwIt(KMError.INVALID_ARGUMENT); } obj = KMByteTag.cast(obj).getValue(); - ((KMJCardSimulator) seProvider).setAttestationId(key, KMByteBlob.cast(obj).getBuffer(), + kmDataStore.setAttestationId(key, KMByteBlob.cast(obj).getBuffer(), KMByteBlob.cast(obj).getStartOff(), KMByteBlob.cast(obj).length()); index++; } @@ -182,22 +246,25 @@ private void processProvisionPreSharedSecretCmd(APDU apdu) { KMException.throwIt(KMError.INVALID_ARGUMENT); } // Persist shared Hmac. - ((KMJCardSimulator) seProvider).createPresharedKey( + kmDataStore.createPresharedKey( KMByteBlob.cast(val).getBuffer(), KMByteBlob.cast(val).getStartOff(), KMByteBlob.cast(val).length()); } private void processGetProvisionStatusCmd(APDU apdu) { + byte[] scratchpad = apdu.getBuffer(); + kmDataStore.getProvisionStatus(scratchpad, (short) 0); 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)); + KMArray.cast(resp).add((short) 1, KMInteger.uint_8(scratchpad[0])); 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()); @@ -211,9 +278,10 @@ private void processSetBootParamsCmd(APDU apdu) { 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(), + kmDataStore.setBootPatchLevel(KMInteger.cast(bootParam).getBuffer(), KMInteger.cast(bootParam).getStartOff(), KMInteger.cast(bootParam).length()); @@ -221,7 +289,7 @@ private void processSetBootParamsCmd(APDU apdu) { if (KMByteBlob.cast(bootParam).length() > BOOT_KEY_MAX_SIZE) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - ((KMJCardSimulator) seProvider).setBootKey(KMByteBlob.cast(bootParam).getBuffer(), + kmDataStore.setBootKey(KMByteBlob.cast(bootParam).getBuffer(), KMByteBlob.cast(bootParam).getStartOff(), KMByteBlob.cast(bootParam).length()); @@ -229,24 +297,24 @@ private void processSetBootParamsCmd(APDU apdu) { if (KMByteBlob.cast(bootParam).length() > BOOT_HASH_MAX_SIZE) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - ((KMJCardSimulator) seProvider).setVerifiedBootHash(KMByteBlob.cast(bootParam).getBuffer(), + kmDataStore.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); + kmDataStore.setBootState(enumVal); bootParam = KMArray.cast(args).get((short) 4); enumVal = KMEnum.cast(bootParam).getVal(); - ((KMJCardSimulator) seProvider).setDeviceLocked(enumVal == KMType.DEVICE_LOCKED_TRUE); + kmDataStore.setDeviceLocked(enumVal == KMType.DEVICE_LOCKED_TRUE); - super.reboot(); - sendError(apdu, KMError.OK); - } - private void processLockProvisioningCmd(APDU apdu) { - ((KMJCardSimulator) seProvider).setProvisionLocked(true); + // Clear the Computed SharedHmac and Hmac nonce from persistent memory. + Util.arrayFillNonAtomic(scratchPad, (short) 0, KMKeymintDataStore.COMPUTED_HMAC_KEY_SIZE, (byte) 0); + kmDataStore.createComputedHmacKey(scratchPad, (short) 0, KMKeymintDataStore.COMPUTED_HMAC_KEY_SIZE); + + super.reboot(); sendError(apdu, KMError.OK); } @@ -270,83 +338,6 @@ private short validateApdu(APDU apdu) { 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(); @@ -359,13 +350,13 @@ private static void processProvisionDeviceUniqueKey(APDU apdu) { 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, + kmDataStore.createDeviceUniqueKey(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); + kmDataStore.persistBootCertificateChain(scratchPad, (short) 0, len); + kmDataStore.setProvisionStatus(PROVISION_STATUS_DEVICE_UNIQUE_KEY); sendError(apdu, KMError.OK); } @@ -380,7 +371,6 @@ private static void processProvisionAdditionalCertChain(APDU apdu) { 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(); @@ -403,7 +393,7 @@ private static void processProvisionAdditionalCertChain(APDU apdu) { srcBuffer, null); // Compare the DK_Pub. short pubKeyLen = KMCoseKey.cast(leafCoseKey).getEcdsa256PublicKey(srcBuffer, (short) 0); - KMDeviceUniqueKey uniqueKey = seProvider.getDeviceUniqueKey(false); + KMDeviceUniqueKey uniqueKey = kmDataStore.getDeviceUniqueKey(false); if (uniqueKey == null) { KMException.throwIt(KMError.STATUS_FAILED); } @@ -412,7 +402,8 @@ private static void processProvisionAdditionalCertChain(APDU apdu) { (0 != Util.arrayCompare(srcBuffer, (short) 0, srcBuffer, pubKeyLen, pubKeyLen))) { KMException.throwIt(KMError.STATUS_FAILED); } - seProvider.persistAdditionalCertChain(buffer, bufferStartOffset, bufferLength); + kmDataStore.persistAdditionalCertChain(buffer, bufferStartOffset, bufferLength); + kmDataStore.setProvisionStatus(PROVISION_STATUS_ADDITIONAL_CERT_CHAIN); //reclaim memory repository.reclaimMemory(bufferLength); sendError(apdu, KMError.OK); @@ -433,7 +424,6 @@ private static short buildErrorStatus(short err) { (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 index 3e9002e2..a2fc8eab 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -16,6 +16,7 @@ package com.android.javacard.keymaster; import com.android.javacard.seprovider.KMException; + import javacard.framework.Util; public class KMUtils { @@ -40,8 +41,8 @@ public class KMUtils { 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 final byte[] firstJan2050 = { + 0, 0, 0x02, 0x4b, (byte) 0xCE, 0x5C, (byte)0xF0, 0x00}; //2524608000000 // msec public static final byte[] febMonthLeapMSec = { 0, 0, 0, 0, (byte) 0x95, 0x58, 0x6C, 0x00}; //2505600000 @@ -79,12 +80,12 @@ public static short convertToDate(short time, byte[] scratchPad, KMException.throwIt(KMError.INVALID_ARGUMENT); } if (utcFlag - && KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, + && KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2050, (short) 0, (short) 8) >= 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2050, (short) 0, (short) 8) < 0) { Util.arrayCopyNonAtomic(firstJan2020, (short) 0, scratchPad, (short) 8, (short) 8); @@ -93,7 +94,7 @@ public static short convertToDate(short time, byte[] scratchPad, (short) 8); } else { from2020 = false; - Util.arrayCopyNonAtomic(firstJan2051, (short) 0, scratchPad, (short) 8, + Util.arrayCopyNonAtomic(firstJan2050, (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, @@ -104,7 +105,7 @@ public static short convertToDate(short time, byte[] scratchPad, (short) 8) >= 0) { Util.arrayCopyNonAtomic(fourYrsMsec, (short) 0, scratchPad, (short) 8, (short) 8); - // quotient is multiple of 4. + // 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 @@ -392,7 +393,7 @@ public static short countTemporalCount(byte[] bufTime, short timeOff, scratchPad, (short) (offset + 8 - timeLen), timeLen); - Util.arrayCopyNonAtomic(oneMonthMsec, (short) 0, scratchPad, (short) (offset + 8), + Util.arrayCopyNonAtomic(ThirtDaysMonthMsec, (short) 0, scratchPad, (short) (offset + 8), (short) 8); return divide(scratchPad, (short) 0, (short) 8, (short) 16); } diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMDataStoreConstants.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMDataStoreConstants.java new file mode 100644 index 00000000..31917a75 --- /dev/null +++ b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMDataStoreConstants.java @@ -0,0 +1,12 @@ +package com.android.javacard.seprovider; + +public class KMDataStoreConstants { + // INTERFACE Types + public static final byte INTERFACE_TYPE_COMPUTED_HMAC_KEY = 0x01; + public static final byte INTERFACE_TYPE_ATTESTATION_KEY = 0x02; + public static final byte INTERFACE_TYPE_DEVICE_UNIQUE_KEY = 0x03; + public static final byte INTERFACE_TYPE_MASTER_KEY = 0x04; + public static final byte INTERFACE_TYPE_PRE_SHARED_KEY = 0x05; + public static final byte INTERFACE_TYPE_RKP_MAC_KEY = 0x06; + +} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java index 735789b6..f975ab62 100644 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java +++ b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java @@ -15,9 +15,11 @@ */ package com.android.javacard.seprovider; +import org.globalplatform.upgrade.Element; + import javacard.security.HMACKey; -public class KMHmacKey implements KMPreSharedKey { +public class KMHmacKey implements KMPreSharedKey, KMComputedHmacKey, KMRkpMacKey { private HMACKey hmacKey; @@ -33,11 +35,30 @@ public byte getKey(byte[] keyData, short kOff) { return hmacKey.getKey(keyData, kOff); } + public HMACKey getKey() { + return hmacKey; + } + public short getKeySizeBits() { return hmacKey.getSize(); } - - public HMACKey getKey() { - return hmacKey; + + public static void onSave(Element element, KMHmacKey kmKey) { + element.write(kmKey.hmacKey); + } + + public static KMHmacKey onRestore(HMACKey hmacKey) { + if (hmacKey == null) { + return null; + } + return new KMHmacKey(hmacKey); + } + + public static short getBackupPrimitiveByteCount() { + return (short) 0; + } + + public static short getBackupObjectCount() { + return (short) 1; } } diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java index ed41afe1..0a9e57e2 100644 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java +++ b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java @@ -69,9 +69,6 @@ public class KMJCardSimulator implements KMSEProvider { 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; @@ -79,8 +76,6 @@ public class KMJCardSimulator implements KMSEProvider { 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; @@ -89,35 +84,7 @@ public class KMJCardSimulator implements KMSEProvider { private static Cipher aesRngCipher; private static byte[] entropyPool; private static byte[] rndNum; - private byte[] certificateChain; - private byte[] additionalCertChain; - private byte[] bcc; - 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; @@ -128,7 +95,6 @@ public static KMJCardSimulator getInstance() { // 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 @@ -143,14 +109,9 @@ public KMJCardSimulator() { } aesRngKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); // various ciphers - //Allocate buffer for certificate chain. - certificateChain = new byte[CERT_CHAIN_MAX_SIZE]; - additionalCertChain = new byte[ADDITIONAL_CERT_CHAIN_MAX_SIZE]; - bcc = new byte[BCC_MAX_SIZE]; jCardSimulator = this; resetFlag = new byte[1]; resetFlag[0] = (byte) POWER_RESET_FALSE; - deviceReboot = false; } @@ -520,7 +481,7 @@ public boolean aesGCMDecrypt( @Override public void getTrueRandomNumber(byte[] buf, short start, short length) { - Util.arrayCopy(entropyPool, (short) 0, buf, start, length); + newRandomNumber(buf, start, length); } public HMACKey cmacKdf(byte[] keyMaterial, short keyMaterialStart, short keyMaterialLen, @@ -647,6 +608,12 @@ public short hmacSign(byte[] keyBuf, short keyStart, short keyLength, byte[] dat return hmacSign(key, data, dataStart, dataLength, mac, macStart); } + @Override + public short hmacSign(Object hmacKey, byte[] data, short dataStart, short dataLength, + byte[] signature, short signatureStart) { + return 0; + } + @Override public boolean hmacVerify(KMComputedHmacKey key, byte[] data, short dataStart, short dataLength, byte[] mac, short macStart, short macLength) { @@ -916,15 +883,6 @@ public Signature createEcSigner(short digest, byte[] secret, short secretStart, 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, @@ -1289,51 +1247,22 @@ public void addRngEntropy(byte[] num, short offset, short length) { } } - /** - * The operation reads the certificate chain from persistent memory. - * - * @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. - */ - public short readCertificateChain(byte[] buf, short offset) { - short len = Util.getShort(certificateChain, (short) 0); - Util.arrayCopyNonAtomic(certificateChain, (short) 2, buf, offset, len); - return len; - } - @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); + public com.android.javacard.seprovider.KMDeviceUniqueKey createDeviceUniqueKey( + com.android.javacard.seprovider.KMDeviceUniqueKey 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); } - 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; + ((KMECDeviceUniqueKey) key).setS(privKey, privKeyOff, privKeyLen); + ((KMECDeviceUniqueKey) key).setW(pubKey, pubKeyOff, pubKeyLen); + return (KMDeviceUniqueKey) key; } @Override @@ -1404,85 +1333,15 @@ public boolean ecVerify256(byte[] pubKey, short pubKeyOffset, short pubKeyLen, b 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(); - } - - /** - * This operation persists the certificate chain in the persistent memory in multiple requests. - * - * @param buf buffer containing certificate chain. - * @param offset is the start of the buffer. - * @param len is the length of the buffer. - * @param totalLen is the total length of cert chain. - */ - void persistPartialCertificateChain(byte[] buf, short offset, short len, short totalLen){ - // _____________________________________________________ - // | 2 Bytes | 1 Byte | 3 Bytes | Cert1 | 3 Bytes | Cert2|... - // |_________|________|_________|_______|_________|______| - // First two bytes holds the length of the total buffer. - // CBOR format: - // Next single byte holds the array header. - // Next 3 bytes holds the Byte array header with the cert1 length. - // Next 3 bytes holds the Byte array header with the cert2 length. - if (totalLen > (short) (CERT_CHAIN_MAX_SIZE - 2)) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - short persistedLen = Util.getShort(certificateChain, (short) 0); - if (persistedLen > totalLen) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - JCSystem.beginTransaction(); - Util.setShort(certificateChain, (short) 0, (short) (len + persistedLen)); - Util.arrayCopyNonAtomic(buf, offset, certificateChain, - (short) (persistedLen + 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) { + public KMComputedHmacKey createComputedHmacKey( + KMComputedHmacKey computedHmacKey, byte[] keyData, + short offset, short length) { if (length != COMPUTED_HMAC_KEY_SIZE) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } @@ -1491,12 +1350,13 @@ public KMComputedHmacKey createComputedHmacKey(byte[] keyData, short offset, sho false); computedHmacKey = new KMHmacKey(key); } - computedHmacKey.setKey(keyData, offset, length); + ((KMHmacKey) computedHmacKey).setKey(keyData, offset, length); return (KMComputedHmacKey) computedHmacKey; } - + @Override - public KMMasterKey createMasterKey(short keySizeBits) { + public com.android.javacard.seprovider.KMMasterKey createMasterKey( + com.android.javacard.seprovider.KMMasterKey masterKey, short keySizeBits) { if (masterKey == null) { AESKey key = (AESKey) KeyBuilder.buildKey( KeyBuilder.TYPE_AES, keySizeBits, false); @@ -1504,7 +1364,7 @@ public KMMasterKey createMasterKey(short keySizeBits) { short keyLen = (short) (keySizeBits / 8); byte[] keyData = new byte[keyLen]; getTrueRandomNumber(keyData, (short) 0, keyLen); - masterKey.setKey(keyData, (short) 0); + ((KMAESKey)masterKey).setKey(keyData, (short) 0); } return (KMMasterKey) masterKey; } @@ -1513,199 +1373,6 @@ public KMMasterKey createMasterKey(short keySizeBits) { 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. - */ - 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. - */ - 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; @@ -1717,96 +1384,79 @@ public boolean isPowerReset(){ } @Override - public short getVerifiedBootHash(byte[] buffer, short start) { - Util.arrayCopyNonAtomic(verifiedHash,(short)0,buffer,start,(short)verifiedHash.length); - return (short)verifiedHash.length; - } + 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) { - @Override - public short getBootKey(byte[] buffer, short start) { - Util.arrayCopyNonAtomic(bootKey,(short) 0, buffer, start, (short)bootKey.length); - return (short)bootKey.length; + } + return len; } @Override - public short getBootState() { - return bootState; + public void onSave(Element element, byte interfaceType, Object object) { + } @Override - public boolean isDeviceBootLocked() { - return deviceBootLocked; + public Object onResore(Element element) { + return null; } @Override - public short getBootPatchLevel(byte[] buffer, short start) { - Util.arrayCopyNonAtomic(bootPatchLevel, (short)0, buffer, start, (short)bootPatchLevel.length); - return (short)bootPatchLevel.length; + public short getBackupPrimitiveByteCount(byte interfaceType) { + return 0; } - 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); + @Override + public short getBackupObjectCount(byte interfaceType) { + return 0; } - public void setBootKey(byte[] buffer, short start, short length) { - if(bootKey == null){ - bootKey = new byte[32]; - } - if(length != 32){ - KMException.throwIt(KMError.UNKNOWN_ERROR); + @Override + public KMRkpMacKey createRkpMacKey(KMRkpMacKey rkpMacKey, byte[] keyData, + short offset, short length) { + if (rkpMacKey == null) { + HMACKey key = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, (short) (length * 8), + false); + rkpMacKey = new KMHmacKey(key); } - Util.arrayCopyNonAtomic(buffer, start, bootKey, (short)0, (short)32); + ((KMHmacKey) rkpMacKey).setKey(keyData, offset, length); + return rkpMacKey; } - 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]; + @Override + public com.android.javacard.seprovider.KMPreSharedKey createPreSharedKey( + com.android.javacard.seprovider.KMPreSharedKey presharedKey, 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(length > 4 || length < 0){ - KMException.throwIt(KMError.UNKNOWN_ERROR); + if (preSharedKey == null) { + HMACKey key = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, lengthInBits, + false); + preSharedKey = new KMHmacKey(key); } - Util.arrayCopyNonAtomic(buffer, start, bootPatchLevel, (short)0, (short) 4); - } - - public void setProvisionLocked(boolean locked) { - isProvisionLocked = locked; + ((KMHmacKey)preSharedKey).setKey(keyData, offset, length); + return (KMPreSharedKey) preSharedKey; } - 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) { - + public com.android.javacard.seprovider.KMAttestationKey createAttestationKey( + com.android.javacard.seprovider.KMAttestationKey attestationKey, 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); } - return len; - } - - @Override - public KMComputedHmacKey getComputedHmacKey() { - return (KMComputedHmacKey) computedHmacKey; + ((KMECPrivateKey) attestationKey).setS(keyData, offset, length); + return (KMAttestationKey) attestationKey; } } diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMRkpMacKey.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMRkpMacKey.java new file mode 100644 index 00000000..62116d24 --- /dev/null +++ b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMRkpMacKey.java @@ -0,0 +1,5 @@ +package com.android.javacard.seprovider; + + +public interface KMRkpMacKey { +} diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java index e493f3aa..4d4570b6 100644 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java +++ b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java @@ -15,13 +15,15 @@ */ package com.android.javacard.seprovider; +import org.globalplatform.upgrade.Element; + /** * 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 { +public interface KMSEProvider { /** * Create a symmetric key instance. If the algorithm and/or keysize are not supported then it @@ -273,6 +275,25 @@ short hmacSign( short dataLength, byte[] signature, short signatureStart); + + /** + * This is a oneshot operation that signs the data using hmac algorithm. + * + * @param hmacKey is the KMHmacKey. + * @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( + Object hmacKey, + 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 @@ -297,7 +318,9 @@ short hmacKDF( /** * This is a oneshot operation that verifies the signature using hmac algorithm. * - * @param hmacKey is the computed hmac key. + * @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. * @param dataStart is the start of the data. * @param dataLength is the length of the data. @@ -559,32 +582,26 @@ KMOperation initAsymmetricOperation( */ 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 instance of the masterkey. * @param keySizeBits key size in bits. * @return An instance of KMMasterKey. */ - KMMasterKey createMasterKey(short keySizeBits); + KMMasterKey createMasterKey(KMMasterKey masterKey, short keySizeBits); /** - * Returns the master key. + * This function creates an HMACKey and initializes the key with the provided input key data. * - * @return Instance of the KMMasterKey + * @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. */ - KMMasterKey getMasterKey(); + KMComputedHmacKey createComputedHmacKey(KMComputedHmacKey computedHmacKey, byte[] keyData, short offset, short length); /** * Returns true if factory provisioned attestation key is supported. @@ -597,54 +614,6 @@ KMOperation initAsymmetricOperation( */ 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. * @@ -657,69 +626,93 @@ KMOperation initAsymmetricOperation( * @param privKeyLen private key buffer length. * @return instance of KMDeviceUniqueKey. */ - KMDeviceUniqueKey createDeviceUniqueKey(boolean testMode, + KMDeviceUniqueKey createDeviceUniqueKey(KMDeviceUniqueKey key, byte[] pubKey, short pubKeyOff, short pubKeyLen, byte[] privKey, short privKeyOff, short privKeyLen); - + /** - * Returns the instance KMDeviceUnique if it is created. + * This is a one-shot operation the does digest of the input mesage. * - * @param testMode Indicates if current execution is for test or production. - * @return instance of KMDeviceUniqueKey if present; null otherwise. + * @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. */ - KMDeviceUniqueKey getDeviceUniqueKey(boolean testMode); - + short messageDigest256(byte[] inBuff, short inOffset, short inLength, byte[] outBuff, + short outOffset); + /** - * Persists the additional certificate chain in persistent memory. + * 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 buf buffer containing the cbor encoded additional certificate chain. - * @param offset start offset of the buffer. - * @param len length of the buffer. + * @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. */ - void persistAdditionalCertChain(byte[] buf, short offset, short len); - + KMAttestationKey createAttestationKey(KMAttestationKey attestationKey, byte[] keyData, + short offset, + short length); + /** - * Returns the additional certificate chain length. + * This function generates a HMAC key from the provided key buffers. * - * @return length of the encoded additional certificate chain. + * @param presharedKey instance of the presharedkey. + * @param key buffer containing the key data. + * @param offset start offset of the buffer. + * @param length is the length of the key. + * @return instance of KMPresharedKey. */ - short getAdditionalCertChainLength(); - + KMPreSharedKey createPreSharedKey(KMPreSharedKey presharedKey, byte[] key, short offset, + short length); + /** - * Returns the additional certificate chain. + * This function saves the key objects while upgrade. * - * @return additional cert chain. + * @param element instance of the Element class where the objects to be stored. + * @param interfaceType the type interface of the parent object. + * @param object instance of the object to be saved. */ - byte[] getAdditionalCertChain(); - - + void onSave(Element element, byte interfaceType, Object object); + /** - * Returns the boot certificate chain. - * - * @return boot certificate chain. + * This function restores the the object from element instance. + * + * @param element instance of the Element class. + * @return restored object. */ - byte[] getBootCertificateChain(); + Object onResore(Element element); /** - * Returns the computed Hmac key. + * This function returns the count of the primitive bytes required to + * be stored by the implementation of the interface type. + * + * @param interfaceType type interface of the parent object. + * @return count of the primitive bytes. + */ + short getBackupPrimitiveByteCount(byte interfaceType); + + /** + * This function returns the object count required to be stored by the + * implementation of the interface type. * - * @return Instance of the computed hmac key. + * @param interfaceType type interface of the parent object. + * @return count of the objects. */ - KMComputedHmacKey getComputedHmacKey(); + short getBackupObjectCount(byte interfaceType); /** - * This is a one-shot operation the does digest of the input mesage. + * This function creates an HMACKey and initializes the key with the provided input key data. * - * @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. + * @param keyData buffer containing the key data. + * @param offset start of the buffer. + * @param length length of the buffer. + * @return An instance of the KMRkpMacKey. */ - short messageDigest256(byte[] inBuff, short inOffset, short inLength, byte[] outBuff, - short outOffset); - - public boolean isProvisionLocked(); + KMRkpMacKey createRkpMacKey(KMRkpMacKey createComputedHmacKey, byte[] keyData, + short offset, short length); } diff --git a/ProvisioningTool/sample_json_keymint_cf.txt b/ProvisioningTool/sample_json_keymint_cf.txt index 70f9c71e..cb454584 100644 --- a/ProvisioningTool/sample_json_keymint_cf.txt +++ b/ProvisioningTool/sample_json_keymint_cf.txt @@ -11,7 +11,7 @@ }, "shared_secret": "0000000000000000000000000000000000000000000000000000000000000000", "set_boot_params": { - "boot_patch_level": 0, + "boot_patch_level": 20220101, "verified_boot_key": "0000000000000000000000000000000000000000000000000000000000000000", "verified_boot_key_hash": "0000000000000000000000000000000000000000000000000000000000000000", "boot_state": 2,