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);