/*
 * 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.Certificate;
import android.hardware.identity.SecureAccessControlProfile;

/**
 * IWritableIdentityCredential is used to personalize a new identity credential.  Credentials cannot
 * be updated or modified after creation; any changes require deletion and re-creation.
 */
@VintfStability
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 following non-optional fields for the X.509 certificate shall be set as follows:
     *
     *  - version: INTEGER 2 (means v3 certificate).
     *
     *  - serialNumber: INTEGER 1 (fixed value: same on all certs).
     *
     *  - signature: must be set to ECDSA.
     *
     *  - subject: CN shall be set to "Android Identity Credential Key". (fixed value:
     *    same on all certs)
     *
     *  - issuer: Same as the subject field of the batch attestation key.
     *
     *  - validity: Should be set to current time and expire at the same time as the
     *    attestation batch certificate used.
     *
     *  - subjectPublicKeyInfo: must contain attested public key.
     *
     * The certificate chain must be generated using Keymaster Attestation
     * (see https://source.android.com/security/keystore/attestation) with the
     * following additional requirements on the data in the attestation extension:
     *
     *  - The attestationVersion field in the attestation extension must be at least 3.
     *
     *  - The attestationSecurityLevel field must be set to either Software (0),
     *    TrustedEnvironment (1), or StrongBox (2) depending on how attestation is
     *    implemented.
     *
     *  - The keymasterVersion field in the attestation extension must be set to the.
     *    same value as used for Android Keystore keys.
     *
     *  - The keymasterSecurityLevel field in the attestation extension must be set to
     *    either Software (0), TrustedEnvironment (1), or StrongBox (2) depending on how
     *    the Trusted Application backing the HAL implementation is implemented.
     *
     *  - The attestationChallenge field must be set to the passed-in challenge.
     *
     *  - The uniqueId field must be empty.
     *
     *  - The softwareEnforced field in the attestation extension must include
     *    Tag::ATTESTATION_APPLICATION_ID which must be set to the bytes of the passed-in
     *    attestationApplicationId.
     *
     *  - The teeEnforced field in the attestation extension must include
     *
     *    - Tag::IDENTITY_CREDENTIAL_KEY which indicates that the 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). This must not be set
     *      for test credentials.
     *
     *    - Tag::PURPOSE must be set to SIGN
     *
     *    - Tag::KEY_SIZE must be set to the appropriate key size, in bits (e.g. 256)
     *
     *    - Tag::ALGORITHM must be set to EC
     *
     *    - Tag::NO_AUTH_REQUIRED must be set
     *
     *    - Tag::DIGEST must be set to SHA_2_256
     *
     *    - Tag::EC_CURVE must be set to P_256
     *
     *    - Tag::ROOT_OF_TRUST must be set
     *
     *    - Tag::OS_VERSION and Tag::OS_PATCHLEVEL must be set
     *
     * Additional authorizations may be appear in the softwareEnforced and teeEnforced
     * fields. For example if the device has a boot or vendor partitions, then BOOT_PATCHLEVEL
     * and VENDOR_PATCHLEVEL should be set.
     *
     * Since the chain is required to be generated using Keymaster Attestation, the returned
     * certificate chain has the following properties:
     *
     *  - The certificate chain is of at least length three.
     *
     *  - The root of trust is the same as for Keymaster Attestation. This is usually
     *    a certificate owned by Google but depending on the specific Android device it may
     *    be another certificate.
     *
     * As with any user of attestation, the Issuing Authority (as a relying party) wishing
     * to issue a credential to a device using these APIs, must carefully examine the
     * returned certificate chain for all of the above (and more). In particular, the Issuing
     * Authority should check the root of trust (which include verified boot state), patch level,
     * attestation application id, etc.
     *
     * This all depends on the needs of the Issuing Authority and the kind of credential but
     * in general an Issuing Authority should never issue a credential to a device without
     * verified boot enabled, to an unrecognized application, or if it appears the device
     * hasn't been updated for a long time.
     *
     * See https://github.com/google/android-key-attestation for an example of how to
     * examine attestations generated from Android devices.
     *
     * @param attestationApplicationId is the DER encoded value to be stored
     *     in Tag::ATTESTATION_APPLICATION_ID. This schema is described in
     *     https://developer.android.com/training/articles/security-key-attestation#certificate_schema_attestationid
     *
     * @param attestationChallenge a challenge set by the issuer to ensure freshness. If
     *    this is empty, the call fails with STATUS_INVALID_DATA.
     *
     * @return the X.509 certificate chain for the credentialKey
     */
    Certificate[] getAttestationCertificate(in byte[] attestationApplicationId, in byte[] attestationChallenge);

    /**
     * Start the personalization process.
     *
     * 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().
     *
     * @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.
     */
    void startPersonalization(in int accessControlProfileCount, in int[] entryCounts);

    /**
     * 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 STATUS_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. This id must be non-negative and less than 32 (allowing
     *     for a total of 32 profiles). If this is not satisfied the call fails with
     *     STATUS_INVALID_DATA.
     *
     * @param readerCertificate if non-empty, specifies a single X.509 certificate (not a 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 STATUS_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
     *     STATUS_INVALID_DATA.
     *
     * @return a structure with the passed-in data and MAC created with storageKey for authenticating
     *     the data at a later point in time.
     */
    SecureAccessControlProfile addAccessControlProfile(in int id, in Certificate readerCertificate,
        in boolean userAuthenticationRequired, in long timeoutMillis, in long secureUserId);

    /**
     * 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 STATUS_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.5.1"
     *
     * @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 STATUS_INVALID_DATA.
     */
    void beginAddEntry(in int[] accessControlProfileIds, in @utf8InCpp String nameSpace,
        in @utf8InCpp String name, in int entrySize);

    /**
     * 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 STATUS_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 the encrypted and MACed content.  For directly-available credentials the contents are
     *     implementation-defined. For other credentials, the result contains
     *
     *         AES-GCM-ENC(storageKey, R, Data, AdditionalData)
     *
     *     where:
     *
     *         Data = any   ; value
     *
     *         AdditionalData = {
     *             "Namespace" : tstr,
     *             "Name" : tstr,
     *             "AccessControlProfileIds" : [ + uint ],
     *         }
     */
    byte[] addEntryValue(in byte[] content);

    /**
     * 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.
     *
     * @param out 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) given below.
     *
     *     In API versions 1 and 2 it was the following
     *
     *         CredentialKeys = [
     *              bstr,   ; storageKey, a 128-bit AES key
     *              bstr    ; credentialPrivKey, the private key for credentialKey
     *                      ; in uncompressed form
     *         ]
     *
     *     In API version 3 or later it must be the following
     *
     *         CredentialKeys = [
     *              bstr,   ; storageKey, a 128-bit AES key
     *              bstr    ; credentialPrivKey, the private key for credentialKey
     *                      ; in uncompressed form
     *              bstr    ; SHA-256(ProofOfProvisioning)
     *         ]
     *
     *     Additional elements may be added to the CredentialKeys array in future versions.
     *
     * @param out 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), 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 ],
     *          }
     */
    @SuppressWarnings(value={"out-array"})
    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);

}
