diff --git a/identity/aidl/Android.bp b/identity/aidl/Android.bp index 7298c7df44..14aef8ee40 100644 --- a/identity/aidl/Android.bp +++ b/identity/aidl/Android.bp @@ -18,5 +18,8 @@ aidl_interface { }, }, }, - versions: ["1"], + versions: [ + "1", + "2", + ], } diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/.hash b/identity/aidl/aidl_api/android.hardware.identity/2/.hash new file mode 100644 index 0000000000..1b2c1b6cdc --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/2/.hash @@ -0,0 +1 @@ +3b0b10b618dbc4bf283aa2bf78833ad3de0a5928 diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/Certificate.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/Certificate.aidl new file mode 100644 index 0000000000..7e3002d70a --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/Certificate.aidl @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +parcelable Certificate { + byte[] encodedCertificate; +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/CipherSuite.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/CipherSuite.aidl new file mode 100644 index 0000000000..447203faa6 --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/CipherSuite.aidl @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@Backing(type="int") @VintfStability +enum CipherSuite { + CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 = 1, +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/HardwareInformation.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/HardwareInformation.aidl new file mode 100644 index 0000000000..e1296e05e8 --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/HardwareInformation.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +parcelable HardwareInformation { + @utf8InCpp String credentialStoreName; + @utf8InCpp String credentialStoreAuthorName; + int dataChunkSize; + boolean isDirectAccess; + @utf8InCpp String[] supportedDocTypes; +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredential.aidl new file mode 100644 index 0000000000..e8e93f82f4 --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredential.aidl @@ -0,0 +1,31 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +interface IIdentityCredential { + byte[] deleteCredential(); + byte[] createEphemeralKeyPair(); + void setReaderEphemeralPublicKey(in byte[] publicKey); + long createAuthChallenge(); + void startRetrieval(in android.hardware.identity.SecureAccessControlProfile[] accessControlProfiles, in android.hardware.keymaster.HardwareAuthToken authToken, in byte[] itemsRequest, in byte[] signingKeyBlob, in byte[] sessionTranscript, in byte[] readerSignature, in int[] requestCounts); + void startRetrieveEntryValue(in @utf8InCpp String nameSpace, in @utf8InCpp String name, in int entrySize, in int[] accessControlProfileIds); + byte[] retrieveEntryValue(in byte[] encryptedContent); + void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces); + android.hardware.identity.Certificate generateSigningKeyPair(out byte[] signingKeyBlob); + void setRequestedNamespaces(in android.hardware.identity.RequestNamespace[] requestNamespaces); +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredentialStore.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredentialStore.aidl new file mode 100644 index 0000000000..5dafb76d1c --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredentialStore.aidl @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +interface IIdentityCredentialStore { + android.hardware.identity.HardwareInformation getHardwareInformation(); + android.hardware.identity.IWritableIdentityCredential createCredential(in @utf8InCpp String docType, in boolean testCredential); + android.hardware.identity.IIdentityCredential getCredential(in android.hardware.identity.CipherSuite cipherSuite, in byte[] credentialData); + const int STATUS_OK = 0; + const int STATUS_FAILED = 1; + const int STATUS_CIPHER_SUITE_NOT_SUPPORTED = 2; + const int STATUS_INVALID_DATA = 3; + const int STATUS_INVALID_AUTH_TOKEN = 4; + const int STATUS_INVALID_ITEMS_REQUEST_MESSAGE = 5; + const int STATUS_READER_SIGNATURE_CHECK_FAILED = 6; + const int STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND = 7; + const int STATUS_USER_AUTHENTICATION_FAILED = 8; + const int STATUS_READER_AUTHENTICATION_FAILED = 9; + const int STATUS_NO_ACCESS_CONTROL_PROFILES = 10; + const int STATUS_NOT_IN_REQUEST_MESSAGE = 11; + const int STATUS_SESSION_TRANSCRIPT_MISMATCH = 12; +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IWritableIdentityCredential.aidl new file mode 100644 index 0000000000..c5ac9d6340 --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IWritableIdentityCredential.aidl @@ -0,0 +1,28 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +interface IWritableIdentityCredential { + android.hardware.identity.Certificate[] getAttestationCertificate(in byte[] attestationApplicationId, in byte[] attestationChallenge); + void startPersonalization(in int accessControlProfileCount, in int[] entryCounts); + android.hardware.identity.SecureAccessControlProfile addAccessControlProfile(in int id, in android.hardware.identity.Certificate readerCertificate, in boolean userAuthenticationRequired, in long timeoutMillis, in long secureUserId); + void beginAddEntry(in int[] accessControlProfileIds, in @utf8InCpp String nameSpace, in @utf8InCpp String name, in int entrySize); + byte[] addEntryValue(in byte[] content); + void finishAddingEntries(out byte[] credentialData, out byte[] proofOfProvisioningSignature); + void setExpectedProofOfProvisioningSize(in int expectedProofOfProvisioningSize); +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/RequestDataItem.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/RequestDataItem.aidl new file mode 100644 index 0000000000..24ec26afdb --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/RequestDataItem.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +parcelable RequestDataItem { + @utf8InCpp String name; + long size; + int[] accessControlProfileIds; +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/RequestNamespace.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/RequestNamespace.aidl new file mode 100644 index 0000000000..af00f3bb62 --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/RequestNamespace.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +parcelable RequestNamespace { + @utf8InCpp String namespaceName; + android.hardware.identity.RequestDataItem[] items; +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/SecureAccessControlProfile.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/SecureAccessControlProfile.aidl new file mode 100644 index 0000000000..dfc1ad0681 --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/SecureAccessControlProfile.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +parcelable SecureAccessControlProfile { + int id; + android.hardware.identity.Certificate readerCertificate; + boolean userAuthenticationRequired; + long timeoutMillis; + long secureUserId; + byte[] mac; +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl index 58b90b54be..e8e93f82f4 100644 --- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl +++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl @@ -27,4 +27,5 @@ interface IIdentityCredential { byte[] retrieveEntryValue(in byte[] encryptedContent); void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces); android.hardware.identity.Certificate generateSigningKeyPair(out byte[] signingKeyBlob); + void setRequestedNamespaces(in android.hardware.identity.RequestNamespace[] requestNamespaces); } diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl index 32f283cc18..c5ac9d6340 100644 --- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl +++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl @@ -24,4 +24,5 @@ interface IWritableIdentityCredential { void beginAddEntry(in int[] accessControlProfileIds, in @utf8InCpp String nameSpace, in @utf8InCpp String name, in int entrySize); byte[] addEntryValue(in byte[] content); void finishAddingEntries(out byte[] credentialData, out byte[] proofOfProvisioningSignature); + void setExpectedProofOfProvisioningSize(in int expectedProofOfProvisioningSize); } diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestDataItem.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestDataItem.aidl new file mode 100644 index 0000000000..24ec26afdb --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestDataItem.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +parcelable RequestDataItem { + @utf8InCpp String name; + long size; + int[] accessControlProfileIds; +} diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestNamespace.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestNamespace.aidl new file mode 100644 index 0000000000..af00f3bb62 --- /dev/null +++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestNamespace.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.identity; +@VintfStability +parcelable RequestNamespace { + @utf8InCpp String namespaceName; + android.hardware.identity.RequestDataItem[] items; +} diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl index 7d14f03b1f..7cd25e6942 100644 --- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl +++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl @@ -17,6 +17,7 @@ package android.hardware.identity; import android.hardware.identity.Certificate; +import android.hardware.identity.RequestNamespace; import android.hardware.identity.SecureAccessControlProfile; import android.hardware.keymaster.HardwareAuthToken; @@ -82,6 +83,8 @@ interface IIdentityCredential { /** * Start an entry retrieval process. * + * The setRequestedNamespaces() method will be called before this method. + * * This method be called after createEphemeralKeyPair(), setReaderEphemeralPublicKey(), * createAuthChallenge() and before startRetrieveEntry(). This method call is followed by * multiple calls of startRetrieveEntryValue(), retrieveEntryValue(), and finally @@ -274,7 +277,7 @@ interface IIdentityCredential { * "DeviceAuthentication", * SessionTranscript, * DocType, - * DeviceNameSpaceBytes, + * DeviceNameSpacesBytes, * ] * * DocType = tstr @@ -343,4 +346,16 @@ interface IIdentityCredential { * @return an X.509 certificate for the new signing key, signed by the credential key. */ Certificate generateSigningKeyPair(out byte[] signingKeyBlob); + + /** + * Sets the namespaces and data items (including their size and access control profiles) + * which will be requested. This method must be called before startRetrieval() is called. + * + * This information is provided to make it possible for a HAL implementation to + * incrementally build up cryptographically authenticated data which includes the + * DeviceNameSpaces CBOR. + * + * @param requestNamespaces Namespaces and data items which will be requested. + */ + void setRequestedNamespaces(in RequestNamespace[] requestNamespaces); } diff --git a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl index 07486e6001..b7ad283bf8 100644 --- a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl +++ b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl @@ -120,6 +120,8 @@ interface IWritableIdentityCredential { * * startPersonalization must not be called more than once. * + * The setExpectedProofOfProvisioningSize() method will be called before this method. + * * @param accessControlProfileCount specifies the number of access control profiles that will * be provisioned with addAccessControlProfile(). * @@ -288,4 +290,16 @@ interface IWritableIdentityCredential { */ void finishAddingEntries(out byte[] credentialData, out byte[] proofOfProvisioningSignature); + + /** + * Sets the expected size of the ProofOfProvisioning returned by finishAddingEntries(). This + * method must be called before startPersonalization() is called. + * + * This information is provided to make it possible for a HAL implementation to + * incrementally build up cryptographically authenticated data which includes the + * ProofOfProvisioning CBOR. + * + * @param expectedProofOfProvisioningSize the expected size of ProofOfProvisioning. + */ + void setExpectedProofOfProvisioningSize(in int expectedProofOfProvisioningSize); } diff --git a/identity/aidl/android/hardware/identity/RequestDataItem.aidl b/identity/aidl/android/hardware/identity/RequestDataItem.aidl new file mode 100644 index 0000000000..05bc7624c9 --- /dev/null +++ b/identity/aidl/android/hardware/identity/RequestDataItem.aidl @@ -0,0 +1,38 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.identity; + +@VintfStability +parcelable RequestDataItem { + /** + * The data item name being requested, for example "driving_privileges". + */ + @utf8InCpp String name; + + /** + * The size of the data item value. + * + * Data item values are always encoded as CBOR so this is the length of + * the CBOR encoding of the value. + */ + long size; + + /** + * The access control profile ids this data item is configured with. + */ + int[] accessControlProfileIds; +} diff --git a/identity/aidl/android/hardware/identity/RequestNamespace.aidl b/identity/aidl/android/hardware/identity/RequestNamespace.aidl new file mode 100644 index 0000000000..4d615067e3 --- /dev/null +++ b/identity/aidl/android/hardware/identity/RequestNamespace.aidl @@ -0,0 +1,33 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.identity; + +import android.hardware.identity.RequestDataItem; + +@VintfStability +parcelable RequestNamespace { + /** + * The name of the namespace that items are being requested from, for + * example "org.iso.18013.5.1". + */ + @utf8InCpp String namespaceName; + + /** + * The data items requested. + */ + RequestDataItem[] items; +} diff --git a/identity/aidl/default/IdentityCredential.cpp b/identity/aidl/default/IdentityCredential.cpp index aaae1f6ae5..ff4107a7b4 100644 --- a/identity/aidl/default/IdentityCredential.cpp +++ b/identity/aidl/default/IdentityCredential.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -32,6 +33,7 @@ namespace aidl::android::hardware::identity { using ::aidl::android::hardware::keymaster::Timestamp; +using ::android::base::StringPrintf; using ::std::optional; using namespace ::android::hardware::identity; @@ -253,6 +255,12 @@ bool checkUserAuthentication(const SecureAccessControlProfile& profile, return true; } +ndk::ScopedAStatus IdentityCredential::setRequestedNamespaces( + const vector& requestNamespaces) { + requestNamespaces_ = requestNamespaces; + return ndk::ScopedAStatus::ok(); +} + ndk::ScopedAStatus IdentityCredential::startRetrieval( const vector& accessControlProfiles, const HardwareAuthToken& authToken, const vector& itemsRequest, @@ -447,7 +455,7 @@ ndk::ScopedAStatus IdentityCredential::startRetrieval( "Type mismatch in nameSpaces map")); } string requestedNamespace = nsKey->value(); - vector requestedKeys; + set requestedKeys; for (size_t m = 0; m < nsInnerMap->size(); m++) { const auto& [innerMapKeyItem, innerMapValueItem] = (*nsInnerMap)[m]; const cppbor::Tstr* nameItem = innerMapKeyItem->asTstr(); @@ -459,13 +467,13 @@ ndk::ScopedAStatus IdentityCredential::startRetrieval( IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE, "Type mismatch in value in nameSpaces map")); } - requestedKeys.push_back(nameItem->value()); + requestedKeys.insert(nameItem->value()); } requestedNameSpacesAndNames_[requestedNamespace] = requestedKeys; } } - // Finally, validate all the access control profiles in the requestData. + // Validate all the access control profiles in the requestData. bool haveAuthToken = (authToken.mac.size() > 0); for (const auto& profile : accessControlProfiles) { if (!secureAccessControlProfileCheckMac(profile, storageKey_)) { @@ -496,10 +504,118 @@ ndk::ScopedAStatus IdentityCredential::startRetrieval( itemsRequest_ = itemsRequest; signingKeyBlob_ = signingKeyBlob; + // Finally, calculate the size of DeviceNameSpaces. We need to know it ahead of time. + expectedDeviceNameSpacesSize_ = calcDeviceNameSpacesSize(); + numStartRetrievalCalls_ += 1; return ndk::ScopedAStatus::ok(); } +size_t cborNumBytesForLength(size_t length) { + if (length < 24) { + return 0; + } else if (length <= 0xff) { + return 1; + } else if (length <= 0xffff) { + return 2; + } else if (length <= 0xffffffff) { + return 4; + } + return 8; +} + +size_t cborNumBytesForTstr(const string& value) { + return 1 + cborNumBytesForLength(value.size()) + value.size(); +} + +size_t IdentityCredential::calcDeviceNameSpacesSize() { + /* + * This is how DeviceNameSpaces is defined: + * + * DeviceNameSpaces = { + * * NameSpace => DeviceSignedItems + * } + * DeviceSignedItems = { + * + DataItemName => DataItemValue + * } + * + * Namespace = tstr + * DataItemName = tstr + * DataItemValue = any + * + * This function will calculate its length using knowledge of how CBOR is + * encoded. + */ + size_t ret = 0; + size_t numNamespacesWithValues = 0; + for (const RequestNamespace& rns : requestNamespaces_) { + vector itemsToInclude; + + for (const RequestDataItem& rdi : rns.items) { + // If we have a CBOR request message, skip if item isn't in it + if (itemsRequest_.size() > 0) { + const auto& it = requestedNameSpacesAndNames_.find(rns.namespaceName); + if (it == requestedNameSpacesAndNames_.end()) { + continue; + } + const set& dataItemNames = it->second; + if (dataItemNames.find(rdi.name) == dataItemNames.end()) { + continue; + } + } + + // Access is granted if at least one of the profiles grants access. + // + // If an item is configured without any profiles, access is denied. + // + bool authorized = false; + for (auto id : rdi.accessControlProfileIds) { + auto it = profileIdToAccessCheckResult_.find(id); + if (it != profileIdToAccessCheckResult_.end()) { + int accessControlForProfile = it->second; + if (accessControlForProfile == IIdentityCredentialStore::STATUS_OK) { + authorized = true; + break; + } + } + } + if (!authorized) { + continue; + } + + itemsToInclude.push_back(rdi); + } + + // If no entries are to be in the namespace, we don't include it... + if (itemsToInclude.size() == 0) { + continue; + } + + // Key: NameSpace + ret += cborNumBytesForTstr(rns.namespaceName); + + // Value: Open the DeviceSignedItems map + ret += 1 + cborNumBytesForLength(itemsToInclude.size()); + + for (const RequestDataItem& item : itemsToInclude) { + // Key: DataItemName + ret += cborNumBytesForTstr(item.name); + + // Value: DataItemValue - entryData.size is the length of serialized CBOR so we use + // that. + ret += item.size; + } + + numNamespacesWithValues++; + } + + // Now that we now the nunber of namespaces with values, we know how many + // bytes the DeviceNamespaces map in the beginning is going to take up. + ret += 1 + cborNumBytesForLength(numNamespacesWithValues); + + return ret; +} + ndk::ScopedAStatus IdentityCredential::startRetrieveEntryValue( const string& nameSpace, const string& name, int32_t entrySize, const vector& accessControlProfileIds) { @@ -558,8 +674,8 @@ ndk::ScopedAStatus IdentityCredential::startRetrieveEntryValue( IIdentityCredentialStore::STATUS_NOT_IN_REQUEST_MESSAGE, "Name space was not requested in startRetrieval")); } - const auto& dataItemNames = it->second; - if (std::find(dataItemNames.begin(), dataItemNames.end(), name) == dataItemNames.end()) { + const set& dataItemNames = it->second; + if (dataItemNames.find(name) == dataItemNames.end()) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_NOT_IN_REQUEST_MESSAGE, "Data item name in name space was not requested in startRetrieval")); @@ -653,6 +769,17 @@ ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector* outMac, } vector encodedDeviceNameSpaces = deviceNameSpacesMap_.encode(); + if (encodedDeviceNameSpaces.size() != expectedDeviceNameSpacesSize_) { + LOG(ERROR) << "encodedDeviceNameSpaces is " << encodedDeviceNameSpaces.size() << " bytes, " + << "was expecting " << expectedDeviceNameSpacesSize_; + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + IIdentityCredentialStore::STATUS_INVALID_DATA, + StringPrintf( + "Unexpected CBOR size %zd for encodedDeviceNameSpaces, was expecting %zd", + encodedDeviceNameSpaces.size(), expectedDeviceNameSpacesSize_) + .c_str())); + } + // If there's no signing key or no sessionTranscript or no reader ephemeral // public key, we return the empty MAC. optional> mac; diff --git a/identity/aidl/default/IdentityCredential.h b/identity/aidl/default/IdentityCredential.h index 6072afe04f..a8bad88f8f 100644 --- a/identity/aidl/default/IdentityCredential.h +++ b/identity/aidl/default/IdentityCredential.h @@ -32,15 +32,17 @@ namespace aidl::android::hardware::identity { using ::aidl::android::hardware::keymaster::HardwareAuthToken; using ::std::map; +using ::std::set; using ::std::string; using ::std::vector; -using MapStringToVectorOfStrings = map>; - class IdentityCredential : public BnIdentityCredential { public: IdentityCredential(const vector& credentialData) - : credentialData_(credentialData), numStartRetrievalCalls_(0), authChallenge_(0) {} + : credentialData_(credentialData), + numStartRetrievalCalls_(0), + authChallenge_(0), + expectedDeviceNameSpacesSize_(0) {} // Parses and decrypts credentialData_, return a status code from // IIdentityCredentialStore. Must be called right after construction. @@ -51,6 +53,8 @@ class IdentityCredential : public BnIdentityCredential { ndk::ScopedAStatus createEphemeralKeyPair(vector* outKeyPair) override; ndk::ScopedAStatus setReaderEphemeralPublicKey(const vector& publicKey) override; ndk::ScopedAStatus createAuthChallenge(int64_t* outChallenge) override; + ndk::ScopedAStatus setRequestedNamespaces( + const vector& requestNamespaces) override; ndk::ScopedAStatus startRetrieval( const vector& accessControlProfiles, const HardwareAuthToken& authToken, const vector& itemsRequest, @@ -86,6 +90,9 @@ class IdentityCredential : public BnIdentityCredential { // Set by createAuthChallenge() uint64_t authChallenge_; + // Set by setRequestedNamespaces() + vector requestNamespaces_; + // Set at startRetrieval() time. map profileIdToAccessCheckResult_; vector signingKeyBlob_; @@ -93,16 +100,21 @@ class IdentityCredential : public BnIdentityCredential { std::unique_ptr sessionTranscriptItem_; vector itemsRequest_; vector requestCountsRemaining_; - MapStringToVectorOfStrings requestedNameSpacesAndNames_; + map> requestedNameSpacesAndNames_; cppbor::Map deviceNameSpacesMap_; cppbor::Map currentNameSpaceDeviceNameSpacesMap_; + // Calculated at startRetrieval() time. + size_t expectedDeviceNameSpacesSize_; + // Set at startRetrieveEntryValue() time. string currentNameSpace_; string currentName_; size_t entryRemainingBytes_; vector entryValue_; vector entryAdditionalData_; + + size_t calcDeviceNameSpacesSize(); }; } // namespace aidl::android::hardware::identity diff --git a/identity/aidl/default/WritableIdentityCredential.cpp b/identity/aidl/default/WritableIdentityCredential.cpp index b3924447b2..8bc4b49a79 100644 --- a/identity/aidl/default/WritableIdentityCredential.cpp +++ b/identity/aidl/default/WritableIdentityCredential.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -34,6 +35,7 @@ namespace aidl::android::hardware::identity { +using ::android::base::StringPrintf; using ::std::optional; using namespace ::android::hardware::identity; @@ -105,6 +107,12 @@ ndk::ScopedAStatus WritableIdentityCredential::getAttestationCertificate( return ndk::ScopedAStatus::ok(); } +ndk::ScopedAStatus WritableIdentityCredential::setExpectedProofOfProvisioningSize( + int32_t expectedProofOfProvisioningSize) { + expectedProofOfProvisioningSize_ = expectedProofOfProvisioningSize; + return ndk::ScopedAStatus::ok(); +} + ndk::ScopedAStatus WritableIdentityCredential::startPersonalization( int32_t accessControlProfileCount, const vector& entryCounts) { if (startPersonalizationCalled_) { @@ -382,6 +390,16 @@ ndk::ScopedAStatus WritableIdentityCredential::finishAddingEntries( .add(testCredential_); vector encodedCbor = popArray.encode(); + if (encodedCbor.size() != expectedProofOfProvisioningSize_) { + LOG(ERROR) << "CBOR for proofOfProvisioning is " << encodedCbor.size() << " bytes, " + << "was expecting " << expectedProofOfProvisioningSize_; + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + IIdentityCredentialStore::STATUS_INVALID_DATA, + StringPrintf("Unexpected CBOR size %zd for proofOfProvisioning, was expecting %zd", + encodedCbor.size(), expectedProofOfProvisioningSize_) + .c_str())); + } + optional> signature = support::coseSignEcDsa(credentialPrivKey_, encodedCbor, // payload {}, // additionalData diff --git a/identity/aidl/default/WritableIdentityCredential.h b/identity/aidl/default/WritableIdentityCredential.h index 976686ad25..56458520c1 100644 --- a/identity/aidl/default/WritableIdentityCredential.h +++ b/identity/aidl/default/WritableIdentityCredential.h @@ -43,6 +43,9 @@ class WritableIdentityCredential : public BnWritableIdentityCredential { const vector& attestationChallenge, vector* outCertificateChain) override; + ndk::ScopedAStatus setExpectedProofOfProvisioningSize( + int32_t expectedProofOfProvisioningSize) override; + ndk::ScopedAStatus startPersonalization(int32_t accessControlProfileCount, const vector& entryCounts) override; @@ -62,7 +65,7 @@ class WritableIdentityCredential : public BnWritableIdentityCredential { vector* outCredentialData, vector* outProofOfProvisioningSignature) override; - // private: + private: string docType_; bool testCredential_; @@ -82,6 +85,7 @@ class WritableIdentityCredential : public BnWritableIdentityCredential { cppbor::Array signedDataAccessControlProfiles_; cppbor::Map signedDataNamespaces_; cppbor::Array signedDataCurrentNamespace_; + size_t expectedProofOfProvisioningSize_; // This field is initialized in addAccessControlProfile set accessControlProfileIds_; diff --git a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp index 8a4e8a7fa1..807feabf80 100644 --- a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp +++ b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp @@ -112,6 +112,11 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { // TODO: set it to something random and check it's in the cert chain ASSERT_GE(attData.attestationCertificate.size(), 2); + // This is kinda of a hack but we need to give the size of + // ProofOfProvisioning that we'll expect to receive. + const int32_t expectedProofOfProvisioningSize = 262861 - 326 + readerCertificate.value().size(); + // OK to fail, not available in v1 HAL + writableCredential->setExpectedProofOfProvisioningSize(expectedProofOfProvisioningSize); ASSERT_TRUE( writableCredential->startPersonalization(testProfiles.size(), testEntriesEntryCounts) .isOk()); @@ -268,6 +273,8 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { Certificate signingKeyCertificate; ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk()); + vector requestedNamespaces = test_utils::buildRequestNamespaces(testEntries); + ASSERT_TRUE(credential->setRequestedNamespaces(requestedNamespaces).isOk()); ASSERT_TRUE(credential ->startRetrieval(secureProfiles.value(), authToken, itemsRequestBytes, signingKeyBlob, sessionTranscriptBytes, diff --git a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp index b68fbb54f1..724aaa1643 100644 --- a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp +++ b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp @@ -279,14 +279,17 @@ TEST_P(IdentityCredentialTests, verifyOneProfileAndEntryPass) { EXPECT_TRUE(attData.result.isOk()) << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl; - const vector entryCounts = {1u}; - writableCredential->startPersonalization(1, entryCounts); - ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() - << endl; - optional> readerCertificate1 = test_utils::GenerateReaderCertificate("123456"); ASSERT_TRUE(readerCertificate1); + const vector entryCounts = {1u}; + size_t expectedPoPSize = 186 + readerCertificate1.value().size(); + // OK to fail, not available in v1 HAL + writableCredential->setExpectedProofOfProvisioningSize(expectedPoPSize); + result = writableCredential->startPersonalization(1, entryCounts); + ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + const vector testProfiles = {{1, readerCertificate1.value(), true, 1}}; optional> secureProfiles = @@ -374,7 +377,11 @@ TEST_P(IdentityCredentialTests, verifyManyProfilesAndEntriesPass) { {2, readerCertificate2.value(), true, 2}, }; const vector entryCounts = {1u, 3u, 1u, 1u, 2u}; - writableCredential->startPersonalization(testProfiles.size(), entryCounts); + size_t expectedPoPSize = + 525021 + readerCertificate1.value().size() + readerCertificate2.value().size(); + // OK to fail, not available in v1 HAL + writableCredential->setExpectedProofOfProvisioningSize(expectedPoPSize); + result = writableCredential->startPersonalization(testProfiles.size(), entryCounts); ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; @@ -518,11 +525,6 @@ TEST_P(IdentityCredentialTests, verifyEmptyNameSpaceMixedWithNonEmptyWorks) { ASSERT_TRUE(attData.result.isOk()) << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl; - const vector entryCounts = {2u, 2u}; - writableCredential->startPersonalization(3, entryCounts); - ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() - << endl; - optional> readerCertificate1 = test_utils::GenerateReaderCertificate("123456"); ASSERT_TRUE(readerCertificate1); @@ -530,6 +532,16 @@ TEST_P(IdentityCredentialTests, verifyEmptyNameSpaceMixedWithNonEmptyWorks) { test_utils::GenerateReaderCertificate("123456987987987987987987"); ASSERT_TRUE(readerCertificate2); + const vector entryCounts = {2u, 2u}; + size_t expectedPoPSize = + 377 + readerCertificate1.value().size() + readerCertificate2.value().size(); + ; + // OK to fail, not available in v1 HAL + writableCredential->setExpectedProofOfProvisioningSize(expectedPoPSize); + writableCredential->startPersonalization(3, entryCounts); + ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + const vector testProfiles = {{0, readerCertificate1.value(), false, 0}, {1, readerCertificate2.value(), true, 1}, {2, {}, false, 0}}; diff --git a/identity/aidl/vts/VtsIdentityTestUtils.cpp b/identity/aidl/vts/VtsIdentityTestUtils.cpp index 3aeebc66b6..48e47dc735 100644 --- a/identity/aidl/vts/VtsIdentityTestUtils.cpp +++ b/identity/aidl/vts/VtsIdentityTestUtils.cpp @@ -176,4 +176,28 @@ void SetImageData(vector& image) { } } +vector buildRequestNamespaces(const vector entries) { + vector ret; + RequestNamespace curNs; + for (const TestEntryData& testEntry : entries) { + if (testEntry.nameSpace != curNs.namespaceName) { + if (curNs.namespaceName.size() > 0) { + ret.push_back(curNs); + } + curNs.namespaceName = testEntry.nameSpace; + curNs.items.clear(); + } + + RequestDataItem item; + item.name = testEntry.name; + item.size = testEntry.valueCbor.size(); + item.accessControlProfileIds = testEntry.profileIds; + curNs.items.push_back(item); + } + if (curNs.namespaceName.size() > 0) { + ret.push_back(curNs); + } + return ret; +} + } // namespace android::hardware::identity::test_utils diff --git a/identity/aidl/vts/VtsIdentityTestUtils.h b/identity/aidl/vts/VtsIdentityTestUtils.h index 043ccd6905..9e1f35271d 100644 --- a/identity/aidl/vts/VtsIdentityTestUtils.h +++ b/identity/aidl/vts/VtsIdentityTestUtils.h @@ -113,6 +113,8 @@ bool ValidateAttestationCertificate(vector& inputCertificates); void SetImageData(vector& image); +vector buildRequestNamespaces(const vector entries); + } // namespace android::hardware::identity::test_utils #endif // VTS_IDENTITY_TEST_UTILS_H