diff --git a/Applet/AndroidSEProvider/AndroidSEProvider.iml b/Applet/AndroidSEProvider/AndroidSEProvider.iml
new file mode 100644
index 00000000..1e48a48d
--- /dev/null
+++ b/Applet/AndroidSEProvider/AndroidSEProvider.iml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java
index 7c6f31fe..d888dcc0 100644
--- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java
+++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java
@@ -19,6 +19,8 @@
import org.globalplatform.upgrade.OnUpgradeListener;
import org.globalplatform.upgrade.UpgradeManager;
+import javacard.framework.Util;
+
public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeListener {
KMAndroidSEApplet() {
@@ -49,8 +51,15 @@ public void onRestore(Element element) {
element.initRead();
provisionStatus = element.readByte();
keymasterState = element.readByte();
- repository.onRestore(element);
- seProvider.onRestore(element);
+ // TODO write a comment
+ if (dataBaseVersion <= CURRENT_DATABASE_VERSION) {
+ dataBaseVersion = element.readShort();
+ }
+ repository.onRestore(element, dataBaseVersion, CURRENT_DATABASE_VERSION);
+ seProvider.onRestore(element, dataBaseVersion, CURRENT_DATABASE_VERSION);
+ if (dataBaseVersion == INVALID_DATA_VERSION) {
+ handleDataUpgradeToVersion1();
+ }
}
@Override
@@ -70,6 +79,7 @@ public Element onSave() {
primitiveCount, objectCount);
element.write(provisionStatus);
element.write(keymasterState);
+ element.write(dataBaseVersion);
repository.onSave(element);
seProvider.onSave(element);
return element;
@@ -77,11 +87,65 @@ public Element onSave() {
private short computePrimitveDataSize() {
// provisionStatus + keymasterState
- return (short) 2;
+ return (short) 4;
}
private short computeObjectCount() {
return (short) 0;
}
+
+ public void handleDataUpgradeToVersion1() {
+ dataBaseVersion = CURRENT_DATABASE_VERSION;
+ // 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()
+ );
+ }
+ 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);
+ repository.reclaimMemory((short) (certExpiryLen + issuerLen + certChainLen));
+ }
}
diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java
index 985d87fb..9c40ffab 100644
--- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java
+++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/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;
@@ -119,13 +121,14 @@ public class KMAndroidSEProvider implements KMSEProvider {
private static final short MAX_OPERATIONS = 4;
private static final short HMAC_MAX_OPERATIONS = 8;
private static final short COMPUTED_HMAC_KEY_SIZE = 32;
+ public static final short INVALID_DATA_VERSION = 0x7FFF;
private static final short CERT_CHAIN_OFFSET = 0;
private static final short CERT_ISSUER_OFFSET = KMConfigurations.CERT_CHAIN_MAX_SIZE;
private static final short CERT_EXPIRY_OFFSET =
(short) (CERT_ISSUER_OFFSET + KMConfigurations.CERT_ISSUER_MAX_SIZE);
- final byte[] CIPHER_ALGS = {
+ private static final byte[] CIPHER_ALGS = {
Cipher.ALG_AES_BLOCK_128_CBC_NOPAD,
Cipher.ALG_AES_BLOCK_128_ECB_NOPAD,
Cipher.ALG_DES_CBC_NOPAD,
@@ -136,7 +139,7 @@ public class KMAndroidSEProvider implements KMSEProvider {
Cipher.ALG_RSA_NOPAD,
AEADCipher.ALG_AES_GCM};
- final byte[] SIG_ALGS = {
+ private static final byte[] SIG_ALGS = {
Signature.ALG_RSA_SHA_256_PKCS1,
Signature.ALG_RSA_SHA_256_PKCS1_PSS,
Signature.ALG_ECDSA_SHA_256,
@@ -145,6 +148,14 @@ public class KMAndroidSEProvider implements KMSEProvider {
KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST,
KMEcdsa256NoDigestSignature.ALG_ECDSA_NODIGEST};
+ // [L] 256 bits - hardcoded 32 bits as per
+ // reference impl in keymaster.
+ private static final byte[] CMAC_KDF_CONSTANT_L = {
+ 0, 0, 1, 0
+ };
+ private static final byte[] CMAC_KDF_CONSTANT_ZERO = {
+ 0
+ };
// AESKey
private AESKey aesKeys[];
// DES3Key
@@ -715,15 +726,7 @@ public HMACKey cmacKdf(KMPreSharedKey preSharedKey, byte[] label, short labelSta
// This is hardcoded to requirement - 32 byte output with two concatenated
// 16 bytes K1 and K2.
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
- };
+
// [i] counter - 32 bits
short iBufLen = 4;
short keyOutLen = n * 16;
@@ -746,10 +749,10 @@ public HMACKey cmacKdf(KMPreSharedKey preSharedKey, byte[] label, short labelSta
// 4 bytes of iBuf with counter in it
kdf.update(tmpArray, (short) 0, (short) iBufLen);
kdf.update(label, labelStart, (short) labelLen); // label
- kdf.update(zero, (short) 0, (short) 1); // 1 byte of 0x00
+ kdf.update(CMAC_KDF_CONSTANT_ZERO, (short) 0, (short) CMAC_KDF_CONSTANT_ZERO.length); // 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(CMAC_KDF_CONSTANT_L, (short) 0, (short) CMAC_KDF_CONSTANT_L.length, tmpArray,
(short) (iBufLen + pos));
i++;
}
@@ -1119,6 +1122,11 @@ public KMAttestationCert getAttestationCert(boolean rsaCert) {
return KMAttestationCertImpl.instance(rsaCert);
}
+ @Override
+ public KMPKCS8Decoder getPKCS8DecoderInstance() {
+ return KMPKCS8DecoderImpl.instance();
+ }
+
@Override
public short cmacKDF(KMPreSharedKey pSharedKey, byte[] label,
short labelStart, short labelLen, byte[] context, short contextStart,
@@ -1147,8 +1155,7 @@ private void persistProvisionData(byte[] buf, short off, short len, short maxSiz
KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
}
JCSystem.beginTransaction();
- Util.setShort(provisionData, copyToOff, len);
- Util.arrayCopyNonAtomic(buf, off, provisionData, (short) (copyToOff + 2), len);
+ Util.arrayCopyNonAtomic(buf, off, provisionData, Util.setShort(provisionData, copyToOff, len), len);
JCSystem.commitTransaction();
}
@@ -1228,12 +1235,20 @@ public void onSave(Element element) {
}
@Override
- public void onRestore(Element element) {
+ public void onRestore(Element element, short oldVersion, short currentVersion) {
provisionData = (byte[]) element.readObject();
masterKey = KMAESKey.onRestore(element);
attestationKey = KMECPrivateKey.onRestore(element);
preSharedKey = KMHmacKey.onRestore(element);
- computedHmacKey = KMHmacKey.onRestore(element);
+ if (oldVersion == INVALID_DATA_VERSION) {
+ handleDataUpgradeToVersion1();
+ } else if (oldVersion <= currentVersion) {
+ computedHmacKey = KMHmacKey.onRestore(element);
+ } else {
+ // Invalid case
+ // TODO test exception in on Restore.
+ ISOException.throwIt(ISO7816.SW_DATA_INVALID);
+ }
}
@Override
@@ -1350,4 +1365,38 @@ public void releaseAllOperations() {
public KMComputedHmacKey getComputedHmacKey() {
return computedHmacKey;
}
+
+ private void handleDataUpgradeToVersion1() {
+ short totalLen = (short) (6 + KMConfigurations.CERT_CHAIN_MAX_SIZE +
+ KMConfigurations.CERT_ISSUER_MAX_SIZE + KMConfigurations.CERT_EXPIRY_MAX_SIZE);
+ byte[] oldBuffer = provisionData;
+ provisionData = new byte[totalLen];
+ persistCertificateChain(
+ oldBuffer,
+ (short) 2,
+ Util.getShort(oldBuffer, (short) 0));
+
+ // Request object deletion
+ oldBuffer = null;
+ JCSystem.requestObjectDeletion();
+
+ }
+
+ @Override
+ public short messageDigest256(byte[] inBuff, short inOffset,
+ short inLength, byte[] outBuff, short outOffset) {
+ MessageDigest.OneShot mDigest = null;
+ short len = 0;
+ try {
+ mDigest = MessageDigest.OneShot.open(MessageDigest.ALG_SHA_256);
+ len = mDigest.doFinal(inBuff, inOffset, inLength, outBuff, outOffset);
+ } finally {
+ if (mDigest != null) {
+ mDigest.close();
+ mDigest = null;
+ }
+ }
+ return len;
+ }
+
}
diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java
index e35853ca..7e5eb5cc 100644
--- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java
+++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java
@@ -70,6 +70,31 @@ public class KMAttestationCertImpl implements KMAttestationCert {
0x03,
0x02
};
+
+ // Below are the allowed softwareEnforced Authorization tags inside the attestation certificate's extension.
+ private static final short[] swTagIds = {
+ KMType.ATTESTATION_APPLICATION_ID,
+ KMType.CREATION_DATETIME,
+ KMType.USAGE_EXPIRE_DATETIME,
+ KMType.ORIGINATION_EXPIRE_DATETIME,
+ KMType.ACTIVE_DATETIME,
+ KMType.UNLOCKED_DEVICE_REQUIRED
+ };
+
+ // Below are the allowed hardwareEnforced Authorization tags inside the attestation certificate's extension.
+ private static final short[] hwTagIds = {
+ KMType.BOOT_PATCH_LEVEL, KMType.VENDOR_PATCH_LEVEL,
+ KMType.ATTESTATION_ID_MODEL, KMType.ATTESTATION_ID_MANUFACTURER,
+ KMType.ATTESTATION_ID_MEID, KMType.ATTESTATION_ID_IMEI,
+ KMType.ATTESTATION_ID_SERIAL, KMType.ATTESTATION_ID_PRODUCT,
+ KMType.ATTESTATION_ID_DEVICE, KMType.ATTESTATION_ID_BRAND,
+ KMType.OS_PATCH_LEVEL, KMType.OS_VERSION, KMType.ROOT_OF_TRUST,
+ KMType.ORIGIN, KMType.AUTH_TIMEOUT, KMType.USER_AUTH_TYPE,
+ KMType.NO_AUTH_REQUIRED, KMType.USER_SECURE_ID,
+ KMType.RSA_PUBLIC_EXPONENT, KMType.ECCURVE, KMType.MIN_MAC_LENGTH,
+ KMType.CALLER_NONCE, KMType.PADDING, KMType.DIGEST, KMType.BLOCK_MODE,
+ KMType.KEYSIZE, KMType.ALGORITHM, KMType.PURPOSE};
+
// Validity is not fixed field
// Subject is a fixed field with only CN= Android Keystore Key - same for all the keys
private static final byte[] X509Subject = {
@@ -451,44 +476,27 @@ private static void pushKeyDescription() {
private static void pushSWParams() {
short last = stackPtr;
- // Below are the allowed softwareEnforced Authorization tags inside the attestation certificate's extension.
- short[] tagIds = {
- KMType.ATTESTATION_APPLICATION_ID, KMType.CREATION_DATETIME,
- KMType.USAGE_EXPIRE_DATETIME, KMType.ORIGINATION_EXPIRE_DATETIME,
- KMType.ACTIVE_DATETIME, KMType.UNLOCKED_DEVICE_REQUIRED};
byte index = 0;
+ short length = (short) swTagIds.length;
do {
- pushParams(swParams, swParamsIndex, tagIds[index]);
- } while (++index < tagIds.length);
+ pushParams(swParams, swParamsIndex, swTagIds[index]);
+ } while (++index < length);
pushSequenceHeader((short) (last - stackPtr));
}
private static void pushHWParams() {
short last = stackPtr;
- // Below are the allowed hardwareEnforced Authorization tags inside the attestation certificate's extension.
- short[] tagIds = {
- KMType.BOOT_PATCH_LEVEL, KMType.VENDOR_PATCH_LEVEL,
- KMType.ATTESTATION_ID_MODEL, KMType.ATTESTATION_ID_MANUFACTURER,
- KMType.ATTESTATION_ID_MEID, KMType.ATTESTATION_ID_IMEI,
- KMType.ATTESTATION_ID_SERIAL, KMType.ATTESTATION_ID_PRODUCT,
- KMType.ATTESTATION_ID_DEVICE, KMType.ATTESTATION_ID_BRAND,
- KMType.OS_PATCH_LEVEL, KMType.OS_VERSION, KMType.ROOT_OF_TRUST,
- KMType.ORIGIN, KMType.AUTH_TIMEOUT, KMType.USER_AUTH_TYPE,
- KMType.NO_AUTH_REQUIRED, KMType.USER_SECURE_ID,
- KMType.RSA_PUBLIC_EXPONENT, KMType.ECCURVE, KMType.MIN_MAC_LENGTH,
- KMType.CALLER_NONCE, KMType.PADDING, KMType.DIGEST, KMType.BLOCK_MODE,
- KMType.KEYSIZE, KMType.ALGORITHM, KMType.PURPOSE};
-
byte index = 0;
+ short length = (short) hwTagIds.length;
do {
- if (tagIds[index] == KMType.ROOT_OF_TRUST) {
+ if (hwTagIds[index] == KMType.ROOT_OF_TRUST) {
pushRoT();
continue;
}
- if (pushParams(hwParams, hwParamsIndex, tagIds[index])) {
+ if (pushParams(hwParams, hwParamsIndex, hwTagIds[index])) {
continue;
}
- } while (++index < tagIds.length);
+ } while (++index < length);
pushSequenceHeader((short) (last - stackPtr));
}
diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java
index 81641ee7..de304d8f 100644
--- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java
+++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java
@@ -28,6 +28,7 @@ public class KMOperationImpl implements KMOperation {
private static final short OPER_MODE_OFFSET = 0x02;
private static final short BLOCK_MODE_OFFSET = 0x03;
private static final short MAC_LENGTH_OFFSET = 0x04;
+ private static final byte[] EMPTY = {};
//This will hold the length of the buffer stored inside the
//Java Card after the GCM update operation.
private static final short AES_GCM_UPDATE_LEN_OFFSET = 0x05;
@@ -239,13 +240,12 @@ public void abort() {
if (operationInst[0] != null) {
if ((parameters[OPER_MODE_OFFSET] == KMType.SIGN || parameters[OPER_MODE_OFFSET] == KMType.VERIFY) &&
(((Signature) operationInst[0]).getAlgorithm() == Signature.ALG_HMAC_SHA_256)) {
- byte[] empty = {};
Signature signer = (Signature) operationInst[0];
try {
if (parameters[OPER_MODE_OFFSET] == KMType.SIGN) {
- signer.verify(empty, (short) 0, (short) 0, empty, (short) 0, (short) 0);
+ signer.sign(EMPTY, (short) 0, (short) 0, EMPTY, (short) 0);
} else {
- signer.sign(empty, (short) 0, (short) 0, empty, (short) 0);
+ signer.verify(EMPTY, (short) 0, (short) 0, EMPTY, (short) 0, (short) 0);
}
} catch(Exception e) {
// Ignore.
diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMPKCS8DecoderImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMPKCS8DecoderImpl.java
new file mode 100644
index 00000000..8585587f
--- /dev/null
+++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMPKCS8DecoderImpl.java
@@ -0,0 +1,185 @@
+package com.android.javacard.keymaster;
+
+import javacard.framework.Util;
+
+public class KMPKCS8DecoderImpl implements KMPKCS8Decoder {
+ public static final byte ASN1_OCTET_STRING= 0x04;
+ public static final byte ASN1_SEQUENCE= 0x30;
+ public static final byte ASN1_INTEGER= 0x02;
+ public static final byte ASN1_A0_TAG = (byte) 0xA0;
+ public static final byte ASN1_A1_TAG = (byte) 0xA1;
+ public static final byte ASN1_BIT_STRING = 0x03;
+ public static final byte[] EC_CURVE = {
+ 0x06,0x08,0x2a,(byte)0x86,0x48,(byte)0xce,0x3d,0x03,
+ 0x01,0x07
+ };
+ public static final byte[] RSA_ALGORITHM = {
+ 0x06,0x09,0x2A,(byte)0x86,0x48,(byte)0x86,
+ (byte)0xF7,0x0D,0x01,0x01,0x01,0x05,0x00
+ };
+ public static final byte[] EC_ALGORITHM = {
+ 0x06,0x07,0x2a,(byte)0x86,0x48,(byte)0xce,
+ 0x3d,0x02,0x01,0x06,0x08,0x2a,(byte)0x86,0x48,
+ (byte)0xce,0x3d,0x03,0x01,0x07
+ };
+ private byte[] data;
+ private short start;
+ private short length;
+ private short cur;
+ private static KMPKCS8DecoderImpl inst;
+ private KMPKCS8DecoderImpl(){
+ start = 0;
+ length = 0;
+ cur = 0;
+ }
+
+ @Override
+ public short decodeRsa(short blob){
+ init(blob);
+ decodeCommon((short)0, RSA_ALGORITHM);
+ return decodeRsaPrivateKey((short)0);
+ }
+
+ @Override
+ public short decodeEc(short blob){
+ init(blob);
+ decodeCommon((short)0, EC_ALGORITHM);
+ return decodeEcPrivateKey((short)1);
+ }
+
+ //Seq[Int,Int,Int,Int,]
+ public short decodeRsaPrivateKey(short version){
+ short resp = KMArray.instance((short)3);
+ header(ASN1_OCTET_STRING);
+ header(ASN1_SEQUENCE);
+ short len =header(ASN1_INTEGER);
+ if(len != 1) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ short ver = getByte();
+ if(ver != version) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ len = header(ASN1_INTEGER);
+ short modulus = getModulus(len);
+ len = header(ASN1_INTEGER);
+ short pubKey = KMByteBlob.instance(len);
+ getBytes(pubKey);
+ len = header(ASN1_INTEGER);
+ short privKey = KMByteBlob.instance(len);
+ getBytes(privKey);
+ KMArray.cast(resp).add((short)0, modulus);
+ KMArray.cast(resp).add((short)1, pubKey);
+ KMArray.cast(resp).add((short)2, privKey);
+ return resp;
+ }
+
+ // Seq [Int, Blob]
+ public void decodeCommon(short version, byte[] alg){
+ short len = header(ASN1_SEQUENCE);
+ len = header(ASN1_INTEGER);
+ if(len != 1) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ short ver = getByte();
+ if(ver !=version) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ len = header(ASN1_SEQUENCE);
+ short blob = KMByteBlob.instance(len);
+ getBytes(blob);
+ if(Util.arrayCompare(
+ KMByteBlob.cast(blob).getBuffer(),
+ KMByteBlob.cast(blob).getStartOff(),
+ alg,
+ (short)0,KMByteBlob.cast(blob).length()) !=0){
+ KMException.throwIt(KMError.UNKNOWN_ERROR);
+ }
+ }
+
+ //Seq[Int,blob,blob]
+ public short decodeEcPrivateKey(short version){
+ short resp = KMArray.instance((short)2);
+ header(ASN1_OCTET_STRING);
+ header(ASN1_SEQUENCE);
+ short len = header(ASN1_INTEGER);
+ if(len != 1) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ short ver = getByte();
+ if(ver != version) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ len = header(ASN1_OCTET_STRING);
+ short privKey = KMByteBlob.instance(len);
+ getBytes(privKey);
+ validateTag0IfPresent();
+ header(ASN1_A1_TAG);
+ len = header(ASN1_BIT_STRING);
+ if(len < 1) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ byte unusedBits = getByte();
+ if(unusedBits != 0) KMException.throwIt(KMError.UNIMPLEMENTED);
+ short pubKey = KMByteBlob.instance((short)(len -1));
+ getBytes(pubKey);
+ KMArray.cast(resp).add((short)0, pubKey);
+ KMArray.cast(resp).add((short)1, privKey);
+ return resp;
+ }
+ private void validateTag0IfPresent(){
+ if(data[cur] != ASN1_A0_TAG) return;;
+ short len = header(ASN1_A0_TAG);
+ if(len != EC_CURVE.length) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ if(Util.arrayCompare(data, cur, EC_CURVE, (short)0, len) != 0) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ incrementCursor(len);
+ }
+ private short header(short tag){
+ short t = getByte();
+ if(t != tag) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ return getLength();
+ }
+
+ private byte getByte(){
+ byte d = data[cur];
+ incrementCursor((short)1);
+ return d;
+ }
+
+ private short getShort(){
+ short d = Util.getShort(data, cur);
+ incrementCursor((short)2);
+ return d;
+ }
+
+ private short getModulus(short modulusLen) {
+ if(0 == data[cur] && modulusLen == 257) {
+ incrementCursor((short) 1);
+ modulusLen--;
+ }
+ short blob = KMByteBlob.instance(modulusLen);
+ getBytes(blob);
+ return blob;
+ }
+
+ private void getBytes(short blob){
+ short len = KMByteBlob.cast(blob).length();
+ Util.arrayCopyNonAtomic(data, cur, KMByteBlob.cast(blob).getBuffer(),
+ KMByteBlob.cast(blob).getStartOff(), len);
+ incrementCursor(len);
+ }
+
+ private short getLength(){
+ byte len = getByte();
+ if(len >= 0) return len;
+ len = (byte)(len & 0x7F);
+ if(len == 1) return (short)(getByte() & 0xFF);
+ else if(len == 2) return getShort();
+ else KMException.throwIt(KMError.UNKNOWN_ERROR);
+ return KMType.INVALID_VALUE; //should not come here
+ }
+ public static KMPKCS8DecoderImpl instance() {
+ if (inst == null) {
+ inst = new KMPKCS8DecoderImpl();
+ }
+ return inst;
+ }
+
+ public void init(short blob) {
+ data = KMByteBlob.cast(blob).getBuffer();
+ start = KMByteBlob.cast(blob).getStartOff();
+ length = KMByteBlob.cast(blob).length();
+ cur = start;
+ }
+
+ public void incrementCursor(short n){
+ cur += n;
+ if(cur > ((short)(start+length))) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ }
+}
diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java
index 88b7b4d1..e41663ec 100644
--- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java
+++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java
@@ -52,6 +52,8 @@ public class KMUtils {
0, 0, 0, 0, (byte) 0x9A, 0x7E, (byte) 0xC8, 0x00};//2592000000
public static final short year2051 = 2051;
public static final short year2020 = 2020;
+ // Convert to milliseconds constants
+ public static final byte[] SEC_TO_MILLIS_SHIFT_POS = {9, 8, 7, 6, 5, 3};
// --------------------------------------
public static short convertToDate(short time, byte[] scratchPad,
@@ -422,11 +424,11 @@ public static short getLeapYrIndex(boolean from2020, short yrsCount) {
// i * 1000 = (i << 9) + (i << 8) + (i << 7) + (i << 6) + (i << 5) + ( i << 3)
public static void convertToMilliseconds(byte[] buf, short inputOff, short outputOff,
short scratchPadOff) {
- byte[] shiftPos = {9, 8, 7, 6, 5, 3};
short index = 0;
- while (index < (short) (shiftPos.length)) {
+ short length = (short) SEC_TO_MILLIS_SHIFT_POS.length;
+ while (index < length) {
Util.arrayCopyNonAtomic(buf, inputOff, buf, scratchPadOff, (short) 8);
- shiftLeft(buf, scratchPadOff, shiftPos[index]);
+ shiftLeft(buf, scratchPadOff, SEC_TO_MILLIS_SHIFT_POS[index]);
Util.arrayCopyNonAtomic(buf, outputOff, buf, (short) (scratchPadOff + 8), (short) 8);
add(buf, scratchPadOff, (short) (8 + scratchPadOff), (short) (16 + scratchPadOff));
Util.arrayCopyNonAtomic(buf, (short) (scratchPadOff + 16), buf, outputOff, (short) 8);
diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java
index e0d2b546..2086620f 100644
--- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java
+++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java
@@ -40,6 +40,7 @@
import javacard.security.Key;
import javacard.security.KeyBuilder;
import javacard.security.KeyPair;
+import javacard.security.MessageDigest;
import javacard.security.RSAPrivateKey;
import javacard.security.RSAPublicKey;
import javacard.security.RandomData;
@@ -1178,6 +1179,12 @@ public void addRngEntropy(byte[] num, short offset, short length) {
public KMAttestationCert getAttestationCert(boolean rsaCert) {
return KMAttestationCertImpl.instance(rsaCert);
}
+
+ @Override
+ public KMPKCS8Decoder getPKCS8DecoderInstance() {
+ return KMPKCS8DecoderImpl.instance();
+ }
+
private short getProvisionDataBufferOffset(byte dataType) {
switch(dataType) {
case CERTIFICATE_CHAIN:
@@ -1286,7 +1293,7 @@ public void onSave(Element ele) {
}
@Override
- public void onRestore(Element ele) {
+ public void onRestore(Element ele, short oldVersion, short currentVersion) {
}
@Override
@@ -1383,4 +1390,19 @@ public KMComputedHmacKey getComputedHmacKey() {
public void releaseAllOperations() {
//Do nothing.
}
+
+ @Override
+ public short messageDigest256(byte[] inBuff, short inOffset,
+ short inLength, byte[] outBuff, short outOffset) {
+ MessageDigest mDigest = null;
+ short len = 0;
+ try {
+ mDigest = MessageDigest.getInitializedMessageDigestInstance(MessageDigest.ALG_SHA_256, false);
+ len = mDigest.doFinal(inBuff, inOffset, inLength, outBuff, outOffset);
+ } catch (Exception e) {
+
+ }
+ return len;
+ }
+
}
diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMPKCS8DecoderImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMPKCS8DecoderImpl.java
new file mode 100644
index 00000000..8585587f
--- /dev/null
+++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMPKCS8DecoderImpl.java
@@ -0,0 +1,185 @@
+package com.android.javacard.keymaster;
+
+import javacard.framework.Util;
+
+public class KMPKCS8DecoderImpl implements KMPKCS8Decoder {
+ public static final byte ASN1_OCTET_STRING= 0x04;
+ public static final byte ASN1_SEQUENCE= 0x30;
+ public static final byte ASN1_INTEGER= 0x02;
+ public static final byte ASN1_A0_TAG = (byte) 0xA0;
+ public static final byte ASN1_A1_TAG = (byte) 0xA1;
+ public static final byte ASN1_BIT_STRING = 0x03;
+ public static final byte[] EC_CURVE = {
+ 0x06,0x08,0x2a,(byte)0x86,0x48,(byte)0xce,0x3d,0x03,
+ 0x01,0x07
+ };
+ public static final byte[] RSA_ALGORITHM = {
+ 0x06,0x09,0x2A,(byte)0x86,0x48,(byte)0x86,
+ (byte)0xF7,0x0D,0x01,0x01,0x01,0x05,0x00
+ };
+ public static final byte[] EC_ALGORITHM = {
+ 0x06,0x07,0x2a,(byte)0x86,0x48,(byte)0xce,
+ 0x3d,0x02,0x01,0x06,0x08,0x2a,(byte)0x86,0x48,
+ (byte)0xce,0x3d,0x03,0x01,0x07
+ };
+ private byte[] data;
+ private short start;
+ private short length;
+ private short cur;
+ private static KMPKCS8DecoderImpl inst;
+ private KMPKCS8DecoderImpl(){
+ start = 0;
+ length = 0;
+ cur = 0;
+ }
+
+ @Override
+ public short decodeRsa(short blob){
+ init(blob);
+ decodeCommon((short)0, RSA_ALGORITHM);
+ return decodeRsaPrivateKey((short)0);
+ }
+
+ @Override
+ public short decodeEc(short blob){
+ init(blob);
+ decodeCommon((short)0, EC_ALGORITHM);
+ return decodeEcPrivateKey((short)1);
+ }
+
+ //Seq[Int,Int,Int,Int,]
+ public short decodeRsaPrivateKey(short version){
+ short resp = KMArray.instance((short)3);
+ header(ASN1_OCTET_STRING);
+ header(ASN1_SEQUENCE);
+ short len =header(ASN1_INTEGER);
+ if(len != 1) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ short ver = getByte();
+ if(ver != version) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ len = header(ASN1_INTEGER);
+ short modulus = getModulus(len);
+ len = header(ASN1_INTEGER);
+ short pubKey = KMByteBlob.instance(len);
+ getBytes(pubKey);
+ len = header(ASN1_INTEGER);
+ short privKey = KMByteBlob.instance(len);
+ getBytes(privKey);
+ KMArray.cast(resp).add((short)0, modulus);
+ KMArray.cast(resp).add((short)1, pubKey);
+ KMArray.cast(resp).add((short)2, privKey);
+ return resp;
+ }
+
+ // Seq [Int, Blob]
+ public void decodeCommon(short version, byte[] alg){
+ short len = header(ASN1_SEQUENCE);
+ len = header(ASN1_INTEGER);
+ if(len != 1) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ short ver = getByte();
+ if(ver !=version) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ len = header(ASN1_SEQUENCE);
+ short blob = KMByteBlob.instance(len);
+ getBytes(blob);
+ if(Util.arrayCompare(
+ KMByteBlob.cast(blob).getBuffer(),
+ KMByteBlob.cast(blob).getStartOff(),
+ alg,
+ (short)0,KMByteBlob.cast(blob).length()) !=0){
+ KMException.throwIt(KMError.UNKNOWN_ERROR);
+ }
+ }
+
+ //Seq[Int,blob,blob]
+ public short decodeEcPrivateKey(short version){
+ short resp = KMArray.instance((short)2);
+ header(ASN1_OCTET_STRING);
+ header(ASN1_SEQUENCE);
+ short len = header(ASN1_INTEGER);
+ if(len != 1) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ short ver = getByte();
+ if(ver != version) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ len = header(ASN1_OCTET_STRING);
+ short privKey = KMByteBlob.instance(len);
+ getBytes(privKey);
+ validateTag0IfPresent();
+ header(ASN1_A1_TAG);
+ len = header(ASN1_BIT_STRING);
+ if(len < 1) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ byte unusedBits = getByte();
+ if(unusedBits != 0) KMException.throwIt(KMError.UNIMPLEMENTED);
+ short pubKey = KMByteBlob.instance((short)(len -1));
+ getBytes(pubKey);
+ KMArray.cast(resp).add((short)0, pubKey);
+ KMArray.cast(resp).add((short)1, privKey);
+ return resp;
+ }
+ private void validateTag0IfPresent(){
+ if(data[cur] != ASN1_A0_TAG) return;;
+ short len = header(ASN1_A0_TAG);
+ if(len != EC_CURVE.length) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ if(Util.arrayCompare(data, cur, EC_CURVE, (short)0, len) != 0) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ incrementCursor(len);
+ }
+ private short header(short tag){
+ short t = getByte();
+ if(t != tag) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ return getLength();
+ }
+
+ private byte getByte(){
+ byte d = data[cur];
+ incrementCursor((short)1);
+ return d;
+ }
+
+ private short getShort(){
+ short d = Util.getShort(data, cur);
+ incrementCursor((short)2);
+ return d;
+ }
+
+ private short getModulus(short modulusLen) {
+ if(0 == data[cur] && modulusLen == 257) {
+ incrementCursor((short) 1);
+ modulusLen--;
+ }
+ short blob = KMByteBlob.instance(modulusLen);
+ getBytes(blob);
+ return blob;
+ }
+
+ private void getBytes(short blob){
+ short len = KMByteBlob.cast(blob).length();
+ Util.arrayCopyNonAtomic(data, cur, KMByteBlob.cast(blob).getBuffer(),
+ KMByteBlob.cast(blob).getStartOff(), len);
+ incrementCursor(len);
+ }
+
+ private short getLength(){
+ byte len = getByte();
+ if(len >= 0) return len;
+ len = (byte)(len & 0x7F);
+ if(len == 1) return (short)(getByte() & 0xFF);
+ else if(len == 2) return getShort();
+ else KMException.throwIt(KMError.UNKNOWN_ERROR);
+ return KMType.INVALID_VALUE; //should not come here
+ }
+ public static KMPKCS8DecoderImpl instance() {
+ if (inst == null) {
+ inst = new KMPKCS8DecoderImpl();
+ }
+ return inst;
+ }
+
+ public void init(short blob) {
+ data = KMByteBlob.cast(blob).getBuffer();
+ start = KMByteBlob.cast(blob).getStartOff();
+ length = KMByteBlob.cast(blob).length();
+ cur = start;
+ }
+
+ public void incrementCursor(short n){
+ cur += n;
+ if(cur > ((short)(start+length))) KMException.throwIt(KMError.UNKNOWN_ERROR);
+ }
+}
diff --git a/Applet/src/com/android/javacard/keymaster/KMDecoder.java b/Applet/src/com/android/javacard/keymaster/KMDecoder.java
index e305913c..7bd0e6ec 100644
--- a/Applet/src/com/android/javacard/keymaster/KMDecoder.java
+++ b/Applet/src/com/android/javacard/keymaster/KMDecoder.java
@@ -436,14 +436,14 @@ private void incrementStartOff(short inc) {
}
}
-//Reads the offset and length values of the ByteBlobs from a CBOR array buffer.
+ // Reads the offset and length values of the ByteBlobs from a CBOR array buffer.
public void decodeCertificateData(short expectedArrLen, byte[] buf, short bufOffset, short bufLen,
byte[] out, short outOff) {
- // Read Array length
bufferRef[0] = buf;
scratchBuf[START_OFFSET] = bufOffset;
scratchBuf[LEN_OFFSET] = (short) (bufOffset + bufLen);
short byteBlobLength = 0;
+ // Read Array length
short payloadLength = readMajorTypeWithPayloadLength(ARRAY_TYPE);
if (expectedArrLen != payloadLength) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID);
@@ -459,5 +459,14 @@ public void decodeCertificateData(short expectedArrLen, byte[] buf, short bufOff
index++;
}
}
+
+ public short getCborBytesStartOffset(byte[] buf, short bufOffset, short bufLen) {
+ bufferRef[0] = buf;
+ scratchBuf[START_OFFSET] = bufOffset;
+ scratchBuf[LEN_OFFSET] = (short) (bufOffset + bufLen);
+
+ readMajorTypeWithPayloadLength(BYTES_TYPE);
+ return scratchBuf[START_OFFSET];
+ }
}
diff --git a/Applet/src/com/android/javacard/keymaster/KMEnum.java b/Applet/src/com/android/javacard/keymaster/KMEnum.java
index 2b55a6ce..a55c243d 100644
--- a/Applet/src/com/android/javacard/keymaster/KMEnum.java
+++ b/Applet/src/com/android/javacard/keymaster/KMEnum.java
@@ -30,7 +30,7 @@ public class KMEnum extends KMType {
private static KMEnum prototype;
// The allowed enum types.
- private static short[] types = {
+ private static final short[] types = {
HARDWARE_TYPE,
KEY_FORMAT,
KEY_DERIVATION_FUNCTION,
diff --git a/Applet/src/com/android/javacard/keymaster/KMEnumTag.java b/Applet/src/com/android/javacard/keymaster/KMEnumTag.java
index 0e45414e..f69aaf51 100644
--- a/Applet/src/com/android/javacard/keymaster/KMEnumTag.java
+++ b/Applet/src/com/android/javacard/keymaster/KMEnumTag.java
@@ -31,7 +31,7 @@ public class KMEnumTag extends KMTag {
// The allowed tag keys of type enum tag.
- private static short[] tags = {
+ private static final short[] tags = {
ALGORITHM, ECCURVE, BLOB_USAGE_REQ, USER_AUTH_TYPE, ORIGIN, HARDWARE_TYPE
};
diff --git a/Applet/src/com/android/javacard/keymaster/KMInteger.java b/Applet/src/com/android/javacard/keymaster/KMInteger.java
index fd080198..2ae32ac1 100644
--- a/Applet/src/com/android/javacard/keymaster/KMInteger.java
+++ b/Applet/src/com/android/javacard/keymaster/KMInteger.java
@@ -101,14 +101,14 @@ public static short uint_16(short num) {
// create integer and copy integer value
public static short uint_32(byte[] num, short offset) {
short ptr = instance(UINT_32);
- Util.arrayCopy(num, offset, heap, (short) (ptr + TLV_HEADER_SIZE), UINT_32);
+ Util.arrayCopyNonAtomic(num, offset, heap, (short) (ptr + TLV_HEADER_SIZE), UINT_32);
return ptr;
}
// create integer and copy integer value
public static short uint_64(byte[] num, short offset) {
short ptr = instance(UINT_64);
- Util.arrayCopy(num, offset, heap, (short) (ptr + TLV_HEADER_SIZE), UINT_64);
+ Util.arrayCopyNonAtomic(num, offset, heap, (short) (ptr + TLV_HEADER_SIZE), UINT_64);
return ptr;
}
diff --git a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java
index 3592e32b..f57fffbe 100644
--- a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java
+++ b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java
@@ -26,9 +26,61 @@
* arrayPtr is a pointer to array with any KMTag subtype instances.
*/
public class KMKeyParameters extends KMType {
-
-
- private static short[] customTags;
+
+ private static final short[] tagArr = {
+ // Unsupported tags.
+ KMType.BOOL_TAG, KMType.TRUSTED_USER_PRESENCE_REQUIRED,
+ KMType.BOOL_TAG, KMType.ALLOW_WHILE_ON_BODY,
+ KMType.UINT_TAG, KMType.MIN_SEC_BETWEEN_OPS
+ };
+
+ private static final short[] hwEnforcedTagArr = {
+ // HW Enforced
+ KMType.ENUM_TAG, KMType.ORIGIN,
+ KMType.ENUM_ARRAY_TAG, KMType.PURPOSE,
+ KMType.ENUM_TAG, KMType.ALGORITHM,
+ KMType.UINT_TAG, KMType.KEYSIZE,
+ KMType.ULONG_TAG, KMType.RSA_PUBLIC_EXPONENT,
+ KMType.ENUM_TAG, KMType.BLOB_USAGE_REQ,
+ KMType.ENUM_ARRAY_TAG, KMType.DIGEST,
+ KMType.ENUM_ARRAY_TAG, KMType.PADDING,
+ KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE,
+ KMType.ULONG_ARRAY_TAG, KMType.USER_SECURE_ID,
+ KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED,
+ KMType.UINT_TAG, KMType.AUTH_TIMEOUT,
+ KMType.BOOL_TAG, KMType.CALLER_NONCE,
+ KMType.UINT_TAG, KMType.MIN_MAC_LENGTH,
+ KMType.ENUM_TAG, KMType.ECCURVE,
+ KMType.BOOL_TAG, KMType.INCLUDE_UNIQUE_ID,
+ KMType.BOOL_TAG, KMType.ROLLBACK_RESISTANCE,
+ KMType.ENUM_TAG, KMType.USER_AUTH_TYPE,
+ KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED,
+ KMType.BOOL_TAG, KMType.RESET_SINCE_ID_ROTATION,
+ KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY,
+ KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY,
+ KMType.UINT_TAG, KMType.MAX_USES_PER_BOOT,
+ KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED
+ };
+
+ private static final short[] swEnforcedTagsArr = {
+ KMType.DATE_TAG, KMType.ACTIVE_DATETIME,
+ KMType.DATE_TAG, KMType.ORIGINATION_EXPIRE_DATETIME,
+ KMType.DATE_TAG, KMType.USAGE_EXPIRE_DATETIME,
+ KMType.UINT_TAG, KMType.USERID,
+ KMType.DATE_TAG, KMType.CREATION_DATETIME,
+ KMType.BOOL_TAG, KMType.ALLOW_WHILE_ON_BODY
+ };
+
+ private static final short[] invalidTagsArr = {
+ KMType.BYTES_TAG, KMType.NONCE,
+ KMType.BYTES_TAG, KMType.ASSOCIATED_DATA,
+ KMType.BYTES_TAG, KMType.UNIQUE_ID,
+ KMType.UINT_TAG, KMType.MAC_LENGTH,
+ };
+
+ private static final short[] customTags = {
+ KMType.ULONG_TAG, KMType.AUTH_TIMEOUT_MILLIS,
+ };
private static KMKeyParameters prototype;
@@ -111,12 +163,6 @@ public short findTag(short tagType, short tagKey) {
}
public static boolean hasUnsupportedTags(short keyParamsPtr) {
- final short[] tagArr = {
- // Unsupported tags.
- KMType.BOOL_TAG, KMType.TRUSTED_USER_PRESENCE_REQUIRED,
- KMType.BOOL_TAG, KMType.ALLOW_WHILE_ON_BODY,
- KMType.UINT_TAG, KMType.MIN_SEC_BETWEEN_OPS
- };
byte index = 0;
short tagInd;
short tagPtr;
@@ -145,33 +191,6 @@ public static boolean hasUnsupportedTags(short keyParamsPtr) {
public static short makeHwEnforced(short keyParamsPtr, byte origin,
short osVersionObjPtr, short osPatchObjPtr, short vendorPatchObjPtr,
short bootPatchObjPtr, byte[] scratchPad) {
- final short[] hwEnforcedTagArr = {
- // HW Enforced
- KMType.ENUM_TAG, KMType.ORIGIN,
- KMType.ENUM_ARRAY_TAG, KMType.PURPOSE,
- KMType.ENUM_TAG, KMType.ALGORITHM,
- KMType.UINT_TAG, KMType.KEYSIZE,
- KMType.ULONG_TAG, KMType.RSA_PUBLIC_EXPONENT,
- KMType.ENUM_TAG, KMType.BLOB_USAGE_REQ,
- KMType.ENUM_ARRAY_TAG, KMType.DIGEST,
- KMType.ENUM_ARRAY_TAG, KMType.PADDING,
- KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE,
- KMType.ULONG_ARRAY_TAG, KMType.USER_SECURE_ID,
- KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED,
- KMType.UINT_TAG, KMType.AUTH_TIMEOUT,
- KMType.BOOL_TAG, KMType.CALLER_NONCE,
- KMType.UINT_TAG, KMType.MIN_MAC_LENGTH,
- KMType.ENUM_TAG, KMType.ECCURVE,
- KMType.BOOL_TAG, KMType.INCLUDE_UNIQUE_ID,
- KMType.BOOL_TAG, KMType.ROLLBACK_RESISTANCE,
- KMType.ENUM_TAG, KMType.USER_AUTH_TYPE,
- KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED,
- KMType.BOOL_TAG, KMType.RESET_SINCE_ID_ROTATION,
- KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY,
- KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY,
- KMType.UINT_TAG, KMType.MAX_USES_PER_BOOT,
- KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED
- };
byte index = 0;
short tagInd;
short arrInd = 0;
@@ -224,14 +243,6 @@ public static short makeHwEnforced(short keyParamsPtr, byte origin,
// ALL_USERS, EXPORTABLE missing from types.hal
public static short makeSwEnforced(short keyParamsPtr, byte[] scratchPad) {
- final short[] swEnforcedTagsArr = {
- KMType.DATE_TAG, KMType.ACTIVE_DATETIME,
- KMType.DATE_TAG, KMType.ORIGINATION_EXPIRE_DATETIME,
- KMType.DATE_TAG, KMType.USAGE_EXPIRE_DATETIME,
- KMType.UINT_TAG, KMType.USERID,
- KMType.DATE_TAG, KMType.CREATION_DATETIME,
- KMType.BOOL_TAG, KMType.ALLOW_WHILE_ON_BODY
- };
byte index = 0;
short tagInd;
short arrInd = 0;
@@ -296,12 +307,6 @@ public static short makeHidden(short appIdBlob, short appDataBlob, short rootOfT
}
public static boolean isValidTag(short tagType, short tagKey) {
- short[] invalidTagsArr = {
- KMType.BYTES_TAG, KMType.NONCE,
- KMType.BYTES_TAG, KMType.ASSOCIATED_DATA,
- KMType.BYTES_TAG, KMType.UNIQUE_ID,
- KMType.UINT_TAG, KMType.MAC_LENGTH,
- };
short index = 0;
if (tagKey == KMType.INVALID_TAG) {
return false;
@@ -326,18 +331,8 @@ public static short createKeyParameters(byte[] ptrArr, short len) {
}
return KMKeyParameters.instance(arrPtr);
}
-
- private static short[] getCustomTags() {
- if (customTags == null) {
- customTags = new short[] {
- KMType.ULONG_TAG, KMType.AUTH_TIMEOUT_MILLIS,
- };
- }
- return customTags;
- }
-
+
public static short addCustomTags(short keyParams, byte[] scratchPad, short offset) {
- short[] customTags = getCustomTags();
short index = 0;
short tagPtr;
short len = (short) customTags.length;
@@ -364,7 +359,6 @@ public static short addCustomTags(short keyParams, byte[] scratchPad, short offs
public void deleteCustomTags() {
short arrPtr = getVals();
- short[] customTags = getCustomTags();
short index = (short) (customTags.length - 1);
short obj;
while (index >= 0) {
diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java
index b2df2690..77bfdf6a 100644
--- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java
+++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java
@@ -40,9 +40,14 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe
public static final short MAX_LENGTH = (short) 0x2000;
private static final byte CLA_ISO7816_NO_SM_NO_CHAN = (byte) 0x80;
private static final short KM_HAL_VERSION = (short) 0x4000;
- private static final short MAX_AUTH_DATA_SIZE = (short) 512;
+ private static final short MAX_AUTH_DATA_SIZE = (short) 256;
private static final short DERIVE_KEY_INPUT_SIZE = (short) 256;
private static final short POWER_RESET_MASK_FLAG = (short) 0x4000;
+ // DATABASE version
+ public static final short DATABASE_VERSION_1 = 1;
+ public static final short CURRENT_DATABASE_VERSION = DATABASE_VERSION_1;
+ public static final short INVALID_DATA_VERSION = 0x7FFF;
+ protected short dataBaseVersion;
// "Keymaster HMAC Verification" - used for HMAC key verification.
public static final byte[] sharingCheck = {
@@ -68,6 +73,14 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe
0x6B,
0x65, 0x6E
};
+
+ // getHardwareInfo constants.
+ private static final byte[] JAVACARD_KEYMASTER_DEVICE = {
+ 0x4A, 0x61, 0x76, 0x61, 0x63, 0x61, 0x72, 0x64, 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74,
+ 0x65, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
+ };
+ private static final byte[] GOOGLE = {0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65};
+
// Possible states of the applet.
private static final byte KM_BEGIN_STATE = 0x00;
@@ -199,9 +212,11 @@ protected KMKeymasterApplet(KMSEProvider seImpl) {
boolean isUpgrading = seImpl.isUpgrading();
repository = new KMRepository(isUpgrading);
initializeTransientArrays();
+ dataBaseVersion = INVALID_DATA_VERSION;
if (!isUpgrading) {
keymasterState = KMKeymasterApplet.INIT_STATE;
seProvider.createMasterKey((short) (KMRepository.MASTER_KEY_SIZE * 8));
+ dataBaseVersion = CURRENT_DATABASE_VERSION;
}
KMType.initialize();
encoder = new KMEncoder();
@@ -615,12 +630,6 @@ public static void receiveIncoming(APDU apdu) {
private void processGetHwInfoCmd(APDU apdu) {
// No arguments expected
- final byte[] JavacardKeymasterDevice = {
- 0x4A, 0x61, 0x76, 0x61, 0x63, 0x61, 0x72, 0x64, 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74,
- 0x65, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
- };
- final byte[] Google = {0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65};
-
// Make the response
short respPtr = KMArray.instance((short) 3);
KMArray resp = KMArray.cast(respPtr);
@@ -628,8 +637,8 @@ private void processGetHwInfoCmd(APDU apdu) {
resp.add(
(short) 1,
KMByteBlob.instance(
- JavacardKeymasterDevice, (short) 0, (short) JavacardKeymasterDevice.length));
- resp.add((short) 2, KMByteBlob.instance(Google, (short) 0, (short) Google.length));
+ JAVACARD_KEYMASTER_DEVICE, (short) 0, (short) JAVACARD_KEYMASTER_DEVICE.length));
+ resp.add((short) 2, KMByteBlob.instance(GOOGLE, (short) 0, (short) GOOGLE.length));
bufferProp[BUF_START_OFFSET] = repository.allocAvailableMemory();
// Encode the response - actual bufferProp[BUF_LEN_OFFSET] is 86
@@ -2025,7 +2034,7 @@ private boolean verifyVerificationTokenMacInBigEndian(short verToken, byte[] scr
// empty
Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0);
// Add "Auth Verification" - 17 bytes.
- Util.arrayCopy(authVerification, (short) 0, scratchPad, (short) 0, (short) authVerification.length);
+ Util.arrayCopyNonAtomic(authVerification, (short) 0, scratchPad, (short) 0, (short) authVerification.length);
short len = (short) authVerification.length;
// concatenate challenge - 8 bytes
short ptr = KMVerificationToken.cast(verToken).getChallenge();
@@ -2063,7 +2072,7 @@ private boolean verifyVerificationTokenMacInLittleEndian(short verToken, byte[]
// empty
Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0);
// Add "Auth Verification" - 17 bytes.
- Util.arrayCopy(authVerification, (short) 0, scratchPad, (short) 0, (short) authVerification.length);
+ Util.arrayCopyNonAtomic(authVerification, (short) 0, scratchPad, (short) 0, (short) authVerification.length);
short len = (short) authVerification.length;
// concatenate challenge - 8 bytes
short ptr = KMVerificationToken.cast(verToken).getChallenge();
@@ -2307,7 +2316,7 @@ private void processBeginOperationCmd(APDU apdu) {
// While sending the iv back for DES/CBC mode of opeation only send
// 8 bytes back.
tmpVariables[1] = KMByteBlob.instance((short) 8);
- Util.arrayCopy(
+ Util.arrayCopyNonAtomic(
KMByteBlob.cast(data[IV]).getBuffer(),
KMByteBlob.cast(data[IV]).getStartOff(),
KMByteBlob.cast(tmpVariables[1]).getBuffer(),
@@ -3081,8 +3090,7 @@ private void decodeRawECKey() {
private void decodePKCS8ECKeys() {
// Decode key material
- KMPKCS8Decoder pkcs8 = KMPKCS8Decoder.instance();
- short keyBlob = pkcs8.decodeEc(data[IMPORTED_KEY_BLOB]);
+ short keyBlob = seProvider.getPKCS8DecoderInstance().decodeEc(data[IMPORTED_KEY_BLOB]);
data[PUB_KEY] = KMArray.cast(keyBlob).get((short) 0);
data[SECRET] = KMArray.cast(keyBlob).get((short) 1);
}
@@ -3233,6 +3241,7 @@ private void importTDESKey(byte[] scratchPad) {
// update the key parameters list
updateKeyParameters(scratchPad, tmpVariables[4]);
// Read Minimum Mac length - it must not be present
+ //Added this error check based on default reference implementation.
tmpVariables[0] =
KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, data[KEY_PARAMETERS]);
if (tmpVariables[0] != KMType.INVALID_VALUE) {
@@ -3287,8 +3296,7 @@ private void importAESKey(byte[] scratchPad) {
private void importRSAKey(byte[] scratchPad) {
// Decode key material
- KMPKCS8Decoder pkcs8 = KMPKCS8Decoder.instance();
- short keyblob = pkcs8.decodeRsa(data[IMPORTED_KEY_BLOB]);
+ short keyblob = seProvider.getPKCS8DecoderInstance().decodeRsa(data[IMPORTED_KEY_BLOB]);
data[PUB_KEY] = KMArray.cast(keyblob).get((short) 0);
short pubKeyExp = KMArray.cast(keyblob).get((short)1);
data[SECRET] = KMArray.cast(keyblob).get((short) 2);
@@ -3989,87 +3997,64 @@ private static void encryptSecret(byte[] scratchPad) {
}
private static void makeAuthData(byte[] scratchPad) {
- tmpVariables[0] =
- addPtrToAAD(KMKeyParameters.cast(data[HW_PARAMETERS]).getVals(), scratchPad, (short) 0);
- tmpVariables[0] +=
- addPtrToAAD(
- KMKeyParameters.cast(data[SW_PARAMETERS]).getVals(), scratchPad, tmpVariables[0]);
- tmpVariables[0] +=
- addPtrToAAD(
- KMKeyParameters.cast(data[HIDDEN_PARAMETERS]).getVals(), scratchPad, tmpVariables[0]);
-
- if (KMArray.cast(data[KEY_BLOB]).length() == 5) {
- tmpVariables[1] = KMArray.instance((short) (tmpVariables[0] + 1));
- } else {
- tmpVariables[1] = KMArray.instance(tmpVariables[0]);
- }
- // convert scratch pad to KMArray
- short index = 0;
- short objPtr;
- while (index < tmpVariables[0]) {
- objPtr = Util.getShort(scratchPad, (short) (index * 2));
- KMArray.cast(tmpVariables[1]).add(index, objPtr);
- index++;
- }
- if (KMArray.cast(data[KEY_BLOB]).length() == 5) {
- KMArray.cast(tmpVariables[1]).add(index, data[PUB_KEY]);
- }
-
- data[AUTH_DATA] = repository.alloc(MAX_AUTH_DATA_SIZE);
- short len = encoder.encode(tmpVariables[1], repository.getHeap(), data[AUTH_DATA]);
- data[AUTH_DATA_LENGTH] = len;
- }
-
- private static short addPtrToAAD(short dataArrPtr, byte[] aadBuf, short offset) {
- short index = (short) (offset * 2);
- short tagInd = 0;
- short tagPtr;
- short arrLen = KMArray.cast(dataArrPtr).length();
- while (tagInd < arrLen) {
- tagPtr = KMArray.cast(dataArrPtr).get(tagInd);
- Util.setShort(aadBuf, index, tagPtr);
- index += 2;
- tagInd++;
- }
- return tagInd;
+
+ short arrayLen = 3;
+ if (KMArray.cast(data[KEY_BLOB]).length() == 5) {
+ arrayLen = 4;
+ }
+ short params = KMArray.instance((short) arrayLen);
+ KMArray.cast(params).add((short) 0, KMKeyParameters.cast(data[HW_PARAMETERS]).getVals());
+ KMArray.cast(params).add((short) 1, KMKeyParameters.cast(data[SW_PARAMETERS]).getVals());
+ KMArray.cast(params).add((short) 2, KMKeyParameters.cast(data[HIDDEN_PARAMETERS]).getVals());
+ if (4 == arrayLen) {
+ KMArray.cast(params).add((short) 3, data[PUB_KEY]);
+ }
+
+ short authIndex = repository.alloc(MAX_AUTH_DATA_SIZE);
+ short index = 0;
+ short len = 0;
+ short paramsLen = KMArray.cast(params).length();
+ Util.arrayFillNonAtomic(repository.getHeap(), authIndex, (short) MAX_AUTH_DATA_SIZE, (byte) 0);
+ while (index < paramsLen) {
+ short tag = KMArray.cast(params).get(index);
+ len = encoder.encode(tag, repository.getHeap(), (short) (authIndex + 32));
+ Util.arrayCopyNonAtomic(repository.getHeap(), (short) authIndex, repository.getHeap(),
+ (short) (authIndex + len + 32), (short) 32);
+ len = seProvider.messageDigest256(repository.getHeap(),
+ (short) (authIndex + 32), (short) (len + 32), repository.getHeap(), (short) authIndex);
+ if (len != 32) {
+ KMException.throwIt(KMError.UNKNOWN_ERROR);
+ }
+ index++;
+ }
+
+ data[AUTH_DATA] = authIndex;
+ data[AUTH_DATA_LENGTH] = len;
}
private static short deriveKey(byte[] scratchPad) {
- tmpVariables[0] = KMKeyParameters.cast(data[HIDDEN_PARAMETERS]).getVals();
- tmpVariables[1] = repository.alloc(DERIVE_KEY_INPUT_SIZE);
- // generate derivation material from hidden parameters
- tmpVariables[2] = encoder.encode(tmpVariables[0], repository.getHeap(), tmpVariables[1]);
- if (DERIVE_KEY_INPUT_SIZE > tmpVariables[2]) {
- // Copy KeyCharacteristics in the remaining space of DERIVE_KEY_INPUT_SIZE
- Util.arrayCopyNonAtomic(repository.getHeap(), (short) (data[AUTH_DATA]),
- repository.getHeap(),
- (short) (tmpVariables[1] + tmpVariables[2]),
- (short) (DERIVE_KEY_INPUT_SIZE - tmpVariables[2]));
- }
+
// KeyDerivation:
- // 1. Do HMAC Sign, with below input parameters.
- // Key - 128 bit master key
- // Input data - HIDDEN_PARAMETERS + KeyCharacateristics
- // - Truncate beyond 256 bytes.
+ // 1. Do HMAC Sign, Auth data.
// 2. HMAC Sign generates an output of 32 bytes length.
- // Consume only first 16 bytes as derived key.
+ // Consume only first 16 bytes as derived key.
// Hmac sign.
- tmpVariables[3] = seProvider.hmacKDF(
+ short len = seProvider.hmacKDF(
seProvider.getMasterKey(),
repository.getHeap(),
- tmpVariables[1],
- DERIVE_KEY_INPUT_SIZE,
+ data[AUTH_DATA],
+ data[AUTH_DATA_LENGTH],
scratchPad,
(short) 0);
- if (tmpVariables[3] < 16) {
+ if (len < 16) {
KMException.throwIt(KMError.UNKNOWN_ERROR);
}
- tmpVariables[3] = 16;
+ len = 16;
+ data[DERIVED_KEY] = repository.alloc(len);
// store the derived secret in data dictionary
- data[DERIVED_KEY] = tmpVariables[1];
Util.arrayCopyNonAtomic(
- scratchPad, (short) 0, repository.getHeap(), data[DERIVED_KEY], tmpVariables[3]);
- return tmpVariables[3];
+ scratchPad, (short) 0, repository.getHeap(), data[DERIVED_KEY], len);
+ return len;
}
// This function masks the error code with POWER_RESET_MASK_FLAG
diff --git a/Applet/src/com/android/javacard/keymaster/KMOperationState.java b/Applet/src/com/android/javacard/keymaster/KMOperationState.java
index 7d2a7f4d..bfd67ceb 100644
--- a/Applet/src/com/android/javacard/keymaster/KMOperationState.java
+++ b/Applet/src/com/android/javacard/keymaster/KMOperationState.java
@@ -88,7 +88,7 @@ public static KMOperationState instance(short opHandle) {
public static KMOperationState read(byte[] oprHandle, short off, byte[] data, short dataOff, Object opr, Object hmacSignerOpr) {
KMOperationState opState = proto();
opState.reset();
- Util.arrayCopy(data, dataOff, prototype.data, (short) 0, (short) prototype.data.length);
+ Util.arrayCopyNonAtomic(data, dataOff, prototype.data, (short) 0, (short) prototype.data.length);
prototype.objRefs[OPERATION] = opr;
prototype.objRefs[HMAC_SIGNER_OPERATION] = hmacSignerOpr;
Util.setShort(prototype.data, OP_HANDLE, KMInteger.uint_64(oprHandle, off));
@@ -176,7 +176,7 @@ public short getAuthTime() {
}
public void setAuthTime(byte[] timeBuf, short start) {
- Util.arrayCopy(timeBuf, start, data, (short) AUTH_TIME, (short) 8);
+ Util.arrayCopyNonAtomic(timeBuf, start, data, (short) AUTH_TIME, (short) 8);
dataUpdated();
}
@@ -220,7 +220,7 @@ public void setUserSecureId(short integerArrayPtr) {
offset += 2;
while (index < length) {
obj = KMIntegerArrayTag.cast(integerArrayPtr).get(index);
- Util.arrayCopy(
+ Util.arrayCopyNonAtomic(
KMInteger.cast(obj).getBuffer(),
KMInteger.cast(obj).getStartOff(),
data,
diff --git a/Applet/src/com/android/javacard/keymaster/KMPKCS8Decoder.java b/Applet/src/com/android/javacard/keymaster/KMPKCS8Decoder.java
index 5e67eb83..d8d472e2 100644
--- a/Applet/src/com/android/javacard/keymaster/KMPKCS8Decoder.java
+++ b/Applet/src/com/android/javacard/keymaster/KMPKCS8Decoder.java
@@ -1,205 +1,36 @@
+/*
+ * Copyright(C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" (short)0IS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.javacard.keymaster;
-import javacard.framework.Util;
+public interface KMPKCS8Decoder {
-public class KMPKCS8Decoder {
- public static final byte ASN1_OCTET_STRING= 0x04;
- public static final byte ASN1_SEQUENCE= 0x30;
- public static final byte ASN1_INTEGER= 0x02;
- public static final byte ASN1_A0_TAG = (byte) 0xA0;
- public static final byte ASN1_A1_TAG = (byte) 0xA1;
- public static final byte ASN1_BIT_STRING = 0x03;
- public static final byte[] EC_CURVE = {
- 0x06,0x08,0x2a,(byte)0x86,0x48,(byte)0xce,0x3d,0x03,
- 0x01,0x07
- };
- public static final byte[] RSA_ALGORITHM = {
- 0x06,0x09,0x2A,(byte)0x86,0x48,(byte)0x86,
- (byte)0xF7,0x0D,0x01,0x01,0x01,0x05,0x00
- };
- public static final byte[] EC_ALGORITHM = {
- 0x06,0x07,0x2a,(byte)0x86,0x48,(byte)0xce,
- 0x3d,0x02,0x01,0x06,0x08,0x2a,(byte)0x86,0x48,
- (byte)0xce,0x3d,0x03,0x01,0x07
- };
- private byte[] data;
- private short start;
- private short length;
- private short cur;
- private static KMPKCS8Decoder inst;
- private KMPKCS8Decoder(){
- start = 0;
- length = 0;
- cur = 0;
- }
-
- public short decodeRsa(short blob){
- init(blob);
- decodeCommon((short)0, RSA_ALGORITHM);
- return decodeRsaPrivateKey((short)0);
- }
-
- public short decodeEc(short blob){
- init(blob);
- decodeCommon((short)0, EC_ALGORITHM);
- return decodeEcPrivateKey((short)1);
- }
-
- public short decodeEcSubjectPublicKeyInfo(short blob) {
- init(blob);
- header(ASN1_SEQUENCE);
- short len = header(ASN1_SEQUENCE);
- short ecPublicInfo = KMByteBlob.instance(len);
- getBytes(ecPublicInfo);
- if(Util.arrayCompare(
- KMByteBlob.cast(ecPublicInfo).getBuffer(),
- KMByteBlob.cast(ecPublicInfo).getStartOff(),
- EC_ALGORITHM,
- (short)0,KMByteBlob.cast(ecPublicInfo).length()) !=0){
- KMException.throwIt(KMError.UNKNOWN_ERROR);
- }
- len = header(ASN1_BIT_STRING);
- if(len < 1) KMException.throwIt(KMError.UNKNOWN_ERROR);
- byte unusedBits = getByte();
- if(unusedBits != 0) KMException.throwIt(KMError.UNIMPLEMENTED);
- short pubKey = KMByteBlob.instance((short)(len -1));
- getBytes(pubKey);
- return pubKey;
- }
-
- //Seq[Int,Int,Int,Int,]
- public short decodeRsaPrivateKey(short version){
- short resp = KMArray.instance((short)3);
- header(ASN1_OCTET_STRING);
- header(ASN1_SEQUENCE);
- short len =header(ASN1_INTEGER);
- if(len != 1) KMException.throwIt(KMError.UNKNOWN_ERROR);
- short ver = getByte();
- if(ver != version) KMException.throwIt(KMError.UNKNOWN_ERROR);
- len = header(ASN1_INTEGER);
- short modulus = getModulus(len);
- len = header(ASN1_INTEGER);
- short pubKey = KMByteBlob.instance(len);
- getBytes(pubKey);
- len = header(ASN1_INTEGER);
- short privKey = KMByteBlob.instance(len);
- getBytes(privKey);
- KMArray.cast(resp).add((short)0, modulus);
- KMArray.cast(resp).add((short)1, pubKey);
- KMArray.cast(resp).add((short)2, privKey);
- return resp;
- }
-
- // Seq [Int, Blob]
- public void decodeCommon(short version, byte[] alg){
- short len = header(ASN1_SEQUENCE);
- len = header(ASN1_INTEGER);
- if(len != 1) KMException.throwIt(KMError.UNKNOWN_ERROR);
- short ver = getByte();
- if(ver !=version) KMException.throwIt(KMError.UNKNOWN_ERROR);
- len = header(ASN1_SEQUENCE);
- short blob = KMByteBlob.instance(len);
- getBytes(blob);
- if(Util.arrayCompare(
- KMByteBlob.cast(blob).getBuffer(),
- KMByteBlob.cast(blob).getStartOff(),
- alg,
- (short)0,KMByteBlob.cast(blob).length()) !=0){
- KMException.throwIt(KMError.UNKNOWN_ERROR);
- }
- }
-
- //Seq[Int,blob,blob]
- public short decodeEcPrivateKey(short version){
- short resp = KMArray.instance((short)2);
- header(ASN1_OCTET_STRING);
- header(ASN1_SEQUENCE);
- short len = header(ASN1_INTEGER);
- if(len != 1) KMException.throwIt(KMError.UNKNOWN_ERROR);
- short ver = getByte();
- if(ver != version) KMException.throwIt(KMError.UNKNOWN_ERROR);
- len = header(ASN1_OCTET_STRING);
- short privKey = KMByteBlob.instance(len);
- getBytes(privKey);
- validateTag0IfPresent();
- header(ASN1_A1_TAG);
- len = header(ASN1_BIT_STRING);
- if(len < 1) KMException.throwIt(KMError.UNKNOWN_ERROR);
- byte unusedBits = getByte();
- if(unusedBits != 0) KMException.throwIt(KMError.UNIMPLEMENTED);
- short pubKey = KMByteBlob.instance((short)(len -1));
- getBytes(pubKey);
- KMArray.cast(resp).add((short)0, pubKey);
- KMArray.cast(resp).add((short)1, privKey);
- return resp;
- }
- private void validateTag0IfPresent(){
- if(data[cur] != ASN1_A0_TAG) return;;
- short len = header(ASN1_A0_TAG);
- if(len != EC_CURVE.length) KMException.throwIt(KMError.UNKNOWN_ERROR);
- if(Util.arrayCompare(data, cur, EC_CURVE, (short)0, len) != 0) KMException.throwIt(KMError.UNKNOWN_ERROR);
- incrementCursor(len);
- }
- private short header(short tag){
- short t = getByte();
- if(t != tag) KMException.throwIt(KMError.UNKNOWN_ERROR);
- return getLength();
- }
-
- private byte getByte(){
- byte d = data[cur];
- incrementCursor((short)1);
- return d;
- }
-
- private short getShort(){
- short d = Util.getShort(data, cur);
- incrementCursor((short)2);
- return d;
- }
+ /**
+ * Decodes the PKCS8 encoded RSA Key and extracts the private and public key
+ *
+ * @param Instance of the PKCS8 encoded data
+ * @return Instance of KMArray holding RSA public key, RSA private key and modulus.
+ */
+ short decodeRsa(short blob);
- private short getModulus(short modulusLen) {
- if(0 == data[cur] && modulusLen == 257) {
- incrementCursor((short) 1);
- modulusLen--;
- }
- short blob = KMByteBlob.instance(modulusLen);
- getBytes(blob);
- return blob;
- }
-
- private void getBytes(short blob){
- short len = KMByteBlob.cast(blob).length();
- Util.arrayCopyNonAtomic(data, cur, KMByteBlob.cast(blob).getBuffer(),
- KMByteBlob.cast(blob).getStartOff(), len);
- incrementCursor(len);
- }
-
- private short getLength(){
- byte len = getByte();
- if(len >= 0) return len;
- len = (byte)(len & 0x7F);
- if(len == 1) return (short)(getByte() & 0xFF);
- else if(len == 2) return getShort();
- else KMException.throwIt(KMError.UNKNOWN_ERROR);
- return KMType.INVALID_VALUE; //should not come here
- }
- public static KMPKCS8Decoder instance() {
- if (inst == null) {
- inst = new KMPKCS8Decoder();
- }
- return inst;
- }
-
- public void init(short blob) {
- data = KMByteBlob.cast(blob).getBuffer();
- start = KMByteBlob.cast(blob).getStartOff();
- length = KMByteBlob.cast(blob).length();
- cur = start;
- }
-
- public void incrementCursor(short n){
- cur += n;
- if(cur > ((short)(start+length))) KMException.throwIt(KMError.UNKNOWN_ERROR);
- }
+ /**
+ * Decodes the PKCS8 encoded EC Key and extracts the private and public key
+ *
+ * @param Instance of the PKCS8 encoded data.
+ * @return Instance of KMArray holding EC public key and EC private key.
+ */
+ short decodeEc(short blob);
+
}
diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java
index d8646130..9755d2e0 100644
--- a/Applet/src/com/android/javacard/keymaster/KMRepository.java
+++ b/Applet/src/com/android/javacard/keymaster/KMRepository.java
@@ -29,25 +29,10 @@
*/
public class KMRepository implements KMUpgradable {
- public static final byte DEFAULT_TABLE_TABLE = 0;
- public static final byte ATTEST_IDS_DATA_TABLE = 1;
+ // Data table configuration
+ public static final short DATA_INDEX_SIZE = 33;
public static final short DATA_INDEX_ENTRY_SIZE = 4;
- // Data table configuration for attestation ids
- public static final short ATTEST_IDS_DATA_INDEX_SIZE = 8;
- public static final short ATTEST_IDS_DATA_TABLE_SIZE =
- (ATTEST_IDS_DATA_INDEX_SIZE * DATA_INDEX_ENTRY_SIZE)
- + KMConfigurations.TOTAL_ATTEST_IDS_SIZE;
- public static final byte ATT_ID_BRAND = 0;
- public static final byte ATT_ID_DEVICE = 1;
- public static final byte ATT_ID_PRODUCT = 2;
- public static final byte ATT_ID_SERIAL = 3;
- public static final byte ATT_ID_IMEI = 4;
- public static final byte ATT_ID_MEID = 5;
- public static final byte ATT_ID_MANUFACTURER = 6;
- public static final byte ATT_ID_MODEL = 7;
-
- // Data table configuration other non provisioned parameters.
- public static final short DATA_INDEX_SIZE = 22;
+ public static final short DATA_MEM_SIZE = 2048;
public static final short HEAP_SIZE = 10000;
public static final short DATA_INDEX_ENTRY_LENGTH = 0;
public static final short DATA_INDEX_ENTRY_OFFSET = 2;
@@ -60,24 +45,33 @@ public class KMRepository implements KMUpgradable {
private static final byte POWER_RESET_STATUS_FLAG = (byte) 0xEF;
// Data table offsets
- public static final byte BEGIN_OFFSET = 0;
- public static final byte HMAC_NONCE = BEGIN_OFFSET + 0;
- public static final byte BOOT_OS_VERSION = BEGIN_OFFSET + 1;
- public static final byte BOOT_OS_PATCH_LEVEL = BEGIN_OFFSET + 2;
- public static final byte VENDOR_PATCH_LEVEL = BEGIN_OFFSET + 3;
- public static final byte BOOT_PATCH_LEVEL = BEGIN_OFFSET + 4;
- public static final byte BOOT_VERIFIED_BOOT_KEY = BEGIN_OFFSET + 5;
- public static final byte BOOT_VERIFIED_BOOT_HASH = BEGIN_OFFSET + 6;
- public static final byte BOOT_VERIFIED_BOOT_STATE = BEGIN_OFFSET + 7;
- public static final byte BOOT_DEVICE_LOCKED_STATUS = BEGIN_OFFSET + 8;
- public static final byte DEVICE_LOCKED_TIME = BEGIN_OFFSET + 9;
- public static final byte DEVICE_LOCKED = BEGIN_OFFSET + 10;
- public static final byte DEVICE_LOCKED_PASSWORD_ONLY = BEGIN_OFFSET + 11;
- // Total 8 Auth Tags start offset 12 and end offset 19.
- public static final byte AUTH_TAG_1 = BEGIN_OFFSET + 12;
- public static final byte BOOT_ENDED_STATUS = BEGIN_OFFSET + 20;
- public static final byte EARLY_BOOT_ENDED_STATUS = BEGIN_OFFSET + 21;
- public static final byte END_OFFSET = 22;
+ public static final byte ATT_ID_BRAND = 0;
+ public static final byte ATT_ID_DEVICE = 1;
+ public static final byte ATT_ID_PRODUCT = 2;
+ public static final byte ATT_ID_SERIAL = 3;
+ public static final byte ATT_ID_IMEI = 4;
+ public static final byte ATT_ID_MEID = 5;
+ public static final byte ATT_ID_MANUFACTURER = 6;
+ public static final byte ATT_ID_MODEL = 7;
+ public static final byte COMPUTED_HMAC_KEY = 8;
+ public static final byte HMAC_NONCE = 9;
+ public static final byte CERT_ISSUER = 10;
+ public static final byte CERT_EXPIRY_TIME = 11;
+ public static final byte BOOT_OS_VERSION = 12;
+ public static final byte BOOT_OS_PATCH_LEVEL = 13;
+ public static final byte VENDOR_PATCH_LEVEL = 14;
+ public static final byte BOOT_PATCH_LEVEL = 15;
+ public static final byte BOOT_VERIFIED_BOOT_KEY = 16;
+ public static final byte BOOT_VERIFIED_BOOT_HASH = 17;
+ public static final byte BOOT_VERIFIED_BOOT_STATE = 18;
+ public static final byte BOOT_DEVICE_LOCKED_STATUS = 19;
+ public static final byte DEVICE_LOCKED_TIME = 20;
+ public static final byte DEVICE_LOCKED = 21;
+ public static final byte DEVICE_LOCKED_PASSWORD_ONLY = 22;
+ // Total 8 auth tags, so the next offset is AUTH_TAG_1 + 8
+ public static final byte AUTH_TAG_1 = 23;
+ public static final byte BOOT_ENDED_STATUS = 31;
+ public static final byte EARLY_BOOT_ENDED_STATUS = 32;
// Data Item sizes
public static final short MASTER_KEY_SIZE = 16;
@@ -94,8 +88,8 @@ public class KMRepository implements KMUpgradable {
public static final short DEVICE_LOCKED_PASSWORD_ONLY_SIZE = 1;
public static final short BOOT_STATE_SIZE = 1;
public static final short MAX_OPS = 4;
- public static final byte BOOT_KEY_MAX_SIZE = 32;
- public static final byte BOOT_HASH_MAX_SIZE = 32;
+ public static final byte BOOT_KEY_MAX_SIZE = 32;
+ public static final byte BOOT_HASH_MAX_SIZE = 32;
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;
@@ -103,23 +97,10 @@ public class KMRepository implements KMUpgradable {
public static final short BOOT_ENDED_FLAG_SIZE = 1;
public static final short EARLY_BOOT_ENDED_FLAG_SIZE = 1;
private static final byte[] zero = {0, 0, 0, 0, 0, 0, 0, 0};
-
- private static final short DATA_MEM_SIZE = (DATA_INDEX_ENTRY_SIZE * DATA_INDEX_SIZE)
- + HMAC_SEED_NONCE_SIZE
- + OS_VERSION_SIZE
- + OS_PATCH_SIZE
- + VENDOR_PATCH_SIZE
- + BOOT_PATCH_SIZE
- + BOOT_KEY_MAX_SIZE
- + BOOT_HASH_MAX_SIZE
- + BOOT_STATE_SIZE
- + BOOT_DEVICE_LOCK_FLAG_SIZE
- + DEVICE_LOCK_TS_SIZE
- + DEVICE_LOCKED_FLAG_SIZE
- + DEVICE_LOCKED_PASSWORD_ONLY_SIZE
- + (8 * AUTH_TAG_ENTRY_SIZE)
- + BOOT_ENDED_FLAG_SIZE
- + EARLY_BOOT_ENDED_FLAG_SIZE;
+
+ // Buffer type
+ public static final byte DEFAULT_BUF_TYPE = 0;
+ public static final byte ATTEST_IDS_BUF_TYPE = 1;
// Class Attributes
private Object[] operationStateTable;
@@ -127,9 +108,8 @@ public class KMRepository implements KMUpgradable {
private short[] heapIndex;
private byte[] dataTable;
private short dataIndex;
- private byte[] attestIdsTable;
- private short attestIdsIdsIndex;
private short[] reclaimIndex;
+ private short attestIdsIndex;
// This variable is used to monitor the power reset status as the Applet does not get
// any power reset event. Initially the value of this variable is set to POWER_RESET_STATUS_FLAG.
// If the power reset happens then this value becomes 0.
@@ -276,7 +256,7 @@ public void persistOperation(byte[] data, short opHandle, KMOperation op, KMOper
KMByteBlob.cast(buf).getBuffer(),
KMByteBlob.cast(buf).getStartOff(),
KMByteBlob.cast(buf).length()))) {
- Util.arrayCopy(data, (short) 0, oprTableData, (short) (offset + OPERATION_HANDLE_ENTRY_SIZE),
+ Util.arrayCopyNonAtomic(data, (short) 0, oprTableData, (short) (offset + OPERATION_HANDLE_ENTRY_SIZE),
KMOperationState.MAX_DATA);
operations[index] = op;
hmacSignerOprs[index] = hmacSignerOp;
@@ -291,13 +271,13 @@ public void persistOperation(byte[] data, short opHandle, KMOperation op, KMOper
offset = (short) (index * OPER_DATA_LEN);
if (0 == oprTableData[(short) (offset + OPERATION_HANDLE_STATUS_OFFSET)]) {
oprTableData[(short) (offset + OPERATION_HANDLE_STATUS_OFFSET)] = 1;/*reserved */
- Util.arrayCopy(
+ Util.arrayCopyNonAtomic(
KMByteBlob.cast(buf).getBuffer(),
KMByteBlob.cast(buf).getStartOff(),
oprTableData,
(short) (offset + OPERATION_HANDLE_OFFSET),
OPERATION_HANDLE_SIZE);
- Util.arrayCopy(data, (short) 0, oprTableData, (short) (offset + OPERATION_HANDLE_ENTRY_SIZE),
+ Util.arrayCopyNonAtomic(data, (short) 0, oprTableData, (short) (offset + OPERATION_HANDLE_ENTRY_SIZE),
KMOperationState.MAX_DATA);
operations[index] = op;
hmacSignerOprs[index] = hmacSignerOp;
@@ -433,54 +413,32 @@ public short alloc(short length) {
return (short) (heapIndex[0] - length);
}
- private short dataAlloc(byte dataTableType, short length) {
- byte[] dataTable = getDataTable(dataTableType);
- short dataIndex = getDataTableIndex(dataTableType);
+ private short dataAlloc(byte bufType, short length) {
+ short maxSize = getMaxLimitSize(bufType);
+ short dataIndex = getDataTableIndex(bufType);
if (length < 0) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
- if (((short) (dataIndex + length)) > dataTable.length) {
+ if (((short) (dataIndex + length)) > maxSize) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
dataIndex += length;
- setDataTableIndex(dataTableType, dataIndex);
+ setDataTableIndex(bufType, dataIndex);
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);
- }
- if (attestIdsTable == null) {
- attestIdsTable = new byte[ATTEST_IDS_DATA_TABLE_SIZE];
- attestIdsIdsIndex = (short) (ATTEST_IDS_DATA_INDEX_SIZE * DATA_INDEX_ENTRY_SIZE);
- }
- }
- }
-
- public byte[] getDataTable(byte dataTableType) {
- if (dataTableType == ATTEST_IDS_DATA_TABLE) {
- return this.attestIdsTable;
- } else {
- return this.dataTable;
- }
- }
-
- private short getDataTableIndex(byte dataTableType) {
- if (dataTableType == ATTEST_IDS_DATA_TABLE) {
- return this.attestIdsIdsIndex;
+ private short getDataTableIndex(byte bufType) {
+ if (bufType == ATTEST_IDS_BUF_TYPE) {
+ return this.attestIdsIndex;
} else {
return this.dataIndex;
}
}
-
- private void setDataTableIndex(byte dataTableType, short index) {
- if (dataTableType == ATTEST_IDS_DATA_TABLE) {
+
+ private void setDataTableIndex(byte bufType, short index) {
+ if (bufType == ATTEST_IDS_BUF_TYPE) {
JCSystem.beginTransaction();
- this.attestIdsIdsIndex = index;
+ this.attestIdsIndex = index;
JCSystem.commitTransaction();
} else {
JCSystem.beginTransaction();
@@ -488,9 +446,30 @@ private void setDataTableIndex(byte dataTableType, short index) {
JCSystem.commitTransaction();
}
}
+
+ private short getMaxLimitSize(byte bufType) {
+ if (bufType == ATTEST_IDS_BUF_TYPE) {
+ return (short) (DATA_INDEX_SIZE * DATA_INDEX_ENTRY_SIZE + KMConfigurations.TOTAL_ATTEST_IDS_SIZE);
+ } else { // Default buf type.
+ return (short) dataTable.length;
+ }
+ }
+
+ private void newDataTable(boolean isUpgrading) {
+ if (!isUpgrading) {
+ if (dataTable == null) {
+ dataTable = new byte[DATA_MEM_SIZE];
+ attestIdsIndex = (short) (DATA_INDEX_SIZE * DATA_INDEX_ENTRY_SIZE);
+ dataIndex = (short) (attestIdsIndex + KMConfigurations.TOTAL_ATTEST_IDS_SIZE);
+ }
+ }
+ }
+
+ public byte[] getDataTable() {
+ return dataTable;
+ }
- private void clearDataEntry(byte dataTableType, short id) {
- byte[] dataTable = getDataTable(dataTableType);
+ 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) {
@@ -501,13 +480,30 @@ private void clearDataEntry(byte dataTableType, short id) {
}
}
- private void writeDataEntry(byte dataTableType, short id, byte[] buf, short offset, short len) {
+ private void writeDataEntry(short id, byte[] buf, short offset, short len) {
+ writeDataEntry(DEFAULT_BUF_TYPE, id, buf, offset, len);
+ }
+
+ 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 void writeDataEntry(byte bufType, short id, byte[] buf, short offset, short len) {
short dataPtr;
- byte[] dataTable = getDataTable(dataTableType);
id = (short) (id * DATA_INDEX_ENTRY_SIZE);
short dataLen = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH));
if (dataLen == 0) {
- dataPtr = dataAlloc(dataTableType, len);
+ dataPtr = dataAlloc(bufType, len);
// Begin Transaction
JCSystem.beginTransaction();
Util.setShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET), dataPtr);
@@ -528,43 +524,11 @@ private void writeDataEntry(byte dataTableType, short id, byte[] buf, short offs
}
}
- private short readDataEntry(byte dataTableType, short id, byte[] buf, short offset) {
- byte[] dataTable = getDataTable(dataTableType);
- 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 void clearDataEntry(short id) {
- clearDataEntry(DEFAULT_TABLE_TABLE, id);
- }
-
- private void writeDataEntry(short id, byte[] buf, short offset, short len) {
- writeDataEntry(DEFAULT_TABLE_TABLE, id, buf, offset, len);
- }
-
- private short readDataEntry(short id, byte[] buf, short offset) {
- return readDataEntry(DEFAULT_TABLE_TABLE, id, buf, offset);
- }
-
- private short dataLength(byte dataTableType, short id) {
- byte[] dataTable = getDataTable(dataTableType);
+ private short dataLength(short id) {
id = (short) (id * DATA_INDEX_ENTRY_SIZE);
return Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH));
}
- private short dataLength(short id) {
- return dataLength(DEFAULT_TABLE_TABLE, id);
- }
-
public byte[] getHeap() {
return heap;
}
@@ -573,35 +537,58 @@ public short getHmacNonce() {
return readData(HMAC_NONCE);
}
+ public short getComputedHmacKey() {
+ return readData(COMPUTED_HMAC_KEY);
+ }
public void persistAttId(byte id, byte[] buf, short start, short len) {
- writeDataEntry(ATTEST_IDS_DATA_TABLE, id, buf, start, len);
+ writeDataEntry(ATTEST_IDS_BUF_TYPE, id, buf, start, len);
}
public short getAttId(byte id) {
- return readData(ATTEST_IDS_DATA_TABLE, id);
+ return readData(id);
}
public void deleteAttIds() {
JCSystem.beginTransaction();
- Util.arrayFillNonAtomic(attestIdsTable, (short) 0, (short) attestIdsTable.length, (byte) 0);
- attestIdsIdsIndex = (short) (ATTEST_IDS_DATA_INDEX_SIZE * DATA_INDEX_ENTRY_SIZE);
+ attestIdsIndex = (DATA_INDEX_SIZE * DATA_INDEX_ENTRY_SIZE);
+ Util.arrayFillNonAtomic(dataTable, attestIdsIndex, KMConfigurations.TOTAL_ATTEST_IDS_SIZE, (byte) 0);
JCSystem.commitTransaction();
}
- public short readData(byte dataTableType, short id) {
- short len = dataLength(dataTableType, id);
+ public short getIssuer() {
+ return readData(CERT_ISSUER);
+ }
+
+ public short readData(short id) {
+ short len = dataLength(id);
if (len != 0) {
short blob = KMByteBlob.instance(len);
- readDataEntry(dataTableType, id, KMByteBlob.cast(blob).getBuffer(),
- KMByteBlob.cast(blob).getStartOff());
+ readDataEntry(id, KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff());
return blob;
}
return KMType.INVALID_VALUE;
}
- public short readData(short id) {
- return readData(DEFAULT_TABLE_TABLE, id);
+ public short readData(byte[] dataTable, short id, byte[] buf, short startOff, short bufLen) {
+ id = (short) (id * DATA_INDEX_ENTRY_SIZE);
+ short len = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH));
+ if (len > bufLen) {
+ return KMType.INVALID_VALUE;
+ }
+ if (len != 0) {
+ Util.arrayCopyNonAtomic(
+ dataTable,
+ Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET)),
+ buf,
+ startOff,
+ len);
+ }
+ return len;
+ }
+
+ public short getCertExpiryTime() {
+ return readData(CERT_EXPIRY_TIME);
}
public short getOsVersion() {
@@ -943,17 +930,24 @@ public void setRateLimitedKeyCount(short authTag, byte[] buf, short off, short l
@Override
public void onSave(Element ele) {
ele.write(dataIndex);
- ele.write(attestIdsIdsIndex);
ele.write(dataTable);
- ele.write(attestIdsTable);
+ ele.write(attestIdsIndex);
}
@Override
- public void onRestore(Element ele) {
+ public void onRestore(Element ele, short oldVersion, short currentVersion) {
dataIndex = ele.readShort();
- attestIdsIdsIndex = ele.readShort();
dataTable = (byte[]) ele.readObject();
- attestIdsTable = (byte[]) ele.readObject();
+ if (oldVersion == KMKeymasterApplet.INVALID_DATA_VERSION) {
+ // Previous revisions does not contain version information.
+ handleDataUpgradeToVersion1();
+ } else if (oldVersion <= currentVersion) {
+ // No change in the data base version.
+ attestIdsIndex = ele.readShort();
+ } else {
+ // Invalid case
+ ISOException.throwIt(ISO7816.SW_DATA_INVALID);
+ }
}
@Override
@@ -965,9 +959,9 @@ public short getBackupPrimitiveByteCount() {
@Override
public short getBackupObjectCount() {
// dataTable
- return (short) 2;
+ return (short) 1;
}
-
+
public boolean getBootEndedStatus() {
short blob = readData(BOOT_ENDED_STATUS);
if (blob == KMType.INVALID_VALUE) {
@@ -1004,4 +998,29 @@ public void setEarlyBootEndedStatus(boolean flag) {
writeDataEntry(EARLY_BOOT_ENDED_STATUS, getHeap(), start, EARLY_BOOT_ENDED_FLAG_SIZE);
}
+ public void handleDataUpgradeToVersion1() {
+ byte[] oldDataTable = dataTable;
+ dataTable = new byte[2048];
+ attestIdsIndex = (short) (DATA_INDEX_SIZE * DATA_INDEX_ENTRY_SIZE);
+ dataIndex = (short) (attestIdsIndex + KMConfigurations.TOTAL_ATTEST_IDS_SIZE);
+ // temp buffer.
+ short startOffset = alloc((short) 256);
+
+ short index = ATT_ID_BRAND;
+ short len = 0;
+ while (index <= DEVICE_LOCKED) {
+ len = readData(oldDataTable, index, heap, startOffset, (short) 256);
+ writeDataEntry(index, heap, startOffset, len);
+ index++;
+ }
+ // set default values for the new IDS.
+ setDeviceLockPasswordOnly(false);
+ setBootEndedStatus(false);
+ setEarlyBootEndedStatus(false);
+
+ // Request object deletion
+ oldDataTable = null;
+ JCSystem.requestObjectDeletion();
+ }
+
}
diff --git a/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java
index da57e3ee..b7cb5609 100644
--- a/Applet/src/com/android/javacard/keymaster/KMSEProvider.java
+++ b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java
@@ -453,6 +453,13 @@ KMOperation initAsymmetricOperation(
*/
KMAttestationCert getAttestationCert(boolean rsaCert);
+ /**
+ * Returns the implementation of the PKCS8 decoder.
+ *
+ * @return Instance of PKCS8 decoder.
+ */
+ KMPKCS8Decoder getPKCS8DecoderInstance();
+
/**
* This operation persists the provision data in the persistent memory.
*
@@ -591,4 +598,16 @@ void persistProvisionData(byte[] buf, short certChainOff, short certChainLen,
*/
void releaseAllOperations();
+ /**
+ * 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);
+
}
diff --git a/Applet/src/com/android/javacard/keymaster/KMUpgradable.java b/Applet/src/com/android/javacard/keymaster/KMUpgradable.java
index 0a241652..87204a06 100644
--- a/Applet/src/com/android/javacard/keymaster/KMUpgradable.java
+++ b/Applet/src/com/android/javacard/keymaster/KMUpgradable.java
@@ -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();