diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java index 39559f70..ffaea2fe 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java @@ -32,6 +32,10 @@ import javacard.security.CryptoException; public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeListener { + // Magic number version + private static final byte KM_MAGIC_NUMBER = (byte) 0x82; + // MSB byte is for Major version and LSB byte is for Minor version. + private static final short CURRENT_PACKAGE_VERSION = 0x0009; // 0.9 private static final byte KM_BEGIN_STATE = 0x00; private static final byte ILLEGAL_STATE = KM_BEGIN_STATE + 1; @@ -69,9 +73,14 @@ public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeLis private static byte keymasterState = ILLEGAL_STATE; private static byte provisionStatus = NOT_PROVISIONED; + // Package version. + protected short packageVersion; KMAndroidSEApplet() { super(new KMAndroidSEProvider()); + if (!UpgradeManager.isUpgrading()) { + packageVersion = CURRENT_PACKAGE_VERSION; + } } /** @@ -107,7 +116,7 @@ public void process(APDU apdu) { case INS_SET_BOOT_ENDED_CMD: //set the flag to mark boot ended - repository.setBootEndedStatus(true); + kmDataStore.setBootEndedStatus(true); sendError(apdu, KMError.OK); break; @@ -184,12 +193,12 @@ 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); short bcc = generateBcc(false, scratchPad); short len = KMKeymasterApplet.encodeToApduBuffer(bcc, scratchPad, (short) 0, MAX_COSE_BUF_SIZE); - ((KMAndroidSEProvider) seProvider).persistBootCertificateChain(scratchPad, (short) 0, len); + kmDataStore.persistBootCertificateChain(scratchPad, (short) 0, len); sendError(apdu, KMError.OK); } @@ -226,7 +235,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); } @@ -235,7 +244,7 @@ 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); //reclaim memory repository.reclaimMemory(bufferLength); sendError(apdu, KMError.OK); @@ -269,7 +278,7 @@ public void setAttestationIds(short attIdVals) { KMException.throwIt(KMError.INVALID_ARGUMENT); } obj = KMByteTag.cast(obj).getValue(); - ((KMAndroidSEProvider) seProvider).setAttestationId(key, KMByteBlob.cast(obj).getBuffer(), + kmDataStore.setAttestationId(key, KMByteBlob.cast(obj).getBuffer(), KMByteBlob.cast(obj).getStartOff(), KMByteBlob.cast(obj).length()); index++; } @@ -288,7 +297,7 @@ private void processProvisionPreSharedSecretCmd(APDU apdu) { KMException.throwIt(KMError.INVALID_ARGUMENT); } // Persist shared Hmac. - ((KMAndroidSEProvider) seProvider).createPresharedKey( + kmDataStore.createPresharedKey( KMByteBlob.cast(val).getBuffer(), KMByteBlob.cast(val).getStartOff(), KMByteBlob.cast(val).length()); @@ -345,7 +354,7 @@ private void processSetBootParamsCmd(APDU apdu) { short bootParam = KMArray.cast(args).get((short) 0); - ((KMAndroidSEProvider) seProvider).setBootPatchLevel(KMInteger.cast(bootParam).getBuffer(), + kmDataStore.setBootPatchLevel(KMInteger.cast(bootParam).getBuffer(), KMInteger.cast(bootParam).getStartOff(), KMInteger.cast(bootParam).length()); @@ -353,7 +362,7 @@ private void processSetBootParamsCmd(APDU apdu) { if (KMByteBlob.cast(bootParam).length() > BOOT_KEY_MAX_SIZE) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - ((KMAndroidSEProvider) seProvider).setBootKey(KMByteBlob.cast(bootParam).getBuffer(), + kmDataStore.setBootKey(KMByteBlob.cast(bootParam).getBuffer(), KMByteBlob.cast(bootParam).getStartOff(), KMByteBlob.cast(bootParam).length()); @@ -361,22 +370,22 @@ private void processSetBootParamsCmd(APDU apdu) { if (KMByteBlob.cast(bootParam).length() > BOOT_HASH_MAX_SIZE) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - ((KMAndroidSEProvider) 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(); - ((KMAndroidSEProvider) seProvider).setBootState(enumVal); + kmDataStore.setBootState(enumVal); bootParam = KMArray.cast(args).get((short) 4); enumVal = KMEnum.cast(bootParam).getVal(); - ((KMAndroidSEProvider) seProvider).setDeviceLocked(enumVal == KMType.DEVICE_LOCKED_TRUE); + kmDataStore.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); + 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); @@ -394,36 +403,55 @@ public void onCleanup() { @Override public void onConsolidate() { } + + private boolean isUpgradeAllowed(short version) { + boolean upgradeAllowed = false; + short oldMajorVersion = (short) ((version >> 8) & 0x00FF); + short oldMinorVersion = (short) (version & 0x00FF); + short currentMajorVersion = (short) (CURRENT_PACKAGE_VERSION >> 8 & 0x00FF); + short currentMinorVersion = (short) (CURRENT_PACKAGE_VERSION & 0x00FF); + // Downgrade of the Applet is not allowed. + // Upgrade is not allowed to a next version which is not immediate. + if ((short) (currentMajorVersion - oldMajorVersion) == 1) { + if (currentMinorVersion == 0) { + upgradeAllowed = true; + } + } else if ((short) (currentMajorVersion - oldMajorVersion) == 0) { + if (currentMinorVersion >= oldMinorVersion) { + upgradeAllowed = true; + } + } + return upgradeAllowed; + } @Override public void onRestore(Element element) { element.initRead(); - provisionStatus = element.readByte(); - keymasterState = element.readByte(); - repository.onRestore(element); - seProvider.onRestore(element); + byte magicNumber = element.readByte(); + if (magicNumber != KM_MAGIC_NUMBER) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } + short packageVersion = element.readShort(); + // Validate version. + if (0 != packageVersion && !isUpgradeAllowed(packageVersion)) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } + kmDataStore.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. + short primitiveCount = 3; + primitiveCount += kmDataStore.getBackupPrimitiveByteCount(); + short objectCount = kmDataStore.getBackupObjectCount(); + // 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; + + element.write(KM_MAGIC_NUMBER); + element.write(packageVersion); + kmDataStore.onSave(element); + return element; } private short computePrimitveDataSize() { diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAESKey.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAESKey.java index 7e34065e..0c3172c2 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAESKey.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAESKey.java @@ -43,10 +43,11 @@ public static void onSave(Element element, KMAESKey kmKey) { element.write(kmKey.aesKey); } - public static KMAESKey onRestore(Element element) { - AESKey aesKey = (AESKey) element.readObject(); - KMAESKey kmKey = new KMAESKey(aesKey); - return kmKey; + public static KMAESKey onRestore(AESKey aesKey) { + if (aesKey == null) { + return null; + } + return new KMAESKey(aesKey); } public static short getBackupPrimitiveByteCount() { diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java index 522f4edf..25a654f1 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java @@ -18,6 +18,8 @@ import org.globalplatform.upgrade.Element; import org.globalplatform.upgrade.UpgradeManager; +import javacard.framework.ISO7816; +import javacard.framework.ISOException; import javacard.framework.JCSystem; import javacard.framework.Util; import javacard.security.AESKey; @@ -60,8 +62,6 @@ public class KMAndroidSEProvider implements KMSEProvider { public static final short TMP_ARRAY_SIZE = 300; private static final short RSA_KEY_SIZE = 256; public static final short CERT_CHAIN_MAX_SIZE = 2500;//First 2 bytes for length. - private static final short ADDITIONAL_CERT_CHAIN_MAX_SIZE = 512;//First 2 bytes for length. - private static final short BCC_MAX_SIZE = 512; public static final short SHARED_SECRET_KEY_SIZE = 32; public static final byte POWER_RESET_FALSE = (byte) 0xAA; public static final byte POWER_RESET_TRUE = (byte) 0x00; @@ -92,35 +92,9 @@ public class KMAndroidSEProvider implements KMSEProvider { private KMRsaOAEPEncoding rsaOaepDecipher; private KMPoolManager poolMgr; - // 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; - // Entropy private RandomData rng; - //For storing root certificate and intermediate certificates. - private byte[] certificateChain; - private KMAESKey masterKey; - private KMECPrivateKey attestationKey; - private KMECDeviceUniqueKey testKey; - private KMECDeviceUniqueKey deviceUniqueKey; - private KMHmacKey preSharedKey; - private KMHmacKey computedHmacKey; - private byte[] additionalCertChain; - private byte[] bcc; + private boolean isProvisionLocked; private static KMAndroidSEProvider androidSEProvider = null; @@ -155,23 +129,9 @@ public KMAndroidSEProvider() { // Temporary transient array created to use locally inside functions. tmpArray = JCSystem.makeTransientByteArray(TMP_ARRAY_SIZE, JCSystem.CLEAR_ON_DESELECT); - + Util.arrayFillNonAtomic(tmpArray, (short) 0, TMP_ARRAY_SIZE, (byte) 0); // Random number generator initialisation. rng = RandomData.getInstance(RandomData.ALG_KEYGENERATION); - //Allocate buffer for certificate chain. - if (!isUpgrading()) { - certificateChain = new byte[CERT_CHAIN_MAX_SIZE]; - additionalCertChain = new byte[ADDITIONAL_CERT_CHAIN_MAX_SIZE]; - bcc = new byte[BCC_MAX_SIZE]; - // Initialize attestationKey and preShared key with zeros. - Util.arrayFillNonAtomic(tmpArray, (short) 0, TMP_ARRAY_SIZE, (byte) 0); - // Create attestation key of P-256 curve. - createAttestationKey(tmpArray, (short) 0, (short) 32); - // Pre-shared secret key length is 32 bytes. - createPresharedKey(tmpArray, (short) 0, (short) SHARED_SECRET_KEY_SIZE); - // Initialize the Computed Hmac Key object. - createComputedHmacKey(tmpArray, (short)0, (short) 32); - } androidSEProvider = this; resetFlag = JCSystem.makeTransientByteArray((short) 1, JCSystem.CLEAR_ON_DESELECT); @@ -603,6 +563,16 @@ public short hmacSign(byte[] keyBuf, short keyStart, short keyLength, HMACKey key = createHMACKey(keyBuf, keyStart, keyLength); return hmacSign(key, data, dataStart, dataLength, mac, macStart); } + + @Override + public short hmacSign(Object key, + byte[] data, short dataStart, short dataLength, byte[] mac, short macStart) { + if(!(key instanceof KMHmacKey)) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + KMHmacKey hmacKey = (KMHmacKey) key; + return hmacSign(hmacKey.getKey(), data, dataStart, dataLength, mac, macStart); + } @Override public short hmacKDF(KMMasterKey masterkey, byte[] data, short dataStart, @@ -894,91 +864,13 @@ public short cmacKDF(KMPreSharedKey pSharedKey, byte[] label, return key.getKey(keyBuf, keyStart); } - public void clearCertificateChain() { - JCSystem.beginTransaction(); - Util.arrayFillNonAtomic(certificateChain, (short) 0, CERT_CHAIN_MAX_SIZE, (byte) 0); - JCSystem.commitTransaction(); - } - - //This function supports multi-part request data. - public void persistPartialCertificateChain(byte[] buf, short offset, short len, short totalLen) { - // _____________________________________________________ - // | 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. - 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(); - } - - public short readCertificateChain(byte[] buf, short offset) { - short len = Util.getShort(certificateChain, (short) 0); - Util.arrayCopyNonAtomic(certificateChain, (short) 2, buf, offset, len); - return len; - } - - public short getCertificateChainLength() { - return Util.getShort(certificateChain, (short) 0); - } - - @Override - public void onSave(Element element) { - element.write(certificateChain); - element.write(additionalCertChain); - element.write(bcc); - KMAESKey.onSave(element, masterKey); - KMECPrivateKey.onSave(element, attestationKey); - KMHmacKey.onSave(element, preSharedKey); - } - - @Override - public void onRestore(Element element) { - certificateChain = (byte[]) element.readObject(); - additionalCertChain = (byte[]) element.readObject(); - bcc = (byte[]) element.readObject(); - masterKey = KMAESKey.onRestore(element); - attestationKey = KMECPrivateKey.onRestore(element); - preSharedKey = KMHmacKey.onRestore(element); - } - - @Override - public short getBackupPrimitiveByteCount() { - short count = - (short) (KMAESKey.getBackupPrimitiveByteCount() + - KMECPrivateKey.getBackupPrimitiveByteCount() + - KMHmacKey.getBackupPrimitiveByteCount()); - return count; - } - - @Override - public short getBackupObjectCount() { - short count = - (short) (1 /*Certificate chain */ + - KMAESKey.getBackupObjectCount() + - KMECPrivateKey.getBackupObjectCount() + - KMHmacKey.getBackupObjectCount()); - return count; - } - @Override public boolean isUpgrading() { return UpgradeManager.isUpgrading(); } @Override - public KMMasterKey createMasterKey(short keySizeBits) { + public KMMasterKey createMasterKey(KMMasterKey masterKey, short keySizeBits) { try { if (masterKey == null) { AESKey key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, @@ -986,7 +878,7 @@ public KMMasterKey createMasterKey(short keySizeBits) { masterKey = new KMAESKey(key); short keyLen = (short) (keySizeBits / 8); getTrueRandomNumber(tmpArray, (short) 0, keyLen); - masterKey.setKey(tmpArray, (short) 0); + ((KMAESKey)masterKey).setKey(tmpArray, (short) 0); } return (KMMasterKey) masterKey; } finally { @@ -994,7 +886,8 @@ public KMMasterKey createMasterKey(short keySizeBits) { } } - public KMAttestationKey createAttestationKey(byte[] keyData, short offset, + @Override + public KMAttestationKey createAttestationKey(KMAttestationKey attestationKey, byte[] keyData, short offset, short length) { if (attestationKey == null) { // Strongbox supports only P-256 curve for EC key. @@ -1002,11 +895,12 @@ public KMAttestationKey createAttestationKey(byte[] keyData, short offset, initECKey(ecKeyPair); attestationKey = new KMECPrivateKey(ecKeyPair); } - attestationKey.setS(keyData, offset, length); + ((KMECPrivateKey) attestationKey).setS(keyData, offset, length); return (KMAttestationKey) attestationKey; } - public KMPreSharedKey createPresharedKey(byte[] keyData, short offset, short length) { + @Override + public KMPreSharedKey createPreSharedKey(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); @@ -1016,12 +910,12 @@ public KMPreSharedKey createPresharedKey(byte[] keyData, short offset, short len false); preSharedKey = new KMHmacKey(key); } - preSharedKey.setKey(keyData, offset, length); + ((KMHmacKey)preSharedKey).setKey(keyData, offset, length); return (KMPreSharedKey) preSharedKey; } @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); } @@ -1030,23 +924,9 @@ 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 getMasterKey() { - return (KMMasterKey) masterKey; - } - - public KMAttestationKey getAttestationKey() { - return (KMAttestationKey) attestationKey; - } - - @Override - public KMPreSharedKey getPresharedKey() { - return (KMPreSharedKey) preSharedKey; - } @Override public short ecSign256(byte[] secret, short secretStart, short secretLength, @@ -1129,198 +1009,6 @@ public short getAttestationKeyAlgorithm() { return KMType.INVALID_VALUE; } - @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: - JCSystem.beginTransaction(); - attIdBrand = new byte[length]; - Util.arrayCopyNonAtomic(buffer, (short) start, attIdBrand, (short) 0, length); - JCSystem.commitTransaction(); - 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(); - 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(); - 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(); - 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(); - 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(); - 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(); - 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(); - 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; - if (poolMgr != null) { - poolMgr.powerReset(); - } - } - 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) length); - } @Override public short hkdf(byte[] ikm, short ikmOff, short ikmLen, byte[] salt, @@ -1420,8 +1108,9 @@ public short ecSign256(KMDeviceUniqueKey ecPrivKey, byte[] inputDataBuf, } } } - - private KMDeviceUniqueKey createDeviceUniqueKey(KMECDeviceUniqueKey key, + + @Override + public KMDeviceUniqueKey createDeviceUniqueKey(KMDeviceUniqueKey key, byte[] pubKey, short pubKeyOff, short pubKeyLen, byte[] privKey, short privKeyOff, short privKeyLen) { if (key == null) { @@ -1429,87 +1118,23 @@ private KMDeviceUniqueKey createDeviceUniqueKey(KMECDeviceUniqueKey key, initECKey(ecKeyPair); key = new KMECDeviceUniqueKey(ecKeyPair); } - key.setS(privKey, privKeyOff, privKeyLen); - key.setW(pubKey, pubKeyOff, pubKeyLen); + ((KMECDeviceUniqueKey) key).setS(privKey, privKeyOff, privKeyLen); + ((KMECDeviceUniqueKey) 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)); - } - - @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 ((short) (len + 2) > ADDITIONAL_CERT_CHAIN_MAX_SIZE) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + 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); } - JCSystem.beginTransaction(); - Util.setShort(additionalCertChain, (short) 0, (short) len); - Util.arrayCopyNonAtomic(buf, offset, additionalCertChain, - (short) 2, len); - JCSystem.commitTransaction(); - + ((KMHmacKey) rkpMacKey).setKey(keyData, offset, length); + return rkpMacKey; } - - @Override - public short getAdditionalCertChainLength() { - return Util.getShort(additionalCertChain, (short) 0); - } - - @Override - public byte[] getAdditionalCertChain() { - return additionalCertChain; - } - - - @Override - public byte[] getBootCertificateChain() { - return bcc; - } - - 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(); - } - + public void setProvisionLocked(boolean locked) { JCSystem.beginTransaction(); isProvisionLocked = locked; @@ -1537,9 +1162,16 @@ public short messageDigest256(byte[] inBuff, short inOffset, return len; } - @Override - public KMComputedHmacKey getComputedHmacKey() { - return computedHmacKey; + public boolean isPowerReset() { + boolean flag = false; + if (resetFlag[0] == POWER_RESET_TRUE) { + resetFlag[0] = POWER_RESET_FALSE; + flag = true; + if (poolMgr != null) { + poolMgr.powerReset(); + } + } + return flag; } private byte mapPurpose(short purpose) { @@ -1555,4 +1187,103 @@ private byte mapPurpose(short purpose) { } return -1; } + + @Override + public void onSave(Element element, byte interfaceType, Object object) { + element.write(interfaceType); + if (object == null) { + element.write(null); + return; + } + switch (interfaceType) { + case KMDataStoreConstants.INTERFACE_TYPE_COMPUTED_HMAC_KEY: + KMHmacKey.onSave(element, (KMHmacKey) object); + break; + case KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY: + KMAESKey.onSave(element, (KMAESKey) object); + break; + case KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY: + KMHmacKey.onSave(element, (KMHmacKey) object); + break; + case KMDataStoreConstants.INTERFACE_TYPE_ATTESTATION_KEY: + KMECPrivateKey.onSave(element, (KMECPrivateKey) object); + break; + case KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY: + KMECDeviceUniqueKey.onSave(element, (KMECDeviceUniqueKey) object); + break; + case KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY: + KMHmacKey.onSave(element, (KMHmacKey) object); + break; + default: + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } + } + + @Override + public Object onResore(Element element) { + if (element == null) { + return null; + } + byte interfaceType = element.readByte(); + switch (interfaceType) { + case KMDataStoreConstants.INTERFACE_TYPE_COMPUTED_HMAC_KEY: + return KMHmacKey.onRestore((HMACKey) element.readObject()); + case KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY: + return KMAESKey.onRestore((AESKey) element.readObject()); + case KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY: + return KMHmacKey.onRestore((HMACKey) element.readObject()); + case KMDataStoreConstants.INTERFACE_TYPE_ATTESTATION_KEY: + return KMECPrivateKey.onRestore((KeyPair) element.readObject()); + case KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY: + return KMECDeviceUniqueKey.onRestore((KeyPair) element.readObject()); + case KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY: + return KMHmacKey.onRestore((HMACKey) element.readObject()); + default: + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } + return null; + } + + @Override + public short getBackupPrimitiveByteCount(byte interfaceType) { + switch (interfaceType) { + case KMDataStoreConstants.INTERFACE_TYPE_COMPUTED_HMAC_KEY: + return KMHmacKey.getBackupPrimitiveByteCount(); + case KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY: + return KMAESKey.getBackupPrimitiveByteCount(); + case KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY: + return KMHmacKey.getBackupPrimitiveByteCount(); + case KMDataStoreConstants.INTERFACE_TYPE_ATTESTATION_KEY: + return KMECPrivateKey.getBackupPrimitiveByteCount(); + case KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY: + return KMECDeviceUniqueKey.getBackupPrimitiveByteCount(); + case KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY: + return KMHmacKey.getBackupPrimitiveByteCount(); + default: + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } + return 0; + } + + @Override + public short getBackupObjectCount(byte interfaceType) { + switch (interfaceType) { + case KMDataStoreConstants.INTERFACE_TYPE_COMPUTED_HMAC_KEY: + return KMHmacKey.getBackupObjectCount(); + case KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY: + return KMAESKey.getBackupObjectCount(); + case KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY: + return KMHmacKey.getBackupObjectCount(); + case KMDataStoreConstants.INTERFACE_TYPE_ATTESTATION_KEY: + return KMECPrivateKey.getBackupObjectCount(); + case KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY: + return KMECDeviceUniqueKey.getBackupObjectCount(); + case KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY: + return KMHmacKey.getBackupObjectCount(); + default: + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } + return 0; + } + } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMDataStoreConstants.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMDataStoreConstants.java new file mode 100644 index 00000000..31917a75 --- /dev/null +++ b/Applet/AndroidSEProviderLib/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/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java index 0f68de61..f7a96100 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java @@ -14,6 +14,8 @@ * limitations under the License. */ package com.android.javacard.seprovider; +import org.globalplatform.upgrade.Element; + import javacard.security.ECPrivateKey; import javacard.security.ECPublicKey; import javacard.security.KeyPair; @@ -49,5 +51,23 @@ public ECPrivateKey getPrivateKey() { public ECPublicKey getPublicKey() { return (ECPublicKey) ecKeyPair.getPublic(); } + + public static void onSave(Element element, KMECDeviceUniqueKey kmKey) { + element.write(kmKey.ecKeyPair); + } + + public static KMECDeviceUniqueKey onRestore(KeyPair ecKey) { + if (ecKey == null) { + return null; + } + return new KMECDeviceUniqueKey(ecKey); + } + public static short getBackupPrimitiveByteCount() { + return (short) 0; + } + + public static short getBackupObjectCount() { + return (short) 1; + } } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECPrivateKey.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECPrivateKey.java index 33372f97..0f9a7f8a 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECPrivateKey.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECPrivateKey.java @@ -47,10 +47,11 @@ public static void onSave(Element element, KMECPrivateKey kmKey) { element.write(kmKey.ecKeyPair); } - public static KMECPrivateKey onRestore(Element element) { - KeyPair ecKey = (KeyPair) element.readObject(); - KMECPrivateKey kmKey = new KMECPrivateKey(ecKey); - return kmKey; + public static KMECPrivateKey onRestore(KeyPair ecKey) { + if (ecKey == null) { + return null; + } + return new KMECPrivateKey(ecKey); } public static short getBackupPrimitiveByteCount() { diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java index a863bf88..bd4523a7 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java @@ -19,7 +19,7 @@ import javacard.security.HMACKey; -public class KMHmacKey implements KMPreSharedKey, KMComputedHmacKey { +public class KMHmacKey implements KMPreSharedKey, KMComputedHmacKey, KMRkpMacKey { private HMACKey hmacKey; @@ -47,10 +47,11 @@ public static void onSave(Element element, KMHmacKey kmKey) { element.write(kmKey.hmacKey); } - public static KMHmacKey onRestore(Element element) { - HMACKey hmacKey = (HMACKey) element.readObject(); - KMHmacKey kmKey = new KMHmacKey(hmacKey); - return kmKey; + public static KMHmacKey onRestore(HMACKey hmacKey) { + if (hmacKey == null) { + return null; + } + return new KMHmacKey(hmacKey); } public static short getBackupPrimitiveByteCount() { diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRkpMacKey.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRkpMacKey.java new file mode 100644 index 00000000..62116d24 --- /dev/null +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRkpMacKey.java @@ -0,0 +1,5 @@ +package com.android.javacard.seprovider; + + +public interface KMRkpMacKey { +} diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java index 18932ee5..4e7a229d 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java +++ b/Applet/AndroidSEProviderLib/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 @@ -554,17 +575,6 @@ KMOperation initAsymmetricOperation( short pubModStart, short pubModLength); - /** - * This operation creates the empty instance of KMAttestationCert for rsa or ec public key - * attestation certificate. It corresponds to attestKEy command from keymaster hal specifications. - * The attestation certificate implementation will comply keymaster hal specifications. - * - * @param rsaCert if true indicates that certificate will attest a rsa public key else if false it - * is for ec public key. - * @return An empty instance of KMAttestationCert implementation. - */ - //KMAttestationCert getAttestationCert(boolean rsaCert); - /** * This function tells if applet is upgrading or not. * @@ -577,10 +587,11 @@ KMOperation initAsymmetricOperation( * 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); /** * This function creates an HMACKey and initializes the key with the provided input key data. @@ -590,14 +601,7 @@ KMOperation initAsymmetricOperation( * @param length length of the buffer. * @return An instance of the KMComputedHmacKey. */ - KMComputedHmacKey createComputedHmacKey(byte[] keyData, short offset, short length); - - /** - * Returns the master key. - * - * @return Instance of the KMMasterKey - */ - KMMasterKey getMasterKey(); + KMComputedHmacKey createComputedHmacKey(KMComputedHmacKey computedHmacKey, byte[] keyData, short offset, short length); /** * Returns true if factory provisioned attestation key is supported. @@ -610,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. * @@ -670,69 +626,98 @@ 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); - + + /** + * 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); + /** - * Returns the instance KMDeviceUnique if it is created. + * 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 testMode Indicates if current execution is for test or production. - * @return instance of KMDeviceUniqueKey if present; null otherwise. + * @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. */ - KMDeviceUniqueKey getDeviceUniqueKey(boolean testMode); - + KMAttestationKey createAttestationKey(KMAttestationKey attestationKey, byte[] keyData, + short offset, + short length); + /** - * Persists the additional certificate chain in persistent memory. + * This function generates a HMAC key from the provided key buffers. * - * @param buf buffer containing the cbor 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 len length of the buffer. + * @param length is the length of the key. + * @return instance of KMPresharedKey. */ - void persistAdditionalCertChain(byte[] buf, short offset, short len); - + KMPreSharedKey createPreSharedKey(KMPreSharedKey presharedKey, byte[] key, short offset, + short length); + /** - * Returns the additional certificate chain length. + * This function saves the key objects while upgrade. * - * @return length of the encoded additional certificate 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. */ - short getAdditionalCertChainLength(); - + void onSave(Element element, byte interfaceType, Object object); + + /** + * This function restores the the object from element instance. + * + * @param element instance of the Element class. + * @return restored object. + */ + Object onResore(Element element); + /** - * Returns the additional certificate chain. + * This function returns the count of the primitive bytes required to + * be stored by the implementation of the interface type. * - * @return additional cert chain. + * @param interfaceType type interface of the parent object. + * @return count of the primitive bytes. */ - byte[] getAdditionalCertChain(); - + short getBackupPrimitiveByteCount(byte interfaceType); /** - * Returns the boot certificate chain. + * This function returns the object count required to be stored by the + * implementation of the interface type. * - * @return boot certificate chain. + * @param interfaceType type interface of the parent object. + * @return count of the objects. */ - byte[] getBootCertificateChain(); + short getBackupObjectCount(byte interfaceType); /** - * Returns the computed Hmac key. + * This function creates an HMACKey and initializes the key with the provided input key data. * - * @return Instance of the computed hmac key. + * @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. */ - KMComputedHmacKey getComputedHmacKey(); - + KMRkpMacKey createRkpMacKey(KMRkpMacKey createComputedHmacKey, byte[] keyData, + short offset, short length); + /** - * 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. + * Returns true if provision is locked. */ - short messageDigest256(byte[] inBuff, short inOffset, short inLength, byte[] outBuff, - short outOffset); - public boolean isProvisionLocked(); diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index d69cc841..2a6aee47 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -216,23 +216,26 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe protected static KMRepository repository; protected static KMSEProvider seProvider; protected static KMOperationState[] opTable; + protected static KMKeymintDataStore kmDataStore; protected static short[] tmpVariables; protected static short[] data; protected static byte[] wrappingKey; + public static void install(byte[] bArray, short bOffset, byte bLength) { + new KMAndroidSEApplet().register(bArray, (short) (bOffset + 1), bArray[bOffset]); + } + /** * Registers this applet. */ protected KMKeymasterApplet(KMSEProvider seImpl) { seProvider = seImpl; boolean isUpgrading = seProvider.isUpgrading(); - if (!isUpgrading) { - seProvider.createMasterKey(MASTER_KEY_SIZE); - } repository = new KMRepository(isUpgrading); encoder = new KMEncoder(); decoder = new KMDecoder(); + kmDataStore = new KMKeymintDataStore(seProvider, repository); data = JCSystem.makeTransientShortArray(DATA_ARRAY_SIZE, JCSystem.CLEAR_ON_DESELECT); tmpVariables = JCSystem.makeTransientShortArray(TMP_VARIABLE_ARRAY_SIZE, JCSystem.CLEAR_ON_DESELECT); @@ -244,18 +247,20 @@ protected KMKeymasterApplet(KMSEProvider seImpl) { opTable[index] = new KMOperationState(); index++; } - KMType.initialize(); - - // initialize default values - initHmacNonceAndSeed(); - initSystemBootParams((short)0,(short)0,(short)0,(short)0); - rkp = new RemotelyProvisionedComponentDevice(encoder, decoder, repository, seProvider); + KMType.initialize(); + if (!isUpgrading) { + kmDataStore.createMasterKey(MASTER_KEY_SIZE); + // initialize default values + initHmacNonceAndSeed(); + initSystemBootParams((short)0,(short)0,(short)0,(short)0); + } + rkp = new RemotelyProvisionedComponentDevice(encoder, decoder, repository, seProvider, kmDataStore); } protected void initHmacNonceAndSeed(){ short nonce = repository.alloc((short)32); - seProvider.newRandomNumber(repository.getHeap(), nonce, KMRepository.HMAC_SEED_NONCE_SIZE); - repository.initHmacNonce(repository.getHeap(), nonce, KMRepository.HMAC_SEED_NONCE_SIZE); + seProvider.newRandomNumber(repository.getHeap(), nonce, KMKeymintDataStore.HMAC_SEED_NONCE_SIZE); + kmDataStore.initHmacNonce(repository.getHeap(), nonce, KMKeymintDataStore.HMAC_SEED_NONCE_SIZE); } private void releaseAllOperations(){ @@ -529,7 +534,7 @@ private void freeOperations() { } private void processEarlyBootEndedCmd(APDU apdu) { - repository.setEarlyBootEndedStatus(true); + kmDataStore.setEarlyBootEndedStatus(true); } private short deviceLockedCmd(APDU apdu){ @@ -550,13 +555,13 @@ private void processDeviceLockedCmd(APDU apdu) { passwordOnly = KMInteger.cast(passwordOnly).getByte(); validateVerificationToken(verToken, scratchPad); short verTime = KMVerificationToken.cast(verToken).getTimestamp(); - short lastDeviceLockedTime = repository.getDeviceTimeStamp(); + short lastDeviceLockedTime = kmDataStore.getDeviceTimeStamp(); if (KMInteger.compare(verTime, lastDeviceLockedTime) > 0) { Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 8, (byte) 0); KMInteger.cast(verTime).getValue(scratchPad, (short) 0, (short) 8); - repository.setDeviceLock(true); - repository.setDeviceLockPasswordOnly(passwordOnly == 0x01); - repository.setDeviceLockTimestamp(scratchPad, (short) 0, (short) 8); + kmDataStore.setDeviceLock(true); + kmDataStore.setDeviceLockPasswordOnly(passwordOnly == 0x01); + kmDataStore.setDeviceLockTimestamp(scratchPad, (short) 0, (short) 8); } sendError(apdu, KMError.OK); } @@ -726,7 +731,7 @@ private void processGetHmacSharingParamCmd(APDU apdu) { // No Arguments // Create HMAC Sharing Parameters short params = KMHmacSharingParameters.instance(); - short nonce = repository.getHmacNonce(); + short nonce = kmDataStore.getHmacNonce(); short seed = KMByteBlob.instance((short) 0); KMHmacSharingParameters.cast(params).setNonce(nonce); KMHmacSharingParameters.cast(params).setSeed(seed); @@ -807,7 +812,7 @@ private void processComputeSharedHmacCmd(APDU apdu) { //tmpVariables[7] = 0; short found = 0; //tmpVariables[9] - short nonce = repository.getHmacNonce(); + short nonce = kmDataStore.getHmacNonce(); while (paramIndex < paramsLen) { // read HmacSharingParam @@ -872,7 +877,7 @@ private void processComputeSharedHmacCmd(APDU apdu) { //tmpVariables[6] short keyLen = seProvider.cmacKDF( - seProvider.getPresharedKey(), + kmDataStore.getPresharedKey(), ckdfLable, (short) 0, (short) ckdfLable.length, @@ -883,11 +888,11 @@ private void processComputeSharedHmacCmd(APDU apdu) { (short) 0); // persist the computed hmac key. - seProvider.createComputedHmacKey(scratchPad, (short) 0, keyLen); + kmDataStore.createComputedHmacKey(scratchPad, (short) 0, keyLen); // Generate sharingKey verification signature and store that in scratch pad. //tmpVariables[5] short signLen = - seProvider.hmacSign( + seProvider.hmacSign( scratchPad, (short) 0, keyLen, @@ -961,12 +966,12 @@ private void processUpgradeKeyCmd(APDU apdu) { parseEncryptedKeyBlob(data[KEY_BLOB], data[APP_ID], data[APP_DATA], scratchPad); boolean isKeyUpgradeRequired = false; // Check if key requires upgrade. - isKeyUpgradeRequired |= isKeyUpgradeRequired(KMType.OS_VERSION, repository.getOsVersion()); - isKeyUpgradeRequired |= isKeyUpgradeRequired(KMType.OS_PATCH_LEVEL, repository.getOsPatch()); + isKeyUpgradeRequired |= isKeyUpgradeRequired(KMType.OS_VERSION, kmDataStore.getOsVersion()); + isKeyUpgradeRequired |= isKeyUpgradeRequired(KMType.OS_PATCH_LEVEL, kmDataStore.getOsPatch()); isKeyUpgradeRequired |= - isKeyUpgradeRequired(KMType.VENDOR_PATCH_LEVEL, repository.getVendorPatchLevel()); + isKeyUpgradeRequired(KMType.VENDOR_PATCH_LEVEL, kmDataStore.getVendorPatchLevel()); // Get boot patch level. - seProvider.getBootPatchLevel(scratchPad, (short) 0); + kmDataStore.getBootPatchLevel(scratchPad, (short) 0); isKeyUpgradeRequired |= isKeyUpgradeRequired(KMType.BOOT_PATCH_LEVEL, KMInteger.uint_32(scratchPad, (short) 0)); @@ -1307,11 +1312,11 @@ private KMAttestationCert makeAttestationCert(short attKeyBlob, short attKeyPara addTags(hwParameters, true, cert); addTags(swParameters, false, cert); // Add Device Boot locked status - cert.deviceLocked(seProvider.isDeviceBootLocked()); + cert.deviceLocked(kmDataStore.isDeviceBootLocked()); // VB data cert.verifiedBootHash(getVerifiedBootHash(scratchPad)); cert.verifiedBootKey(getBootKey(scratchPad)); - cert.verifiedBootState((byte)seProvider.getBootState()); + cert.verifiedBootState((byte)kmDataStore.getBootState()); //TODO remove the following line makeKeyCharacteristics(scratchPad); @@ -1553,7 +1558,7 @@ private KMAttestationCert makeSelfSignedCert(short attPrivKey, short attPubKey, protected short getBootKey(byte[] scratchPad){ Util.arrayFillNonAtomic(scratchPad, (short)0, VERIFIED_BOOT_KEY_SIZE, (byte)0); - short len = seProvider.getBootKey(scratchPad, (short) 0); + short len = kmDataStore.getBootKey(scratchPad, (short) 0); if(len != VERIFIED_BOOT_KEY_SIZE) { KMException.throwIt(KMError.UNKNOWN_ERROR); } @@ -1562,7 +1567,7 @@ protected short getBootKey(byte[] scratchPad){ protected short getVerifiedBootHash(byte[] scratchPad){ Util.arrayFillNonAtomic(scratchPad, (short)0, VERIFIED_BOOT_HASH_SIZE, (byte)0); - short len = seProvider.getVerifiedBootHash(scratchPad, (short) 0); + short len = kmDataStore.getVerifiedBootHash(scratchPad, (short) 0); if(len != VERIFIED_BOOT_HASH_SIZE) { KMException.throwIt(KMError.UNKNOWN_ERROR); } @@ -1594,7 +1599,7 @@ private void addAttestationIds(KMAttestationCert cert, byte[] scratchPad) { attIdTag = KMKeyParameters.findTag(KMType.BYTES_TAG, attTags[index], data[KEY_PARAMETERS]); if (attIdTag != KMType.INVALID_VALUE) { attIdTagValue = KMByteTag.cast(attIdTag).getValue(); - storedAttIdLen = seProvider.getAttestationId(attTags[index],scratchPad, (short)0); + storedAttIdLen = kmDataStore.getAttestationId(attTags[index],scratchPad, (short)0); // Return CANNOT_ATTEST_IDS if Attestation IDs are not provisioned or // Attestation IDs are deleted. if (storedAttIdLen == 0) { @@ -1655,11 +1660,11 @@ private static void setUniqueId(KMAttestationCert cert, byte[] scratchPad) { 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, - seProvider.getMasterKey()); + kmDataStore.getMasterKey()); } private void processDestroyAttIdsCmd(APDU apdu) { - seProvider.deleteAttestationIds(); + kmDataStore.deleteAttestationIds(); sendError(apdu, KMError.OK); } @@ -1973,9 +1978,9 @@ private void authorizeKeyUsageForCount(byte[] scratchPad) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - if (repository.isAuthTagPersisted(data[AUTH_TAG])) { + if (kmDataStore.isAuthTagPersisted(data[AUTH_TAG])) { // Get current counter, update and increment it. - short len = repository + short len = kmDataStore .getRateLimitedKeyCount(data[AUTH_TAG], scratchPad, (short) (scratchPadOff + 4)); if (len != 4) { KMException.throwIt(KMError.UNKNOWN_ERROR); @@ -1990,12 +1995,12 @@ private void authorizeKeyUsageForCount(byte[] scratchPad) { KMUtils.add(scratchPad, scratchPadOff, (short) (scratchPadOff + len), (short) (scratchPadOff + len * 2)); - repository + kmDataStore .setRateLimitedKeyCount(data[AUTH_TAG], scratchPad, (short) (scratchPadOff + len * 2), len); } else { // Persist auth tag. - if (!repository.persistAuthTag(data[AUTH_TAG])) { + if (!kmDataStore.persistAuthTag(data[AUTH_TAG])) { KMException.throwIt(KMError.TOO_MANY_OPERATIONS); } } @@ -2008,19 +2013,19 @@ private void authorizeDeviceUnlock(byte[] scratchPad) { KMKeyParameters.findTag( KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED, data[HW_PARAMETERS]); - if (ptr != KMType.INVALID_VALUE && repository.getDeviceLock()) { + if (ptr != KMType.INVALID_VALUE && kmDataStore.getDeviceLock()) { if (!validateHwToken(data[HW_TOKEN], scratchPad)) { KMException.throwIt(KMError.DEVICE_LOCKED); } ptr = KMHardwareAuthToken.cast(data[HW_TOKEN]).getTimestamp(); // Check if the current auth time stamp is greater than device locked time stamp - short ts = repository.getDeviceTimeStamp(); + short ts = kmDataStore.getDeviceTimeStamp(); if (KMInteger.compare(ptr, ts) <= 0) { KMException.throwIt(KMError.DEVICE_LOCKED); } // Now check if the device unlock requires password only authentication and whether // auth token is generated through password authentication or not. - if (repository.getDeviceLockPasswordOnly()) { + if (kmDataStore.getDeviceLockPasswordOnly()) { ptr = KMHardwareAuthToken.cast(data[HW_TOKEN]).getHwAuthenticatorType(); ptr = KMEnum.cast(ptr).getVal(); if (((byte) ptr & KMType.PASSWORD) == 0) { @@ -2029,8 +2034,8 @@ private void authorizeDeviceUnlock(byte[] scratchPad) { } // Unlock the device // repository.deviceLockedFlag = false; - repository.setDeviceLock(false); - repository.clearDeviceLockTimeStamp(); + kmDataStore.setDeviceLock(false); + kmDataStore.clearDeviceLockTimeStamp(); } } @@ -2059,7 +2064,7 @@ private boolean verifyVerificationTokenMacInBigEndian(short verToken, byte[] scr ptr = KMVerificationToken.cast(verToken).getMac(); return seProvider.hmacVerify( - seProvider.getComputedHmacKey(), + kmDataStore.getComputedHmacKey(), scratchPad, (short) 0, len, @@ -2614,13 +2619,13 @@ private void authorizeAndBeginOperation(KMOperationState op, byte[] scratchPad) //Validate early boot //VTS expects error code EARLY_BOOT_ONLY during begin operation if eary boot ended tag is present - if (repository.getEarlyBootEndedStatus()) { + if (kmDataStore.getEarlyBootEndedStatus()) { KMTag.assertAbsence(data[HW_PARAMETERS], KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, KMError.EARLY_BOOT_ENDED); } //Validate bootloader only - if (repository.getBootEndedStatus()) { + if (kmDataStore.getBootEndedStatus()) { KMTag.assertAbsence(data[HW_PARAMETERS], KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY, KMError.INVALID_KEY_BLOB); } @@ -2766,7 +2771,7 @@ private void beginTrustedConfirmationOperation(KMOperationState op) { data[HW_PARAMETERS]) != KMType.INVALID_VALUE) { op.setTrustedConfirmationSigner( - seProvider.initTrustedConfirmationSymmetricOperation(seProvider.getComputedHmacKey())); + seProvider.initTrustedConfirmationSymmetricOperation(kmDataStore.getComputedHmacKey())); op.getTrustedConfirmationSigner().update( confirmationToken, @@ -2986,7 +2991,7 @@ private boolean verifyHwTokenMacInBigEndian(short hwToken, byte[] scratchPad) { ptr = KMHardwareAuthToken.cast(hwToken).getMac(); return seProvider.hmacVerify( - seProvider.getComputedHmacKey(), + kmDataStore.getComputedHmacKey(), scratchPad, (short) 0, len, @@ -3027,7 +3032,7 @@ private boolean verifyHwTokenMacInLittleEndian(short hwToken, byte[] scratchPad) ptr = KMHardwareAuthToken.cast(hwToken).getMac(); return seProvider.hmacVerify( - seProvider.getComputedHmacKey(), + kmDataStore.getComputedHmacKey(), scratchPad, (short) 0, len, @@ -3469,17 +3474,17 @@ private void processInitStrongBoxCmd(APDU apdu) { } public void reboot() { - repository.clearHmacNonce(); + kmDataStore.clearHmacNonce(); //flag to maintain the boot state - repository.setBootEndedStatus(false); + kmDataStore.setBootEndedStatus(false); //flag to maintain early boot ended state - repository.setEarlyBootEndedStatus(false); + kmDataStore.setEarlyBootEndedStatus(false); //Clear all the operation state. releaseAllOperations(); // Hmac is cleared, so generate a new Hmac nonce. initHmacNonceAndSeed(); // Clear all auth tags. - repository.removeAllAuthTags(); + kmDataStore.removeAllAuthTags(); } protected void initSystemBootParams(short osVersion, @@ -3493,21 +3498,21 @@ protected void initSystemBootParams(short osVersion, } protected void setOsVersion(short version){ - repository.setOsVersion( + kmDataStore.setOsVersion( KMInteger.cast(version).getBuffer(), KMInteger.cast(version).getStartOff(), KMInteger.cast(version).length()); } protected void setOsPatchLevel(short patch){ - repository.setOsPatch( + kmDataStore.setOsPatch( KMInteger.cast(patch).getBuffer(), KMInteger.cast(patch).getStartOff(), KMInteger.cast(patch).length()); } protected void setVendorPatchLevel(short patch){ - repository.setVendorPatchLevel( + kmDataStore.setVendorPatchLevel( KMInteger.cast(patch).getBuffer(), KMInteger.cast(patch).getStartOff(), KMInteger.cast(patch).length()); @@ -3858,7 +3863,7 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { KMIntegerTag.getValue( scratchPad, (short) 0, KMType.UINT_TAG, KMType.OS_VERSION, data[HW_PARAMETERS]); if (len != KMType.INVALID_VALUE) { - short provOsVersion = repository.getOsVersion(); + short provOsVersion = kmDataStore.getOsVersion(); short status = KMInteger.unsignedByteArrayCompare( KMInteger.cast(provOsVersion).getBuffer(), @@ -3877,7 +3882,7 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { KMIntegerTag.getValue( scratchPad, (short) 0, KMType.UINT_TAG, KMType.OS_PATCH_LEVEL, data[HW_PARAMETERS]); if (len != KMType.INVALID_VALUE) { - short osPatch = repository.getOsPatch(); + short osPatch = kmDataStore.getOsPatch(); short status = KMInteger.unsignedByteArrayCompare( KMInteger.cast(osPatch).getBuffer(), @@ -3894,7 +3899,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); + short len = kmDataStore.getBootPatchLevel(scratchPad,(short)0); if(len != BOOT_PATCH_LVL_SIZE){ KMException.throwIt(KMError.UNKNOWN_ERROR); } @@ -3902,9 +3907,9 @@ protected static short getBootPatchLevel(byte[] scratchPad){ } private static void makeKeyCharacteristics(byte[] scratchPad) { - short osVersion = repository.getOsVersion(); - short osPatch = repository.getOsPatch(); - short vendorPatch = repository.getVendorPatchLevel(); + short osVersion = kmDataStore.getOsVersion(); + short osPatch = kmDataStore.getOsPatch(); + short vendorPatch = kmDataStore.getVendorPatchLevel(); short bootPatch = getBootPatchLevel(scratchPad); data[SB_PARAMETERS] = KMKeyParameters.makeSbEnforced( data[KEY_PARAMETERS], (byte) data[ORIGIN], osVersion, osPatch, vendorPatch, bootPatch, scratchPad); @@ -3997,11 +4002,11 @@ private short parseEncryptedKeyBlob(short keyBlob, short appId, short appData, b // Read RoT public static short readROT(byte[] scratchPad) { Util.arrayFillNonAtomic(scratchPad,(short)0, (short)256,(byte)0); - short len = seProvider.getBootKey(scratchPad, (short)0); - len += seProvider.getVerifiedBootHash(scratchPad, (short)len); - short bootState = seProvider.getBootState(); + short len = kmDataStore.getBootKey(scratchPad, (short)0); + len += kmDataStore.getVerifiedBootHash(scratchPad, (short)len); + short bootState = kmDataStore.getBootState(); len = Util.setShort(scratchPad, len, bootState); - if(seProvider.isDeviceBootLocked()){ + if(kmDataStore.isDeviceBootLocked()){ scratchPad[len] = (byte)1; }else{ scratchPad[len] = (byte)0; @@ -4117,7 +4122,7 @@ private static short deriveKey(byte[] scratchPad) { // Consume only first 16 bytes as derived key. // Hmac sign. short len = seProvider.hmacKDF( - seProvider.getMasterKey(), + kmDataStore.getMasterKey(), repository.getHeap(), data[AUTH_DATA], data[AUTH_DATA_LENGTH], @@ -4306,7 +4311,7 @@ public static short generateBcc(boolean testMode, byte[] scratchPad) { if (!testMode && seProvider.isProvisionLocked()) { KMException.throwIt(KMError.STATUS_FAILED); } - KMDeviceUniqueKey deviceUniqueKey = seProvider.getDeviceUniqueKey(testMode); + KMDeviceUniqueKey deviceUniqueKey = kmDataStore.getDeviceUniqueKey(testMode); short temp = deviceUniqueKey.getPublicKey(scratchPad, (short) 0); short coseKey = KMCose.constructCoseKey( diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java b/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java new file mode 100644 index 00000000..94b7d6ec --- /dev/null +++ b/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java @@ -0,0 +1,844 @@ +package com.android.javacard.keymaster; + +import org.globalplatform.upgrade.Element; + +import com.android.javacard.seprovider.KMAESKey; +import com.android.javacard.seprovider.KMAttestationKey; +import com.android.javacard.seprovider.KMComputedHmacKey; +import com.android.javacard.seprovider.KMDataStoreConstants; +import com.android.javacard.seprovider.KMDeviceUniqueKey; +import com.android.javacard.seprovider.KMECDeviceUniqueKey; +import com.android.javacard.seprovider.KMECPrivateKey; +import com.android.javacard.seprovider.KMError; +import com.android.javacard.seprovider.KMException; +import com.android.javacard.seprovider.KMHmacKey; +import com.android.javacard.seprovider.KMMasterKey; +import com.android.javacard.seprovider.KMPreSharedKey; +import com.android.javacard.seprovider.KMRkpMacKey; +import com.android.javacard.seprovider.KMSEProvider; +import com.android.javacard.seprovider.KMType; +import com.android.javacard.seprovider.KMUpgradable; + +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.HMACKey; +import javacard.security.KeyBuilder; +import javacard.security.KeyPair; + +public class KMKeymintDataStore implements KMUpgradable { + + // Data table configuration + public static final short DATA_INDEX_SIZE = 17; + public static final short DATA_INDEX_ENTRY_SIZE = 4; + public static final short DATA_INDEX_ENTRY_LENGTH = 0; + public static final short DATA_INDEX_ENTRY_OFFSET = 2; + + //TODO reduced data table size from 2048 to 300. + public static final short DATA_MEM_SIZE = 300; + + // Data table offsets + public static final byte COMPUTED_HMAC_KEY = 0; + public static final byte HMAC_NONCE = 1; + public static final byte BOOT_OS_VERSION = 2; + public static final byte BOOT_OS_PATCH_LEVEL = 3; + public static final byte VENDOR_PATCH_LEVEL = 4; + public static final byte DEVICE_LOCKED_TIME = 5; + public static final byte DEVICE_LOCKED = 6; + public static final byte DEVICE_LOCKED_PASSWORD_ONLY = 7; + // Total 8 auth tags, so the next offset is AUTH_TAG_1 + 8 + public static final byte AUTH_TAG_1 = 8; + public static final byte BOOT_ENDED_FLAG = 15; + public static final byte EARLY_BOOT_ENDED_FLAG = 16; + + // Data Item sizes + public static final short HMAC_SEED_NONCE_SIZE = 32; + public static final short COMPUTED_HMAC_KEY_SIZE = 32; + public static final short OS_VERSION_SIZE = 4; + public static final short OS_PATCH_SIZE = 4; + public static final short VENDOR_PATCH_SIZE = 4; + public static final short DEVICE_LOCK_TS_SIZE = 8; + public static final short MAX_BLOB_STORAGE = 8; + 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); + private static final short MASTER_KEY_SIZE = 16; + private static final short SHARED_SECRET_KEY_SIZE = 32; + + private static final short ADDITIONAL_CERT_CHAIN_MAX_SIZE = 512;//First 2 bytes for length. + private static final short BCC_MAX_SIZE = 512; + + // 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 byte[] dataTable; + private short dataIndex; + private KMSEProvider seProvider; + private KMRepository repository; + private byte[] additionalCertChain; + private byte[] bcc; + private KMMasterKey masterKey; + private KMDeviceUniqueKey testDeviceUniqueKey; + private KMDeviceUniqueKey deviceUniqueKey; + private KMPreSharedKey preSharedKey; + private KMComputedHmacKey computedHmacKey; + private KMRkpMacKey rkpMacKey; + + public KMKeymintDataStore(KMSEProvider provider, KMRepository repo) { + seProvider = provider; + repository = repo; + boolean isUpgrading = provider.isUpgrading(); + initDataTable(isUpgrading); + //Initialize the device locked status + if (!isUpgrading) { + additionalCertChain = new byte[ADDITIONAL_CERT_CHAIN_MAX_SIZE]; + bcc = new byte[BCC_MAX_SIZE]; + setDeviceLock(false); + setDeviceLockPasswordOnly(false); + } +// initializeCertificateDataBuffer(isUpgrading, factoryAttestSupport); + } + + private void initDataTable(boolean isUpgrading) { + if (!isUpgrading) { + if (dataTable == null) { + dataTable = new byte[DATA_MEM_SIZE]; + dataIndex = (short) (DATA_INDEX_SIZE * DATA_INDEX_ENTRY_SIZE); + } + } + } + + private short dataAlloc(short length) { + if (((short) (dataIndex + length)) > dataTable.length) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } + dataIndex += length; + return (short) (dataIndex - length); + } + + private void clearDataEntry(short id) { + id = (short) (id * DATA_INDEX_ENTRY_SIZE); + short dataLen = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH)); + if (dataLen != 0) { + short dataPtr = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET)); + JCSystem.beginTransaction(); + Util.arrayFillNonAtomic(dataTable, dataPtr, dataLen, (byte) 0); + JCSystem.commitTransaction(); + } + } + + private void writeDataEntry(short id, byte[] buf, short offset, short len) { + short dataPtr; + id = (short) (id * DATA_INDEX_ENTRY_SIZE); + short dataLen = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH)); + if (dataLen == 0) { + dataPtr = dataAlloc(len); + 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(); + } else { + if (len != dataLen) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } + dataPtr = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET)); + JCSystem.beginTransaction(); + Util.arrayCopyNonAtomic(buf, offset, dataTable, dataPtr, len); + JCSystem.commitTransaction(); + } + } + + private short readDataEntry(short id, byte[] buf, short offset) { + id = (short) (id * DATA_INDEX_ENTRY_SIZE); + short len = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH)); + if (len != 0) { + Util.arrayCopyNonAtomic( + dataTable, + Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET)), + buf, + offset, + len); + } + return len; + } + + private short dataLength(short id) { + id = (short) (id * DATA_INDEX_ENTRY_SIZE); + return Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH)); + } + + 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()); + return blob; + } + return KMType.INVALID_VALUE; + } + + public short getHmacNonce() { + return readData(HMAC_NONCE); + } + + 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()); + } else { + return KMInteger.uint_32(zero, (short) 0); + } + } + + 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()); + } else { + return KMInteger.uint_32(zero, (short) 0); + } + } + + 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()); + } else { + return KMInteger.uint_32(zero, (short) 0); + } + } + + private boolean readBoolean(short id) { + short blob = readData(id); + if (blob == KMType.INVALID_VALUE) { + KMException.throwIt(KMError.INVALID_DATA); + } + return (byte) ((repository.getHeap())[KMByteBlob.cast(blob).getStartOff()]) == 0x01; + } + + public boolean getDeviceLock() { + return readBoolean(DEVICE_LOCKED); + } + + public boolean getDeviceLockPasswordOnly() { + return readBoolean(DEVICE_LOCKED_PASSWORD_ONLY); + } + + public boolean getEarlyBootEndedStatus() { + return readBoolean(EARLY_BOOT_ENDED_FLAG); + } + + public boolean getBootEndedStatus() { + return readBoolean(BOOT_ENDED_FLAG); + } + + 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()); + } else { + return KMInteger.uint_64(zero, (short) 0); + } + } + + public void setOsVersion(byte[] buf, short start, short len) { + if (len != OS_VERSION_SIZE) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + writeDataEntry(BOOT_OS_VERSION, buf, start, len); + } + + public void setVendorPatchLevel(byte[] buf, short start, short len) { + if (len != VENDOR_PATCH_SIZE) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + writeDataEntry(VENDOR_PATCH_LEVEL, buf, start, len); + } + + private void writeBoolean(short id, boolean flag) { + short start = repository.alloc((short) 1); + if (flag) { + (repository.getHeap())[start] = (byte) 0x01; + } else { + (repository.getHeap())[start] = (byte) 0x00; + } + writeDataEntry(id, repository.getHeap(), start, (short) 1); + } + + public void setDeviceLock(boolean flag) { + writeBoolean(DEVICE_LOCKED, flag); + } + + public void setDeviceLockPasswordOnly(boolean flag) { + writeBoolean(DEVICE_LOCKED_PASSWORD_ONLY, flag); + } + + public void setDeviceLockTimestamp(byte[] buf, short start, short len) { + if (len != DEVICE_LOCK_TS_SIZE) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + writeDataEntry(DEVICE_LOCKED_TIME, buf, start, len); + } + + public void setEarlyBootEndedStatus(boolean flag) { + writeBoolean(EARLY_BOOT_ENDED_FLAG, flag); + } + + public void setBootEndedStatus(boolean flag) { + writeBoolean(BOOT_ENDED_FLAG, flag); + } + + public void clearDeviceLockTimeStamp() { + clearDataEntry(DEVICE_LOCKED_TIME); + } + + public void setOsPatch(byte[] buf, short start, short len) { + if (len != OS_PATCH_SIZE) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + writeDataEntry(BOOT_OS_PATCH_LEVEL, buf, start, len); + } + + private boolean isAuthTagSlotAvailable(short tagId, byte[] buf, short offset) { + readDataEntry(tagId, buf, offset); + return (0 == buf[offset]); + } + + public void initHmacNonce(byte[] nonce, short offset, short len) { + if (len != HMAC_SEED_NONCE_SIZE) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + writeDataEntry(HMAC_NONCE, nonce, offset, len); + } + + public void clearHmacNonce() { + clearDataEntry(HMAC_NONCE); + } + + public boolean persistAuthTag(short authTag) { + + if (KMByteBlob.cast(authTag).length() != AUTH_TAG_LENGTH) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + + short authTagEntry = repository.alloc(AUTH_TAG_ENTRY_SIZE); + short scratchPadOff = repository.alloc(AUTH_TAG_ENTRY_SIZE); + byte[] scratchPad = repository.getHeap(); + writeAuthTagState(repository.getHeap(), authTagEntry, (byte) 1); + Util.arrayCopyNonAtomic( + KMByteBlob.cast(authTag).getBuffer(), + KMByteBlob.cast(authTag).getStartOff(), + repository.getHeap(), (short) (authTagEntry + 1), AUTH_TAG_LENGTH); + Util.setShort(repository.getHeap(), (short) (authTagEntry + AUTH_TAG_LENGTH + 1 + 2), + (short) 1); + short index = 0; + while (index < MAX_BLOB_STORAGE) { + if ((dataLength((short) (index + AUTH_TAG_1)) == 0) || + isAuthTagSlotAvailable((short) (index + AUTH_TAG_1), scratchPad, scratchPadOff)) { + + writeDataEntry((short) (index + AUTH_TAG_1), repository.getHeap(), authTagEntry, AUTH_TAG_ENTRY_SIZE); + return true; + } + index++; + } + return false; + } + + public void removeAllAuthTags() { + short index = 0; + while (index < MAX_BLOB_STORAGE) { + clearDataEntry((short) (index + AUTH_TAG_1)); + index++; + } + } + + public boolean isAuthTagPersisted(short authTag) { + return (KMType.INVALID_VALUE != findTag(authTag)); + } + + private short findTag(short authTag) { + if (KMByteBlob.cast(authTag).length() != AUTH_TAG_LENGTH) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + short index = 0; + short found; + short offset = repository.alloc(AUTH_TAG_ENTRY_SIZE); + while (index < MAX_BLOB_STORAGE) { + if (dataLength((short) (index + AUTH_TAG_1)) != 0) { + readDataEntry((short) (index + AUTH_TAG_1), + repository.getHeap(), offset); + found = + Util.arrayCompare( + repository.getHeap(), + (short) (offset + 1), + KMByteBlob.cast(authTag).getBuffer(), + KMByteBlob.cast(authTag).getStartOff(), + AUTH_TAG_LENGTH); + if (found == 0) { + return (short) (index + AUTH_TAG_1); + } + } + index++; + } + return KMType.INVALID_VALUE; + } + + public short getRateLimitedKeyCount(short authTag, byte[] out, short outOff) { + short tag = findTag(authTag); + short blob; + if (tag != KMType.INVALID_VALUE) { + blob = readData(tag); + Util.arrayCopyNonAtomic( + KMByteBlob.cast(blob).getBuffer(), + (short) (KMByteBlob.cast(blob).getStartOff() + AUTH_TAG_LENGTH + 1), + out, + outOff, + AUTH_TAG_COUNTER_SIZE); + return AUTH_TAG_COUNTER_SIZE; + } + return (short) 0; + } + + public void setRateLimitedKeyCount(short authTag, byte[] buf, short off, short len) { + short tag = findTag(authTag); + if (tag != KMType.INVALID_VALUE) { + short dataPtr = readData(tag); + Util.arrayCopyNonAtomic( + buf, + off, + KMByteBlob.cast(dataPtr).getBuffer(), + (short) (KMByteBlob.cast(dataPtr).getStartOff() + AUTH_TAG_LENGTH + 1), + len); + writeDataEntry(tag, + KMByteBlob.cast(dataPtr).getBuffer(), + KMByteBlob.cast(dataPtr).getStartOff(), + KMByteBlob.cast(dataPtr).length()); + } + } + + 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 ((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(); + + } + + public short getAdditionalCertChainLength() { + return Util.getShort(additionalCertChain, (short) 0); + } + + public byte[] getAdditionalCertChain() { + return additionalCertChain; + } + + public byte[] getBootCertificateChain() { + return bcc; + } + + 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(); + } + + private void writeAuthTagState(byte[] buf, short offset, byte state) { + buf[offset] = state; + } + + public KMMasterKey createMasterKey(short keySizeBits) { + if (masterKey == null) { + masterKey = seProvider.createMasterKey(masterKey, keySizeBits); + } + return (KMMasterKey) masterKey; + } + + public KMMasterKey getMasterKey() { + return masterKey; + } + + public void createPresharedKey(byte[] keyData, short offset, short length) { + if (length != SHARED_SECRET_KEY_SIZE) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + if (preSharedKey == null) { + preSharedKey = seProvider.createPreSharedKey(preSharedKey, keyData, offset, length); + } + } + + public KMPreSharedKey getPresharedKey() { + return preSharedKey; + } + + public void createComputedHmacKey(byte[] keyData, short offset, short length) { + if (length != COMPUTED_HMAC_KEY_SIZE) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + if (computedHmacKey == null) { + computedHmacKey = seProvider.createComputedHmacKey(computedHmacKey, keyData, offset, length); + } else { + seProvider.createComputedHmacKey(computedHmacKey, keyData, offset, length); + } + } + + public KMComputedHmacKey getComputedHmacKey() { + return computedHmacKey; + } + + public KMDeviceUniqueKey createTestDeviceUniqueKey(byte[] pubKey, short pubKeyOff, short pubKeyLen, + byte[] privKey, short privKeyOff, short privKeyLen) { + if (testDeviceUniqueKey == null) { + testDeviceUniqueKey = seProvider.createDeviceUniqueKey(testDeviceUniqueKey, pubKey, pubKeyOff, + pubKeyLen, privKey, + privKeyOff, privKeyLen); + } else { + seProvider.createDeviceUniqueKey(testDeviceUniqueKey, pubKey, pubKeyOff, pubKeyLen, privKey, + privKeyOff, + privKeyLen); + } + return testDeviceUniqueKey; + } + + public KMDeviceUniqueKey createDeviceUniqueKey(byte[] pubKey, short pubKeyOff, short pubKeyLen, + byte[] privKey, short privKeyOff, + short privKeyLen) { + if (deviceUniqueKey == null) { + deviceUniqueKey = seProvider.createDeviceUniqueKey(deviceUniqueKey, pubKey, pubKeyOff, + pubKeyLen, privKey, + privKeyOff, privKeyLen); + } else { + seProvider.createDeviceUniqueKey(deviceUniqueKey, pubKey, pubKeyOff, pubKeyLen, privKey, + privKeyOff, privKeyLen); + } + return deviceUniqueKey; + } + + public KMDeviceUniqueKey getDeviceUniqueKey(boolean testMode) { + return ((KMDeviceUniqueKey) (testMode ? testDeviceUniqueKey : deviceUniqueKey)); + } + + public void createRkpMacKey(byte[] keydata, short offset, short length) { + if (rkpMacKey == null) { + rkpMacKey = seProvider.createRkpMacKey(rkpMacKey, keydata, offset, length); + } else { + seProvider.createRkpMacKey(rkpMacKey, keydata, offset, length); + } + } + + public KMRkpMacKey getRkpMacacKey() { + return rkpMacKey; + } + + 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: + JCSystem.beginTransaction(); + attIdBrand = new byte[length]; + Util.arrayCopyNonAtomic(buffer, (short) start, attIdBrand, (short) 0, length); + JCSystem.commitTransaction(); + 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(); + 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(); + 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(); + 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(); + 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(); + 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(); + 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(); + break; + } + } + + public void deleteAttestationIds() { + attIdBrand = null; + attIdDevice = null; + attIdProduct = null; + attIdSerial = null; + attIdImei = null; + attIdMeId = null; + attIdManufacturer = null; + attIdModel = null; + } + + public short getVerifiedBootHash(byte[] buffer, short start) { + Util.arrayCopyNonAtomic(verifiedHash, (short) 0, buffer, start, (short) verifiedHash.length); + return (short) verifiedHash.length; + } + + public short getBootKey(byte[] buffer, short start) { + Util.arrayCopyNonAtomic(bootKey, (short) 0, buffer, start, (short) bootKey.length); + return (short) bootKey.length; + } + + public short getBootState() { + return bootState; + } + + public boolean isDeviceBootLocked() { + return deviceBootLocked; + } + + 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) length); + } + + + @Override + public void onSave(Element element) { + // Prmitives + element.write(dataIndex); + element.write(deviceBootLocked); + element.write(bootState); + // Objects + element.write(dataTable); + // element.write(certificateData); + element.write(attIdBrand); + element.write(attIdDevice); + element.write(attIdProduct); + element.write(attIdSerial); + element.write(attIdImei); + element.write(attIdMeId); + element.write(attIdManufacturer); + element.write(attIdModel); + element.write(verifiedHash); + element.write(bootKey); + element.write(bootPatchLevel); + element.write(additionalCertChain); + element.write(bcc); + // Key Objects + seProvider.onSave(element, KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY, masterKey); + seProvider.onSave(element, KMDataStoreConstants.INTERFACE_TYPE_COMPUTED_HMAC_KEY, + computedHmacKey); + seProvider.onSave(element, KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY, preSharedKey); + seProvider.onSave(element, KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY, deviceUniqueKey); + seProvider.onSave(element, KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY, rkpMacKey); + } + + @Override + public void onRestore(Element element) { + // Read Primitives + dataIndex = element.readShort(); + deviceBootLocked = element.readBoolean(); + bootState = element.readShort(); + // Read Objects + dataTable = (byte[]) element.readObject(); +// certificateData = (byte[]) element.readObject(); + attIdBrand = (byte[]) element.readObject(); + attIdDevice = (byte[]) element.readObject(); + attIdProduct = (byte[]) element.readObject(); + attIdSerial = (byte[]) element.readObject(); + attIdImei = (byte[]) element.readObject(); + attIdMeId = (byte[]) element.readObject(); + attIdManufacturer = (byte[]) element.readObject(); + attIdModel = (byte[]) element.readObject(); + verifiedHash = (byte[]) element.readObject(); + bootKey = (byte[]) element.readObject(); + bootPatchLevel = (byte[]) element.readObject(); + additionalCertChain = (byte[]) element.readObject(); + bcc = (byte[]) element.readObject(); + // Read Key Objects + masterKey = (KMMasterKey) seProvider.onResore(element); + computedHmacKey = (KMComputedHmacKey) seProvider.onResore(element); + preSharedKey = (KMPreSharedKey) seProvider.onResore(element); + deviceUniqueKey = (KMDeviceUniqueKey) seProvider.onResore(element); + rkpMacKey = (KMRkpMacKey) seProvider.onResore(element); + } + + @Override + public short getBackupPrimitiveByteCount() { + // Magic Number - 1 byte + // Package Version - 2 bytes + // dataIndex - 2 bytes + // deviceLocked - 1 byte + // deviceState = 2 bytes + // interface types - 4 bytes + return (short) (12 + + seProvider.getBackupPrimitiveByteCount(KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY) + + seProvider.getBackupPrimitiveByteCount( + KMDataStoreConstants.INTERFACE_TYPE_COMPUTED_HMAC_KEY) + + seProvider.getBackupPrimitiveByteCount(KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY) + + seProvider.getBackupPrimitiveByteCount( KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY) + + seProvider.getBackupPrimitiveByteCount(KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY)); + } + + @Override + public short getBackupObjectCount() { + // dataTable - 1 + // AttestationIds - 8 + // bootParameters - 3 + // AdditionalCertificateChain - 1 + // BCC - 1 + return (short) (14 + + seProvider.getBackupObjectCount(KMDataStoreConstants.INTERFACE_TYPE_COMPUTED_HMAC_KEY) + + seProvider.getBackupObjectCount(KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY) + + seProvider.getBackupObjectCount(KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY) + + seProvider.getBackupObjectCount(KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY) + + seProvider.getBackupObjectCount( + KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY)); + } + +} diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index 03791210..0a158878 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -16,6 +16,7 @@ package com.android.javacard.keymaster; +import org.globalplatform.upgrade.Element; import com.android.javacard.seprovider.KMException; import com.android.javacard.seprovider.KMUpgradable; import org.globalplatform.upgrade.Element; @@ -29,50 +30,13 @@ * KMRepository class manages persistent and volatile memory usage by the applet. Note the * repository is only used by applet and it is not intended to be used by seProvider. */ -public class KMRepository implements KMUpgradable { +public class KMRepository { public static final short HEAP_SIZE = 15000; - // Data table configuration - public static final short DATA_INDEX_SIZE = 17; - public static final short DATA_INDEX_ENTRY_SIZE = 4; - public static final short DATA_INDEX_ENTRY_LENGTH = 0; - public static final short DATA_INDEX_ENTRY_OFFSET = 2; - - //TODO reduced data table size from 2048 to 300. - public static final short DATA_MEM_SIZE = 300; - - // Data table offsets - public static final byte COMPUTED_HMAC_KEY = 0; - public static final byte HMAC_NONCE = 1; - public static final byte BOOT_OS_VERSION = 2; - public static final byte BOOT_OS_PATCH_LEVEL = 3; - public static final byte VENDOR_PATCH_LEVEL = 4; - public static final byte DEVICE_LOCKED_TIME = 5; - public static final byte DEVICE_LOCKED = 6; - public static final byte DEVICE_LOCKED_PASSWORD_ONLY = 7; - // Total 8 auth tags, so the next offset is AUTH_TAG_1 + 8 - public static final byte AUTH_TAG_1 = 8; - public static final byte BOOT_ENDED_FLAG = 15; - public static final byte EARLY_BOOT_ENDED_FLAG = 16; - - // Data Item sizes - public static final short HMAC_SEED_NONCE_SIZE = 32; - public static final short COMPUTED_HMAC_KEY_SIZE = 32; - public static final short OS_VERSION_SIZE = 4; - public static final short OS_PATCH_SIZE = 4; - public static final short VENDOR_PATCH_SIZE = 4; - public static final short DEVICE_LOCK_TS_SIZE = 8; - public static final short MAX_BLOB_STORAGE = 8; - 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); - // Class Attributes private byte[] heap; private short[] heapIndex; - private byte[] dataTable; - private short dataIndex; private short reclaimIndex; // Singleton instance @@ -83,30 +47,12 @@ public static KMRepository instance() { } public KMRepository(boolean isUpgrading) { - newDataTable(isUpgrading); heap = JCSystem.makeTransientByteArray(HEAP_SIZE, JCSystem.CLEAR_ON_RESET); heapIndex = JCSystem.makeTransientShortArray((short)1, JCSystem.CLEAR_ON_RESET); reclaimIndex = HEAP_SIZE; - - //Initialize the device locked status - if (!isUpgrading) { - setDeviceLock(false); - setDeviceLockPasswordOnly(false); - } repository = this; } - public void initHmacNonce(byte[] nonce, short offset, short len) { - if (len != HMAC_SEED_NONCE_SIZE) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - writeDataEntry(HMAC_NONCE, nonce, offset, len); - } - - public void clearHmacNonce() { - clearDataEntry(HMAC_NONCE); - } - public void onUninstall() { // Javacard Runtime environment cleans up the data. @@ -165,348 +111,8 @@ public short alloc(short length) { return (short) (heapIndex[0] - length); } - private short dataAlloc(short length) { - if (((short) (dataIndex + length)) > dataTable.length) { - ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); - } - dataIndex += length; - return (short) (dataIndex - length); - } - - private void newDataTable(boolean isUpgrading) { - if (!isUpgrading) { - if (dataTable == null) { - dataTable = new byte[DATA_MEM_SIZE]; - dataIndex = (short) (DATA_INDEX_SIZE * DATA_INDEX_ENTRY_SIZE); - } - } - } - - private void clearDataEntry(short id) { - id = (short) (id * DATA_INDEX_ENTRY_SIZE); - short dataLen = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH)); - if (dataLen != 0) { - short dataPtr = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET)); - JCSystem.beginTransaction(); - Util.arrayFillNonAtomic(dataTable, dataPtr, dataLen, (byte) 0); - JCSystem.commitTransaction(); - } - } - - private void writeDataEntry(short id, byte[] buf, short offset, short len) { - short dataPtr; - id = (short) (id * DATA_INDEX_ENTRY_SIZE); - short dataLen = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH)); - if (dataLen == 0) { - dataPtr = dataAlloc(len); - 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(); - } else { - if (len != dataLen) { - KMException.throwIt(KMError.UNKNOWN_ERROR); - } - dataPtr = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET)); - JCSystem.beginTransaction(); - Util.arrayCopyNonAtomic(buf, offset, dataTable, dataPtr, len); - JCSystem.commitTransaction(); - } - } - - private short readDataEntry(short id, byte[] buf, short offset) { - id = (short) (id * DATA_INDEX_ENTRY_SIZE); - short len = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH)); - if (len != 0) { - Util.arrayCopyNonAtomic( - dataTable, - Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET)), - buf, - offset, - len); - } - return len; - } - - private short dataLength(short id) { - id = (short) (id * DATA_INDEX_ENTRY_SIZE); - return Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH)); - } - public byte[] getHeap() { return heap; } - public short getHmacNonce() { - return readData(HMAC_NONCE); - } - - 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()); - 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()); - } else { - return KMInteger.uint_32(zero, (short) 0); - } - } - - 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()); - } else { - return KMInteger.uint_32(zero, (short) 0); - } - } - - 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()); - } else { - return KMInteger.uint_32(zero, (short) 0); - } - } - - private boolean readBoolean(short id) { - short blob = readData(id); - if (blob == KMType.INVALID_VALUE) { - KMException.throwIt(KMError.INVALID_DATA); - } - return (byte) ((getHeap())[KMByteBlob.cast(blob).getStartOff()]) == 0x01; - } - - public boolean getDeviceLock() { - return readBoolean(DEVICE_LOCKED); - } - - public boolean getDeviceLockPasswordOnly() { - return readBoolean(DEVICE_LOCKED_PASSWORD_ONLY); - } - - public boolean getEarlyBootEndedStatus() { - return readBoolean(EARLY_BOOT_ENDED_FLAG); - } - - public boolean getBootEndedStatus() { - return readBoolean(BOOT_ENDED_FLAG); - } - - 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()); - } else { - return KMInteger.uint_64(zero, (short) 0); - } - } - - public void setOsVersion(byte[] buf, short start, short len) { - if (len != OS_VERSION_SIZE) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - writeDataEntry(BOOT_OS_VERSION, buf, start, len); - } - - public void setVendorPatchLevel(byte[] buf, short start, short len) { - if (len != VENDOR_PATCH_SIZE) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - writeDataEntry(VENDOR_PATCH_LEVEL, buf, start, len); - } - - private void writeBoolean(short id, boolean flag) { - short start = alloc((short) 1); - if (flag) { - (getHeap())[start] = (byte) 0x01; - } else { - (getHeap())[start] = (byte) 0x00; - } - writeDataEntry(id, getHeap(), start, (short) 1); - } - - public void setDeviceLock(boolean flag) { - writeBoolean(DEVICE_LOCKED, flag); - } - - public void setDeviceLockPasswordOnly(boolean flag) { - writeBoolean(DEVICE_LOCKED_PASSWORD_ONLY, flag); - } - - public void setDeviceLockTimestamp(byte[] buf, short start, short len) { - if (len != DEVICE_LOCK_TS_SIZE) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - writeDataEntry(DEVICE_LOCKED_TIME, buf, start, len); - } - - public void setEarlyBootEndedStatus(boolean flag) { - writeBoolean(EARLY_BOOT_ENDED_FLAG, flag); - } - - public void setBootEndedStatus(boolean flag) { - writeBoolean(BOOT_ENDED_FLAG, flag); - } - - public void clearDeviceLockTimeStamp() { - clearDataEntry(DEVICE_LOCKED_TIME); - } - - public void setOsPatch(byte[] buf, short start, short len) { - if (len != OS_PATCH_SIZE) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - writeDataEntry(BOOT_OS_PATCH_LEVEL, buf, start, len); - } - - private boolean isAuthTagSlotAvailable(short tagId, byte[] buf, short offset) { - readDataEntry(tagId, buf, offset); - return (0 == buf[offset]); - } - - private void writeAuthTagState(byte[] buf, short offset, byte state) { - buf[offset] = state; - } - - public boolean persistAuthTag(short authTag) { - - if (KMByteBlob.cast(authTag).length() != AUTH_TAG_LENGTH) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - - short authTagEntry = alloc(AUTH_TAG_ENTRY_SIZE); - short scratchPadOff = alloc(AUTH_TAG_ENTRY_SIZE); - byte[] scratchPad = getHeap(); - writeAuthTagState(getHeap(), authTagEntry, (byte) 1); - Util.arrayCopyNonAtomic( - KMByteBlob.cast(authTag).getBuffer(), - KMByteBlob.cast(authTag).getStartOff(), - getHeap(), (short) (authTagEntry + 1), AUTH_TAG_LENGTH); - Util.setShort(getHeap(), (short) (authTagEntry + AUTH_TAG_LENGTH + 1 + 2), - (short) 1); - short index = 0; - while (index < MAX_BLOB_STORAGE) { - if ((dataLength((short) (index + AUTH_TAG_1)) == 0) || - isAuthTagSlotAvailable((short) (index + AUTH_TAG_1), scratchPad, scratchPadOff)) { - - writeDataEntry((short) (index + AUTH_TAG_1), getHeap(), authTagEntry, AUTH_TAG_ENTRY_SIZE); - return true; - } - index++; - } - return false; - } - - public void removeAllAuthTags() { - short index = 0; - while (index < MAX_BLOB_STORAGE) { - clearDataEntry((short) (index + AUTH_TAG_1)); - index++; - } - } - - public boolean isAuthTagPersisted(short authTag) { - return (KMType.INVALID_VALUE != findTag(authTag)); - } - - private short findTag(short authTag) { - if (KMByteBlob.cast(authTag).length() != AUTH_TAG_LENGTH) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - short index = 0; - short found; - short offset = alloc(AUTH_TAG_ENTRY_SIZE); - while (index < MAX_BLOB_STORAGE) { - if (dataLength((short) (index + AUTH_TAG_1)) != 0) { - readDataEntry((short) (index + AUTH_TAG_1), - getHeap(), offset); - found = - Util.arrayCompare( - getHeap(), - (short) (offset + 1), - KMByteBlob.cast(authTag).getBuffer(), - KMByteBlob.cast(authTag).getStartOff(), - AUTH_TAG_LENGTH); - if (found == 0) { - return (short) (index + AUTH_TAG_1); - } - } - index++; - } - return KMType.INVALID_VALUE; - } - - public short getRateLimitedKeyCount(short authTag, byte[] out, short outOff) { - short tag = findTag(authTag); - short blob; - if (tag != KMType.INVALID_VALUE) { - blob = readData(tag); - Util.arrayCopyNonAtomic( - KMByteBlob.cast(blob).getBuffer(), - (short) (KMByteBlob.cast(blob).getStartOff() + AUTH_TAG_LENGTH + 1), - out, - outOff, - AUTH_TAG_COUNTER_SIZE); - return AUTH_TAG_COUNTER_SIZE; - } - return (short) 0; - } - - public void setRateLimitedKeyCount(short authTag, byte[] buf, short off, short len) { - short tag = findTag(authTag); - if (tag != KMType.INVALID_VALUE) { - short dataPtr = readData(tag); - Util.arrayCopyNonAtomic( - buf, - off, - KMByteBlob.cast(dataPtr).getBuffer(), - (short) (KMByteBlob.cast(dataPtr).getStartOff() + AUTH_TAG_LENGTH + 1), - len); - writeDataEntry(tag, - KMByteBlob.cast(dataPtr).getBuffer(), - KMByteBlob.cast(dataPtr).getStartOff(), - KMByteBlob.cast(dataPtr).length()); - } - } - - @Override - public void onSave(Element ele) { - ele.write(dataIndex); - ele.write(dataTable); - } - - @Override - public void onRestore(Element ele) { - dataIndex = ele.readShort(); - dataTable = (byte[]) ele.readObject(); - } - - @Override - public short getBackupPrimitiveByteCount() { - // dataIndex - return (short) 2; - } - - @Override - public short getBackupObjectCount() { - // dataTable - return (short) 1; - } } diff --git a/Applet/src/com/android/javacard/keymaster/RemotelyProvisionedComponentDevice.java b/Applet/src/com/android/javacard/keymaster/RemotelyProvisionedComponentDevice.java index 595d6daa..548812d8 100644 --- a/Applet/src/com/android/javacard/keymaster/RemotelyProvisionedComponentDevice.java +++ b/Applet/src/com/android/javacard/keymaster/RemotelyProvisionedComponentDevice.java @@ -129,25 +129,36 @@ public class RemotelyProvisionedComponentDevice { private static final byte UPDATE = 0x02; private static final byte FINISH = 0x04; private static final byte GET_RESPONSE = 0x06; + + //RKP mac key size + private static final short RKP_MAC_KEY_SIZE = 32; + // variables private byte[] data; private KMEncoder encoder; private KMDecoder decoder; private KMRepository repository; private KMSEProvider seProvider; + private KMKeymintDataStore storeDataInst; private Object[] operation; private short[] dataIndex; public static Object[] authorizedEekRoots; public RemotelyProvisionedComponentDevice(KMEncoder encoder, KMDecoder decoder, - KMRepository repository, KMSEProvider seProvider) { + KMRepository repository, KMSEProvider seProvider, KMKeymintDataStore storeDInst) { this.encoder = encoder; this.decoder = decoder; this.repository = repository; this.seProvider = seProvider; + this.storeDataInst = storeDInst; 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); + // Initialize RKP mac key + short offset = repository.alloc((short) RKP_MAC_KEY_SIZE); + byte[] buffer = repository.getHeap(); + seProvider.getTrueRandomNumber(buffer, offset, RKP_MAC_KEY_SIZE); + storeDataInst.createRkpMacKey(buffer, offset, RKP_MAC_KEY_SIZE); operation[0] = null; createAuthorizedEEKRoot(); } @@ -541,7 +552,7 @@ public void process(short ins, APDU apdu) throws Exception { } private boolean isAdditionalCertificateChainPresent() { - return (seProvider.getAdditionalCertChainLength() == 0 ? false : true); + return (storeDataInst.getAdditionalCertChainLength() == 0 ? false : true); } private short processFinalData(byte[] scratchPad) { @@ -565,35 +576,6 @@ private void updateOutputProcessingState(byte state) { data[dataEntryIndex] = 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); - if (!testMode) { - Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) (2 * MAC_KEY_SIZE), (byte) 0); - short len = - seProvider.hkdf( - scratchPad, //ikm - (short) 0, // ikm offset - MAC_KEY_SIZE, // ikm size - scratchPad, // salt - MAC_KEY_SIZE, // salt offset - MAC_KEY_SIZE, // salt length - KMCose.MAC_DERIVE_KEY_CTX, - (short) 0, - (short) KMCose.MAC_DERIVE_KEY_CTX.length, - KMByteBlob.cast(macKey).getBuffer(), - KMByteBlob.cast(macKey).getStartOff(), - MAC_KEY_SIZE - ); - if (len != MAC_KEY_SIZE) { - KMException.throwIt(KMError.INVALID_MAC_LENGTH); - } - } - return macKey; - } - /** * Validates the CoseMac message and extracts the CoseKey from it. * @@ -607,9 +589,7 @@ private short validateAndExtractPublicKey(short coseMacPtr, byte[] scratchPad) { short coseHeadersExp = KMCoseHeaders.exp(); // Exp for coseky short coseKeyExp = KMCoseKey.exp(); - // Get the mackey. - 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(), @@ -645,9 +625,7 @@ private short validateAndExtractPublicKey(short coseMacPtr, byte[] scratchPad) { short encodedLen = KMKeymasterApplet.encodeToApduBuffer(macStructure, scratchPad, (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE); - short hmacLen = seProvider.hmacSign(KMByteBlob.cast(macKey).getBuffer(), - KMByteBlob.cast(macKey).getStartOff(), - (short) 32, scratchPad, (short) 0, encodedLen, scratchPad, encodedLen); + short hmacLen = rkpHmacSign(testMode, scratchPad, (short) 0, encodedLen, scratchPad, encodedLen); if (hmacLen != KMByteBlob.cast( KMArray.cast(coseMacPtr).get(KMCose.COSE_MAC0_TAG_OFFSET)).length()) { @@ -834,10 +812,10 @@ private KMDeviceUniqueKey createDeviceUniqueKey(boolean testMode, byte[] scratch (short) 128, lengths); deviceUniqueKey = - seProvider.createDeviceUniqueKey(true, scratchPad, (short) 128, lengths[1], + storeDataInst.createTestDeviceUniqueKey(scratchPad, (short) 128, lengths[1], scratchPad, (short) 0, lengths[0]); } else { - deviceUniqueKey = seProvider.getDeviceUniqueKey(false); + deviceUniqueKey = storeDataInst.getDeviceUniqueKey(false); } return deviceUniqueKey; } @@ -939,7 +917,7 @@ private void updateItem(short[] deviceIds, short[] meta, byte[] item, short valu } private short getAttestationId(short attestId, byte[] scratchpad) { - short attIdTagLen = seProvider.getAttestationId(attestId, scratchpad, (short) 0); + short attIdTagLen = storeDataInst.getAttestationId(attestId, scratchpad, (short) 0); if (attIdTagLen != 0) { return KMTextString.instance(scratchpad, (short) 0, attIdTagLen); } @@ -947,7 +925,7 @@ private short getAttestationId(short attestId, byte[] scratchpad) { } private short getVerifiedBootHash(byte[] scratchPad) { - short len = seProvider.getVerifiedBootHash(scratchPad, (short) 0); + short len = storeDataInst.getVerifiedBootHash(scratchPad, (short) 0); if (len != 0) { return KMByteBlob.instance(scratchPad, (short) 0, len); } @@ -956,7 +934,7 @@ private short getVerifiedBootHash(byte[] scratchPad) { private short getBootloaderState() { short bootloaderState; - if (seProvider.isDeviceBootLocked()) { + if (storeDataInst.isDeviceBootLocked()) { bootloaderState = KMTextString.instance(LOCKED, (short) 0, (short) LOCKED.length); } else { bootloaderState = KMTextString.instance(UNLOCKED, (short) 0, (short) UNLOCKED.length); @@ -965,7 +943,7 @@ private short getBootloaderState() { } private short getVbState() { - short state = seProvider.getBootState(); + short state = storeDataInst.getBootState(); short vbState = KMType.INVALID_VALUE; if (state == KMType.VERIFIED_BOOT) { vbState = KMTextString.instance(VB_STATE_GREEN, (short) 0, (short) VB_STATE_GREEN.length); @@ -1017,17 +995,17 @@ private short getBootParams(byte bootParam, byte[] scratchPad) { short value = KMType.INVALID_VALUE; switch (bootParam) { case OS_VERSION_ID: - value = repository.getOsVersion(); + value = storeDataInst.getOsVersion(); break; case SYSTEM_PATCH_LEVEL_ID: - value = repository.getOsPatch(); + value = storeDataInst.getOsPatch(); break; case BOOT_PATCH_LEVEL_ID: - short len = seProvider.getBootPatchLevel(scratchPad, (short) 0); + short len = storeDataInst.getBootPatchLevel(scratchPad, (short) 0); value = KMByteBlob.instance(scratchPad, (short) 0, len); break; case VENDOR_PATCH_LEVEL_ID: - value = repository.getVendorPatchLevel(); + value = storeDataInst.getVendorPatchLevel(); break; default: KMException.throwIt(KMError.INVALID_ARGUMENT); @@ -1229,7 +1207,7 @@ private void updateAdditionalCertChainProcessedLength(short processedLen) { } private short processAdditionalCertificateChain(byte[] scratchPad) { - byte[] persistedData = seProvider.getAdditionalCertChain(); + byte[] persistedData = storeDataInst.getAdditionalCertChain(); short totalAccLen = Util.getShort(persistedData, (short) 0); if (totalAccLen == 0) { // No Additional certificate chain present. @@ -1261,7 +1239,7 @@ private short processBcc(byte[] scratchPad) { len = KMKeymasterApplet .encodeToApduBuffer(bcc, scratchPad, (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE); } else { - byte[] bcc = seProvider.getBootCertificateChain(); + byte[] bcc = storeDataInst.getBootCertificateChain(); len = Util.getShort(bcc, (short) 0); Util.arrayCopyNonAtomic(bcc, (short) 2, scratchPad, (short) 0, len); } @@ -1360,8 +1338,6 @@ private short constructCoseMacForRkpKey(boolean testMode, byte[] scratchPad, sho short len = KMKeymasterApplet .encodeToApduBuffer(coseKey, scratchPad, (short) 0, KMKeymasterApplet.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( KMInteger.uint_8(KMCose.COSE_ALG_HMAC_256), @@ -1379,9 +1355,7 @@ private short constructCoseMacForRkpKey(boolean testMode, byte[] scratchPad, sho len = KMKeymasterApplet.encodeToApduBuffer(macStructure, scratchPad, (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE); // HMAC Sign. - short hmacLen = seProvider - .hmacSign(KMByteBlob.cast(macKey).getBuffer(), KMByteBlob.cast(macKey).getStartOff(), - (short) 32, scratchPad, (short) 0, len, scratchPad, len); + short hmacLen = rkpHmacSign(testMode, scratchPad, (short) 0, len, scratchPad, len); // Create COSE_MAC0 object short coseMac0 = KMCose @@ -1486,4 +1460,18 @@ public short encodeES256CoseSignSignature(byte[] input, short offset, short len, return length; } + private short rkpHmacSign(boolean testMode, byte[] data, short dataStart, short dataLength, byte[] signature, + short signatureStart) { + short result; + if(testMode) { + short macKey = KMByteBlob.instance(MAC_KEY_SIZE); + Util.arrayFillNonAtomic(KMByteBlob.cast(macKey).getBuffer(), + KMByteBlob.cast(macKey).getStartOff(), MAC_KEY_SIZE, (byte) 0); + result = seProvider.hmacSign(KMByteBlob.cast(macKey).getBuffer(), KMByteBlob.cast(macKey).getStartOff(), MAC_KEY_SIZE, data, dataStart, dataLength, signature, signatureStart); + } else { + result = seProvider.hmacSign(storeDataInst.getRkpMacacKey(), data, dataStart, dataLength, signature, signatureStart); + } + return result; + } + } diff --git a/aosp_integration_patches/device_google_cuttlefish.patch b/aosp_integration_patches/device_google_cuttlefish.patch index 1f5e0765..7d8461a6 100644 --- a/aosp_integration_patches/device_google_cuttlefish.patch +++ b/aosp_integration_patches/device_google_cuttlefish.patch @@ -1,8 +1,8 @@ diff --git a/shared/device.mk b/shared/device.mk -index 54042c107..622c6a549 100644 +index 36c66ce18..2f6505d4f 100644 --- a/shared/device.mk +++ b/shared/device.mk -@@ -607,6 +607,9 @@ endif +@@ -622,6 +622,9 @@ endif PRODUCT_PACKAGES += \ $(LOCAL_KEYMINT_PRODUCT_PACKAGE) @@ -13,18 +13,32 @@ index 54042c107..622c6a549 100644 ifneq ($(LOCAL_PREFER_VENDOR_APEX),true) PRODUCT_COPY_FILES += \ diff --git a/shared/sepolicy/vendor/file_contexts b/shared/sepolicy/vendor/file_contexts -index 55b8d964e..a0e88fb2e 100644 +index 6c471b8b8..cc223bdc4 100644 --- a/shared/sepolicy/vendor/file_contexts +++ b/shared/sepolicy/vendor/file_contexts -@@ -85,6 +85,7 @@ - /vendor/bin/hw/android\.hardware\.input\.classifier@1\.0-service.default u:object_r:hal_input_classifier_default_exec:s0 +@@ -93,6 +93,7 @@ /vendor/bin/hw/android\.hardware\.thermal@2\.0-service\.mock u:object_r:hal_thermal_default_exec:s0 + /vendor/bin/hw/android\.hardware\.identity-service\.remote u:object_r:hal_identity_remote_exec:s0 /vendor/bin/hw/android\.hardware\.security\.keymint-service\.remote u:object_r:hal_keymint_remote_exec:s0 +/vendor/bin/hw/android\.hardware\.security\.keymint-service\.strongbox u:object_r:hal_keymint_strongbox_exec:s0 /vendor/bin/hw/android\.hardware\.keymaster@4\.1-service.remote u:object_r:hal_keymaster_remote_exec:s0 /vendor/bin/hw/android\.hardware\.gatekeeper@1\.0-service.remote u:object_r:hal_gatekeeper_remote_exec:s0 /vendor/bin/hw/android\.hardware\.confirmationui@1\.0-service.cuttlefish u:object_r:hal_confirmationui_cuttlefish_exec:s0 -diff --git a/shared/sepolicy/vendor/hal_keymint_strongbox.te b/shared/sepolicy/vendor/hal_keymint_strongbox.te +diff --git a/shared/sepolicy/vendor/service_contexts b/shared/sepolicy/vendor/service_contexts +index c41503e3b..acd78e1ce 100644 +--- a/shared/sepolicy/vendor/service_contexts ++++ b/shared/sepolicy/vendor/service_contexts +@@ -5,6 +5,9 @@ android.hardware.neuralnetworks.IDevice/nnapi-sample_float_slow u:object_r:hal_n + android.hardware.neuralnetworks.IDevice/nnapi-sample_minimal u:object_r:hal_neuralnetworks_service:s0 + android.hardware.neuralnetworks.IDevice/nnapi-sample_quant u:object_r:hal_neuralnetworks_service:s0 + android.hardware.neuralnetworks.IDevice/nnapi-sample_sl_shim u:object_r:hal_neuralnetworks_service:s0 ++android.hardware.security.keymint.IKeyMintDevice/strongbox u:object_r:hal_keymint_service:s0 ++android.hardware.security.sharedsecret.ISharedSecret/strongbox u:object_r:hal_sharedsecret_service:s0 ++android.hardware.security.keymint.IRemotelyProvisionedComponent/strongbox u:object_r:hal_keymint_service:s0 + + # Binder service mappings + gce u:object_r:gce_service:s0 + diff --git a/shared/sepolicy/vendor/hal_keymint_strongbox.te b/shared/sepolicy/vendor/hal_keymint_strongbox.te new file mode 100644 index 000000000..839fd1a6b --- /dev/null @@ -44,17 +58,3 @@ index 000000000..839fd1a6b +allow hal_keymint_strongbox port_type:tcp_socket name_connect; +allow hal_keymint_strongbox port:tcp_socket { name_connect }; +allow hal_keymint_strongbox vendor_data_file:file { open read getattr }; -diff --git a/shared/sepolicy/vendor/service_contexts b/shared/sepolicy/vendor/service_contexts -index d20d026cf..b8f0155ab 100644 ---- a/shared/sepolicy/vendor/service_contexts -+++ b/shared/sepolicy/vendor/service_contexts -@@ -4,6 +4,9 @@ android.hardware.neuralnetworks.IDevice/nnapi-sample_float_slow u:object_r:hal_n - android.hardware.neuralnetworks.IDevice/nnapi-sample_minimal u:object_r:hal_neuralnetworks_service:s0 - android.hardware.neuralnetworks.IDevice/nnapi-sample_quant u:object_r:hal_neuralnetworks_service:s0 - android.hardware.neuralnetworks.IDevice/nnapi-sample_sl_shim u:object_r:hal_neuralnetworks_service:s0 -+android.hardware.security.keymint.IKeyMintDevice/strongbox u:object_r:hal_keymint_service:s0 -+android.hardware.security.sharedsecret.ISharedSecret/strongbox u:object_r:hal_sharedsecret_service:s0 -+android.hardware.security.keymint.IRemotelyProvisionedComponent/strongbox u:object_r:hal_keymint_service:s0 - - # Binder service mappings - gce u:object_r:gce_service:s0 diff --git a/aosp_integration_patches/hardware_interfaces.patch b/aosp_integration_patches/hardware_interfaces.patch index bd06e4cb..9b7797a1 100644 --- a/aosp_integration_patches/hardware_interfaces.patch +++ b/aosp_integration_patches/hardware_interfaces.patch @@ -1,1127 +1,12 @@ diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml -index c39db36ae..39cce859b 100644 +index 8c5a812b0..8bb513be6 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml -@@ -355,6 +355,7 @@ +@@ -353,6 +353,7 @@ + 1-2 IRemotelyProvisionedComponent - default + strongbox + default - -diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp -index 64550eff2..49283e8e3 100644 ---- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp -+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp -@@ -198,7 +198,7 @@ TEST_P(AttestKeyTest, RsaAttestedAttestKeys) { - AttestationKey attest_key; - vector attest_key_characteristics; - vector attest_key_cert_chain; -- ASSERT_EQ(ErrorCode::OK, -+ auto result = - GenerateKey(AuthorizationSetBuilder() - .RsaKey(2048, 65537) - .AttestKey() -@@ -209,7 +209,14 @@ TEST_P(AttestKeyTest, RsaAttestedAttestKeys) { - .Authorization(TAG_NO_AUTH_REQUIRED) - .SetDefaultValidity(), - {} /* attestation signing key */, &attest_key.keyBlob, -- &attest_key_characteristics, &attest_key_cert_chain)); -+ &attest_key_characteristics, &attest_key_cert_chain); -+ //Strongbox does not support Factory provisioned attestation key. -+ if (SecLevel() == SecurityLevel::STRONGBOX) { -+ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result); -+ return; -+ } -+ ASSERT_EQ(ErrorCode::OK, result); -+ - - EXPECT_GT(attest_key_cert_chain.size(), 1); - verify_subject_and_serial(attest_key_cert_chain[0], serial_int, subject, false); -@@ -297,7 +304,7 @@ TEST_P(AttestKeyTest, RsaAttestKeyChaining) { - attest_key_opt = attest_key; - } - -- EXPECT_EQ(ErrorCode::OK, -+ auto result = - GenerateKey(AuthorizationSetBuilder() - .RsaKey(2048, 65537) - .AttestKey() -@@ -308,7 +315,14 @@ TEST_P(AttestKeyTest, RsaAttestKeyChaining) { - .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der) - .SetDefaultValidity(), - attest_key_opt, &key_blob_list[i], &attested_key_characteristics, -- &cert_chain_list[i])); -+ &cert_chain_list[i]); -+ // Strongbox does not support Factory provisioned attestation key. -+ if (SecLevel() == SecurityLevel::STRONGBOX) { -+ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result); -+ return; -+ } -+ ASSERT_EQ(ErrorCode::OK, result); -+ - - AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics); - AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics); -@@ -369,7 +383,7 @@ TEST_P(AttestKeyTest, EcAttestKeyChaining) { - attest_key_opt = attest_key; - } - -- EXPECT_EQ(ErrorCode::OK, -+ auto result = - GenerateKey(AuthorizationSetBuilder() - .EcdsaKey(EcCurve::P_256) - .AttestKey() -@@ -380,7 +394,13 @@ TEST_P(AttestKeyTest, EcAttestKeyChaining) { - .Authorization(TAG_NO_AUTH_REQUIRED) - .SetDefaultValidity(), - attest_key_opt, &key_blob_list[i], &attested_key_characteristics, -- &cert_chain_list[i])); -+ &cert_chain_list[i]); -+ // Strongbox does not support Factory provisioned attestation key. -+ if (SecLevel() == SecurityLevel::STRONGBOX) { -+ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result); -+ return; -+ } -+ ASSERT_EQ(ErrorCode::OK, result); - - AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics); - AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics); -@@ -443,8 +463,9 @@ TEST_P(AttestKeyTest, AlternateAttestKeyChaining) { - attest_key_opt = attest_key; - } - -+ ErrorCode result; - if ((i & 0x1) == 1) { -- EXPECT_EQ(ErrorCode::OK, -+ result = - GenerateKey(AuthorizationSetBuilder() - .EcdsaKey(EcCurve::P_256) - .AttestKey() -@@ -455,9 +476,9 @@ TEST_P(AttestKeyTest, AlternateAttestKeyChaining) { - .Authorization(TAG_NO_AUTH_REQUIRED) - .SetDefaultValidity(), - attest_key_opt, &key_blob_list[i], &attested_key_characteristics, -- &cert_chain_list[i])); -+ &cert_chain_list[i]); - } else { -- EXPECT_EQ(ErrorCode::OK, -+ result = - GenerateKey(AuthorizationSetBuilder() - .RsaKey(2048, 65537) - .AttestKey() -@@ -468,8 +489,14 @@ TEST_P(AttestKeyTest, AlternateAttestKeyChaining) { - .Authorization(TAG_NO_AUTH_REQUIRED) - .SetDefaultValidity(), - attest_key_opt, &key_blob_list[i], &attested_key_characteristics, -- &cert_chain_list[i])); -+ &cert_chain_list[i]); -+ } -+ // Strongbox does not support Factory provisioned attestation key. -+ if (SecLevel() == SecurityLevel::STRONGBOX) { -+ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result); -+ return; - } -+ ASSERT_EQ(ErrorCode::OK, result); - - AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics); - AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics); -diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp -index 6140df135..b73d325c6 100644 ---- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp -+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp -@@ -1156,6 +1156,15 @@ vector KeyMintAidlTestBase::InvalidCurves() { - } - } - -+vector KeyMintAidlTestBase::ValidExponents() { -+ if (SecLevel() == SecurityLevel::STRONGBOX) { -+ return {65537}; -+ } else { -+ return {3, 65537}; -+ } -+} -+ -+ - vector KeyMintAidlTestBase::ValidDigests(bool withNone, bool withMD5) { - switch (SecLevel()) { - case SecurityLevel::SOFTWARE: -diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h -index 7b3b9d4b4..c564d509a 100644 ---- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h -+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h -@@ -250,7 +250,9 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam { - .SetDefaultValidity(); - tagModifier(&rsaBuilder); - errorCode = GenerateKey(rsaBuilder, &rsaKeyData.blob, &rsaKeyData.characteristics); -- EXPECT_EQ(expectedReturn, errorCode); -+ if (!(SecLevel() == SecurityLevel::STRONGBOX && ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED == errorCode)) { -+ EXPECT_EQ(expectedReturn, errorCode); -+ } - - /* ECDSA */ - KeyData ecdsaKeyData; -@@ -262,7 +264,10 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam { - .SetDefaultValidity(); - tagModifier(&ecdsaBuilder); - errorCode = GenerateKey(ecdsaBuilder, &ecdsaKeyData.blob, &ecdsaKeyData.characteristics); -- EXPECT_EQ(expectedReturn, errorCode); -+ if (!(SecLevel() == SecurityLevel::STRONGBOX && ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED == errorCode)) { -+ EXPECT_EQ(expectedReturn, errorCode); -+ } -+ - return {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData}; - } - bool IsSecure() const { return securityLevel_ != SecurityLevel::SOFTWARE; } -@@ -279,6 +284,7 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam { - vector InvalidCurves(); - - vector ValidDigests(bool withNone, bool withMD5); -+ vector ValidExponents(); - - static vector build_params() { - auto params = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor); -diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp -index 2a7911cc3..639b2a5dc 100644 ---- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp -+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp -@@ -912,8 +912,8 @@ TEST_P(NewKeyGenerationTest, RsaWithAttestation) { - for (auto key_size : ValidKeySizes(Algorithm::RSA)) { - vector key_blob; - vector key_characteristics; -- ASSERT_EQ(ErrorCode::OK, -- GenerateKey(AuthorizationSetBuilder() -+ -+ auto result = GenerateKey(AuthorizationSetBuilder() - .RsaSigningKey(key_size, 65537) - .Digest(Digest::NONE) - .Padding(PaddingMode::NONE) -@@ -923,8 +923,14 @@ TEST_P(NewKeyGenerationTest, RsaWithAttestation) { - .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob) - .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der) - .SetDefaultValidity(), -- &key_blob, &key_characteristics)); -+ &key_blob, &key_characteristics); - -+ // Strongbox does not support Factory provisioned attestation key -+ if (SecLevel() == SecurityLevel::STRONGBOX) { -+ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result); -+ return; -+ } -+ ASSERT_EQ(ErrorCode::OK, result); - ASSERT_GT(key_blob.size(), 0U); - CheckBaseParams(key_characteristics); - CheckCharacteristics(key_blob, key_characteristics); -@@ -1045,8 +1051,7 @@ TEST_P(NewKeyGenerationTest, RsaEncryptionWithAttestation) { - - vector key_blob; - vector key_characteristics; -- ASSERT_EQ(ErrorCode::OK, -- GenerateKey(AuthorizationSetBuilder() -+ auto result = GenerateKey(AuthorizationSetBuilder() - .RsaEncryptionKey(key_size, 65537) - .Padding(PaddingMode::NONE) - .AttestationChallenge(challenge) -@@ -1055,8 +1060,14 @@ TEST_P(NewKeyGenerationTest, RsaEncryptionWithAttestation) { - .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob) - .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der) - .SetDefaultValidity(), -- &key_blob, &key_characteristics)); -+ &key_blob, &key_characteristics); - -+ // Strongbox does not support Factory provisioned attestation key -+ if (SecLevel() == SecurityLevel::STRONGBOX) { -+ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result); -+ return; -+ } -+ ASSERT_EQ(ErrorCode::OK, result); - ASSERT_GT(key_blob.size(), 0U); - AuthorizationSet auths; - for (auto& entry : key_characteristics) { -@@ -1157,15 +1168,21 @@ TEST_P(NewKeyGenerationTest, RsaWithAttestationMissAppId) { - vector key_blob; - vector key_characteristics; - -- ASSERT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING, -- GenerateKey(AuthorizationSetBuilder() -+ auto result = GenerateKey(AuthorizationSetBuilder() - .RsaSigningKey(2048, 65537) - .Digest(Digest::NONE) - .Padding(PaddingMode::NONE) - .AttestationChallenge(challenge) - .Authorization(TAG_NO_AUTH_REQUIRED) - .SetDefaultValidity(), -- &key_blob, &key_characteristics)); -+ &key_blob, &key_characteristics); -+ -+ // Strongbox does not support Factory provisioned attestation key -+ if (SecLevel() == SecurityLevel::STRONGBOX) { -+ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result); -+ return; -+ } -+ ASSERT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING, result); - } - - /* -@@ -1275,8 +1292,8 @@ TEST_P(NewKeyGenerationTest, LimitedUsageRsaWithAttestation) { - for (auto key_size : ValidKeySizes(Algorithm::RSA)) { - vector key_blob; - vector key_characteristics; -- ASSERT_EQ(ErrorCode::OK, -- GenerateKey(AuthorizationSetBuilder() -+ -+ auto result = GenerateKey(AuthorizationSetBuilder() - .RsaSigningKey(key_size, 65537) - .Digest(Digest::NONE) - .Padding(PaddingMode::NONE) -@@ -1287,7 +1304,14 @@ TEST_P(NewKeyGenerationTest, LimitedUsageRsaWithAttestation) { - .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob) - .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der) - .SetDefaultValidity(), -- &key_blob, &key_characteristics)); -+ &key_blob, &key_characteristics); -+ -+ //Strongbox does not support Factory provisioned attestation key -+ if (SecLevel() == SecurityLevel::STRONGBOX) { -+ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result); -+ return; -+ } -+ ASSERT_EQ(ErrorCode::OK, result); - - ASSERT_GT(key_blob.size(), 0U); - CheckBaseParams(key_characteristics); -@@ -1418,8 +1442,8 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestation) { - for (auto curve : ValidCurves()) { - vector key_blob; - vector key_characteristics; -- ASSERT_EQ(ErrorCode::OK, -- GenerateKey(AuthorizationSetBuilder() -+ -+ auto result = GenerateKey(AuthorizationSetBuilder() - .Authorization(TAG_NO_AUTH_REQUIRED) - .EcdsaSigningKey(curve) - .Digest(Digest::NONE) -@@ -1428,7 +1452,15 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestation) { - .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob) - .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der) - .SetDefaultValidity(), -- &key_blob, &key_characteristics)); -+ &key_blob, &key_characteristics); -+ -+ //Strongbox does not support Factory provisioned attestation key -+ if (SecLevel() == SecurityLevel::STRONGBOX) { -+ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result); -+ return; -+ } -+ ASSERT_EQ(ErrorCode::OK, result); -+ - ASSERT_GT(key_blob.size(), 0U); - CheckBaseParams(key_characteristics); - CheckCharacteristics(key_blob, key_characteristics); -@@ -1506,6 +1538,12 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestationTags) { - // Tag not required to be supported by all KeyMint implementations. - continue; - } -+ -+ //Strongbox does not support Factory provisioned attestation key -+ if (SecLevel() == SecurityLevel::STRONGBOX) { -+ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result); -+ continue; -+ } - ASSERT_EQ(result, ErrorCode::OK); - ASSERT_GT(key_blob.size(), 0U); - -@@ -1555,8 +1593,14 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestationTags) { - .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der) - .SetDefaultValidity(); - builder.push_back(tag); -- ASSERT_EQ(ErrorCode::CANNOT_ATTEST_IDS, -- GenerateKey(builder, &key_blob, &key_characteristics)); -+ -+ auto result = GenerateKey(builder, &key_blob, &key_characteristics); -+ //Strongbox does not support Factory provisioned attestation key -+ if (SecLevel() == SecurityLevel::STRONGBOX) { -+ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result); -+ continue; -+ } -+ ASSERT_EQ(ErrorCode::CANNOT_ATTEST_IDS, result); - } - } - -@@ -1756,6 +1800,13 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestationTagNoApplicationId) { - .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der) - .SetDefaultValidity(), - &key_blob, &key_characteristics); -+ -+ // Strongbox does not support Factory provisioned attestation key -+ if (SecLevel() == SecurityLevel::STRONGBOX) { -+ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result); -+ return; -+ } -+ - ASSERT_EQ(result, ErrorCode::OK); - ASSERT_GT(key_blob.size(), 0U); - -@@ -1834,13 +1885,19 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestationRequireAppId) { - vector key_blob; - vector key_characteristics; - -- ASSERT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING, -- GenerateKey(AuthorizationSetBuilder() -+ auto result = GenerateKey(AuthorizationSetBuilder() - .EcdsaSigningKey(EcCurve::P_256) - .Digest(Digest::NONE) - .AttestationChallenge(challenge) - .SetDefaultValidity(), -- &key_blob, &key_characteristics)); -+ &key_blob, &key_characteristics); -+ -+ // Strongbox does not support Factory provisioned attestation key -+ if (SecLevel() == SecurityLevel::STRONGBOX) { -+ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result); -+ return; -+ } -+ ASSERT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING, result); - } - - /* -@@ -1897,14 +1954,21 @@ TEST_P(NewKeyGenerationTest, AttestationApplicationIDLengthProperlyEncoded) { - const string app_id(length, 'a'); - vector key_blob; - vector key_characteristics; -- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() -+ auto result = GenerateKey(AuthorizationSetBuilder() - .Authorization(TAG_NO_AUTH_REQUIRED) - .EcdsaSigningKey(EcCurve::P_256) - .Digest(Digest::NONE) - .AttestationChallenge(challenge) - .AttestationApplicationId(app_id) - .SetDefaultValidity(), -- &key_blob, &key_characteristics)); -+ &key_blob, &key_characteristics); -+ //Strongbox does not support Factory provisioned attestation key -+ if (SecLevel() == SecurityLevel::STRONGBOX) { -+ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result); -+ return; -+ } -+ ASSERT_EQ(ErrorCode::OK, result); -+ - ASSERT_GT(key_blob.size(), 0U); - CheckBaseParams(key_characteristics); - CheckCharacteristics(key_blob, key_characteristics); -@@ -3945,25 +4009,27 @@ typedef KeyMintAidlTestBase EncryptionOperationsTest; - * Verifies that raw RSA decryption works. - */ - TEST_P(EncryptionOperationsTest, RsaNoPaddingSuccess) { -- for (uint64_t exponent : {3, 65537}) { -- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() -- .Authorization(TAG_NO_AUTH_REQUIRED) -- .RsaEncryptionKey(2048, exponent) -- .Padding(PaddingMode::NONE) -- .SetDefaultValidity())); - -- string message = string(2048 / 8, 'a'); -- auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE); -- string ciphertext1 = LocalRsaEncryptMessage(message, params); -- EXPECT_EQ(2048U / 8, ciphertext1.size()); -+ for (uint64_t exponent : ValidExponents()) -+ { -+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() -+ .Authorization(TAG_NO_AUTH_REQUIRED) -+ .RsaEncryptionKey(2048, exponent) -+ .Padding(PaddingMode::NONE) -+ .SetDefaultValidity())); - -- string ciphertext2 = LocalRsaEncryptMessage(message, params); -- EXPECT_EQ(2048U / 8, ciphertext2.size()); -+ string message = string(2048 / 8, 'a'); -+ auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE); -+ string ciphertext1 = LocalRsaEncryptMessage(message, params); -+ EXPECT_EQ(2048U / 8, ciphertext1.size()); - -- // Unpadded RSA is deterministic -- EXPECT_EQ(ciphertext1, ciphertext2); -+ string ciphertext2 = LocalRsaEncryptMessage(message, params); -+ EXPECT_EQ(2048U / 8, ciphertext2.size()); - -- CheckedDeleteKey(); -+ // Unpadded RSA is deterministic -+ EXPECT_EQ(ciphertext1, ciphertext2); -+ -+ CheckedDeleteKey(); - } - } - -@@ -6503,7 +6569,7 @@ TEST_P(ClearOperationsTest, TooManyOperations) { - size_t i; - - for (i = 0; i < max_operations; i++) { -- result = Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, op_handles[i]); -+ result = Begin(KeyPurpose::DECRYPT, key_blob_, params, &out_params, op_handles[i]); - if (ErrorCode::OK != result) { - break; - } -@@ -6511,12 +6577,12 @@ TEST_P(ClearOperationsTest, TooManyOperations) { - EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS, result); - // Try again just in case there's a weird overflow bug - EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS, -- Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params)); -+ Begin(KeyPurpose::DECRYPT, key_blob_, params, &out_params)); - for (size_t j = 0; j < i; j++) { - EXPECT_EQ(ErrorCode::OK, Abort(op_handles[j])) - << "Aboort failed for i = " << j << std::endl; - } -- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params)); -+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, key_blob_, params, &out_params)); - AbortIfNeeded(); - } - -@@ -6615,7 +6681,6 @@ TEST_P(KeyAgreementTest, Ecdh) { - OPENSSL_free(p); - - // Generate EC key in KeyMint (only access to public key material) -- vector challenge = {0x41, 0x42}; - EXPECT_EQ( - ErrorCode::OK, - GenerateKey(AuthorizationSetBuilder() -@@ -6624,7 +6689,6 @@ TEST_P(KeyAgreementTest, Ecdh) { - .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY) - .Authorization(TAG_ALGORITHM, Algorithm::EC) - .Authorization(TAG_ATTESTATION_APPLICATION_ID, {0x61, 0x62}) -- .Authorization(TAG_ATTESTATION_CHALLENGE, challenge) - .SetDefaultValidity())) - << "Failed to generate key"; - ASSERT_GT(cert_chain_.size(), 0); -@@ -6704,14 +6768,24 @@ TEST_P(EarlyBootKeyTest, CreateEarlyBootKeys) { - CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::OK); - - for (const auto& keyData : {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData}) { -+ -+ if (SecLevel() == SecurityLevel::STRONGBOX && keyData.blob.size() == 0U) { -+ continue; -+ } - ASSERT_GT(keyData.blob.size(), 0U); - AuthorizationSet crypto_params = SecLevelAuthorizations(keyData.characteristics); - EXPECT_TRUE(crypto_params.Contains(TAG_EARLY_BOOT_ONLY)) << crypto_params; - } - CheckedDeleteKey(&aesKeyData.blob); - CheckedDeleteKey(&hmacKeyData.blob); -- CheckedDeleteKey(&rsaKeyData.blob); -- CheckedDeleteKey(&ecdsaKeyData.blob); -+ -+ if (rsaKeyData.blob.size() != 0U) { -+ CheckedDeleteKey(&rsaKeyData.blob); -+ } -+ if (ecdsaKeyData.blob.size() != 0U) { -+ CheckedDeleteKey(&ecdsaKeyData.blob); -+ } -+ - } - - /* -@@ -6727,14 +6801,21 @@ TEST_P(EarlyBootKeyTest, CreateAttestedEarlyBootKey) { - }); - - for (const auto& keyData : {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData}) { -+ if (SecLevel() == SecurityLevel::STRONGBOX && keyData.blob.size() == 0U) { -+ continue; -+ } - ASSERT_GT(keyData.blob.size(), 0U); - AuthorizationSet crypto_params = SecLevelAuthorizations(keyData.characteristics); - EXPECT_TRUE(crypto_params.Contains(TAG_EARLY_BOOT_ONLY)) << crypto_params; - } - CheckedDeleteKey(&aesKeyData.blob); - CheckedDeleteKey(&hmacKeyData.blob); -- CheckedDeleteKey(&rsaKeyData.blob); -- CheckedDeleteKey(&ecdsaKeyData.blob); -+ if (rsaKeyData.blob.size() != 0U) { -+ CheckedDeleteKey(&rsaKeyData.blob); -+ } -+ if (ecdsaKeyData.blob.size() != 0U) { -+ CheckedDeleteKey(&ecdsaKeyData.blob); -+ } - } - - /* -diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp -index 76fb79b61..6e57d913b 100644 ---- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp -+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp -@@ -164,6 +164,7 @@ class VtsRemotelyProvisionedComponentTests : public testing::TestWithParamgetHardwareInfo(&rpcHardwareInfo).isOk()); - } - - static vector build_params() { -@@ -173,6 +174,7 @@ class VtsRemotelyProvisionedComponentTests : public testing::TestWithParam provisionable_; -+ RpcHardwareInfo rpcHardwareInfo; - }; - - using GenerateKeyTests = VtsRemotelyProvisionedComponentTests; -@@ -273,11 +275,10 @@ TEST_P(GenerateKeyTests, generateEcdsaP256Key_testMode) { - class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests { - protected: - CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(32)) { -- generateTestEekChain(3); - } - - void generateTestEekChain(size_t eekLength) { -- auto chain = generateEekChain(eekLength, eekId_); -+ auto chain = generateEekChain(rpcHardwareInfo.supportedEekCurve, eekLength, eekId_); - EXPECT_TRUE(chain) << chain.message(); - if (chain) testEekChain_ = chain.moveValue(); - testEekLength_ = eekLength; -@@ -298,6 +299,17 @@ class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests { - } - } - -+ ErrMsgOr getSessionKey(ErrMsgOr>& senderPubkey) { -+ if (rpcHardwareInfo.supportedEekCurve == RpcHardwareInfo::CURVE_25519 || -+ rpcHardwareInfo.supportedEekCurve == RpcHardwareInfo::CURVE_NONE) { -+ return x25519_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey, -+ senderPubkey->first, false /* senderIsA */); -+ } else { -+ return ECDH_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey, -+ senderPubkey->first, false /* senderIsA */); -+ } -+ } -+ - void checkProtectedData(const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign, - const bytevec& keysToSignMac, const ProtectedData& protectedData, - std::vector* bccOutput = nullptr) { -@@ -310,9 +322,7 @@ class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests { - ASSERT_TRUE(senderPubkey) << senderPubkey.message(); - EXPECT_EQ(senderPubkey->second, eekId_); - -- auto sessionKey = -- x25519_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey, -- senderPubkey->first, false /* senderIsA */); -+ auto sessionKey = getSessionKey(senderPubkey); - ASSERT_TRUE(sessionKey) << sessionKey.message(); - - auto protectedDataPayload = -@@ -322,7 +332,7 @@ class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests { - auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload); - ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg; - ASSERT_TRUE(parsedPayload->asArray()); -- EXPECT_EQ(parsedPayload->asArray()->size(), 2U); -+ EXPECT_LE(parsedPayload->asArray()->size(), 3U); - - auto& signedMac = parsedPayload->asArray()->get(0); - auto& bcc = parsedPayload->asArray()->get(1); -@@ -406,6 +416,7 @@ TEST_P(CertificateRequestTest, NewKeyPerCallInTestMode) { - bytevec keysToSignMac; - DeviceInfo deviceInfo; - ProtectedData protectedData; -+ generateTestEekChain(3); - auto status = provisionable_->generateCertificateRequest( - testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo, - &protectedData, &keysToSignMac); -@@ -445,7 +456,7 @@ TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_prodMode) { - DeviceInfo deviceInfo; - ProtectedData protectedData; - auto status = provisionable_->generateCertificateRequest( -- testMode, {} /* keysToSign */, getProdEekChain(), challenge_, &deviceInfo, -+ testMode, {} /* keysToSign */, getProdEekChain(rpcHardwareInfo.supportedEekCurve), challenge_, &deviceInfo, - &protectedData, &keysToSignMac); - EXPECT_TRUE(status.isOk()); - } -@@ -486,7 +497,7 @@ TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodMode) { - DeviceInfo deviceInfo; - ProtectedData protectedData; - auto status = provisionable_->generateCertificateRequest( -- testMode, keysToSign_, getProdEekChain(), challenge_, &deviceInfo, &protectedData, -+ testMode, keysToSign_, getProdEekChain(rpcHardwareInfo.supportedEekCurve), challenge_, &deviceInfo, &protectedData, - &keysToSignMac); - EXPECT_TRUE(status.isOk()); - } -@@ -502,6 +513,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_testMode) { - bytevec keysToSignMac; - DeviceInfo deviceInfo; - ProtectedData protectedData; -+ generateTestEekChain(3); - auto status = provisionable_->generateCertificateRequest( - testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo, - &protectedData, &keysToSignMac); -@@ -521,7 +533,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) { - DeviceInfo deviceInfo; - ProtectedData protectedData; - auto status = provisionable_->generateCertificateRequest( -- testMode, {keyWithCorruptMac}, getProdEekChain(), challenge_, &deviceInfo, -+ testMode, {keyWithCorruptMac}, getProdEekChain(rpcHardwareInfo.supportedEekCurve), challenge_, &deviceInfo, - &protectedData, &keysToSignMac); - ASSERT_FALSE(status.isOk()) << status.getMessage(); - EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC); -@@ -535,7 +547,7 @@ TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) { - bool testMode = false; - generateKeys(testMode, 4 /* numKeys */); - -- auto prodEekChain = getProdEekChain(); -+ auto prodEekChain = getProdEekChain(rpcHardwareInfo.supportedEekCurve); - auto [parsedChain, _, parseErr] = cppbor::parse(prodEekChain); - ASSERT_NE(parsedChain, nullptr) << parseErr; - ASSERT_NE(parsedChain->asArray(), nullptr); -@@ -566,7 +578,7 @@ TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) { - - // Build an EEK chain that omits the first self-signed cert. - auto truncatedChain = cppbor::Array(); -- auto [chain, _, parseErr] = cppbor::parse(getProdEekChain()); -+ auto [chain, _, parseErr] = cppbor::parse(getProdEekChain(rpcHardwareInfo.supportedEekCurve)); - ASSERT_TRUE(chain); - auto eekChain = chain->asArray(); - ASSERT_NE(eekChain, nullptr); -@@ -594,6 +606,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) { - bytevec keysToSignMac; - DeviceInfo deviceInfo; - ProtectedData protectedData; -+ generateTestEekChain(3); - auto status = provisionable_->generateCertificateRequest( - true /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo, - &protectedData, &keysToSignMac); -@@ -612,6 +625,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_testKeyInProdCert) { - bytevec keysToSignMac; - DeviceInfo deviceInfo; - ProtectedData protectedData; -+ generateTestEekChain(3); - auto status = provisionable_->generateCertificateRequest( - false /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo, - &protectedData, &keysToSignMac); -diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp -index 36969bbdb..b3552d38b 100644 ---- a/security/keymint/support/Android.bp -+++ b/security/keymint/support/Android.bp -@@ -66,6 +66,7 @@ cc_library { - "libcppcose_rkp", - "libcrypto", - "libjsoncpp", -+ "android.hardware.security.keymint-V1-ndk", - ], - } - -diff --git a/security/keymint/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h -index 406b7a9b7..4d9ed2b0c 100644 ---- a/security/keymint/support/include/remote_prov/remote_prov_utils.h -+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h -@@ -52,6 +52,20 @@ inline constexpr uint8_t kCoseEncodedGeekCert[] = { - 0x31, 0xbf, 0x6b, 0xe8, 0x1e, 0x35, 0xe2, 0xf0, 0x2d, 0xce, 0x6c, 0x2f, 0x4f, 0xf2, - 0xf5, 0x4f, 0xa5, 0xd4, 0x83, 0xad, 0x96, 0xa2, 0xf1, 0x87, 0x58, 0x04}; - -+// The Google ECDSA root key for the Endpoint Encryption Key chain, encoded as COSE_Sign1 -+inline constexpr uint8_t kCoseEncodedEcdsaRootCert[] = { -+ 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x58, 0x4d, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, -+ 0x21, 0x58, 0x20, 0xf7, 0x14, 0x8a, 0xdb, 0x97, 0xf4, 0xcc, 0x53, 0xef, 0xd2, 0x64, 0x11, -+ 0xc4, 0xe3, 0x75, 0x1f, 0x66, 0x1f, 0xa4, 0x71, 0x0c, 0x6c, 0xcf, 0xfa, 0x09, 0x46, 0x80, -+ 0x74, 0x87, 0x54, 0xf2, 0xad, 0x22, 0x58, 0x20, 0x5e, 0x7f, 0x5b, 0xf6, 0xec, 0xe4, 0xf6, -+ 0x19, 0xcc, 0xff, 0x13, 0x37, 0xfd, 0x0f, 0xa1, 0xc8, 0x93, 0xdb, 0x18, 0x06, 0x76, 0xc4, -+ 0x5d, 0xe6, 0xd7, 0x6a, 0x77, 0x86, 0xc3, 0x2d, 0xaf, 0x8f, 0x58, 0x47, 0x30, 0x45, 0x02, -+ 0x20, 0x2f, 0x97, 0x8e, 0x42, 0xfb, 0xbe, 0x07, 0x2d, 0x95, 0x47, 0x85, 0x47, 0x93, 0x40, -+ 0xb0, 0x1f, 0xd4, 0x9b, 0x47, 0xa4, 0xc4, 0x44, 0xa9, 0xf2, 0xa1, 0x07, 0x87, 0x10, 0xc7, -+ 0x9f, 0xcb, 0x11, 0x02, 0x21, 0x00, 0xf4, 0xbf, 0x9f, 0xe8, 0x3b, 0xe0, 0xe7, 0x34, 0x4c, -+ 0x15, 0xfc, 0x7b, 0xc3, 0x7e, 0x33, 0x05, 0xf4, 0xd1, 0x34, 0x3c, 0xed, 0x02, 0x04, 0x60, -+ 0x7a, 0x15, 0xe0, 0x79, 0xd3, 0x8a, 0xff, 0x24}; -+ - /** - * Generates random bytes. - */ -@@ -67,12 +81,12 @@ struct EekChain { - * Generates an X25518 EEK with the specified eekId and an Ed25519 chain of the - * specified length. All keys are generated randomly. - */ --ErrMsgOr generateEekChain(size_t length, const bytevec& eekId); -+ErrMsgOr generateEekChain(int32_t supportedEekCurve, size_t length, const bytevec& eekId); - - /** - * Returns the CBOR-encoded, production Google Endpoint Encryption Key chain. - */ --bytevec getProdEekChain(); -+bytevec getProdEekChain(int32_t supportedEekCurve); - - struct BccEntryData { - bytevec pubKey; -diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp -index 0cbee5104..ae5120f8b 100644 ---- a/security/keymint/support/remote_prov_utils.cpp -+++ b/security/keymint/support/remote_prov_utils.cpp -@@ -17,15 +17,195 @@ - #include - #include - -+#include - #include - #include - #include -+#include -+#include -+#include -+#include - #include -+#include - #include - #include - - namespace aidl::android::hardware::security::keymint::remote_prov { - -+constexpr int kP256AffinePointSize = 32; -+ -+using EC_KEY_Ptr = bssl::UniquePtr; -+using EVP_PKEY_Ptr = bssl::UniquePtr; -+using EVP_PKEY_CTX_Ptr = bssl::UniquePtr; -+ -+ErrMsgOr ecKeyGetPrivateKey(const EC_KEY* ecKey) { -+ // Extract private key. -+ const BIGNUM* bignum = EC_KEY_get0_private_key(ecKey); -+ if (bignum == nullptr) { -+ return "Error getting bignum from private key"; -+ } -+ int size = BN_num_bytes(bignum); -+ // Pad with zeros incase the length is lesser than 32. -+ bytevec privKey(32, 0); -+ BN_bn2bin(bignum, privKey.data() + 32 - size); -+ return privKey; -+} -+ -+ErrMsgOr ecKeyGetPublicKey(const EC_KEY* ecKey) { -+ // Extract public key. -+ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); -+ if (group.get() == nullptr) { -+ return "Error creating EC group by curve name"; -+ } -+ const EC_POINT* point = EC_KEY_get0_public_key(ecKey); -+ if (point == nullptr) return "Error getting ecpoint from public key"; -+ -+ int size = EC_POINT_point2oct(group.get(), point, -+ POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, -+ nullptr); -+ if (size == 0) { -+ return "Error generating public key encoding"; -+ } -+ -+ bytevec publicKey; -+ publicKey.resize(size); -+ EC_POINT_point2oct(group.get(), point, -+ POINT_CONVERSION_UNCOMPRESSED, publicKey.data(), -+ publicKey.size(), nullptr); -+ return publicKey; -+} -+ -+ErrMsgOr> getAffineCoordinates( -+ const bytevec& pubKey) { -+ auto group = EC_GROUP_Ptr( -+ EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); -+ if (group.get() == nullptr) { -+ return "Error creating EC group by curve name"; -+ } -+ auto point = EC_POINT_Ptr(EC_POINT_new(group.get())); -+ if (EC_POINT_oct2point(group.get(), point.get(), pubKey.data(), -+ pubKey.size(), nullptr) != 1) { -+ return "Error decoding publicKey"; -+ } -+ BIGNUM_Ptr x(BN_new()); -+ BIGNUM_Ptr y(BN_new()); -+ BN_CTX_Ptr ctx(BN_CTX_new()); -+ if (!ctx.get()) return "Failed to create BN_CTX instance"; -+ -+ if (!EC_POINT_get_affine_coordinates_GFp(group.get(), point.get(), -+ x.get(), y.get(), -+ ctx.get())) { -+ return "Failed to get affine coordinates from ECPoint"; -+ } -+ bytevec pubX(kP256AffinePointSize); -+ bytevec pubY(kP256AffinePointSize); -+ if (BN_bn2binpad(x.get(), pubX.data(), kP256AffinePointSize) != -+ kP256AffinePointSize) { -+ return "Error in converting absolute value of x cordinate to big-endian"; -+ } -+ if (BN_bn2binpad(y.get(), pubY.data(), kP256AffinePointSize) != -+ kP256AffinePointSize) { -+ return "Error in converting absolute value of y cordinate to big-endian"; -+ } -+ return std::make_tuple(std::move(pubX), std::move(pubY)); -+} -+ -+ErrMsgOr> generateEc256KeyPair() { -+ auto ec_key = EC_KEY_Ptr(EC_KEY_new()); -+ if (ec_key.get() == nullptr) { -+ return "Failed to allocate ec key"; -+ } -+ -+ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); -+ if (group.get() == nullptr) { -+ return "Error creating EC group by curve name"; -+ } -+ -+ if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 || -+ EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) { -+ return "Error generating key"; -+ } -+ -+ auto privKey = ecKeyGetPrivateKey(ec_key.get()); -+ if (!privKey) return privKey.moveMessage(); -+ -+ auto pubKey = ecKeyGetPublicKey(ec_key.get()); -+ if (!pubKey) return pubKey.moveMessage(); -+ -+ return std::make_tuple(pubKey.moveValue(), privKey.moveValue()); -+} -+ -+ErrMsgOr> generateX25519KeyPair() { -+ /* Generate X25519 key pair */ -+ bytevec pubKey(X25519_PUBLIC_VALUE_LEN); -+ bytevec privKey(X25519_PRIVATE_KEY_LEN); -+ X25519_keypair(pubKey.data(), privKey.data()); -+ return std::make_tuple(std::move(pubKey), std::move(privKey)); -+} -+ -+ErrMsgOr> generateED25519KeyPair() { -+ /* Generate ED25519 key pair */ -+ bytevec pubKey(ED25519_PUBLIC_KEY_LEN); -+ bytevec privKey(ED25519_PRIVATE_KEY_LEN); -+ ED25519_keypair(pubKey.data(), privKey.data()); -+ return std::make_tuple(std::move(pubKey), std::move(privKey)); -+} -+ -+ErrMsgOr> generateKeyPair( -+ int32_t supportedEekCurve, bool isEek) { -+ -+ switch (supportedEekCurve) { -+ case RpcHardwareInfo::CURVE_NONE: -+ case RpcHardwareInfo::CURVE_25519: -+ if (isEek) { -+ return generateX25519KeyPair(); -+ } -+ return generateED25519KeyPair(); -+ case RpcHardwareInfo::CURVE_P256: -+ return generateEc256KeyPair(); -+ default: -+ return "Unknown EEK Curve."; -+ } -+} -+ -+ErrMsgOr constructCoseKey(int32_t supportedEekCurve, const bytevec& eekId, -+ const bytevec& pubKey) { -+ CoseKeyType keyType; -+ CoseKeyAlgorithm algorithm; -+ CoseKeyCurve curve; -+ bytevec pubX; -+ bytevec pubY; -+ switch (supportedEekCurve) { -+ case RpcHardwareInfo::CURVE_NONE: -+ case RpcHardwareInfo::CURVE_25519: -+ keyType = OCTET_KEY_PAIR; -+ algorithm = (eekId.empty()) ? EDDSA : ECDH_ES_HKDF_256; -+ curve = (eekId.empty()) ? ED25519 : cppcose::X25519; -+ pubX = pubKey; -+ break; -+ case RpcHardwareInfo::CURVE_P256: { -+ keyType = EC2; -+ algorithm = (eekId.empty()) ? ES256 : ECDH_ES_HKDF_256; -+ curve = P256; -+ auto affineCoordinates = getAffineCoordinates(pubKey); -+ if (!affineCoordinates) return affineCoordinates.moveMessage(); -+ std::tie(pubX, pubY) = affineCoordinates.moveValue(); -+ } break; -+ default: -+ return "Unknown EEK Curve."; -+ } -+ cppbor::Map coseKey = cppbor::Map() -+ .add(CoseKey::KEY_TYPE, keyType) -+ .add(CoseKey::ALGORITHM, algorithm) -+ .add(CoseKey::CURVE, curve) -+ .add(CoseKey::PUBKEY_X, pubX); -+ -+ if (!pubY.empty()) coseKey.add(CoseKey::PUBKEY_Y, pubY); -+ if (!eekId.empty()) coseKey.add(CoseKey::KEY_ID, eekId); -+ -+ return coseKey.canonicalize().encode(); -+} -+ - bytevec kTestMacKey(32 /* count */, 0 /* byte value */); - - bytevec randomBytes(size_t numBytes) { -@@ -34,7 +214,17 @@ bytevec randomBytes(size_t numBytes) { - return retval; - } - --ErrMsgOr generateEekChain(size_t length, const bytevec& eekId) { -+ErrMsgOr constructCoseSign1(int32_t supportedEekCurve, const bytevec& key, -+ const bytevec& payload, const bytevec& aad) { -+ if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) { -+ return constructECDSACoseSign1(key, {} /* protectedParams */, payload, aad); -+ } else { -+ return cppcose::constructCoseSign1(key, payload, aad); -+ } -+} -+ -+ErrMsgOr generateEekChain(int32_t supportedEekCurve, size_t length, -+ const bytevec& eekId) { - if (length < 2) { - return "EEK chain must contain at least 2 certs."; - } -@@ -43,42 +233,31 @@ ErrMsgOr generateEekChain(size_t length, const bytevec& eekId) { - - bytevec prev_priv_key; - for (size_t i = 0; i < length - 1; ++i) { -- bytevec pub_key(ED25519_PUBLIC_KEY_LEN); -- bytevec priv_key(ED25519_PRIVATE_KEY_LEN); -- -- ED25519_keypair(pub_key.data(), priv_key.data()); -+ auto keyPair = generateKeyPair(supportedEekCurve, false); -+ if (!keyPair) keyPair.moveMessage(); -+ auto [pub_key, priv_key] = keyPair.moveValue(); - - // The first signing key is self-signed. - if (prev_priv_key.empty()) prev_priv_key = priv_key; - -- auto coseSign1 = constructCoseSign1(prev_priv_key, -- cppbor::Map() /* payload CoseKey */ -- .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR) -- .add(CoseKey::ALGORITHM, EDDSA) -- .add(CoseKey::CURVE, ED25519) -- .add(CoseKey::PUBKEY_X, pub_key) -- .canonicalize() -- .encode(), -+ auto coseKey = constructCoseKey(supportedEekCurve, {}, pub_key); -+ if (!coseKey) return coseKey.moveMessage(); -+ -+ auto coseSign1 = constructCoseSign1(supportedEekCurve, prev_priv_key, coseKey.moveValue(), - {} /* AAD */); - if (!coseSign1) return coseSign1.moveMessage(); - eekChain.add(coseSign1.moveValue()); - - prev_priv_key = priv_key; - } -+ auto keyPair = generateKeyPair(supportedEekCurve, true); -+ if (!keyPair) keyPair.moveMessage(); -+ auto [pub_key, priv_key] = keyPair.moveValue(); - -- bytevec pub_key(X25519_PUBLIC_VALUE_LEN); -- bytevec priv_key(X25519_PRIVATE_KEY_LEN); -- X25519_keypair(pub_key.data(), priv_key.data()); -+ auto coseKey = constructCoseKey(supportedEekCurve, eekId, pub_key); -+ if (!coseKey) return coseKey.moveMessage(); - -- auto coseSign1 = constructCoseSign1(prev_priv_key, -- cppbor::Map() /* payload CoseKey */ -- .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR) -- .add(CoseKey::KEY_ID, eekId) -- .add(CoseKey::ALGORITHM, ECDH_ES_HKDF_256) -- .add(CoseKey::CURVE, cppcose::X25519) -- .add(CoseKey::PUBKEY_X, pub_key) -- .canonicalize() -- .encode(), -+ auto coseSign1 = constructCoseSign1(supportedEekCurve, prev_priv_key, coseKey.moveValue(), - {} /* AAD */); - if (!coseSign1) return coseSign1.moveMessage(); - eekChain.add(coseSign1.moveValue()); -@@ -86,16 +265,15 @@ ErrMsgOr generateEekChain(size_t length, const bytevec& eekId) { - return EekChain{eekChain.encode(), pub_key, priv_key}; - } - --bytevec getProdEekChain() { -- bytevec prodEek; -- prodEek.reserve(1 + sizeof(kCoseEncodedRootCert) + sizeof(kCoseEncodedGeekCert)); -- -- // In CBOR encoding, 0x82 indicates an array of two items -- prodEek.push_back(0x82); -- prodEek.insert(prodEek.end(), std::begin(kCoseEncodedRootCert), std::end(kCoseEncodedRootCert)); -- prodEek.insert(prodEek.end(), std::begin(kCoseEncodedGeekCert), std::end(kCoseEncodedGeekCert)); -- -- return prodEek; -+bytevec getProdEekChain(int32_t supportedEekCurve) { -+ cppbor::Array chain; -+ if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) { -+ chain.add(cppbor::EncodedItem(bytevec(std::begin(kCoseEncodedEcdsaRootCert), std::end(kCoseEncodedEcdsaRootCert)))); -+ } else { -+ chain.add(cppbor::EncodedItem(bytevec(std::begin(kCoseEncodedRootCert), std::end(kCoseEncodedRootCert)))); -+ chain.add(cppbor::EncodedItem(bytevec(std::begin(kCoseEncodedGeekCert), std::end(kCoseEncodedGeekCert)))); -+ } -+ return chain.encode(); - } - - ErrMsgOr verifyAndParseCoseSign1Cwt(const cppbor::Array* coseSign1, -@@ -122,7 +300,8 @@ ErrMsgOr verifyAndParseCoseSign1Cwt(const cppbor::Array* coseSign1, - } - - auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM); -- if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) { -+ if (!algorithm || !algorithm->asInt() || (algorithm->asInt()->value() != EDDSA && -+ algorithm->asInt()->value() != ES256)) { - return "Unsupported signature algorithm"; - } - -@@ -136,16 +315,35 @@ ErrMsgOr verifyAndParseCoseSign1Cwt(const cppbor::Array* coseSign1, - if (!serializedKey || !serializedKey->asBstr()) return "Could not find key entry"; - - bool selfSigned = signingCoseKey.empty(); -- auto key = -+ bytevec key; -+ if (algorithm->asInt()->value() == EDDSA) { -+ auto key = - CoseKey::parseEd25519(selfSigned ? serializedKey->asBstr()->value() : signingCoseKey); -- if (!key) return "Bad signing key: " + key.moveMessage(); -+ if (!key) return "Bad signing key: " + key.moveMessage(); - -- bytevec signatureInput = -+ bytevec signatureInput = - cppbor::Array().add("Signature1").add(*protectedParams).add(aad).add(*payload).encode(); - -- if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(), -- key->getBstrValue(CoseKey::PUBKEY_X)->data())) { -- return "Signature verification failed"; -+ if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(), -+ key->getBstrValue(CoseKey::PUBKEY_X)->data())) { -+ return "Signature verification failed"; -+ } -+ } else { // P256 -+ auto key = -+ CoseKey::parseP256(selfSigned ? serializedKey->asBstr()->value() : signingCoseKey); -+ if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty() || -+ key->getBstrValue(CoseKey::PUBKEY_Y)->empty()) { -+ return "Bad signing key: " + key.moveMessage(); -+ } -+ auto publicKey = key->getEcPublicKey(); -+ if (!publicKey) return publicKey.moveMessage(); -+ -+ bytevec signatureInput = -+ cppbor::Array().add("Signature1").add(*protectedParams).add(aad).add(*payload).encode(); -+ -+ if (!verifyEcdsaDigest(publicKey.moveValue(), sha256(signatureInput), signature->value())) { -+ return "Signature verification failed"; -+ } - } - - return serializedKey->asBstr()->value(); -diff --git a/security/keymint/support/remote_prov_utils_test.cpp b/security/keymint/support/remote_prov_utils_test.cpp -index 8697c5190..0009bf713 100644 ---- a/security/keymint/support/remote_prov_utils_test.cpp -+++ b/security/keymint/support/remote_prov_utils_test.cpp -@@ -14,6 +14,7 @@ - * limitations under the License. - */ - -+#include - #include - #include - #include -@@ -35,13 +36,13 @@ using ::keymaster::validateAndExtractEekPubAndId; - using ::testing::ElementsAreArray; - - TEST(RemoteProvUtilsTest, GenerateEekChainInvalidLength) { -- ASSERT_FALSE(generateEekChain(1, /*eekId=*/{})); -+ ASSERT_FALSE(generateEekChain(CURVE_25519, 1, /*eekId=*/{})); - } - - TEST(RemoteProvUtilsTest, GenerateEekChain) { - bytevec kTestEekId = {'t', 'e', 's', 't', 'I', 'd', 0}; - for (size_t length : {2, 3, 31}) { -- auto get_eek_result = generateEekChain(length, kTestEekId); -+ auto get_eek_result = generateEekChain(CURVE_25519, length, kTestEekId); - ASSERT_TRUE(get_eek_result) << get_eek_result.message(); - - auto& [chain, pubkey, privkey] = *get_eek_result; diff --git a/aosp_integration_patches/system_keymaster.patch b/aosp_integration_patches/system_keymaster.patch deleted file mode 100644 index b994b768..00000000 --- a/aosp_integration_patches/system_keymaster.patch +++ /dev/null @@ -1,441 +0,0 @@ -diff --git a/cppcose/cppcose.cpp b/cppcose/cppcose.cpp -index bfe9928..5009bfe 100644 ---- a/cppcose/cppcose.cpp -+++ b/cppcose/cppcose.cpp -@@ -21,10 +21,17 @@ - - #include - #include -+#include - - #include - - namespace cppcose { -+constexpr int kP256AffinePointSize = 32; -+ -+using EVP_PKEY_Ptr = bssl::UniquePtr; -+using EVP_PKEY_CTX_Ptr = bssl::UniquePtr; -+using ECDSA_SIG_Ptr = bssl::UniquePtr; -+using EC_KEY_Ptr = bssl::UniquePtr; - - namespace { - -@@ -51,6 +58,92 @@ ErrMsgOr> aesGcmInitAndProcessAad(const bytevec& - return std::move(ctx); - } - -+ -+ErrMsgOr signEcdsaDigest(const bytevec& key, const bytevec& data) { -+ auto bn = BIGNUM_Ptr(BN_bin2bn(key.data(), key.size(), nullptr)); -+ if (bn.get() == nullptr) { -+ return "Error creating BIGNUM"; -+ } -+ -+ auto ec_key = EC_KEY_Ptr(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); -+ if (EC_KEY_set_private_key(ec_key.get(), bn.get()) != 1) { -+ return "Error setting private key from BIGNUM"; -+ } -+ -+ ECDSA_SIG* sig = ECDSA_do_sign(data.data(), data.size(), ec_key.get()); -+ if (sig == nullptr) { -+ return "Error signing digest"; -+ } -+ size_t len = i2d_ECDSA_SIG(sig, nullptr); -+ bytevec signature(len); -+ unsigned char* p = (unsigned char*)signature.data(); -+ i2d_ECDSA_SIG(sig, &p); -+ ECDSA_SIG_free(sig); -+ return signature; -+} -+ -+ErrMsgOr ecdh(const bytevec& publicKey, const bytevec& privateKey) { -+ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); -+ auto point = EC_POINT_Ptr(EC_POINT_new(group.get())); -+ if (EC_POINT_oct2point(group.get(), point.get(), publicKey.data(), publicKey.size(), nullptr) != -+ 1) { -+ return "Error decoding publicKey"; -+ } -+ auto ecKey = EC_KEY_Ptr(EC_KEY_new()); -+ auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new()); -+ if (ecKey.get() == nullptr || pkey.get() == nullptr) { -+ return "Memory allocation failed"; -+ } -+ if (EC_KEY_set_group(ecKey.get(), group.get()) != 1) { -+ return "Error setting group"; -+ } -+ if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) { -+ return "Error setting point"; -+ } -+ if (EVP_PKEY_set1_EC_KEY(pkey.get(), ecKey.get()) != 1) { -+ return "Error setting key"; -+ } -+ -+ auto bn = BIGNUM_Ptr(BN_bin2bn(privateKey.data(), privateKey.size(), nullptr)); -+ if (bn.get() == nullptr) { -+ return "Error creating BIGNUM for private key"; -+ } -+ auto privEcKey = EC_KEY_Ptr(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); -+ if (EC_KEY_set_private_key(privEcKey.get(), bn.get()) != 1) { -+ return "Error setting private key from BIGNUM"; -+ } -+ auto privPkey = EVP_PKEY_Ptr(EVP_PKEY_new()); -+ if (EVP_PKEY_set1_EC_KEY(privPkey.get(), privEcKey.get()) != 1) { -+ return "Error setting private key"; -+ } -+ -+ auto ctx = EVP_PKEY_CTX_Ptr(EVP_PKEY_CTX_new(privPkey.get(), NULL)); -+ if (ctx.get() == nullptr) { -+ return "Error creating context"; -+ } -+ -+ if (EVP_PKEY_derive_init(ctx.get()) != 1) { -+ return "Error initializing context"; -+ } -+ -+ if (EVP_PKEY_derive_set_peer(ctx.get(), pkey.get()) != 1) { -+ return "Error setting peer"; -+ } -+ -+ /* Determine buffer length for shared secret */ -+ size_t secretLen = 0; -+ if (EVP_PKEY_derive(ctx.get(), NULL, &secretLen) != 1) { -+ return "Error determing length of shared secret"; -+ } -+ bytevec sharedSecret; -+ sharedSecret.resize(secretLen); -+ -+ if (EVP_PKEY_derive(ctx.get(), sharedSecret.data(), &secretLen) != 1) { -+ return "Error deriving shared secret"; -+ } -+ return sharedSecret; -+} -+ - } // namespace - - ErrMsgOr generateHmacSha256(const bytevec& key, const bytevec& data) { -@@ -134,6 +227,17 @@ ErrMsgOr verifyAndParseCoseMac0(const cppbor::Item* macIt - return payload->value(); - } - -+ErrMsgOr createECDSACoseSign1Signature(const bytevec& key, const bytevec& protectedParams, -+ const bytevec& payload, const bytevec& aad) { -+ bytevec signatureInput = cppbor::Array() -+ .add("Signature1") // -+ .add(protectedParams) -+ .add(aad) -+ .add(payload) -+ .encode(); -+ return signEcdsaDigest(key, sha256(signatureInput)); -+} -+ - ErrMsgOr createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams, - const bytevec& payload, const bytevec& aad) { - bytevec signatureInput = cppbor::Array() -@@ -152,6 +256,19 @@ ErrMsgOr createCoseSign1Signature(const bytevec& key, const bytevec& pr - return signature; - } - -+ErrMsgOr constructECDSACoseSign1(const bytevec& key, cppbor::Map protectedParams, -+ const bytevec& payload, const bytevec& aad) { -+ bytevec protParms = protectedParams.add(ALGORITHM, ES256).canonicalize().encode(); -+ auto signature = createECDSACoseSign1Signature(key, protParms, payload, aad); -+ if (!signature) return signature.moveMessage(); -+ -+ return cppbor::Array() -+ .add(std::move(protParms)) -+ .add(cppbor::Map() /* unprotected parameters */) -+ .add(std::move(payload)) -+ .add(std::move(*signature)); -+} -+ - ErrMsgOr constructCoseSign1(const bytevec& key, cppbor::Map protectedParams, - const bytevec& payload, const bytevec& aad) { - bytevec protParms = protectedParams.add(ALGORITHM, EDDSA).canonicalize().encode(); -@@ -193,7 +310,8 @@ ErrMsgOr verifyAndParseCoseSign1(const cppbor::Array* coseSign1, - } - - auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM); -- if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) { -+ if (!algorithm || !algorithm->asInt() || -+ !(algorithm->asInt()->value() == EDDSA || algorithm->asInt()->value() == ES256)) { - return "Unsupported signature algorithm"; - } - -@@ -203,17 +321,30 @@ ErrMsgOr verifyAndParseCoseSign1(const cppbor::Array* coseSign1, - } - - bool selfSigned = signingCoseKey.empty(); -- auto key = CoseKey::parseEd25519(selfSigned ? payload->value() : signingCoseKey); -- if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty()) { -- return "Bad signing key: " + key.moveMessage(); -- } -- - bytevec signatureInput = - cppbor::Array().add("Signature1").add(*protectedParams).add(aad).add(*payload).encode(); -- -- if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(), -- key->getBstrValue(CoseKey::PUBKEY_X)->data())) { -- return "Signature verification failed"; -+ if (algorithm->asInt()->value() == EDDSA) { -+ auto key = CoseKey::parseEd25519(selfSigned ? payload->value() : signingCoseKey); -+ if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty()) { -+ return "Bad signing key: " + key.moveMessage(); -+ } -+ -+ if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(), -+ key->getBstrValue(CoseKey::PUBKEY_X)->data())) { -+ return "Signature verification failed"; -+ } -+ } else { // P256 -+ auto key = CoseKey::parseP256(selfSigned ? payload->value() : signingCoseKey); -+ if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty() || -+ key->getBstrValue(CoseKey::PUBKEY_Y)->empty()) { -+ return "Bad signing key: " + key.moveMessage(); -+ } -+ auto publicKey = key->getEcPublicKey(); -+ if (!publicKey) return publicKey.moveMessage(); -+ -+ if (!verifyEcdsaDigest(publicKey.moveValue(), sha256(signatureInput), signature->value())) { -+ return "Signature verification failed"; -+ } - } - - return payload->value(); -@@ -294,28 +425,47 @@ getSenderPubKeyFromCoseEncrypt(const cppbor::Item* coseEncrypt) { - if (!senderCoseKey || !senderCoseKey->asMap()) return "Invalid sender COSE_Key"; - - auto& keyType = senderCoseKey->asMap()->get(CoseKey::KEY_TYPE); -- if (!keyType || !keyType->asInt() || keyType->asInt()->value() != OCTET_KEY_PAIR) { -+ if (!keyType || !keyType->asInt() || (keyType->asInt()->value() != OCTET_KEY_PAIR && -+ keyType->asInt()->value() != EC2)) { - return "Invalid key type"; - } - - auto& curve = senderCoseKey->asMap()->get(CoseKey::CURVE); -- if (!curve || !curve->asInt() || curve->asInt()->value() != X25519) { -+ if (!curve || !curve->asInt() || -+ (keyType->asInt()->value() == OCTET_KEY_PAIR && curve->asInt()->value() != X25519) || -+ (keyType->asInt()->value() == EC2 && curve->asInt()->value() != P256)) { - return "Unsupported curve"; - } - -- auto& pubkey = senderCoseKey->asMap()->get(CoseKey::PUBKEY_X); -- if (!pubkey || !pubkey->asBstr() || -- pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) { -- return "Invalid X25519 public key"; -+ bytevec publicKey; -+ if (keyType->asInt()->value() == EC2) { -+ auto& pubX = senderCoseKey->asMap()->get(CoseKey::PUBKEY_X); -+ if (!pubX || !pubX->asBstr() || pubX->asBstr()->value().size() != kP256AffinePointSize) { -+ return "Invalid EC public key"; -+ } -+ auto& pubY = senderCoseKey->asMap()->get(CoseKey::PUBKEY_Y); -+ if (!pubY || !pubY->asBstr() || pubY->asBstr()->value().size() != kP256AffinePointSize) { -+ return "Invalid EC public key"; -+ } -+ auto key = CoseKey::getEcPublicKey(pubX->asBstr()->value(), pubY->asBstr()->value()); -+ if (!key) return key.moveMessage(); -+ publicKey = key.moveValue(); -+ } else { -+ auto& pubkey = senderCoseKey->asMap()->get(CoseKey::PUBKEY_X); -+ if (!pubkey || !pubkey->asBstr() || -+ pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) { -+ return "Invalid X25519 public key"; -+ } -+ publicKey = pubkey->asBstr()->value(); - } - - auto& key_id = unprotParms->asMap()->get(KEY_ID); - if (key_id && key_id->asBstr()) { -- return std::make_pair(pubkey->asBstr()->value(), key_id->asBstr()->value()); -+ return std::make_pair(publicKey, key_id->asBstr()->value()); - } - - // If no key ID, just return an empty vector. -- return std::make_pair(pubkey->asBstr()->value(), bytevec{}); -+ return std::make_pair(publicKey, bytevec{}); - } - - ErrMsgOr decryptCoseEncrypt(const bytevec& key, const cppbor::Item* coseEncrypt, -@@ -367,6 +517,43 @@ ErrMsgOr decryptCoseEncrypt(const bytevec& key, const cppbor::Item* cos - return aesGcmDecrypt(key, nonce->asBstr()->value(), aad, ciphertext->asBstr()->value()); - } - -+ErrMsgOr ECDH_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA, -+ const bytevec& pubKeyB, bool senderIsA) { -+ if (privKeyA.empty() || pubKeyA.empty() || pubKeyB.empty()) { -+ return "Missing input key parameters"; -+ } -+ -+ auto rawSharedKey = ecdh(pubKeyB, privKeyA); -+ if (!rawSharedKey) return rawSharedKey.moveMessage(); -+ -+ bytevec kdfContext = cppbor::Array() -+ .add(AES_GCM_256) -+ .add(cppbor::Array() // Sender Info -+ .add(cppbor::Bstr("client")) -+ .add(bytevec{} /* nonce */) -+ .add(senderIsA ? pubKeyA : pubKeyB)) -+ .add(cppbor::Array() // Recipient Info -+ .add(cppbor::Bstr("server")) -+ .add(bytevec{} /* nonce */) -+ .add(senderIsA ? pubKeyB : pubKeyA)) -+ .add(cppbor::Array() // SuppPubInfo -+ .add(kAesGcmKeySizeBits) // output key length -+ .add(bytevec{})) // protected -+ .encode(); -+ -+ bytevec retval(SHA256_DIGEST_LENGTH); -+ bytevec salt{}; -+ if (!HKDF(retval.data(), retval.size(), // -+ EVP_sha256(), // -+ rawSharedKey->data(), rawSharedKey->size(), // -+ salt.data(), salt.size(), // -+ kdfContext.data(), kdfContext.size())) { -+ return "ECDH HKDF failed"; -+ } -+ -+ return retval; -+} -+ - ErrMsgOr x25519_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA, - const bytevec& pubKeyB, bool senderIsA) { - if (privKeyA.empty() || pubKeyA.empty() || pubKeyB.empty()) { -@@ -460,4 +647,43 @@ ErrMsgOr aesGcmDecrypt(const bytevec& key, const bytevec& nonce, const - return plaintext; - } - -+bytevec sha256(const bytevec& data) { -+ bytevec ret(SHA256_DIGEST_LENGTH); -+ SHA256_CTX ctx; -+ SHA256_Init(&ctx); -+ SHA256_Update(&ctx, data.data(), data.size()); -+ SHA256_Final((unsigned char*)ret.data(), &ctx); -+ return ret; -+} -+ -+bool verifyEcdsaDigest(const bytevec& key, const bytevec& digest, const bytevec& signature) { -+ const unsigned char* p = (unsigned char*)signature.data(); -+ auto sig = ECDSA_SIG_Ptr(d2i_ECDSA_SIG(nullptr, &p, signature.size())); -+ if (sig.get() == nullptr) { -+ return false; -+ } -+ -+ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); -+ auto point = EC_POINT_Ptr(EC_POINT_new(group.get())); -+ if (EC_POINT_oct2point(group.get(), point.get(), key.data(), key.size(), nullptr) != 1) { -+ return false; -+ } -+ auto ecKey = EC_KEY_Ptr(EC_KEY_new()); -+ if (ecKey.get() == nullptr) { -+ return false; -+ } -+ if (EC_KEY_set_group(ecKey.get(), group.get()) != 1) { -+ return false; -+ } -+ if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) { -+ return false; -+ } -+ -+ int rc = ECDSA_do_verify(digest.data(), digest.size(), sig.get(), ecKey.get()); -+ if (rc != 1) { -+ return false; -+ } -+ return true; -+} -+ - } // namespace cppcose -diff --git a/include/keymaster/cppcose/cppcose.h b/include/keymaster/cppcose/cppcose.h -index 0f97388..03251f1 100644 ---- a/include/keymaster/cppcose/cppcose.h -+++ b/include/keymaster/cppcose/cppcose.h -@@ -24,17 +24,25 @@ - - #include - #include -- -+#include -+#include -+#include - #include - #include - #include - #include -+#include - #include - #include - #include - - namespace cppcose { - -+using BIGNUM_Ptr = bssl::UniquePtr; -+using EC_GROUP_Ptr = bssl::UniquePtr; -+using EC_POINT_Ptr = bssl::UniquePtr; -+using BN_CTX_Ptr = bssl::UniquePtr; -+ - template class ErrMsgOr; - using bytevec = std::vector; - using HmacSha256 = std::array; -@@ -203,6 +211,41 @@ class CoseKey { - return key; - } - -+ static ErrMsgOr getEcPublicKey(const bytevec& pubX, const bytevec& pubY) { -+ auto bnX = BIGNUM_Ptr(BN_bin2bn(pubX.data(), pubX.size(), nullptr)); -+ if (bnX.get() == nullptr) { -+ return "Error creating BIGNUM X Coordinate"; -+ } -+ auto bnY = BIGNUM_Ptr(BN_bin2bn(pubY.data(), pubY.size(), nullptr)); -+ if (bnY.get() == nullptr) { -+ return "Error creating BIGNUM Y Coordinate"; -+ } -+ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); -+ auto point = EC_POINT_Ptr(EC_POINT_new(group.get())); -+ if (!point) return "Failed to create EC_POINT instance"; -+ BN_CTX_Ptr ctx(BN_CTX_new()); -+ if (!ctx.get()) return "Failed to create BN_CTX instance"; -+ if (!EC_POINT_set_affine_coordinates_GFp(group.get(), point.get(), bnX.get(), bnY.get(), -+ ctx.get())) { -+ return "Failed to set affine coordinates."; -+ } -+ int size = EC_POINT_point2oct(group.get(), point.get(), POINT_CONVERSION_UNCOMPRESSED, -+ nullptr, 0, nullptr); -+ if (size == 0) { -+ return "Error generating public key encoding"; -+ } -+ bytevec publicKey(size); -+ EC_POINT_point2oct(group.get(), point.get(), POINT_CONVERSION_UNCOMPRESSED, -+ publicKey.data(), publicKey.size(), nullptr); -+ return publicKey; -+ } -+ -+ ErrMsgOr getEcPublicKey() { -+ auto pubX = getBstrValue(PUBKEY_X).value(); -+ auto pubY = getBstrValue(PUBKEY_Y).value(); -+ return getEcPublicKey(pubX, pubY); -+ } -+ - std::optional getIntValue(Label label) { - const auto& value = key_->get(label); - if (!value || !value->asInt()) return {}; -@@ -252,6 +295,8 @@ ErrMsgOr constructCoseSign1(const bytevec& key, const bytevec& pa - const bytevec& aad); - ErrMsgOr constructCoseSign1(const bytevec& key, cppbor::Map extraProtectedFields, - const bytevec& payload, const bytevec& aad); -+ErrMsgOr constructECDSACoseSign1(const bytevec& key, cppbor::Map extraProtectedFields, -+ const bytevec& payload, const bytevec& aad); - /** - * Verify and parse a COSE_Sign1 message, returning the payload. - * -@@ -282,7 +327,10 @@ decryptCoseEncrypt(const bytevec& key, const cppbor::Item* encryptItem, const by - - ErrMsgOr x25519_HKDF_DeriveKey(const bytevec& senderPubKey, const bytevec& senderPrivKey, - const bytevec& recipientPubKey, bool senderIsA); -- -+ErrMsgOr ECDH_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA, -+ const bytevec& pubKeyB, bool senderIsA); -+bool verifyEcdsaDigest(const bytevec& key, const bytevec& digest, const bytevec& signature); -+bytevec sha256(const bytevec& data); - ErrMsgOr aesGcmEncrypt(const bytevec& key, const bytevec& nonce, - const bytevec& aad, - const bytevec& plaintext);