Skip to content

Commit

Permalink
Rename KeystoreEngine to SecureArea. (#355)
Browse files Browse the repository at this point in the history
It's likely we want to add features implemented in the secure area in the
future that are specific to real-world identity credentials in addition to
symmetric and asymmetric keys that are guaranteed to never leave the secure
area. For example, this could include keys and objects needed for ZKP and
storage of credential data.

Also add a feature to the Android Keystore implementation of SecureArea
to allow specifying whether LSKF, biometric, or both can be used to unlock
the key. Make a note in the docs that this only works with API 30 or later.

Also fix a bug in DeviceRetrievalHelperTest.

Test: All unit tests pass.
Test: Manually tested with holder and reader.
  • Loading branch information
davidz25 authored Aug 16, 2023
1 parent c035ca3 commit 9798871
Show file tree
Hide file tree
Showing 21 changed files with 870 additions and 630 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import com.android.identity.android.mdoc.transport.DataTransport
import com.android.identity.android.mdoc.deviceretrieval.DeviceRetrievalHelper
import com.android.identity.android.legacy.PresentationSession
import com.android.identity.android.mdoc.engagement.QrEngagementHelper
import com.android.identity.keystore.KeystoreEngine
import com.android.mdl.app.util.log
import com.android.mdl.app.util.mainExecutor
import java.security.PublicKey
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
import android.content.Context;

import com.android.identity.AndroidAttestationExtensionParser;
import com.android.identity.android.keystore.AndroidKeystore;
import com.android.identity.android.securearea.AndroidKeystoreSecureArea;
import com.android.identity.android.storage.AndroidStorageEngine;
import com.android.identity.credential.Credential;
import com.android.identity.credential.CredentialStore;
import com.android.identity.keystore.KeystoreEngine;
import com.android.identity.keystore.KeystoreEngineRepository;
import com.android.identity.securearea.SecureArea;
import com.android.identity.securearea.SecureAreaRepository;
import com.android.identity.storage.StorageEngine;

import org.junit.Assert;
Expand All @@ -39,37 +39,37 @@
// See CredentialStoreTest in non-Android tests for main tests for CredentialStore. These
// tests are just for the Android-specific bits including attestation.
//
public class AndroidKeystoreCredentialStoreTest {
public class AndroidKeystoreSecureAreaCredentialStoreTest {

StorageEngine mStorageEngine;

KeystoreEngine mKeystoreEngine;
SecureArea mSecureArea;

KeystoreEngineRepository mKeystoreEngineRepository;
SecureAreaRepository mSecureAreaRepository;

@Before
public void setup() {
Context context = androidx.test.InstrumentationRegistry.getTargetContext();
File storageDir = new File(context.getDataDir(), "ic-testing");
mStorageEngine = new AndroidStorageEngine.Builder(context, storageDir).build();

mKeystoreEngineRepository = new KeystoreEngineRepository();
mKeystoreEngine = new AndroidKeystore(context, mStorageEngine);
mKeystoreEngineRepository.addImplementation(mKeystoreEngine);
mSecureAreaRepository = new SecureAreaRepository();
mSecureArea = new AndroidKeystoreSecureArea(context, mStorageEngine);
mSecureAreaRepository.addImplementation(mSecureArea);
}

@Test
public void testBasic() throws IOException {

CredentialStore credentialStore = new CredentialStore(
mStorageEngine,
mKeystoreEngineRepository);
mSecureAreaRepository);

byte[] credentialKeyAttestationChallenge = new byte[] {10, 11, 12};

Credential credential = credentialStore.createCredential(
"testCredential",
new AndroidKeystore.CreateKeySettings.Builder(credentialKeyAttestationChallenge).build());
new AndroidKeystoreSecureArea.CreateKeySettings.Builder(credentialKeyAttestationChallenge).build());
Assert.assertEquals("testCredential", credential.getName());
List<X509Certificate> certChain = credential.getAttestation();

Expand All @@ -82,8 +82,10 @@ public void testBasic() throws IOException {
// Create pending authentication key and check its attestation
byte[] authKeyChallenge = new byte[] {20, 21, 22};
Credential.PendingAuthenticationKey pendingAuthenticationKey =
credential.createPendingAuthenticationKey(new AndroidKeystore.CreateKeySettings.Builder(authKeyChallenge)
.setUserAuthenticationRequired(true, 30*1000)
credential.createPendingAuthenticationKey(new AndroidKeystoreSecureArea.CreateKeySettings.Builder(authKeyChallenge)
.setUserAuthenticationRequired(true, 30*1000,
AndroidKeystoreSecureArea.USER_AUTHENTICATION_TYPE_LSKF
| AndroidKeystoreSecureArea.USER_AUTHENTICATION_TYPE_BIOMETRIC)
.build(),
null);
parser = new AndroidAttestationExtensionParser(pendingAuthenticationKey.getAttestation().get(0));
Expand All @@ -107,7 +109,7 @@ public void testBasic() throws IOException {
// Check creating a credential with an existing name overwrites the existing one
credential = credentialStore.createCredential(
"testCredential",
new AndroidKeystore.CreateKeySettings.Builder(credentialKeyAttestationChallenge).build());
new AndroidKeystoreSecureArea.CreateKeySettings.Builder(credentialKeyAttestationChallenge).build());
Assert.assertEquals("testCredential", credential.getName());
// At least the leaf certificate should be different
List<X509Certificate> certChain3 = credential.getAttestation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,8 @@ public void onDeviceDisconnected(boolean transportSpecificTermination) {

@Override
public void onError(@NonNull Throwable error) {
Assert.assertEquals("Error decoding EReaderKey in SessionEstablishment",
Assert.assertEquals(
"Error decoding EReaderKey in SessionEstablishment, returning status 10",
error.getMessage());
condVarDecryptionErrorReceived.open();
}
Expand Down
Loading

0 comments on commit 9798871

Please sign in to comment.