Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,10 @@ public class KMFunctionalTest {
(byte) 0xe9, (byte) 0x77, (byte) 0x4c, (byte) 0x45, (byte) 0xc3, (byte) 0xa3, (byte) 0xcf,
(byte) 0x0d, (byte) 0x16, (byte) 0x10, (byte) 0xe4, (byte) 0x79, (byte) 0x43, (byte) 0x3a,
(byte) 0x21, (byte) 0x5a, (byte) 0x30, (byte) 0xcf};
private static final int OS_VERSION = 1;
private static final int OS_PATCH_LEVEL = 1;
private static final int VENDOR_PATCH_LEVEL = 1;
private static final int BOOT_PATCH_LEVEL = 1;

private CardSimulator simulator;
private KMEncoder encoder;
Expand Down Expand Up @@ -657,7 +661,8 @@ private void provisionCmd(CardSimulator simulator) {
provisionSharedSecret(simulator);
provisionAttestIds(simulator);
// set bootup parameters
setBootParams(simulator, (short) 1, (short) 1, (short) 0, (short) 0);
setBootParams(simulator, (short) OS_VERSION, (short) OS_PATCH_LEVEL,
(short) VENDOR_PATCH_LEVEL, (short) BOOT_PATCH_LEVEL);
provisionLocked(simulator);
}

Expand Down Expand Up @@ -2699,18 +2704,63 @@ public void testUpgradeKey() {
osPatch = KMIntegerTag.cast(osPatch).getValue();
Assert.assertEquals(KMInteger.cast(osVersion).getShort(), 1);
Assert.assertEquals(KMInteger.cast(osPatch).getShort(), 1);
setBootParams(simulator, (short) 2, (short) 2, (short) 1, (short) 1);
ret = upgradeKey(KMByteBlob.instance(keyBlob, (short) 0, (short) keyBlob.length), null, null);
keyBlobPtr = KMArray.cast(ret).get((short) 1);
ret = getKeyCharacteristics(keyBlobPtr);
keyCharacteristics = KMArray.cast(ret).get((short) 1);
hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced();
osVersion = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.OS_VERSION, hwParams);
osVersion = KMIntegerTag.cast(osVersion).getValue();
osPatch = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.OS_PATCH_LEVEL, hwParams);
osPatch = KMIntegerTag.cast(osPatch).getValue();
Assert.assertEquals(KMInteger.cast(osVersion).getShort(), 2);
Assert.assertEquals(KMInteger.cast(osPatch).getShort(), 2);
short NO_UPGRADE = 0x01;
short UPGRADE = 0x02;
short[][] test_data = {
{OS_VERSION, OS_PATCH_LEVEL, VENDOR_PATCH_LEVEL, BOOT_PATCH_LEVEL, NO_UPGRADE, KMError.OK },
{OS_VERSION+1, OS_PATCH_LEVEL, VENDOR_PATCH_LEVEL, BOOT_PATCH_LEVEL, UPGRADE, KMError.OK },
{OS_VERSION, OS_PATCH_LEVEL+1, VENDOR_PATCH_LEVEL, BOOT_PATCH_LEVEL, UPGRADE, KMError.OK },
{OS_VERSION, OS_PATCH_LEVEL, VENDOR_PATCH_LEVEL+1, BOOT_PATCH_LEVEL, UPGRADE, KMError.OK },
{OS_VERSION, OS_PATCH_LEVEL, VENDOR_PATCH_LEVEL, BOOT_PATCH_LEVEL+1, UPGRADE, KMError.OK },
{OS_VERSION+1, OS_PATCH_LEVEL+1, VENDOR_PATCH_LEVEL+1, BOOT_PATCH_LEVEL+1, UPGRADE, KMError.OK },
{OS_VERSION+1, OS_PATCH_LEVEL, VENDOR_PATCH_LEVEL+1, BOOT_PATCH_LEVEL, UPGRADE, KMError.OK },
{OS_VERSION+1, OS_PATCH_LEVEL+1, VENDOR_PATCH_LEVEL, BOOT_PATCH_LEVEL, UPGRADE, KMError.OK },
{OS_VERSION, OS_PATCH_LEVEL, VENDOR_PATCH_LEVEL, BOOT_PATCH_LEVEL-1, NO_UPGRADE, KMError.INVALID_ARGUMENT },
{OS_VERSION-1/*0*/, OS_PATCH_LEVEL, VENDOR_PATCH_LEVEL, BOOT_PATCH_LEVEL, UPGRADE, KMError.OK },
{OS_VERSION, OS_PATCH_LEVEL, VENDOR_PATCH_LEVEL-1, BOOT_PATCH_LEVEL, NO_UPGRADE, KMError.INVALID_ARGUMENT },
{OS_VERSION, OS_PATCH_LEVEL+1, VENDOR_PATCH_LEVEL-1, BOOT_PATCH_LEVEL, NO_UPGRADE, KMError.INVALID_ARGUMENT },
{0, OS_PATCH_LEVEL+1, VENDOR_PATCH_LEVEL-1, BOOT_PATCH_LEVEL+1, NO_UPGRADE, KMError.INVALID_ARGUMENT },
};
for (int i = 0; i < test_data.length; i++) {
setBootParams(simulator, (short) test_data[i][0], (short) test_data[i][1],
(short) test_data[i][2], (short) test_data[i][3]);
ret = upgradeKey(
KMByteBlob.instance(keyBlob, (short) 0, (short) keyBlob.length),
null, null, test_data[i][5]);
if (test_data[i][5] != KMError.OK)
continue;
keyBlobPtr = KMArray.cast(ret).get((short) 1);
if (test_data[i][4] == UPGRADE)
Assert.assertNotEquals(KMByteBlob.cast(keyBlobPtr).length(), 0);
else
Assert.assertEquals(KMByteBlob.cast(keyBlobPtr).length(), 0);
if (KMByteBlob.cast(keyBlobPtr).length() != 0) {
ret = getKeyCharacteristics(keyBlobPtr);
keyCharacteristics = KMArray.cast(ret).get((short) 1);
hwParams = KMKeyCharacteristics.cast(keyCharacteristics)
.getHardwareEnforced();
osVersion = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.OS_VERSION,
hwParams);
osVersion = KMIntegerTag.cast(osVersion).getValue();
osPatch = KMKeyParameters.findTag(KMType.UINT_TAG,
KMType.OS_PATCH_LEVEL, hwParams);
osPatch = KMIntegerTag.cast(osPatch).getValue();
short ptr = KMKeyParameters.findTag(KMType.UINT_TAG,
KMType.VENDOR_PATCH_LEVEL, hwParams);
short vendorPatchLevel = KMIntegerTag.cast(ptr).getValue();
ptr = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.BOOT_PATCH_LEVEL,
hwParams);
short bootPatchLevel = KMIntegerTag.cast(ptr).getValue();
Assert.assertEquals(KMInteger.cast(osVersion).getShort(),
test_data[i][0]);
Assert.assertEquals(KMInteger.cast(osPatch).getShort(),
test_data[i][1]);
Assert.assertEquals(KMInteger.cast(vendorPatchLevel).getShort(),
test_data[i][2]);
Assert.assertEquals(KMInteger.cast(bootPatchLevel).getShort(),
test_data[i][3]);
}
}
cleanUp();
}

Expand All @@ -2724,7 +2774,7 @@ public void testDestroyAttIds() {
cleanUp();
}

private short upgradeKey(short keyBlobPtr, byte[] clientId, byte[] appData) {
private short upgradeKey(short keyBlobPtr, byte[] clientId, byte[] appData, short expectedErr) {
short tagCount = 0;
short clientIdTag = 0;
short appDataTag = 0;
Expand Down Expand Up @@ -2753,15 +2803,21 @@ private short upgradeKey(short keyBlobPtr, byte[] clientId, byte[] appData) {
CommandAPDU apdu = encodeApdu((byte) INS_UPGRADE_KEY_CMD, arr);
// print(commandAPDU.getBytes());
ResponseAPDU response = simulator.transmitCommand(apdu);
short ret = KMArray.instance((short) 2);
KMArray.cast(ret).add((short) 0, KMInteger.exp());
KMArray.cast(ret).add((short) 1, KMByteBlob.exp());
byte[] respBuf = response.getBytes();
short len = (short) respBuf.length;
ret = decoder.decode(ret, respBuf, (short) 0, len);
short error = KMInteger.cast(KMArray.cast(ret).get((short) 0)).getShort();
Assert.assertEquals(error, KMError.OK);
return ret;
if (KMError.OK == expectedErr) {
short ret = KMArray.instance((short) 2);
KMArray.cast(ret).add((short) 0, KMInteger.exp());
KMArray.cast(ret).add((short) 1, KMByteBlob.exp());
ret = decoder.decode(ret, respBuf, (short) 0, len);
Assert.assertEquals(expectedErr, KMInteger.cast(KMArray.cast(ret).get((short) 0)).getShort());
return ret;
} else {
short ret = KMInteger.exp();
ret = decoder.decode(ret, respBuf, (short) 0, len);
Assert.assertEquals(expectedErr, KMInteger.cast(ret).getShort());
return ret;
}
}

@Test
Expand Down
88 changes: 33 additions & 55 deletions Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java
Original file line number Diff line number Diff line change
Expand Up @@ -1096,6 +1096,31 @@ private void processComputeSharedHmacCmd(APDU apdu) {
sendOutgoing(apdu);
}

private boolean isKeyUpgradeRequired(short tag, short systemParam) {
// validate the tag and check if key needs upgrade.
tmpVariables[0] = KMKeyParameters.findTag(KMType.UINT_TAG, tag, data[HW_PARAMETERS]);
tmpVariables[0] = KMIntegerTag.cast(tmpVariables[0]).getValue();
tmpVariables[1] = KMInteger.uint_8((byte) 0);
if (tmpVariables[0] != KMType.INVALID_VALUE) {
// OS version in key characteristics must be less the OS version stored in Javacard or the
// stored version must be zero. Then only upgrade is allowed else it is invalid argument.
if ((tag == KMType.OS_VERSION
&& KMInteger.compare(tmpVariables[0], systemParam) == 1
&& KMInteger.compare(systemParam, tmpVariables[1]) == 0)) {
// Key needs upgrade.
return true;
} else if ((KMInteger.compare(tmpVariables[0], systemParam) == -1)) {
// Each os version or patch level associated with the key must be less than it's
// corresponding value stored in Javacard, then only upgrade is allowed otherwise it
// is invalid argument.
return true;
} else if (KMInteger.compare(tmpVariables[0], systemParam) == 1) {
KMException.throwIt(KMError.INVALID_ARGUMENT);
}
}
return false;
}

private void processUpgradeKeyCmd(APDU apdu) {
// Receive the incoming request fully from the master into buffer.
receiveIncoming(apdu);
Expand Down Expand Up @@ -1123,61 +1148,14 @@ private void processUpgradeKeyCmd(APDU apdu) {
}
// parse existing key blob
parseEncryptedKeyBlob(scratchPad);
// validate characteristics to be upgraded.
tmpVariables[0] =
KMKeyParameters.findTag(KMType.UINT_TAG, KMType.OS_VERSION, data[HW_PARAMETERS]);
tmpVariables[0] = KMIntegerTag.cast(tmpVariables[0]).getValue();
tmpVariables[1] =
KMKeyParameters.findTag(KMType.UINT_TAG, KMType.OS_PATCH_LEVEL, data[HW_PARAMETERS]);
tmpVariables[1] = KMIntegerTag.cast(tmpVariables[1]).getValue();
tmpVariables[2] = repository.getOsVersion();
tmpVariables[3] = repository.getOsPatch();
tmpVariables[4] = KMInteger.uint_8((byte) 0);
if (tmpVariables[0] != KMType.INVALID_VALUE) {
// os version in key characteristics must be less the os version stored in javacard or the
// stored version must be zero. Then only upgrade is allowed else it is invalid argument.
if (KMInteger.compare(tmpVariables[0], tmpVariables[2]) != -1
&& KMInteger.compare(tmpVariables[2], tmpVariables[4]) != 0) {
// Key Should not be upgraded, but error code should be OK, As per VTS.
tmpVariables[5] = KMError.INVALID_ARGUMENT;
}
}
if (tmpVariables[1] != KMType.INVALID_VALUE) {
// The key characteristics should have had os patch level < os patch level stored in javacard
// then only upgrade is allowed.
if (KMInteger.compare(tmpVariables[1], tmpVariables[3]) != -1) {
// Key Should not be upgraded, but error code should be OK, As per VTS.
tmpVariables[5] = KMError.INVALID_ARGUMENT;
}
}
//Compare vendor patch levels
tmpVariables[1] =
KMKeyParameters.findTag(KMType.UINT_TAG, KMType.VENDOR_PATCH_LEVEL, data[HW_PARAMETERS]);
tmpVariables[1] = KMIntegerTag.cast(tmpVariables[1]).getValue();
tmpVariables[2] = repository.getVendorPatchLevel();
if (tmpVariables[1] != KMType.INVALID_VALUE) {
// The key characteristics should have had vendor patch level < vendor patch level stored in javacard
// then only upgrade is allowed.
if (KMInteger.compare(tmpVariables[1], tmpVariables[2]) != -1) {
// Key Should not be upgraded, but error code should be OK, As per VTS.
tmpVariables[5] = KMError.INVALID_ARGUMENT;
}
}
//Compare boot patch levels
tmpVariables[1] =
KMKeyParameters.findTag(KMType.UINT_TAG, KMType.BOOT_PATCH_LEVEL, data[HW_PARAMETERS]);
tmpVariables[1] = KMIntegerTag.cast(tmpVariables[1]).getValue();
tmpVariables[2] = repository.getBootPatchLevel();
if (tmpVariables[1] != KMType.INVALID_VALUE) {
// The key characteristics should have had boot patch level < boot patch level stored in javacard
// then only upgrade is allowed.
if (KMInteger.compare(tmpVariables[1], tmpVariables[2]) != -1) {
// Key Should not be upgraded, but error code should be OK, As per VTS.
tmpVariables[5] = KMError.INVALID_ARGUMENT;
}
}

if (tmpVariables[5] != KMError.INVALID_ARGUMENT) {
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.VENDOR_PATCH_LEVEL, repository.getVendorPatchLevel());
isKeyUpgradeRequired |= isKeyUpgradeRequired(KMType.BOOT_PATCH_LEVEL, repository.getBootPatchLevel());

if (isKeyUpgradeRequired) {
// copy origin
data[ORIGIN] = KMEnumTag.getValue(KMType.ORIGIN, data[HW_PARAMETERS]);
// create new key blob with current os version etc.
Expand Down