@@ -33,6 +33,7 @@ import com.android.identity.crypto.CertificateChain
33
33
import com.android.identity.crypto.EcCurve
34
34
import com.android.identity.crypto.EcPublicKey
35
35
import com.android.identity.crypto.javaPublicKey
36
+ import com.android.identity.securearea.KeyInvalidatedException
36
37
import com.android.identity.securearea.KeyLockedException
37
38
import com.android.identity.securearea.KeyPurpose
38
39
import com.android.identity.securearea.SecureArea
@@ -197,6 +198,12 @@ class AndroidKeystoreSecureArea(
197
198
else -> throw IllegalArgumentException (" Curve is not supported" )
198
199
}
199
200
if (aSettings.userAuthenticationRequired) {
201
+ val keyguardManager = context.getSystemService(Context .KEYGUARD_SERVICE ) as KeyguardManager
202
+ if (! keyguardManager.isDeviceSecure) {
203
+ throw ScreenLockRequiredException (
204
+ " Screen lock must be set up to create keys with user authentication"
205
+ )
206
+ }
200
207
builder.setUserAuthenticationRequired(true )
201
208
val timeoutMillis = aSettings.userAuthenticationTimeoutMillis
202
209
if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .R ) {
@@ -246,7 +253,7 @@ class AndroidKeystoreSecureArea(
246
253
try {
247
254
kpg.initialize(builder.build())
248
255
} catch (e: InvalidAlgorithmParameterException ) {
249
- throw IllegalStateException (e.message, e )
256
+ throw IllegalStateException (e)
250
257
}
251
258
kpg.generateKeyPair()
252
259
} catch (e: NoSuchAlgorithmException ) {
@@ -282,11 +289,13 @@ class AndroidKeystoreSecureArea(
282
289
* @param existingAlias the alias of the existing key.
283
290
*/
284
291
fun createKeyForExistingAlias (existingAlias : String ) {
292
+
293
+ val ks = KeyStore .getInstance(" AndroidKeyStore" )
294
+ ks.load(null )
295
+ val entry = ks.getEntry(existingAlias, null )
296
+ ? : throw IllegalArgumentException (" A key with this alias doesn't exist" )
297
+
285
298
var keyInfo: android.security.keystore.KeyInfo = try {
286
- val ks = KeyStore .getInstance(" AndroidKeyStore" )
287
- ks.load(null )
288
- val entry = ks.getEntry(existingAlias, null )
289
- ? : throw IllegalArgumentException (" No entry for alias" )
290
299
val privateKey = (entry as KeyStore .PrivateKeyEntry ).privateKey
291
300
val factory = KeyFactory .getInstance(privateKey.algorithm, " AndroidKeyStore" )
292
301
try {
@@ -415,11 +424,10 @@ class AndroidKeystoreSecureArea(
415
424
}
416
425
}
417
426
}
427
+
428
+ val (entry, _) = loadKey(alias)
429
+
418
430
return try {
419
- val ks = KeyStore .getInstance(" AndroidKeyStore" )
420
- ks.load(null )
421
- val entry = ks.getEntry(alias, null )
422
- ? : throw IllegalArgumentException (" No entry for alias" )
423
431
val privateKey = (entry as KeyStore .PrivateKeyEntry ).privateKey
424
432
val s = Signature .getInstance(getSignatureAlgorithmName(signatureAlgorithm))
425
433
s.initSign(privateKey)
@@ -447,11 +455,8 @@ class AndroidKeystoreSecureArea(
447
455
otherKey : EcPublicKey ,
448
456
keyUnlockData : com.android.identity.securearea.KeyUnlockData ?
449
457
): ByteArray {
458
+ val (entry, _) = loadKey(alias)
450
459
return try {
451
- val ks = KeyStore .getInstance(" AndroidKeyStore" )
452
- ks.load(null )
453
- val entry = ks.getEntry(alias, null )
454
- ? : throw IllegalArgumentException (" No entry for alias" )
455
460
val privateKey = (entry as KeyStore .PrivateKeyEntry ).privateKey
456
461
val ka = KeyAgreement .getInstance(" ECDH" , " AndroidKeyStore" )
457
462
ka.init (privateKey)
@@ -474,19 +479,37 @@ class AndroidKeystoreSecureArea(
474
479
}
475
480
}
476
481
482
+ // @throws IllegalArgumentException if the key doesn't exist.
483
+ // @throws KeyInvalidatedException if LSKF was removed and the key is no longer available.
484
+ private fun loadKey (alias : String ): Pair <KeyStore .Entry , ByteArray > {
485
+ val data = storageEngine[PREFIX + alias] ? : throw IllegalArgumentException (" No key with given alias" )
486
+
487
+ val ks = KeyStore .getInstance(" AndroidKeyStore" )
488
+ ks.load(null )
489
+ // If the LSKF is removed, all auth-bound keys are removed and the result is
490
+ // that KeyStore.getEntry() returns null.
491
+ val entry = ks.getEntry(alias, null )
492
+ ? : throw KeyInvalidatedException (" This key is no longer available" )
493
+
494
+ return Pair (entry, data)
495
+ }
496
+
497
+ override fun getKeyInvalidated (alias : String ): Boolean {
498
+ try {
499
+ loadKey(alias)
500
+ } catch (e: KeyInvalidatedException ) {
501
+ return true
502
+ }
503
+ return false
504
+ }
505
+
477
506
override fun getKeyInfo (alias : String ): AndroidKeystoreKeyInfo {
507
+ val (entry, data) = loadKey(alias)
478
508
return try {
479
- val ks = KeyStore .getInstance(" AndroidKeyStore" )
480
- ks.load(null )
481
- val entry = ks.getEntry(alias, null )
482
- ? : throw IllegalArgumentException (" No entry for alias" )
483
509
val privateKey = (entry as KeyStore .PrivateKeyEntry ).privateKey
484
510
val factory = KeyFactory .getInstance(privateKey.algorithm, " AndroidKeyStore" )
485
511
val keyInfo =
486
512
factory.getKeySpec(privateKey, android.security.keystore.KeyInfo ::class .java)
487
-
488
- val data = storageEngine[PREFIX + alias]
489
- ? : throw IllegalArgumentException (" No key with given alias" )
490
513
val map = Cbor .decode(data)
491
514
val keyPurposes = map[" keyPurposes" ].asNumber.keyPurposeSet
492
515
val userAuthenticationRequired = map[" userAuthenticationRequired" ].asBoolean
@@ -572,16 +595,16 @@ class AndroidKeystoreSecureArea(
572
595
* @param context the application context.
573
596
*/
574
597
class Capabilities (context : Context ) {
575
- private val mKeyguardManager : KeyguardManager
576
- private val mApiLevel : Int
577
- private val mTeeFeatureLevel : Int
578
- private val mSbFeatureLevel : Int
598
+ private val keyguardManager : KeyguardManager
599
+ private val apiLevel : Int
600
+ private val teeFeatureLevel : Int
601
+ private val sbFeatureLevel : Int
579
602
580
603
init {
581
- mKeyguardManager = context.getSystemService(Context .KEYGUARD_SERVICE ) as KeyguardManager
582
- mTeeFeatureLevel = getFeatureVersionKeystore(context, false )
583
- mSbFeatureLevel = getFeatureVersionKeystore(context, true )
584
- mApiLevel = Build .VERSION .SDK_INT
604
+ keyguardManager = context.getSystemService(Context .KEYGUARD_SERVICE ) as KeyguardManager
605
+ teeFeatureLevel = getFeatureVersionKeystore(context, false )
606
+ sbFeatureLevel = getFeatureVersionKeystore(context, true )
607
+ apiLevel = Build .VERSION .SDK_INT
585
608
}
586
609
587
610
val secureLockScreenSetup: Boolean
@@ -591,7 +614,7 @@ class AndroidKeystoreSecureArea(
591
614
* This checks whether the device currently has a secure lock
592
615
* screen (either PIN, pattern, or password).
593
616
*/
594
- get() = mKeyguardManager .isDeviceSecure
617
+ get() = keyguardManager .isDeviceSecure
595
618
596
619
/* *
597
620
* Whether it's possible to specify multiple authentication types.
@@ -602,63 +625,63 @@ class AndroidKeystoreSecureArea(
602
625
* Biometric only, or both).
603
626
*/
604
627
val multipleAuthenticationTypesSupported: Boolean
605
- get() = mApiLevel >= Build .VERSION_CODES .R
628
+ get() = apiLevel >= Build .VERSION_CODES .R
606
629
607
630
/* *
608
631
* Whether Attest Keys are supported.
609
632
*
610
633
* This is only supported in KeyMint 1.0 (version 100) and higher.
611
634
*/
612
635
val attestKeySupported: Boolean
613
- get() = mTeeFeatureLevel >= 100
636
+ get() = teeFeatureLevel >= 100
614
637
615
638
/* *
616
639
* Whether Key Agreement is supported.
617
640
*
618
641
* This is only supported in KeyMint 1.0 (version 100) and higher.
619
642
*/
620
643
val keyAgreementSupported: Boolean
621
- get() = mTeeFeatureLevel >= 100
644
+ get() = teeFeatureLevel >= 100
622
645
623
646
/* *
624
647
* Whether Curve25519 is supported.
625
648
*
626
649
* This is only supported in KeyMint 2.0 (version 200) and higher.
627
650
*/
628
651
val curve25519Supported: Boolean
629
- get() = mTeeFeatureLevel >= 200
652
+ get() = teeFeatureLevel >= 200
630
653
631
654
/* *
632
655
* Whether StrongBox is supported.
633
656
*
634
657
* StrongBox requires dedicated hardware and is not available on all devices.
635
658
*/
636
659
val strongBoxSupported: Boolean
637
- get() = mSbFeatureLevel > 0
660
+ get() = sbFeatureLevel > 0
638
661
639
662
/* *
640
663
* Whether StrongBox Attest Keys are supported.
641
664
*
642
665
* This is only supported in StrongBox KeyMint 1.0 (version 100) and higher.
643
666
*/
644
667
val strongBoxAttestKeySupported: Boolean
645
- get() = mSbFeatureLevel >= 100
668
+ get() = sbFeatureLevel >= 100
646
669
647
670
/* *
648
671
* Whether StrongBox Key Agreement is supported.
649
672
*
650
673
* This is only supported in StrongBox KeyMint 1.0 (version 100) and higher.
651
674
*/
652
675
val strongBoxKeyAgreementSupported: Boolean
653
- get() = mSbFeatureLevel >= 100
676
+ get() = sbFeatureLevel >= 100
654
677
655
678
/* *
656
679
* Whether StrongBox Curve25519 is supported.
657
680
*
658
681
* This is only supported in StrongBox KeyMint 2.0 (version 200) and higher.
659
682
*/
660
683
val strongBoxCurve25519Supported: Boolean
661
- get() = mSbFeatureLevel >= 200
684
+ get() = sbFeatureLevel >= 200
662
685
}
663
686
664
687
companion object {
0 commit comments