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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.android.javacard.keymaster;

import javacard.framework.Shareable;

public interface KMBackupRestoreAgent extends Shareable {
void backup(byte[] buf, short start, short len);
short restore(byte[] buf, short start);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.android.javacard.keymaster;

import javacard.framework.AID;
import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.JCSystem;
import javacard.framework.Shareable;
import javacard.framework.Util;

public class KMBackupStoreApplet extends Applet implements KMBackupRestoreAgent {
private static final short DATA_TABLE_MEM_SIZE = 2048;
private static final byte[] aidArr = new byte[]{ (byte)0xA0, 0x00, 0x00, 0x00, 0x62};

private byte[] dataTable;
private short dataTableSize;

private KMBackupStoreApplet() {
dataTable = new byte[DATA_TABLE_MEM_SIZE];
}

public static void install(byte bArray[], short bOffset, byte bLength) {
new KMBackupStoreApplet().register();
}

@Override
public boolean select() {
return true;
}

@Override
public void process(APDU apdu) {

}

@Override
public void backup(byte[] buf, short start, short len) {
// Store the data
if (len > 0) {
JCSystem.beginTransaction();
dataTableSize = len;
Util.arrayCopy(buf, start, dataTable, (short) 0, len);
JCSystem.commitTransaction();
}
}

@Override
public short restore(byte[] buf, short start) {
// Restore the data
Util.arrayCopy(dataTable, (short) 0, buf, start, dataTableSize);
return dataTableSize;
}

@Override
public Shareable getShareableInterfaceObject(AID aid, byte param){
byte[] aidBytes = new byte[10];
byte len = aid.getBytes(aidBytes, (short)0);
if(Util.arrayCompare(aidArr,(short)0,aidBytes,(short)0,len) == 0){
return this;
}
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import javacard.framework.AID;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.JCSystem;
Expand Down Expand Up @@ -68,6 +69,9 @@ public class KMJcardSimulator implements KMSEProvider {
public static final short ENTROPY_POOL_SIZE = 16; // simulator does not support 256 bit aes keys
public static final byte[] aesICV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
private static final int AES_GCM_KEY_SIZE = 16;
private static final byte[] aidArr = new byte[]{ (byte)0xA0, 0x00, 0x00, 0x00, 0x63};


public static boolean jcardSim = false;
private static Signature kdf;
private static Signature hmacSignature;
Expand Down Expand Up @@ -478,18 +482,19 @@ public byte[] getTrueRandomNumber(short i) {

@Override
public short aesCCMSign(
byte[] bufIn,
short bufInStart,
short buffInLength,
byte[] masterKeySecret,
byte[] bufOut,
short bufStart) {
if (masterKeySecret.length > 16) {
byte[] bufIn,
short bufInStart,
short buffInLength,
byte[] masterKeySecret,
short masterKeyStart,
short masterKeyLen,
byte[] bufOut,
short bufStart) {
if (masterKeyLen > 16) {
return -1;
}

AESKey key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false);
key.setKey(masterKeySecret, (short) 0);
key.setKey(masterKeySecret, masterKeyStart);
byte[] in = new byte[buffInLength];
Util.arrayCopyNonAtomic(bufIn, bufInStart,in,(short)0,buffInLength);
kdf.init(key, Signature.MODE_SIGN);
Expand All @@ -499,7 +504,7 @@ public short aesCCMSign(
return len;
}

public HMACKey cmacKdf(byte[] keyMaterial, byte[] label, byte[] context, short contextStart, short contextLength) {
public HMACKey cmacKdf(byte[] keyMaterial, short keyMaterialStart, short keyMaterialLen, byte[] label, byte[] context, short contextStart, short contextLength) {
// This is hardcoded to requirement - 32 byte output with two concatenated 16 bytes K1 and K2.
final byte n = 2; // hardcoded
final byte[] L = {0,0,1,0}; // [L] 256 bits - hardcoded 32 bits as per reference impl in keymaster.
Expand All @@ -508,7 +513,7 @@ public HMACKey cmacKdf(byte[] keyMaterial, byte[] label, byte[] context, short c
byte[] keyOut = new byte[(short)(n*16)];
Signature prf = Signature.getInstance(Signature.ALG_AES_CMAC_128, false);
AESKey key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false);
key.setKey(keyMaterial, (short) 0);
key.setKey(keyMaterial, keyMaterialStart);
prf.init(key, Signature.MODE_SIGN);
byte i =1;
short pos = 0;
Expand All @@ -525,8 +530,8 @@ public HMACKey cmacKdf(byte[] keyMaterial, byte[] label, byte[] context, short c
}

@Override
public short cmacKdf(byte[] keyMaterial, byte[] label, byte[] context, short contextStart, short contextLength, byte[] keyBuf, short keyStart) {
HMACKey key = cmacKdf(keyMaterial,label,context,contextStart,contextLength);
public short cmacKdf(byte[] keyMaterial, short keyMaterialStart, short keyMaterialLen, byte[] label, byte[] context, short contextStart, short contextLength, byte[] keyBuf, short keyStart) {
HMACKey key = cmacKdf(keyMaterial,keyMaterialStart, keyMaterialLen, label,context,contextStart,contextLength);
return key.getKey(keyBuf,keyStart);
}

Expand Down Expand Up @@ -1235,75 +1240,35 @@ public Signature createEcVerifier(short digest, byte[] pubKey, short pubKeyStart
return ecVerifier;
}

@Override
public short getSystemTimeInMilliSeconds(byte[] timeBuf, short timeStart, short timeOffset) {
return 0;
}

@Override
public short addListener(KMEventListener listener, byte eventType) {
return 0;
}

@Override
public short getEventData(byte[] eventBuf, short eventStart, short eventLength) {
return 0;
}

@Override
public boolean isAlgSupported(byte alg) {
return true;
}

@Override
public boolean isKeySizeSupported(byte alg, short keySize) {
return true;
}

@Override
public boolean isCurveSupported(byte eccurve) {
return true;
}

@Override
public boolean isDigestSupported(byte alg, byte digest) {
public boolean isBackupRestoreSupported() {
return true;
}

@Override
public boolean isPaddingSupported(byte alg, byte padding) {
return true;
}

@Override
public boolean isBlockModeSupported(byte alg, byte blockMode) {
return true;
}

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

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

@Override
public boolean isPkcs8ParsingSupported() {
return false;
public KMAttestationCert getAttestationCert(boolean rsaCert) {
//certBuilder.reset();
return KMAttestationCertImpl.instance(rsaCert);
}

@Override
public boolean isAttestationCertSupported() {
return true;
public void backup(byte[] buf, short start, short len) {
byte[] data = new byte[len];
AID aid = JCSystem.lookupAID(aidArr,(short)0,(byte)aidArr.length);
KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem.getAppletShareableInterfaceObject(aid,(byte)0);
Util.arrayCopyNonAtomic(buf,start,data,(short)0,len);
backupStore.backup(data,(short)0,len);
}

@Override
public KMAttestationCert getAttestationCert(boolean rsaCert) {
//certBuilder.reset();
return KMAttestationCertImpl.instance(rsaCert);
public short restore(byte[] buf, short start) {
byte[] data = new byte[2200];
AID aid = JCSystem.lookupAID(aidArr,(short)0,(byte)aidArr.length);
KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem.getAppletShareableInterfaceObject(aid,(byte)0);
short len = backupStore.restore(data,(short)0);
Util.arrayCopyNonAtomic(data,(short)0,buf,start,len);
return len;
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,12 @@ public boolean aesGCMDecrypt(
return verification;
}


@Override
public short cmacKdf(byte[] keyMaterial, short keyMaterialStart, short keyMaterialLen, byte[] label, byte[] context, short contextStart, short contextLength, byte[] keyBuf, short keyStart) {
return 0;
}

@Override
public byte[] getTrueRandomNumber(short i) {
// ignore the size as simulator only supports 128 bit entropy
Expand All @@ -319,13 +325,15 @@ public short aesCCMSign(
short bufInStart,
short buffInLength,
byte[] masterKeySecret,
short masterKeyStart,
short masterKeyLen,
byte[] bufOut,
short bufStart) {
if (masterKeySecret.length > 16) {
if (masterKeyLen > 16) {

return -1;
}
aes128Key.setKey(masterKeySecret, (short) 0);
aes128Key.setKey(masterKeySecret, masterKeyStart);
kdf.init(aes128Key, Signature.MODE_SIGN);
return kdf.sign(bufIn, bufInStart, buffInLength, bufOut, bufStart);
}
Expand Down Expand Up @@ -374,11 +382,6 @@ public HMACKey cmacKdf(byte[] keyMaterial, byte[] label, byte[] context, short c
return null;
}

@Override
public short cmacKdf(byte[] keyMaterial, byte[] label, byte[] context, short contextStart, short contextLength, byte[] keyBuf, short keyStart) {
return 0;
}

public short hmacSign(HMACKey key, byte[] data, short dataStart, short dataLength, byte[] mac, short macStart) {
return 0;
}
Expand Down Expand Up @@ -498,73 +501,23 @@ private void incrementCounter() {
}

@Override
public short getSystemTimeInMilliSeconds(byte[] timeBuf, short timeStart, short timeOffset) {
return 0;
}

@Override
public short addListener(KMEventListener listener, byte eventType) {
return 0;
}

@Override
public short getEventData(byte[] eventBuf, short eventStart, short eventLength) {
return 0;
}

@Override
public boolean isAlgSupported(byte alg) {
public boolean isBackupRestoreSupported() {
return false;
}

@Override
public boolean isKeySizeSupported(byte alg, short keySize) {
return false;
}

@Override
public boolean isCurveSupported(byte eccurve) {
return false;
}

@Override
public boolean isDigestSupported(byte alg, byte digest) {
return false;
}

@Override
public boolean isPaddingSupported(byte alg, byte padding) {
return false;
}

@Override
public boolean isBlockModeSupported(byte alg, byte blockMode) {
return false;
}

@Override
public boolean isSystemTimerSupported() {
return false;
public KMAttestationCert getAttestationCert(boolean rsaCert) {
return null;
}

@Override
public boolean isBootEventSupported() {
return false;
}
public void backup(byte[] buf, short start, short len) {

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

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

@Override
public KMAttestationCert getAttestationCert(boolean rsaCert) {
return null;
public short restore(byte[] buf, short start) {
return 0;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ public class KMBoolTag extends KMTag {
TRUSTED_USER_PRESENCE_REQUIRED,
TRUSTED_CONFIRMATION_REQUIRED,
UNLOCKED_DEVICE_REQUIRED,
RESET_SINCE_ID_ROTATION
RESET_SINCE_ID_ROTATION,
EARLY_BOOT_ENDED,
DEVICE_UNIQUE_ATTESTATION
};

private KMBoolTag() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,10 @@ public boolean isValid(){
}
return true;
}

public void decrementLength(short len){
short length = Util.getShort(heap, (short) (instPtr + 1));
length = (short)(length - len);
Util.setShort(heap, (short) (instPtr + 1),length);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public class KMError {
public static short CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = 70;
public static short NO_USER_CONFIRMATION = 71;
public static short DEVICE_LOCKED = 72;
public static short EARLY_BOOT_ENDED = 73;
public static short UNIMPLEMENTED = 100;
public static short VERSION_MISMATCH = 101;
public static short UNKNOWN_ERROR = 1000;
Expand Down
Loading