Skip to content
This repository was archived by the owner on May 24, 2026. It is now read-only.
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

Large diffs are not rendered by default.

Original file line numberDiff line numberDiff line change
Expand Up@@ -117,7 +117,7 @@ public KMAndroidSEProvider() {
rng = RandomData.getInstance(RandomData.ALG_KEYGENERATION);
androidSEProvider = this;
resetFlag = JCSystem.makeTransientByteArray((short) 1,
JCSystem.CLEAR_ON_DESELECT);
JCSystem.CLEAR_ON_RESET);
resetFlag[0] = (byte) POWER_RESET_FALSE;
}

Expand DownExpand Up@@ -407,13 +407,18 @@ public HMACKey cmacKdf(KMPreSharedKey preSharedKey, byte[] label, short labelSta
final byte n = 2; // hardcoded
// [L] 256 bits - hardcoded 32 bits as per
// reference impl in keymaster.
final byte[] L = {
0, 0, 1, 0
};
// byte
final byte[] zero = {
0
};
short zeroIndex = 0;
short LIndex = 1;
short bufIndex = 5;
short keyIndex = 9;
//1st byte in tempArray is reserved for zero
//next 4 bytes in tempArray is reserved for L
tmpArray[0] = 0;
tmpArray[1] = 0;
tmpArray[2] = 0;
tmpArray[3] = 1;
tmpArray[4] = 0;

// [i] counter - 32 bits
short iBufLen = 4;
short keyOutLen = n * 16;
Expand All@@ -434,12 +439,12 @@ public HMACKey cmacKdf(KMPreSharedKey preSharedKey, byte[] label, short labelSta
while (i <= n) {
tmpArray[3] = i;
// 4 bytes of iBuf with counter in it
kdf.update(tmpArray, (short) 0, (short) iBufLen);
kdf.update(tmpArray, bufIndex, iBufLen);
kdf.update(label, labelStart, (short) labelLen); // label
kdf.update(zero, (short) 0, (short) 1); // 1 byte of 0x00
kdf.update(tmpArray, zeroIndex, (short) 1); // 1 byte of 0x00
kdf.update(context, contextStart, contextLength); // context
// 4 bytes of L - signature of 16 bytes
pos = kdf.sign(L, (short) 0, (short) 4, tmpArray,
pos = kdf.sign(tmpArray, LIndex, (short) 4, tmpArray,
(short) (iBufLen + pos));
i++;
}
Expand DownExpand Up@@ -969,22 +974,21 @@ private short hkdfExpand(byte[] prk, short prkOff, short prkLen, byte[] info, sh
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
}
HMACKey hmacKey = createHMACKey(prk, prkOff, prkLen);
Util.arrayFill(tmpArray, (short) 0, (short) 32, (byte) 0);
byte[] cnt = {(byte) 0};
Util.arrayFill(tmpArray, (short) 0, (short) 33, (byte) 0);
short bytesCopied = 0;
short len = 0;
for (short i = 0; i < n; i++) {
cnt[0]++;
tmpArray[0]++;
hmacSignature.init(hmacKey, Signature.MODE_SIGN);
if (i != 0) {
hmacSignature.update(tmpArray, (short) 0, (short) 32);
hmacSignature.update(tmpArray, (short) 1, (short) 32);
}
hmacSignature.update(info, infoOff, infoLen);
len = hmacSignature.sign(cnt, (short) 0, (short) 1, tmpArray, (short) 0);
len = hmacSignature.sign(tmpArray, (short) 0, (short) 1, tmpArray, (short) 1);
if ((short) (bytesCopied + len) > outLen) {
len = (short) (outLen - bytesCopied);
}
Util.arrayCopyNonAtomic(tmpArray, (short) 0, out, (short) (outOff + bytesCopied), len);
Util.arrayCopyNonAtomic(tmpArray, (short) 1, out, (short) (outOff + bytesCopied), len);
bytesCopied += len;
}
return outLen;
Expand DownExpand Up@@ -1125,7 +1129,7 @@ public void onSave(Element element, byte interfaceType, Object object) {
}

@Override
public Object onResore(Element element) {
public Object onRestore(Element element) {
if (element == null) {
return null;
}
Expand DownExpand Up@@ -1197,5 +1201,20 @@ public short getBackupObjectCount(byte interfaceType) {
}
return 0;
}

@Override
public boolean isBootSignalEventSupported() {
return false;
}

@Override
public boolean isDeviceRebooted() {
return false;
}

@Override
public void clearDeviceBooted(boolean resetBootFlag) {
// To be filled
}

}
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,28 @@
*/
public interface KMSEProvider {

/**
* This function tells if boot signal event is supported or not.
*
* @return true if supported, false otherwise.
*/
boolean isBootSignalEventSupported();

/**
* This function tells if the device is booted or not.
*
* @return true if device booted, false otherwise.
*/
boolean isDeviceRebooted();

/**
* This function is supposed to be used to reset the device booted stated after set boot param is
* handled
*
* @param resetBootFlag is false if event has been handled
*/
void clearDeviceBooted(boolean resetBootFlag);

/**
* Create a symmetric key instance. If the algorithm and/or keysize are not supported then it
* should throw a CryptoException.
Expand DownExpand Up@@ -704,7 +726,7 @@ KMPreSharedKey createPreSharedKey(KMPreSharedKey presharedKey, byte[] key, short
* @param element instance of the Element class.
* @return restored object.
*/
Object onResore(Element element);
Object onRestore(Element element);

/**
* This function returns the count of the primitive bytes required to
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@ public interface KMUpgradable {

void onSave(Element ele);

void onRestore(Element ele);
void onRestore(Element ele, short oldVersion, short currentVersion);

short getBackupPrimitiveByteCount();

Expand Down
77 changes: 42 additions & 35 deletions Applet/src/com/android/javacard/keymaster/KMCose.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,6 +120,9 @@ public class KMCose {
{0x4B, 0x65, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x4D, 0x41, 0x43, 0x20, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63,
0x20, 0x6B, 0x65, 0x79, 0x73}; // "Key to MAC public keys"

public static final short[] coseKeyConst = {KMCose.COSE_KEY_KEY_TYPE, KMCose.COSE_KEY_KEY_ID, KMCose.COSE_KEY_ALGORITHM, KMCose.COSE_KEY_KEY_OPS,
KMCose.COSE_KEY_CURVE, KMCose.COSE_KEY_PUBKEY_X, KMCose.COSE_KEY_PUBKEY_Y, KMCose.COSE_KEY_PRIV_KEY};
public static final short[] coseHeaderConst = {KMCose.COSE_LABEL_ALGORITHM, KMCose.COSE_LABEL_KEYID, KMCose.COSE_LABEL_IV, KMCose.COSE_LABEL_COSE_KEY};
/**
* Constructs the Cose MAC structure.
*
Expand DownExpand Up@@ -240,32 +243,33 @@ public static short constructCoseSign1(short protectedHeader, short unProtectedH
/**
* Constructs array based on the tag values provided.
*
* @param tags array of tag values to be constructed.
* @param tags array of tag values to be constructed.
* @param includeTestMode flag which indicates if TEST_COSE_KEY should be included or not.
* @return instance of KMArray.
*/
private static short handleCosePairTags(short[] tags, boolean includeTestMode) {
private static short handleCosePairTags(short[] tag, short[] keyValues, short valueIndex, boolean includeTestMode) {
short index = 0;
// var is used to calculate the length of the array.
short var = 0;
while (index < tags.length) {
if (tags[(short) (index + 1)] != KMType.INVALID_VALUE) {
tags[(short) (index + 2)] =
buildCosePairTag((byte) tags[index], tags[(short) (index + 1)]);
var++;
short tagLen = (short) tag.length;
// var is used to calculate the length of the array.
while (index < tagLen) {
if (keyValues[index] != KMType.INVALID_VALUE) {
keyValues[(short)(index + valueIndex)] = buildCosePairTag((byte) tag[index], keyValues[index]);
var++;
}
index += 3;
index++;
}
var += includeTestMode ? 1 : 0;
short arrPtr = KMArray.instance(var);
index = 0;
// var is used to index the array.
var = 0;
while (index < tags.length) {
if (tags[(short)(index + 2)] != KMType.INVALID_VALUE) {
KMArray.cast(arrPtr).add(var++, tags[(short)(index + 2)]);
while (index < tagLen) {
if (keyValues[(short)(index + valueIndex)] != KMType.INVALID_VALUE) {
KMArray.cast(arrPtr).add(var++, keyValues[(short)(index + valueIndex)]);
}
index += 3;
index++;
}
return arrPtr;
}
Expand DownExpand Up@@ -300,14 +304,15 @@ public static short constructCoseCertPayload(short issuer, short subject, short
* @param ephemeralKey instance of KMCoseKey.
* @return instance of KMCoseHeaders.
*/
public static short constructHeaders(short alg, short keyId, short iv, short ephemeralKey) {
short[] coseHeaderTags = {
KMCose.COSE_LABEL_ALGORITHM, alg, KMType.INVALID_VALUE,
KMCose.COSE_LABEL_KEYID, keyId, KMType.INVALID_VALUE,
KMCose.COSE_LABEL_IV, iv, KMType.INVALID_VALUE,
KMCose.COSE_LABEL_COSE_KEY, ephemeralKey, KMType.INVALID_VALUE
};
short ptr = handleCosePairTags(coseHeaderTags, false);
public static short constructHeaders(short []buff, short alg, short keyId, short iv, short ephemeralKey) {
buff[0]= alg;
buff[1]= keyId;
buff[2]= iv;
buff[3]= ephemeralKey;
for(short i = 4; i < 8; i++) {
buff[i] = KMType.INVALID_VALUE;
}
short ptr = handleCosePairTags(coseHeaderConst, buff, (short)4, false);
ptr = KMCoseHeaders.instance(ptr);
KMCoseHeaders.cast(ptr).canonicalize();
return ptr;
Expand DownExpand Up@@ -443,7 +448,7 @@ public static short buildCosePairTag(byte key, short valuePtr) {
* @param testMode Represents if key is used in test mode or production mode.
* @return Instance of the CoseKey structure.
*/
public static short constructCoseKey(short keyType, short keyId, short keyAlg, short keyOps,
public static short constructCoseKey(short []buff, short keyType, short keyId, short keyAlg, short keyOps,
short curve, byte[] pubKey, short pubKeyOff, short pubKeyLen,
short privKeyPtr, boolean testMode) {
if (pubKey[pubKeyOff] == 0x04) { // uncompressed format
Expand All@@ -453,7 +458,7 @@ public static short constructCoseKey(short keyType, short keyId, short keyAlg, s
pubKeyLen = (short) (pubKeyLen / 2);
short xPtr = KMByteBlob.instance(pubKey, pubKeyOff, pubKeyLen);
short yPtr = KMByteBlob.instance(pubKey, (short) (pubKeyOff + pubKeyLen), pubKeyLen);
short coseKey = constructCoseKey(keyType, keyId, keyAlg, keyOps, curve, xPtr, yPtr, privKeyPtr, testMode);
short coseKey = constructCoseKey(buff, keyType, keyId, keyAlg, keyOps, curve, xPtr, yPtr, privKeyPtr, testMode);
KMCoseKey.cast(coseKey).canonicalize();
return coseKey;
}
Expand All@@ -473,19 +478,21 @@ public static short constructCoseKey(short keyType, short keyId, short keyAlg, s
* @param includeTestKey flag which identifies whether to construct test key or production key.
* @return instance of the KMCoseKey object.
*/
public static short constructCoseKey(short keyType, short keyId, short keyAlg, short keyOps, short curve,
public static short constructCoseKey(short []buff, short keyType, short keyId, short keyAlg, short keyOps, short curve,
short pubX, short pubY, short priv, boolean includeTestKey) {
short[] coseKeyTags = {
KMCose.COSE_KEY_KEY_TYPE, keyType, KMType.INVALID_VALUE,
KMCose.COSE_KEY_KEY_ID, keyId, KMType.INVALID_VALUE,
KMCose.COSE_KEY_ALGORITHM, keyAlg, KMType.INVALID_VALUE,
KMCose.COSE_KEY_KEY_OPS, keyOps, KMType.INVALID_VALUE,
KMCose.COSE_KEY_CURVE, curve, KMType.INVALID_VALUE,
KMCose.COSE_KEY_PUBKEY_X, pubX, KMType.INVALID_VALUE,
KMCose.COSE_KEY_PUBKEY_Y, pubY, KMType.INVALID_VALUE,
KMCose.COSE_KEY_PRIV_KEY, priv, KMType.INVALID_VALUE
};
short arrPtr = handleCosePairTags(coseKeyTags, includeTestKey);
short valueIndex = 8;
buff[0] = keyType;
buff[1] = keyId;
buff[2] = keyAlg;
buff[3] = keyOps;
buff[4] = curve;
buff[5] = pubX;
buff[6] = pubY;
buff[7] = priv;
for (short i = valueIndex; i < 16; i++) {
buff[i] = KMType.INVALID_VALUE;
}
short arrPtr = handleCosePairTags(coseKeyConst, buff, valueIndex, includeTestKey);
if (includeTestKey) {
short testKey =
KMCosePairSimpleValueTag.instance(KMNInteger.uint_32(KMCose.COSE_TEST_KEY, (short) 0),
Expand DownExpand Up@@ -546,4 +553,4 @@ public static short constructKdfContext(byte[] publicKeyA, short publicKeyAOff,

return arrPtr;
}
}
}
17 changes: 9 additions & 8 deletions Applet/src/com/android/javacard/keymaster/KMCoseHeaders.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -152,20 +152,21 @@ public short getAlgorithm() {
return getValueType(KMCose.COSE_LABEL_ALGORITHM);
}

public boolean isDataValid(short alg, short keyIdPtr) {
short[] headerTags = {
KMCose.COSE_LABEL_ALGORITHM, alg,
KMCose.COSE_LABEL_KEYID, keyIdPtr,
};
public boolean isDataValid(short []buff, short alg, short keyIdPtr) {
short bufLen = 4;
buff[0] = KMCose.COSE_LABEL_ALGORITHM;
buff[1] = alg;
buff[2] = KMCose.COSE_LABEL_KEYID;
buff[3] = keyIdPtr;
boolean valid = false;
short value;
short ptr;
short tagIndex = 0;
while (tagIndex < headerTags.length) {
value = headerTags[(short) (tagIndex + 1)];
while (tagIndex < bufLen) {
value = buff[(short) (tagIndex + 1)];
if (value != KMType.INVALID_VALUE) {
valid = false;
ptr = getValueType(headerTags[tagIndex]);
ptr = getValueType(buff[tagIndex]);
switch (KMType.getType(ptr)) {
case KMType.BYTE_BLOB_TYPE:
if ((KMByteBlob.cast(value).length() == KMByteBlob.cast(ptr).length()) &&
Expand Down
26 changes: 15 additions & 11 deletions Applet/src/com/android/javacard/keymaster/KMCoseKey.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -179,23 +179,27 @@ public boolean isTestKey() {
* @param curve value of the curve.
* @return true if valid, otherwise false.
*/
public boolean isDataValid(short keyType, short keyIdPtr, short keyAlg, short keyOps, short curve) {
short[] coseKeyTags = {
KMCose.COSE_KEY_KEY_TYPE, keyType,
KMCose.COSE_KEY_KEY_ID, keyIdPtr,
KMCose.COSE_KEY_ALGORITHM, keyAlg,
KMCose.COSE_KEY_KEY_OPS, keyOps,
KMCose.COSE_KEY_CURVE, curve,
};
public boolean isDataValid(short []buff, short keyType, short keyIdPtr, short keyAlg, short keyOps, short curve) {
short buffLen = 10;
buff[0] = KMCose.COSE_KEY_KEY_TYPE;
buff[1] = keyType;
buff[2] = KMCose.COSE_KEY_KEY_ID;
buff[3] = keyIdPtr;
buff[4] = KMCose.COSE_KEY_ALGORITHM;
buff[5] = keyAlg;
buff[6] = KMCose.COSE_KEY_KEY_OPS;
buff[7] = keyOps;
buff[8] = KMCose.COSE_KEY_CURVE;
buff[9] = curve;
boolean valid = false;
short ptr;
short tagIndex = 0;
short value;
while (tagIndex < coseKeyTags.length) {
value = coseKeyTags[(short) (tagIndex + 1)];
while (tagIndex < buffLen) {
value = buff[(short) (tagIndex + 1)];
if (value != KMType.INVALID_VALUE) {
valid = false;
ptr = getValueType(coseKeyTags[tagIndex], KMType.INVALID_VALUE);
ptr = getValueType(buff[tagIndex], KMType.INVALID_VALUE);
switch (KMType.getType(ptr)) {
case KMType.BYTE_BLOB_TYPE:
if ((KMByteBlob.cast(value).length() == KMByteBlob.cast(ptr).length()) &&
Expand Down
Loading