Add Identity Credential HAL, default implementation, and VTS tests.
IIdentityCredentialStore provides an interface to a secure store for
user identity documents. This HAL is deliberately fairly general and
abstract. To the extent possible, specification of the message
formats and semantics of communication with credential verification
devices and issuing authorities (IAs) is out of scope for this HAL.
It provides the interface with secure storage but a
credential-specific Android application will be required to implement
the presentation and verification protocols and processes appropriate
for the specific credential type.
Bug: 111446262
Test: VtsHalIdentityCredentialTargetTest
Test: android.hardware.identity-support-lib-test
Test: CtsIdentityTestCases
Change-Id: I64eb50114d645dd475012ad1b889d2177aaf1d37
diff --git a/identity/1.0/IWritableIdentityCredential.hal b/identity/1.0/IWritableIdentityCredential.hal
new file mode 100644
index 0000000..b1ce00d
--- /dev/null
+++ b/identity/1.0/IWritableIdentityCredential.hal
@@ -0,0 +1,236 @@
+/*
+ * 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@1.0;
+
+/**
+ * IWritableIdentityCredential is used to personalize a new identity credential. Credentials cannot
+ * be updated or modified after creation; any changes require deletion and re-creation.
+ */
+interface IWritableIdentityCredential {
+ /**
+ * Gets the certificate chain for credentialKey which can be used to prove the hardware
+ * characteristics to an issuing authority. Must not be called more than once.
+ *
+ * The certificate chain must be generated using Keymaster Attestation
+ * (see https://source.android.com/security/keystore/attestation) and must also
+ * have the Tag::IDENTITY_CREDENTIAL_KEY tag from KeyMaster 4.1 set. This tag indicates
+ * that this key is an Identity Credential key (which can only sign/MAC very
+ * specific messages) and not an Android Keystore key (which can be used to sign/MAC
+ * anything).
+ *
+ * @param attestationChallenge a challenge set by the issuer to ensure freshness.
+ *
+ * @return result is OK on success, FAILED if an error occurred.
+ *
+ * @return certificate is the X.509 certificate chain for the credentialKey
+ */
+ getAttestationCertificate(vec<uint8_t> attestationChallenge)
+ generates(Result result, vec<uint8_t> certificate);
+
+ /**
+ * Start the personalization process.
+ *
+ * startPersonalization must not be called more than once.
+ *
+ * @param accessControlProfileCount specifies the number of access control profiles that will be
+ * provisioned with addAccessControlProfile().
+ *
+ * @param entryCounts specifies the number of data entries that will be provisioned with
+ * beginAddEntry() and addEntry(). Each item in the array specifies how many entries
+ * will be added for each name space.
+ *
+ * @return result is OK on success, FAILED if an error occurred.
+ *
+ */
+ startPersonalization(uint16_t accessControlProfileCount, vec<uint16_t> entryCounts)
+ generates(Result result);
+
+ /**
+ * Add an access control profile, which defines the requirements or retrieval of one or more
+ * entries. If both readerCertificate and userAuthenticationRequired are empty/false,
+ * associated entries are open access, requiring no authentication to read (though the caller
+ * is free to require other authentication above this HAL).
+ *
+ * This method must be called exactly as many times as specified in the startPersonalization()
+ * accessControlProfileCount parameter. If this is requirement is not met, the method fails
+ * with INVALID_DATA.
+ *
+ * @param id a numeric identifier that must be unique within the context of a Credential and may
+ * be used to reference the profile. If this is not satisfied the call fails with
+ * INVALID_DATA.
+ *
+ * @param readerCertificate if non-empty, specifies a X.509 certificate (or chain of certificates)
+ * that must be used to authenticate requests (see the readerSignature parameter in
+ * IIdentityCredential.startRetrieval).
+ *
+ * @param userAuthenticationRequired if true, specifies that the user is required to
+ * authenticate to allow requests. Required authentication freshness is specified by
+ * timeout below.
+ *
+ * @param timeoutMillis specifies the amount of time, in milliseconds, for which a user
+ * authentication (see userAuthenticationRequired above) is valid, if
+ * userAuthenticationRequired is true. If the timout is zero then authentication is
+ * required for each reader session. If userAuthenticationRequired is false, the timeout
+ * must be zero. If this requirement is not met the call fails with INVALID_DATA.
+ *
+ * @param secureUserId must be non-zero if userAuthenticationRequired is true. It is not
+ * related to any Android user ID or UID, but is created in the Gatekeeper application
+ * in the secure environment. If this requirement is not met the call fails with
+ * INVALID_DATA.
+ *
+ * @return result is OK on success, INVALID_DATA or FAILED if an error occurred.
+ *
+ * @return secureAccessControlProfile is a structure with the passed-in data and MAC created
+ * with storageKey for authenticating the data at a later point in time.
+ */
+ addAccessControlProfile(uint16_t id, vec<uint8_t> readerCertificate,
+ bool userAuthenticationRequired, uint64_t timeoutMillis,
+ uint64_t secureUserId)
+ generates(Result result, SecureAccessControlProfile secureAccessControlProfile);
+
+ /**
+ * Begins the process of adding an entry to the credential. All access control profiles must be
+ * added before calling this method. Entries must be added in namespace "groups", meaning all
+ * entries of one namespace must be added before adding entries from another namespace.
+ *
+ * This method must be called exactly as many times as the sum of the items in the entryCounts
+ * parameter specified in the startPersonalization(), and must be followed by one or more calls
+ * to addEntryValue(). If this requirement is not met the method fails with INVALID_DATA.
+ *
+ * @param accessControlProfileIds specifies the set of access control profiles that can
+ * authorize access to the provisioned element.
+ *
+ * @param nameSpace is the namespace of the element, e.g. "org.iso.18013"
+ *
+ * @param name is the name of the element.
+ *
+ * @param entrySize is the size of the entry value. If this requirement
+ * is not met this method fails with INVALID_DATA.
+ *
+ * @return result is OK on success, INVALID_DATA or FAILED if an error occurred.
+ */
+ beginAddEntry(vec<uint16_t> accessControlProfileIds, string nameSpace,
+ string name, uint32_t entrySize)
+ generates(Result result);
+
+ /**
+ * Continues the process of adding an entry, providing a value or part of a value.
+ *
+ * In the common case, this method will be called only once per entry added. In the case of
+ * values that are larger than the secure environment's GCM chunk size
+ * (see IIdentityCredentialStore.getHardwareInformation()), the caller must provide the
+ * value in chunks. All chunks must be exactly gcmChunkSize except the last and the sum of all
+ * chunk sizes must equal the value of the beginAddEntry() entrySize argument. If this
+ * requirement is not met the call fails with INVALID_DATA.
+ *
+ * @param content is the entry value, encoded as CBOR. In the case the content exceeds gcmChunkSize,
+ * this may be partial content up to gcmChunkSize bytes long.
+ *
+ * @return result is OK on success, INVALID_DATA or FAILED if an error occurred.
+ *
+ * @return encryptedContent contains the encrypted and MACed content. For directly-available
+ * credentials the contents are implementation-defined but must not exceed 32 bytes in
+ * length.
+ *
+ * For other credentials, encryptedContent contains:
+ *
+ * AES-GCM-ENC(storageKey, R, Data, AdditionalData)
+ *
+ * where:
+ *
+ * Data = any ; value
+ *
+ * AdditionalData = {
+ * "Namespace" : tstr,
+ * "Name" : tstr,
+ * "AccessControlProfileIds" : [ + uint ],
+ * }
+ */
+ addEntryValue(vec<uint8_t> content)
+ generates(Result result, vec<uint8_t> encryptedContent);
+
+ /**
+ * Finishes adding entries and returns a signature that an issuing authority may use to validate
+ * that all data was provisioned correctly.
+ *
+ * After this method is called, the IWritableIdentityCredential is no longer usable.
+ *
+ * @return result is OK on success or FAILED if an error occurred.
+ *
+ * @return credentialData is a CBOR-encoded structure (in CDDL notation):
+ *
+ * CredentialData = [
+ * tstr, ; docType, an optional name that identifies the type of credential
+ * bool, ; testCredential, indicates if this is a test credential
+ * bstr ; an opaque byte vector with encrypted data, see below
+ * ]
+ *
+ * The last element is an opaque byte vector which contains encrypted copies of the
+ * secrets used to secure the new credential's data and to authenticate the credential to
+ * the issuing authority. It contains:
+ *
+ * AES-GCM-ENC(HBK, R, CredentialKeys, docType)
+ *
+ * where HBK is a unique hardware-bound key that has never existed outside of the secure
+ * environment (except it's all zeroes if testCredential is True) and CredentialKeys is
+ * the CBOR-encoded structure (in CDDL notation):
+ *
+ * CredentialKeys = [
+ * bstr, ; storageKey, a 128-bit AES key
+ * bstr ; credentialPrivKey, the private key for credentialKey
+ * ]
+ *
+ * @return proofOfProvisioningSignature proves to the IA that the credential was imported into the
+ * secure hardware without alteration or error. When the final addEntry() call is made
+ * (when the number of provisioned entries equals the sum of the items in
+ * startPersonalization() entryCounts parameter), it a COSE_Sign1 structure
+ * signed by CredentialKey with payload set to the ProofOfProvisioning CBOR below:
+ *
+ * ProofOfProvisioning = [
+ * "ProofOfProvisioning",
+ * tstr, ; DocType
+ * [ * AccessControlProfile ],
+ * ProvisionedData,
+ * bool ; true if this is a test credential, should
+ * ; always be false.
+ * ]
+ *
+ * AccessControlProfile = {
+ * "id" : uint,
+ * ? "readerCertificate" : bstr,
+ * ? (
+ * "userAuthenticationRequired" : bool,
+ * "timeoutMillis" : uint,
+ * )
+ * }
+ *
+ * ProvisionedData = {
+ * * Namespace => [ + Entry ]
+ * },
+ *
+ * Namespace = tstr
+ *
+ * Entry = {
+ * "name" : tstr,
+ * "value" : any,
+ * "accessControlProfiles" : [ * uint ],
+ * }
+ */
+ finishAddingEntries()
+ generates(Result result, vec<uint8_t> credentialData,
+ vec<uint8_t> proofOfProvisioningSignature);
+};