1 package com.android.javacard.keymaster;
2 
3 import com.android.javacard.seprovider.KMDataStoreConstants;
4 import com.android.javacard.seprovider.KMException;
5 import com.android.javacard.seprovider.KMKey;
6 import com.android.javacard.seprovider.KMSEProvider;
7 import com.android.javacard.seprovider.KMUpgradable;
8 import javacard.framework.ISO7816;
9 import javacard.framework.ISOException;
10 import javacard.framework.JCSystem;
11 import javacard.framework.Util;
12 import org.globalplatform.upgrade.Element;
13 
14 /**
15  * This is a storage class which helps in storing the provisioned data, ROT, OS version, Boot patch
16  * level, Vendor Patchlevel, HMAC nonce, computed shared secret, 8 auth tags, device-locked,
17  * device-locked timestamp and device-locked password only. Only the provisioned data is restored
18  * back during applet upgrades and the remaining data is flushed.
19  */
20 public class KMKeymintDataStore implements KMUpgradable {
21 
22   // Data table configuration
23   public static final short KM_APPLET_PACKAGE_VERSION_1 = 0x0100;
24   public static final short KM_APPLET_PACKAGE_VERSION_2 = 0x0200;
25   public static final short KM_APPLET_PACKAGE_VERSION_3 = 0x0300;
26   public static final byte DATA_INDEX_SIZE = 17;
27   public static final byte DATA_INDEX_ENTRY_SIZE = 4;
28   public static final byte DATA_INDEX_ENTRY_LENGTH = 0;
29   public static final byte DATA_INDEX_ENTRY_OFFSET = 2;
30   public static final short DATA_MEM_SIZE = 300;
31   // Data table offsets
32   public static final byte HMAC_NONCE = 0;
33   public static final byte BOOT_OS_VERSION = 1;
34   public static final byte BOOT_OS_PATCH_LEVEL = 2;
35   public static final byte VENDOR_PATCH_LEVEL = 3;
36   public static final byte DEVICE_LOCKED_TIME = 4;
37   public static final byte DEVICE_LOCKED = 5;
38   public static final byte DEVICE_LOCKED_PASSWORD_ONLY = 6;
39   // Total 8 auth tags, so the next offset is AUTH_TAG_1 + 8
40   public static final byte AUTH_TAG_1 = 7;
41   public static final byte DEVICE_STATUS_FLAG = 15;
42   public static final byte EARLY_BOOT_ENDED_FLAG = 16;
43   // Data Item sizes
44   public static final byte HMAC_SEED_NONCE_SIZE = 32;
45   public static final byte COMPUTED_HMAC_KEY_SIZE = 32;
46   public static final byte OS_VERSION_SIZE = 4;
47   public static final byte OS_PATCH_SIZE = 4;
48   public static final byte VENDOR_PATCH_SIZE = 4;
49   public static final byte DEVICE_LOCK_TS_SIZE = 8;
50   public static final byte MAX_BLOB_STORAGE = 8;
51   public static final byte AUTH_TAG_LENGTH = 16;
52   public static final byte AUTH_TAG_COUNTER_SIZE = 4;
53   public static final byte AUTH_TAG_ENTRY_SIZE = (AUTH_TAG_LENGTH + AUTH_TAG_COUNTER_SIZE + 1);
54   // Device boot states. Applet starts executing the
55   // core commands once all the states are set. The commands
56   // that are allowed irrespective of these states are:
57   // All the provision commands
58   // INS_GET_HW_INFO_CMD
59   // INS_ADD_RNG_ENTROPY_CMD
60   // INS_COMPUTE_SHARED_HMAC_CMD
61   // INS_GET_HMAC_SHARING_PARAM_CMD
62   public static final byte SET_BOOT_PARAMS_SUCCESS = 0x01;
63   public static final byte SET_SYSTEM_PROPERTIES_SUCCESS = 0x02;
64   public static final byte NEGOTIATED_SHARED_SECRET_SUCCESS = 0x04;
65   // Old Data table offsets
66   private static final byte OLD_PROVISIONED_STATUS_OFFSET = 18;
67   private static final byte SHARED_SECRET_KEY_SIZE = 32;
68   private static final byte DEVICE_STATUS_FLAG_SIZE = 1;
69   private static final short ADDITIONAL_CERT_CHAIN_MAX_SIZE = 2500; // First 2 bytes for length.
70   private static final short BCC_MAX_SIZE = 512;
71   private static KMKeymintDataStore kmDataStore;
72   // Secure Boot Mode
73   public byte secureBootMode;
74   // Data - originally was in repository
75   private byte[] attIdBrand;
76   private byte[] attIdDevice;
77   private byte[] attIdProduct;
78   private byte[] attIdSerial;
79   private byte[] attIdImei;
80   private byte[] attIdMeId;
81   private byte[] attIdManufacturer;
82   private byte[] attIdModel;
83   // Boot parameters
84   private byte[] verifiedHash;
85   private byte[] bootKey;
86   private byte[] bootPatchLevel;
87   private boolean deviceBootLocked;
88   private short bootState;
89   // Challenge for Root of trust
90   private byte[] challenge;
91   private short dataIndex;
92   private byte[] dataTable;
93   private KMSEProvider seProvider;
94   private KMRepository repository;
95   private byte[] additionalCertChain;
96   private byte[] bcc;
97   private KMKey masterKey;
98   private KMKey testDeviceUniqueKeyPair;
99   private KMKey deviceUniqueKeyPair;
100   private KMKey preSharedKey;
101   private KMKey computedHmacKey;
102   private KMKey rkpMacKey;
103   private byte[] oemRootPublicKey;
104   private short provisionStatus;
105 
KMKeymintDataStore(KMSEProvider provider, KMRepository repo)106   public KMKeymintDataStore(KMSEProvider provider, KMRepository repo) {
107     seProvider = provider;
108     repository = repo;
109     boolean isUpgrading = provider.isUpgrading();
110     initDataTable();
111     // Initialize the device locked status
112     if (!isUpgrading) {
113       additionalCertChain = new byte[ADDITIONAL_CERT_CHAIN_MAX_SIZE];
114       bcc = new byte[BCC_MAX_SIZE];
115       oemRootPublicKey = new byte[65];
116     }
117     setDeviceLockPasswordOnly(false);
118     setDeviceLock(false);
119     kmDataStore = this;
120   }
121 
instance()122   public static KMKeymintDataStore instance() {
123     return kmDataStore;
124   }
125 
initDataTable()126   private void initDataTable() {
127     if (dataTable == null) {
128       dataTable = new byte[DATA_MEM_SIZE];
129       dataIndex = (short) (DATA_INDEX_SIZE * DATA_INDEX_ENTRY_SIZE);
130     }
131   }
132 
dataAlloc(short length)133   private short dataAlloc(short length) {
134     if (((short) (dataIndex + length)) > dataTable.length) {
135       ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
136     }
137     dataIndex += length;
138     return (short) (dataIndex - length);
139   }
140 
clearDataEntry(short id)141   private void clearDataEntry(short id) {
142     id = (short) (id * DATA_INDEX_ENTRY_SIZE);
143     short dataLen = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH));
144     if (dataLen != 0) {
145       short dataPtr = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET));
146       JCSystem.beginTransaction();
147       Util.arrayFillNonAtomic(dataTable, dataPtr, dataLen, (byte) 0);
148       JCSystem.commitTransaction();
149     }
150   }
151 
writeDataEntry(short id, byte[] buf, short offset, short len)152   private void writeDataEntry(short id, byte[] buf, short offset, short len) {
153     short dataPtr;
154     id = (short) (id * DATA_INDEX_ENTRY_SIZE);
155     short dataLen = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH));
156     if (dataLen == 0) {
157       dataPtr = dataAlloc(len);
158       JCSystem.beginTransaction();
159       Util.setShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET), dataPtr);
160       Util.setShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH), len);
161       Util.arrayCopyNonAtomic(buf, offset, dataTable, dataPtr, len);
162       JCSystem.commitTransaction();
163     } else {
164       if (len != dataLen) {
165         KMException.throwIt(KMError.UNKNOWN_ERROR);
166       }
167       dataPtr = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET));
168       JCSystem.beginTransaction();
169       Util.arrayCopyNonAtomic(buf, offset, dataTable, dataPtr, len);
170       JCSystem.commitTransaction();
171     }
172   }
173 
readDataEntry(short id, byte[] buf, short offset)174   private short readDataEntry(short id, byte[] buf, short offset) {
175     id = (short) (id * DATA_INDEX_ENTRY_SIZE);
176     short len = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH));
177     if (len != 0) {
178       Util.arrayCopyNonAtomic(
179           dataTable,
180           Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET)),
181           buf,
182           offset,
183           len);
184     }
185     return len;
186   }
187 
readDataEntry(byte[] dataTable, short id, byte[] buf, short offset)188   private short readDataEntry(byte[] dataTable, short id, byte[] buf, short offset) {
189     id = (short) (id * DATA_INDEX_ENTRY_SIZE);
190     short len = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH));
191     if (len != 0) {
192       Util.arrayCopyNonAtomic(
193           dataTable,
194           Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET)),
195           buf,
196           offset,
197           len);
198     }
199     return len;
200   }
201 
dataLength(short id)202   private short dataLength(short id) {
203     id = (short) (id * DATA_INDEX_ENTRY_SIZE);
204     return Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH));
205   }
206 
readData(short id)207   public short readData(short id) {
208     short len = dataLength(id);
209     if (len != 0) {
210       short blob = KMByteBlob.instance(dataLength(id));
211       readDataEntry(id, KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff());
212       return blob;
213     }
214     return KMType.INVALID_VALUE;
215   }
216 
getHmacNonce()217   public short getHmacNonce() {
218     return readData(HMAC_NONCE);
219   }
220 
getOsVersion()221   public short getOsVersion() {
222     short blob = readData(BOOT_OS_VERSION);
223     if (blob == KMType.INVALID_VALUE) {
224       KMException.throwIt(KMError.INVALID_DATA);
225     }
226     return KMInteger.uint_32(
227         KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff());
228   }
229 
getVendorPatchLevel()230   public short getVendorPatchLevel() {
231     short blob = readData(VENDOR_PATCH_LEVEL);
232     if (blob == KMType.INVALID_VALUE) {
233       KMException.throwIt(KMError.INVALID_DATA);
234     }
235     return KMInteger.uint_32(
236         KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff());
237   }
238 
getOsPatch()239   public short getOsPatch() {
240     short blob = readData(BOOT_OS_PATCH_LEVEL);
241     if (blob == KMType.INVALID_VALUE) {
242       KMException.throwIt(KMError.INVALID_DATA);
243     }
244     return KMInteger.uint_32(
245         KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff());
246   }
247 
readBoolean(short id)248   private boolean readBoolean(short id) {
249     short blob = readData(id);
250     if (blob == KMType.INVALID_VALUE) {
251       KMException.throwIt(KMError.INVALID_DATA);
252     }
253     return (byte) ((repository.getHeap())[KMByteBlob.cast(blob).getStartOff()]) == 0x01;
254   }
255 
getDeviceLock()256   public boolean getDeviceLock() {
257     return readBoolean(DEVICE_LOCKED);
258   }
259 
setDeviceLock(boolean flag)260   public void setDeviceLock(boolean flag) {
261     writeBoolean(DEVICE_LOCKED, flag);
262   }
263 
getDeviceLockPasswordOnly()264   public boolean getDeviceLockPasswordOnly() {
265     return readBoolean(DEVICE_LOCKED_PASSWORD_ONLY);
266   }
267 
setDeviceLockPasswordOnly(boolean flag)268   public void setDeviceLockPasswordOnly(boolean flag) {
269     writeBoolean(DEVICE_LOCKED_PASSWORD_ONLY, flag);
270   }
271 
getEarlyBootEndedStatus()272   public boolean getEarlyBootEndedStatus() {
273     return readBoolean(EARLY_BOOT_ENDED_FLAG);
274   }
275 
setEarlyBootEndedStatus(boolean flag)276   public void setEarlyBootEndedStatus(boolean flag) {
277     writeBoolean(EARLY_BOOT_ENDED_FLAG, flag);
278   }
279 
getDeviceTimeStamp()280   public short getDeviceTimeStamp() {
281     short blob = readData(DEVICE_LOCKED_TIME);
282     if (blob == KMType.INVALID_VALUE) {
283       KMException.throwIt(KMError.INVALID_DATA);
284     }
285     return KMInteger.uint_64(
286         KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff());
287   }
288 
setOsVersion(byte[] buf, short start, short len)289   public void setOsVersion(byte[] buf, short start, short len) {
290     if (len != OS_VERSION_SIZE) {
291       KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
292     }
293     writeDataEntry(BOOT_OS_VERSION, buf, start, len);
294   }
295 
setVendorPatchLevel(byte[] buf, short start, short len)296   public void setVendorPatchLevel(byte[] buf, short start, short len) {
297     if (len != VENDOR_PATCH_SIZE) {
298       KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
299     }
300     writeDataEntry(VENDOR_PATCH_LEVEL, buf, start, len);
301   }
302 
writeBoolean(short id, boolean flag)303   private void writeBoolean(short id, boolean flag) {
304     short start = repository.alloc((short) 1);
305     if (flag) {
306       (repository.getHeap())[start] = (byte) 0x01;
307     } else {
308       (repository.getHeap())[start] = (byte) 0x00;
309     }
310     writeDataEntry(id, repository.getHeap(), start, (short) 1);
311   }
312 
setDeviceLockTimestamp(byte[] buf, short start, short len)313   public void setDeviceLockTimestamp(byte[] buf, short start, short len) {
314     if (len != DEVICE_LOCK_TS_SIZE) {
315       KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
316     }
317     writeDataEntry(DEVICE_LOCKED_TIME, buf, start, len);
318   }
319 
clearDeviceBootStatus()320   public void clearDeviceBootStatus() {
321     clearDataEntry(DEVICE_STATUS_FLAG);
322   }
323 
setDeviceBootStatus(byte initStatus)324   public void setDeviceBootStatus(byte initStatus) {
325     short offset = repository.allocReclaimableMemory(DEVICE_STATUS_FLAG_SIZE);
326     byte[] buf = repository.getHeap();
327     getDeviceBootStatus(buf, offset);
328     buf[offset] |= initStatus;
329     writeDataEntry(DEVICE_STATUS_FLAG, buf, offset, DEVICE_STATUS_FLAG_SIZE);
330     repository.reclaimMemory(DEVICE_STATUS_FLAG_SIZE);
331   }
332 
isDeviceReady()333   public boolean isDeviceReady() {
334     boolean result = false;
335     short offset = repository.allocReclaimableMemory(DEVICE_STATUS_FLAG_SIZE);
336     byte[] buf = repository.getHeap();
337     getDeviceBootStatus(buf, offset);
338     byte bootCompleteStatus =
339         (SET_BOOT_PARAMS_SUCCESS
340             | SET_SYSTEM_PROPERTIES_SUCCESS
341             | NEGOTIATED_SHARED_SECRET_SUCCESS);
342     if (bootCompleteStatus == (buf[offset] & bootCompleteStatus)) {
343       result = true;
344     }
345     repository.reclaimMemory(DEVICE_STATUS_FLAG_SIZE);
346     return result;
347   }
348 
getDeviceBootStatus(byte[] scratchpad, short offset)349   public short getDeviceBootStatus(byte[] scratchpad, short offset) {
350     scratchpad[offset] = 0;
351     return readDataEntry(DEVICE_STATUS_FLAG, scratchpad, offset);
352   }
353 
clearDeviceLockTimeStamp()354   public void clearDeviceLockTimeStamp() {
355     clearDataEntry(DEVICE_LOCKED_TIME);
356   }
357 
setOsPatch(byte[] buf, short start, short len)358   public void setOsPatch(byte[] buf, short start, short len) {
359     if (len != OS_PATCH_SIZE) {
360       KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
361     }
362     writeDataEntry(BOOT_OS_PATCH_LEVEL, buf, start, len);
363   }
364 
isAuthTagSlotAvailable(short tagId, byte[] buf, short offset)365   private boolean isAuthTagSlotAvailable(short tagId, byte[] buf, short offset) {
366     readDataEntry(tagId, buf, offset);
367     return (0 == buf[offset]);
368   }
369 
initHmacNonce(byte[] nonce, short offset, short len)370   public void initHmacNonce(byte[] nonce, short offset, short len) {
371     if (len != HMAC_SEED_NONCE_SIZE) {
372       KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
373     }
374     writeDataEntry(HMAC_NONCE, nonce, offset, len);
375   }
376 
persistAuthTag(short authTag)377   public boolean persistAuthTag(short authTag) {
378 
379     if (KMByteBlob.cast(authTag).length() != AUTH_TAG_LENGTH) {
380       KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
381     }
382 
383     short authTagEntry = repository.alloc(AUTH_TAG_ENTRY_SIZE);
384     short scratchPadOff = repository.alloc(AUTH_TAG_ENTRY_SIZE);
385     byte[] scratchPad = repository.getHeap();
386     writeAuthTagState(repository.getHeap(), authTagEntry, (byte) 1);
387     Util.arrayCopyNonAtomic(
388         KMByteBlob.cast(authTag).getBuffer(),
389         KMByteBlob.cast(authTag).getStartOff(),
390         repository.getHeap(),
391         (short) (authTagEntry + 1),
392         AUTH_TAG_LENGTH);
393     Util.setShort(
394         repository.getHeap(), (short) (authTagEntry + AUTH_TAG_LENGTH + 1 + 2), (short) 1);
395     short index = 0;
396     while (index < MAX_BLOB_STORAGE) {
397       if ((dataLength((short) (index + AUTH_TAG_1)) == 0)
398           || isAuthTagSlotAvailable((short) (index + AUTH_TAG_1), scratchPad, scratchPadOff)) {
399 
400         writeDataEntry(
401             (short) (index + AUTH_TAG_1), repository.getHeap(), authTagEntry, AUTH_TAG_ENTRY_SIZE);
402         return true;
403       }
404       index++;
405     }
406     return false;
407   }
408 
removeAllAuthTags()409   public void removeAllAuthTags() {
410     short index = 0;
411     while (index < MAX_BLOB_STORAGE) {
412       clearDataEntry((short) (index + AUTH_TAG_1));
413       index++;
414     }
415   }
416 
isAuthTagPersisted(short authTag)417   public boolean isAuthTagPersisted(short authTag) {
418     return (KMType.INVALID_VALUE != findTag(authTag));
419   }
420 
findTag(short authTag)421   private short findTag(short authTag) {
422     if (KMByteBlob.cast(authTag).length() != AUTH_TAG_LENGTH) {
423       KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
424     }
425     short index = 0;
426     short found;
427     short offset = repository.alloc(AUTH_TAG_ENTRY_SIZE);
428     while (index < MAX_BLOB_STORAGE) {
429       if (dataLength((short) (index + AUTH_TAG_1)) != 0) {
430         readDataEntry((short) (index + AUTH_TAG_1), repository.getHeap(), offset);
431         found =
432             Util.arrayCompare(
433                 repository.getHeap(),
434                 (short) (offset + 1),
435                 KMByteBlob.cast(authTag).getBuffer(),
436                 KMByteBlob.cast(authTag).getStartOff(),
437                 AUTH_TAG_LENGTH);
438         if (found == 0) {
439           return (short) (index + AUTH_TAG_1);
440         }
441       }
442       index++;
443     }
444     return KMType.INVALID_VALUE;
445   }
446 
getRateLimitedKeyCount(short authTag, byte[] out, short outOff)447   public short getRateLimitedKeyCount(short authTag, byte[] out, short outOff) {
448     short tag = findTag(authTag);
449     short blob;
450     if (tag != KMType.INVALID_VALUE) {
451       blob = readData(tag);
452       Util.arrayCopyNonAtomic(
453           KMByteBlob.cast(blob).getBuffer(),
454           (short) (KMByteBlob.cast(blob).getStartOff() + AUTH_TAG_LENGTH + 1),
455           out,
456           outOff,
457           AUTH_TAG_COUNTER_SIZE);
458       return AUTH_TAG_COUNTER_SIZE;
459     }
460     return (short) 0;
461   }
462 
setRateLimitedKeyCount(short authTag, byte[] buf, short off, short len)463   public void setRateLimitedKeyCount(short authTag, byte[] buf, short off, short len) {
464     short tag = findTag(authTag);
465     if (tag != KMType.INVALID_VALUE) {
466       short dataPtr = readData(tag);
467       Util.arrayCopyNonAtomic(
468           buf,
469           off,
470           KMByteBlob.cast(dataPtr).getBuffer(),
471           (short) (KMByteBlob.cast(dataPtr).getStartOff() + AUTH_TAG_LENGTH + 1),
472           len);
473       writeDataEntry(
474           tag,
475           KMByteBlob.cast(dataPtr).getBuffer(),
476           KMByteBlob.cast(dataPtr).getStartOff(),
477           KMByteBlob.cast(dataPtr).length());
478     }
479   }
480 
persistAdditionalCertChain(byte[] buf, short offset, short len)481   public void persistAdditionalCertChain(byte[] buf, short offset, short len) {
482     // Input buffer contains encoded additional certificate chain as shown below.
483     //    AdditionalDKSignatures = {
484     //      + SignerName => DKCertChain
485     //    }
486     //    SignerName = tstr
487     //    DKCertChain = [
488     //      2* Certificate // Root -> Leaf. Root is the vendo r
489     //            // self-signed cert, leaf contains DK_pu b
490     //    ]
491     //    Certificate = COSE_Sign1 of a public key
492     if ((short) (len + 2) > ADDITIONAL_CERT_CHAIN_MAX_SIZE) {
493       KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
494     }
495     JCSystem.beginTransaction();
496     Util.setShort(additionalCertChain, (short) 0, (short) len);
497     Util.arrayCopyNonAtomic(buf, offset, additionalCertChain, (short) 2, len);
498     JCSystem.commitTransaction();
499   }
500 
getAdditionalCertChainLength()501   public short getAdditionalCertChainLength() {
502     return Util.getShort(additionalCertChain, (short) 0);
503   }
504 
getAdditionalCertChain()505   public byte[] getAdditionalCertChain() {
506     return additionalCertChain;
507   }
508 
getBootCertificateChain()509   public byte[] getBootCertificateChain() {
510     return bcc;
511   }
512 
persistBootCertificateChain(byte[] buf, short offset, short len)513   public void persistBootCertificateChain(byte[] buf, short offset, short len) {
514     if ((short) (len + 2) > BCC_MAX_SIZE) {
515       KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
516     }
517     JCSystem.beginTransaction();
518     Util.setShort(bcc, (short) 0, (short) len);
519     Util.arrayCopyNonAtomic(buf, offset, bcc, (short) 2, len);
520     JCSystem.commitTransaction();
521   }
522 
writeAuthTagState(byte[] buf, short offset, byte state)523   private void writeAuthTagState(byte[] buf, short offset, byte state) {
524     buf[offset] = state;
525   }
526 
527   // The master key should only be generated during applet installation and
528   // during a device factory reset event.
createMasterKey(short keySizeBits)529   public KMKey createMasterKey(short keySizeBits) {
530     if (masterKey == null) {
531       masterKey = seProvider.createMasterKey(masterKey, keySizeBits);
532     }
533     return (KMKey) masterKey;
534   }
535 
regenerateMasterKey()536   public KMKey regenerateMasterKey() {
537     return seProvider.createMasterKey(masterKey, KMKeymasterApplet.MASTER_KEY_SIZE);
538   }
539 
getMasterKey()540   public KMKey getMasterKey() {
541     return masterKey;
542   }
543 
createPresharedKey(byte[] keyData, short offset, short length)544   public void createPresharedKey(byte[] keyData, short offset, short length) {
545     if (length != SHARED_SECRET_KEY_SIZE) {
546       KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
547     }
548     if (preSharedKey == null) {
549       preSharedKey = seProvider.createPreSharedKey(preSharedKey, keyData, offset, length);
550     } else {
551       seProvider.createPreSharedKey(preSharedKey, keyData, offset, length);
552     }
553   }
554 
getPresharedKey()555   public KMKey getPresharedKey() {
556     if (preSharedKey == null) {
557       KMException.throwIt(KMError.INVALID_DATA);
558     }
559     return preSharedKey;
560   }
561 
createComputedHmacKey(byte[] keyData, short offset, short length)562   public void createComputedHmacKey(byte[] keyData, short offset, short length) {
563     if (length != COMPUTED_HMAC_KEY_SIZE) {
564       KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
565     }
566     if (computedHmacKey == null) {
567       computedHmacKey = seProvider.createComputedHmacKey(computedHmacKey, keyData, offset, length);
568     } else {
569       seProvider.createComputedHmacKey(computedHmacKey, keyData, offset, length);
570     }
571   }
572 
getComputedHmacKey()573   public KMKey getComputedHmacKey() {
574     if (computedHmacKey == null) {
575       KMException.throwIt(KMError.INVALID_DATA);
576     }
577     return computedHmacKey;
578   }
579 
createRkpTestDeviceUniqueKeyPair( byte[] pubKey, short pubKeyOff, short pubKeyLen, byte[] privKey, short privKeyOff, short privKeyLen)580   public KMKey createRkpTestDeviceUniqueKeyPair(
581       byte[] pubKey,
582       short pubKeyOff,
583       short pubKeyLen,
584       byte[] privKey,
585       short privKeyOff,
586       short privKeyLen) {
587     if (testDeviceUniqueKeyPair == null) {
588       testDeviceUniqueKeyPair =
589           seProvider.createRkpDeviceUniqueKeyPair(
590               testDeviceUniqueKeyPair,
591               pubKey,
592               pubKeyOff,
593               pubKeyLen,
594               privKey,
595               privKeyOff,
596               privKeyLen);
597     } else {
598       seProvider.createRkpDeviceUniqueKeyPair(
599           testDeviceUniqueKeyPair, pubKey, pubKeyOff, pubKeyLen, privKey, privKeyOff, privKeyLen);
600     }
601     return testDeviceUniqueKeyPair;
602   }
603 
createRkpDeviceUniqueKeyPair( byte[] pubKey, short pubKeyOff, short pubKeyLen, byte[] privKey, short privKeyOff, short privKeyLen)604   public KMKey createRkpDeviceUniqueKeyPair(
605       byte[] pubKey,
606       short pubKeyOff,
607       short pubKeyLen,
608       byte[] privKey,
609       short privKeyOff,
610       short privKeyLen) {
611     if (deviceUniqueKeyPair == null) {
612       deviceUniqueKeyPair =
613           seProvider.createRkpDeviceUniqueKeyPair(
614               deviceUniqueKeyPair, pubKey, pubKeyOff, pubKeyLen, privKey, privKeyOff, privKeyLen);
615     } else {
616       seProvider.createRkpDeviceUniqueKeyPair(
617           deviceUniqueKeyPair, pubKey, pubKeyOff, pubKeyLen, privKey, privKeyOff, privKeyLen);
618     }
619     return deviceUniqueKeyPair;
620   }
621 
getRkpDeviceUniqueKeyPair(boolean testMode)622   public KMKey getRkpDeviceUniqueKeyPair(boolean testMode) {
623     return ((KMKey) (testMode ? testDeviceUniqueKeyPair : deviceUniqueKeyPair));
624   }
625 
createRkpMacKey(byte[] keydata, short offset, short length)626   public void createRkpMacKey(byte[] keydata, short offset, short length) {
627     if (rkpMacKey == null) {
628       rkpMacKey = seProvider.createRkpMacKey(rkpMacKey, keydata, offset, length);
629     } else {
630       seProvider.createRkpMacKey(rkpMacKey, keydata, offset, length);
631     }
632   }
633 
getRkpMacKey()634   public KMKey getRkpMacKey() {
635     if (rkpMacKey == null) {
636       KMException.throwIt(KMError.INVALID_DATA);
637     }
638     return rkpMacKey;
639   }
640 
getAttestationId(short tag, byte[] buffer, short start)641   public short getAttestationId(short tag, byte[] buffer, short start) {
642     byte[] attestId = null;
643     switch (tag) {
644         // Attestation Id Brand
645       case KMType.ATTESTATION_ID_BRAND:
646         attestId = attIdBrand;
647         break;
648         // Attestation Id Device
649       case KMType.ATTESTATION_ID_DEVICE:
650         attestId = attIdDevice;
651         break;
652         // Attestation Id Product
653       case KMType.ATTESTATION_ID_PRODUCT:
654         attestId = attIdProduct;
655         break;
656         // Attestation Id Serial
657       case KMType.ATTESTATION_ID_SERIAL:
658         attestId = attIdSerial;
659         break;
660         // Attestation Id IMEI
661       case KMType.ATTESTATION_ID_IMEI:
662         attestId = attIdImei;
663         break;
664         // Attestation Id MEID
665       case KMType.ATTESTATION_ID_MEID:
666         attestId = attIdMeId;
667         break;
668         // Attestation Id Manufacturer
669       case KMType.ATTESTATION_ID_MANUFACTURER:
670         attestId = attIdManufacturer;
671         break;
672         // Attestation Id Model
673       case KMType.ATTESTATION_ID_MODEL:
674         attestId = attIdModel;
675         break;
676     }
677     if (attestId == null) {
678       KMException.throwIt(KMError.CANNOT_ATTEST_IDS);
679     }
680     Util.arrayCopyNonAtomic(attestId, (short) 0, buffer, start, (short) attestId.length);
681     return (short) attestId.length;
682   }
683 
setAttestationId(short tag, byte[] buffer, short start, short length)684   public void setAttestationId(short tag, byte[] buffer, short start, short length) {
685     switch (tag) {
686         // Attestation Id Brand
687       case KMType.ATTESTATION_ID_BRAND:
688         JCSystem.beginTransaction();
689         attIdBrand = new byte[length];
690         Util.arrayCopyNonAtomic(buffer, (short) start, attIdBrand, (short) 0, length);
691         JCSystem.commitTransaction();
692         break;
693         // Attestation Id Device
694       case KMType.ATTESTATION_ID_DEVICE:
695         JCSystem.beginTransaction();
696         attIdDevice = new byte[length];
697         Util.arrayCopyNonAtomic(buffer, (short) start, attIdDevice, (short) 0, length);
698         JCSystem.commitTransaction();
699         break;
700         // Attestation Id Product
701       case KMType.ATTESTATION_ID_PRODUCT:
702         JCSystem.beginTransaction();
703         attIdProduct = new byte[length];
704         Util.arrayCopyNonAtomic(buffer, (short) start, attIdProduct, (short) 0, length);
705         JCSystem.commitTransaction();
706         break;
707         // Attestation Id Serial
708       case KMType.ATTESTATION_ID_SERIAL:
709         JCSystem.beginTransaction();
710         attIdSerial = new byte[length];
711         Util.arrayCopyNonAtomic(buffer, (short) start, attIdSerial, (short) 0, length);
712         JCSystem.commitTransaction();
713         break;
714         // Attestation Id IMEI
715       case KMType.ATTESTATION_ID_IMEI:
716         JCSystem.beginTransaction();
717         attIdImei = new byte[length];
718         Util.arrayCopyNonAtomic(buffer, (short) start, attIdImei, (short) 0, length);
719         JCSystem.commitTransaction();
720         break;
721         // Attestation Id MEID
722       case KMType.ATTESTATION_ID_MEID:
723         JCSystem.beginTransaction();
724         attIdMeId = new byte[length];
725         Util.arrayCopyNonAtomic(buffer, (short) start, attIdMeId, (short) 0, length);
726         JCSystem.commitTransaction();
727         break;
728         // Attestation Id Manufacturer
729       case KMType.ATTESTATION_ID_MANUFACTURER:
730         JCSystem.beginTransaction();
731         attIdManufacturer = new byte[length];
732         Util.arrayCopyNonAtomic(buffer, (short) start, attIdManufacturer, (short) 0, length);
733         JCSystem.commitTransaction();
734         break;
735         // Attestation Id Model
736       case KMType.ATTESTATION_ID_MODEL:
737         JCSystem.beginTransaction();
738         attIdModel = new byte[length];
739         Util.arrayCopyNonAtomic(buffer, (short) start, attIdModel, (short) 0, length);
740         JCSystem.commitTransaction();
741         break;
742     }
743   }
744 
deleteAttestationIds()745   public void deleteAttestationIds() {
746     attIdBrand = null;
747     attIdDevice = null;
748     attIdProduct = null;
749     attIdSerial = null;
750     attIdImei = null;
751     attIdMeId = null;
752     attIdManufacturer = null;
753     attIdModel = null;
754     // Trigger garbage collection.
755     JCSystem.requestObjectDeletion();
756   }
757 
getVerifiedBootHash(byte[] buffer, short start)758   public short getVerifiedBootHash(byte[] buffer, short start) {
759     if (verifiedHash == null) {
760       KMException.throwIt(KMError.INVALID_DATA);
761     }
762     Util.arrayCopyNonAtomic(verifiedHash, (short) 0, buffer, start, (short) verifiedHash.length);
763     return (short) verifiedHash.length;
764   }
765 
getBootKey(byte[] buffer, short start)766   public short getBootKey(byte[] buffer, short start) {
767     if (bootKey == null) {
768       KMException.throwIt(KMError.INVALID_DATA);
769     }
770     Util.arrayCopyNonAtomic(bootKey, (short) 0, buffer, start, (short) bootKey.length);
771     return (short) bootKey.length;
772   }
773 
getBootState()774   public short getBootState() {
775     return bootState;
776   }
777 
setBootState(short state)778   public void setBootState(short state) {
779     bootState = state;
780   }
781 
isDeviceBootLocked()782   public boolean isDeviceBootLocked() {
783     return deviceBootLocked;
784   }
785 
getBootPatchLevel()786   public short getBootPatchLevel() {
787     if (bootPatchLevel == null) {
788       KMException.throwIt(KMError.INVALID_DATA);
789     }
790     return KMInteger.uint_32(bootPatchLevel, (short) 0);
791   }
792 
setVerifiedBootHash(byte[] buffer, short start, short length)793   public void setVerifiedBootHash(byte[] buffer, short start, short length) {
794     if (verifiedHash == null) {
795       verifiedHash = new byte[32];
796     }
797     if (length != 32) {
798       KMException.throwIt(KMError.UNKNOWN_ERROR);
799     }
800     Util.arrayCopy(buffer, start, verifiedHash, (short) 0, (short) 32);
801   }
802 
setBootKey(byte[] buffer, short start, short length)803   public void setBootKey(byte[] buffer, short start, short length) {
804     if (bootKey == null) {
805       bootKey = new byte[32];
806     }
807     if (length != 32) {
808       KMException.throwIt(KMError.UNKNOWN_ERROR);
809     }
810     Util.arrayCopy(buffer, start, bootKey, (short) 0, (short) 32);
811   }
812 
setDeviceLocked(boolean state)813   public void setDeviceLocked(boolean state) {
814     deviceBootLocked = state;
815   }
816 
setBootPatchLevel(byte[] buffer, short start, short length)817   public void setBootPatchLevel(byte[] buffer, short start, short length) {
818     if (bootPatchLevel == null) {
819       bootPatchLevel = new byte[4];
820     }
821     if (length > 4 || length < 0) {
822       KMException.throwIt(KMError.UNKNOWN_ERROR);
823     }
824     Util.arrayCopy(buffer, start, bootPatchLevel, (short) 0, (short) length);
825   }
826 
setChallenge(byte[] buf, short start, short length)827   public void setChallenge(byte[] buf, short start, short length) {
828     if (challenge == null) {
829       challenge = new byte[16];
830     }
831     if (length != 16) {
832       KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
833     }
834     Util.arrayCopy(buf, start, challenge, (short) 0, (short) length);
835   }
836 
getChallenge(byte[] buffer, short start)837   public short getChallenge(byte[] buffer, short start) {
838     if (challenge == null) {
839       KMException.throwIt(KMError.INVALID_DATA);
840     }
841     Util.arrayCopyNonAtomic(challenge, (short) 0, buffer, start, (short) challenge.length);
842     return (short) challenge.length;
843   }
844 
isProvisionLocked()845   public boolean isProvisionLocked() {
846     if (0 != (provisionStatus & KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED)) {
847       return true;
848     }
849     return false;
850   }
851 
getProvisionStatus()852   public short getProvisionStatus() {
853     return provisionStatus;
854   }
855 
setProvisionStatus(short pStatus)856   public void setProvisionStatus(short pStatus) {
857     JCSystem.beginTransaction();
858     provisionStatus |= pStatus;
859     JCSystem.commitTransaction();
860   }
861 
unlockProvision()862   public void unlockProvision() {
863     JCSystem.beginTransaction();
864     provisionStatus &= ~KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED;
865     JCSystem.commitTransaction();
866   }
867 
persistOEMRootPublicKey(byte[] inBuff, short inOffset, short inLength)868   public void persistOEMRootPublicKey(byte[] inBuff, short inOffset, short inLength) {
869     if (inLength != 65) {
870       KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
871     }
872     if (oemRootPublicKey == null) {
873       oemRootPublicKey = new byte[65];
874     }
875     Util.arrayCopy(inBuff, inOffset, oemRootPublicKey, (short) 0, inLength);
876   }
877 
getOEMRootPublicKey()878   public byte[] getOEMRootPublicKey() {
879     if (oemRootPublicKey == null) {
880       KMException.throwIt(KMError.INVALID_DATA);
881     }
882     return oemRootPublicKey;
883   }
884 
885   @Override
onSave(Element element)886   public void onSave(Element element) {
887     // Prmitives
888     element.write(provisionStatus);
889     element.write(secureBootMode);
890     // Objects
891     element.write(attIdBrand);
892     element.write(attIdDevice);
893     element.write(attIdProduct);
894     element.write(attIdSerial);
895     element.write(attIdImei);
896     element.write(attIdMeId);
897     element.write(attIdManufacturer);
898     element.write(attIdModel);
899     element.write(additionalCertChain);
900     element.write(bcc);
901     element.write(oemRootPublicKey);
902 
903     // Key Objects
904     seProvider.onSave(element, KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY, masterKey);
905     seProvider.onSave(element, KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY, preSharedKey);
906     seProvider.onSave(
907         element, KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY_PAIR, deviceUniqueKeyPair);
908     seProvider.onSave(element, KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY, rkpMacKey);
909   }
910 
911   @Override
onRestore(Element element, short oldVersion, short currentVersion)912   public void onRestore(Element element, short oldVersion, short currentVersion) {
913     if (oldVersion <= KM_APPLET_PACKAGE_VERSION_1) {
914       // 1.0 to 3.1 Upgrade happens here.
915       handlePreviousVersionUpgrade(element);
916       return;
917     } else if (oldVersion == KM_APPLET_PACKAGE_VERSION_2) {
918       handleUpgrade(element, oldVersion);
919       JCSystem.beginTransaction();
920       // While upgrading Secure Boot Mode flag from 2.0 to 3.0, implementations
921       // have to update the secureBootMode with the correct input.
922       secureBootMode = 0;
923       provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SECURE_BOOT_MODE;
924       // Applet package Versions till 2 had CoseSign1 for additionalCertificateChain.
925       // From package version 3, the additionalCertificateChain is in X.509 format.
926       // So Unreference the old address and allocate new persistent memory.
927       additionalCertChain = new byte[ADDITIONAL_CERT_CHAIN_MAX_SIZE];
928       JCSystem.commitTransaction();
929       // Request for ObjectDeletion for unreferenced address of additionalCertChain.
930       JCSystem.requestObjectDeletion();
931       return;
932     }
933     handleUpgrade(element, oldVersion);
934   }
935 
handlePreviousVersionUpgrade(Element element)936   private void handlePreviousVersionUpgrade(Element element) {
937     // Read Primitives
938     // restore old data table index
939     short oldDataIndex = element.readShort();
940     element.readBoolean(); // pop deviceBootLocked
941     element.readShort(); // pop bootState
942 
943     // Read Objects
944     // restore old data table
945     byte[] oldDataTable = (byte[]) element.readObject();
946 
947     attIdBrand = (byte[]) element.readObject();
948     attIdDevice = (byte[]) element.readObject();
949     attIdProduct = (byte[]) element.readObject();
950     attIdSerial = (byte[]) element.readObject();
951     attIdImei = (byte[]) element.readObject();
952     attIdMeId = (byte[]) element.readObject();
953     attIdManufacturer = (byte[]) element.readObject();
954     attIdModel = (byte[]) element.readObject();
955     element.readObject(); // pop verifiedHash
956     element.readObject(); // pop bootKey
957     element.readObject(); // pop bootPatchLevel
958     additionalCertChain = (byte[]) element.readObject();
959     bcc = (byte[]) element.readObject();
960 
961     // Read Key Objects
962     masterKey = (KMKey) seProvider.onRestore(element);
963     seProvider.onRestore(element); // pop computedHmacKey
964     preSharedKey = (KMKey) seProvider.onRestore(element);
965     deviceUniqueKeyPair = (KMKey) seProvider.onRestore(element);
966     rkpMacKey = (KMKey) seProvider.onRestore(element);
967     handleProvisionStatusUpgrade(oldDataTable, oldDataIndex);
968   }
969 
handleUpgrade(Element element, short oldVersion)970   private void handleUpgrade(Element element, short oldVersion) {
971     // Read Primitives
972     provisionStatus = element.readShort();
973     if (oldVersion >= KM_APPLET_PACKAGE_VERSION_3) {
974       secureBootMode = element.readByte();
975     }
976     // Read Objects
977     attIdBrand = (byte[]) element.readObject();
978     attIdDevice = (byte[]) element.readObject();
979     attIdProduct = (byte[]) element.readObject();
980     attIdSerial = (byte[]) element.readObject();
981     attIdImei = (byte[]) element.readObject();
982     attIdMeId = (byte[]) element.readObject();
983     attIdManufacturer = (byte[]) element.readObject();
984     attIdModel = (byte[]) element.readObject();
985     additionalCertChain = (byte[]) element.readObject();
986     bcc = (byte[]) element.readObject();
987     oemRootPublicKey = (byte[]) element.readObject();
988     // Read Key Objects
989     masterKey = (KMKey) seProvider.onRestore(element);
990     preSharedKey = (KMKey) seProvider.onRestore(element);
991     deviceUniqueKeyPair = (KMKey) seProvider.onRestore(element);
992     rkpMacKey = (KMKey) seProvider.onRestore(element);
993   }
994 
getProvisionStatus(byte[] dataTable, byte[] scratchpad, short offset)995   public void getProvisionStatus(byte[] dataTable, byte[] scratchpad, short offset) {
996     Util.setShort(scratchpad, offset, (short) 0);
997     readDataEntry(dataTable, OLD_PROVISIONED_STATUS_OFFSET, scratchpad, offset);
998   }
999 
handleProvisionStatusUpgrade(byte[] dataTable, short dataTableIndex)1000   void handleProvisionStatusUpgrade(byte[] dataTable, short dataTableIndex) {
1001     short dInex = repository.allocReclaimableMemory((short) 2);
1002     byte data[] = repository.getHeap();
1003     getProvisionStatus(dataTable, data, dInex);
1004     short pStatus = (short) (data[dInex] & 0x00ff);
1005     if (KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED
1006         == (pStatus & KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED)) {
1007       pStatus |=
1008           KMKeymasterApplet.PROVISION_STATUS_SE_LOCKED
1009               | KMKeymasterApplet.PROVISION_STATUS_SECURE_BOOT_MODE;
1010     }
1011     JCSystem.beginTransaction();
1012     // While upgrading Secure Boot Mode flag from 1.0 to 3.0, implementations
1013     // have to update the secureBootMode with the correct input.
1014     secureBootMode = 0;
1015     provisionStatus = pStatus;
1016     // Applet package Versions till 2 had CoseSign1 for additionalCertificateChain.
1017     // From package version 3, the additionalCertificateChain is in X.509 format.
1018     // So Unreference the old address and allocate new persistent memory.
1019     additionalCertChain = new byte[ADDITIONAL_CERT_CHAIN_MAX_SIZE];
1020     JCSystem.commitTransaction();
1021     repository.reclaimMemory((short) 2);
1022     // Request object deletion for unreferenced address for additionalCertChain
1023     JCSystem.requestObjectDeletion();
1024   }
1025 
1026   @Override
getBackupPrimitiveByteCount()1027   public short getBackupPrimitiveByteCount() {
1028     // provisionStatus - 2 bytes
1029     // secureBootMode - 1 byte
1030     return (short)
1031         (3
1032             + seProvider.getBackupPrimitiveByteCount(KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY)
1033             + seProvider.getBackupPrimitiveByteCount(
1034                 KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY)
1035             + seProvider.getBackupPrimitiveByteCount(
1036                 KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY_PAIR)
1037             + seProvider.getBackupPrimitiveByteCount(
1038                 KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY));
1039   }
1040 
1041   @Override
getBackupObjectCount()1042   public short getBackupObjectCount() {
1043     // AttestationIds - 8
1044     // AdditionalCertificateChain - 1
1045     // BCC - 1
1046     // oemRootPublicKey - 1
1047     return (short)
1048         (11
1049             + seProvider.getBackupObjectCount(KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY)
1050             + seProvider.getBackupObjectCount(KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY)
1051             + seProvider.getBackupObjectCount(
1052                 KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY_PAIR)
1053             + seProvider.getBackupObjectCount(KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY));
1054   }
1055 }
1056