Skip to content
Closed
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 @@ -19,6 +19,10 @@
import org.globalplatform.upgrade.OnUpgradeListener;
import org.globalplatform.upgrade.UpgradeManager;

import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.Util;

public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeListener {

KMAndroidSEApplet() {
Expand Down Expand Up @@ -47,10 +51,22 @@ public void onConsolidate() {
@Override
public void onRestore(Element element) {
element.initRead();
provisionStatus = element.readByte();
byte firstByte = element.readByte();
short packageVersion_ = 0;
byte provisionStatus_ = firstByte;
if (firstByte == KMKeymasterApplet.KM_MAGIC_NUMBER) {
packageVersion_ = element.readShort();
provisionStatus_ = element.readByte();
}
if (0 != packageVersion_ && !isUpgradeAllowed(packageVersion_)) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
packageVersion = packageVersion_;
provisionStatus = provisionStatus_;
keymasterState = element.readByte();
repository.onRestore(element);
seProvider.onRestore(element);
repository.onRestore(element, packageVersion, CURRENT_PACKAGE_VERSION);
seProvider.onRestore(element, packageVersion, CURRENT_PACKAGE_VERSION);
handleDataUpgradeToVersion1_1();
}

@Override
Expand All @@ -68,6 +84,8 @@ public Element onSave() {
// Create element.
Element element = UpgradeManager.createElement(Element.TYPE_SIMPLE,
primitiveCount, objectCount);
element.write(KM_MAGIC_NUMBER);
element.write(packageVersion);
element.write(provisionStatus);
element.write(keymasterState);
repository.onSave(element);
Expand All @@ -76,12 +94,113 @@ public Element onSave() {
}

private short computePrimitveDataSize() {
// provisionStatus + keymasterState
return (short) 2;
// provisionStatus + keymasterState + magic byte + version
return (short) 5;
}

private short computeObjectCount() {
return (short) 0;
}

public 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 ((short) (currentMinorVersion - oldMinorVersion) == 1) {
upgradeAllowed = true;
}
}
return upgradeAllowed;
}

public void handleDataUpgradeToVersion1_1() {

if (packageVersion != 0) {
// No Data upgrade required.
return;
}
byte status = provisionStatus;
// In the current version of the applet set boot parameters is removed from
// provision status so readjust the provision locked flag.
// 0x40 is provision locked flag in the older applet.
// Unset the 5th bit. setboot parameters flag.
status = (byte) (status & 0xDF);
// Readjust the lock provisioned status flag.
if ((status & 0x40) == 0x40) {
// 0x40 to 0x20
// Unset 6th bit
status = (byte) (status & 0xBF);
// set the 5th bit
status = (byte) (status | 0x20);
}
provisionStatus = status;
packageVersion = CURRENT_PACKAGE_VERSION;

short certExpiryLen = 0;
short issuerLen = 0;
short certExpiry = repository.getCertExpiryTime();
if (certExpiry != KMType.INVALID_VALUE) {
certExpiryLen = KMByteBlob.cast(certExpiry).length();
}
short issuer = repository.getIssuer();
if (issuer != KMType.INVALID_VALUE) {
issuerLen = KMByteBlob.cast(issuer).length();
}
short certChainLen = seProvider.getProvisionedDataLength(KMSEProvider.CERTIFICATE_CHAIN);
short offset = repository.allocReclaimableMemory((short) (certExpiryLen + issuerLen + certChainLen));
// Get the start offset of the certificate chain.
short certChaionOff =
decoder.getCborBytesStartOffset(
repository.getHeap(),
offset,
seProvider.readProvisionedData(KMSEProvider.CERTIFICATE_CHAIN, repository.getHeap(), offset));
certChainLen -= (short) (certChaionOff - offset);
Util.arrayCopyNonAtomic(
KMByteBlob.cast(issuer).getBuffer(),
KMByteBlob.cast(issuer).getStartOff(),
repository.getHeap(),
(short) (certChaionOff + certChainLen),
issuerLen);
Util.arrayCopyNonAtomic(
KMByteBlob.cast(certExpiry).getBuffer(),
KMByteBlob.cast(certExpiry).getStartOff(),
repository.getHeap(),
(short) (certChaionOff + certChainLen + issuerLen),
certExpiryLen);

seProvider.persistProvisionData(
repository.getHeap(),
certChaionOff, // cert chain offset
certChainLen,
(short) (certChaionOff + certChainLen), // issuer offset
issuerLen,
(short) (certChaionOff + certChainLen + issuerLen), // cert expiry offset
certExpiryLen);


// Update computed HMAC key.
short blob = repository.getComputedHmacKey();
if (blob != KMType.INVALID_VALUE) {
seProvider.createComputedHmacKey(
KMByteBlob.cast(blob).getBuffer(),
KMByteBlob.cast(blob).getStartOff(),
KMByteBlob.cast(blob).length()
);
} else {
// Initialize the Key object.
Util.arrayFillNonAtomic(repository.getHeap(), offset, (short) 32, (byte) 0);
seProvider.createComputedHmacKey(repository.getHeap(), offset,(short) 32);
}
repository.reclaimMemory((short) (certExpiryLen + issuerLen + certChainLen));
}
}

Loading