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